Received: by 10.223.176.46 with SMTP id f43csp3899223wra; Tue, 23 Jan 2018 00:38:27 -0800 (PST) X-Google-Smtp-Source: AH8x225DSBWJ9O0awotBsb6dK+Tw1YI1fZTeYzMn/PjIEg9XtWNmdbXsAC5JHE0x3cEJLdw6DDD+ X-Received: by 10.98.218.24 with SMTP id c24mr9846289pfh.145.1516696707515; Tue, 23 Jan 2018 00:38:27 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516696707; cv=none; d=google.com; s=arc-20160816; b=EF0vLYhtn8LX0jTTCn6itbaDqn7p6eXzlx1Cx3Du5tXj5lq+TahnhrtmklGW0tGmRO scv0V0quR+nZU4ByVhSgJD2N/cLTtMqbr1ZCRTKJ3DVyLCm+AG/PgP00ZekacOuIyIR8 qQds2COXITob0C3AB1RH7rEx0h0vFaHeLmF00SjaVp8hkVy3ZKx2szsyU6oynyaM7cX+ qGqEjsU/7GeyT8maQrVFU7d3u3YI7mejXkRkb/+DZ1yQx8wDI0vvfdb+DMw4L7cSK5gL 0zlWBcmxiyWER7eQ6Et1xDev9urxPctZ618yV4GRgwpbUmH4wNeOF8/6n8y+EYAN7M4A 3M0A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date:arc-authentication-results; bh=dlXJ4CGk3Lb+8BY850GRZWaKFZhTgC+5wC1XM7nBzV0=; b=DThLXtRSuq5wpbmODvmA32jyjM367dvLCcIQVtL0QT1zkLUNpayFPLmZpVA9pGiP01 +dJxN17WEkuybAgLMblnynRE1DlLkkbEwvMcB5R+E8yhDAj6r6pcsnEyPwBpd3xxX8SB Q8dWgRNXMT7Cql2Im63GLh/ZIJaTQ8xQwkXKsBa/ZMGrGAZRSj6v3yKku9lMFdDQxFir 86tACkDh30xyLdXIgYZbkHnZ3bakiFil71JKSU0DPMM+DghJw8OEQDElrFgGC9UeTJpM yAI9Xx3knEEJirXEmoRXFBVYiGF5FEkGRnU8jBliPl5y9/4iLxta1pimkGLZ3uGMQ7un tYkA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s23si9669469pgo.378.2018.01.23.00.38.12; Tue, 23 Jan 2018 00:38:27 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751351AbeAWIhf (ORCPT + 99 others); Tue, 23 Jan 2018 03:37:35 -0500 Received: from mail.linuxfoundation.org ([140.211.169.12]:45652 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751173AbeAWIhd (ORCPT ); Tue, 23 Jan 2018 03:37:33 -0500 Received: from localhost (LFbn-1-12258-90.w90-92.abo.wanadoo.fr [90.92.71.90]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 2252C109A; Tue, 23 Jan 2018 08:37:32 +0000 (UTC) Date: Tue, 23 Jan 2018 09:37:32 +0100 From: Greg KH To: Jolly Shah Cc: ard.biesheuvel@linaro.org, mingo@kernel.org, matt@codeblueprint.co.uk, sudeep.holla@arm.com, hkallweit1@gmail.com, keescook@chromium.org, dmitry.torokhov@gmail.com, michal.simek@xilinx.com, robh+dt@kernel.org, mark.rutland@arm.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, rajanv@xilinx.com, Jolly Shah Subject: Re: [PATCH v2 3/4] drivers: firmware: xilinx: Add sysfs interface Message-ID: <20180123083732.GA21463@kroah.com> References: <1516220434-22204-1-git-send-email-jollys@xilinx.com> <1516220434-22204-4-git-send-email-jollys@xilinx.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1516220434-22204-4-git-send-email-jollys@xilinx.com> User-Agent: Mutt/1.9.2 (2017-12-15) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Jan 17, 2018 at 12:20:33PM -0800, Jolly Shah wrote: > Add Firmware-ggs sysfs interface which provides read/write > interface to global storage registers. > > Signed-off-by: Jolly Shah > Signed-off-by: Rajan Vaja > --- > .../ABI/stable/sysfs-driver-zynqmp-firmware | 33 +++ > drivers/firmware/xilinx/zynqmp/Makefile | 2 +- > drivers/firmware/xilinx/zynqmp/firmware-ggs.c | 298 +++++++++++++++++++++ > drivers/firmware/xilinx/zynqmp/firmware.c | 26 ++ > include/linux/firmware/xilinx/zynqmp/firmware.h | 2 + > 5 files changed, 360 insertions(+), 1 deletion(-) > create mode 100644 Documentation/ABI/stable/sysfs-driver-zynqmp-firmware > create mode 100644 drivers/firmware/xilinx/zynqmp/firmware-ggs.c > > diff --git a/Documentation/ABI/stable/sysfs-driver-zynqmp-firmware b/Documentation/ABI/stable/sysfs-driver-zynqmp-firmware > new file mode 100644 > index 0000000..2483215 > --- /dev/null > +++ b/Documentation/ABI/stable/sysfs-driver-zynqmp-firmware > @@ -0,0 +1,33 @@ > +What: /sys/devices/platform/zynqmp-firmware/ggs* > +Date: January 2018 > +KernelVersion: 4.15.0 > +Contact: "Jolly Shah" > +Description: > + Shows PMU global general storage register value, > + GLOBAL_GEN_STORAGE{0:3}. > + Global general storage register that can be used > + by system to pass information between masters. > + > + The register is reset during system or power-on > + resets. Three registers are used by the FSBL and > + other Xilinx software products: GLOBAL_GEN_STORAGE{4:6}. > + > +Users: Xilinx > + > +What: /sys/devices/platform/zynqmp-firmware/pggs* > +Date: January 2018 > +KernelVersion: 4.15.0 > +Contact: "Jolly Shah" > +Description: > + Shows PMU persistent global general storage register > + value, PERS_GLOB_GEN_STORAGE{0:3}. > + Persistent global general storage register that > + can be used by system to pass information between > + masters. > + > + This register is only reset by the power-on reset > + and maintains its value through a system reset. > + Four registers are used by the FSBL and other Xilinx > + software products: PERS_GLOB_GEN_STORAGE{4:7}. > + Register is reset only by a POR reset. > +Users: Xilinx > diff --git a/drivers/firmware/xilinx/zynqmp/Makefile b/drivers/firmware/xilinx/zynqmp/Makefile > index c3ec669..6629781 100644 > --- a/drivers/firmware/xilinx/zynqmp/Makefile > +++ b/drivers/firmware/xilinx/zynqmp/Makefile > @@ -1,4 +1,4 @@ > # SPDX-License-Identifier: GPL-2.0+ > # Makefile for Xilinx firmwares > > -obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware.o > +obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware.o firmware-ggs.o > diff --git a/drivers/firmware/xilinx/zynqmp/firmware-ggs.c b/drivers/firmware/xilinx/zynqmp/firmware-ggs.c > new file mode 100644 > index 0000000..be47ca2 > --- /dev/null > +++ b/drivers/firmware/xilinx/zynqmp/firmware-ggs.c > @@ -0,0 +1,298 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Xilinx Zynq MPSoC Firmware layer > + * > + * Copyright (C) 2014-2018 Xilinx, Inc. > + * > + * Jolly Shah > + * Rajan Vaja > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include That's crazy deep nesting, why? > + > +static ssize_t read_register(char *buf, u32 ioctl_id, u32 reg) > +{ > + int ret; > + u32 ret_payload[PAYLOAD_ARG_CNT]; > + const struct zynqmp_eemi_ops *eemi_ops = get_eemi_ops(); > + > + if (!eemi_ops || !eemi_ops->ioctl) > + return 0; Not an error? > + > + ret = eemi_ops->ioctl(0, ioctl_id, reg, 0, ret_payload); > + if (ret) > + return ret; > + > + return snprintf(buf, PAGE_SIZE, "0x%x\n", ret_payload[1]); Minor nit, you never need to use snprintf() for a sysfs file, as you "know" the size and you can't overflow it with just a single value. Yeah, some tool-checkers hate to see a "raw" sprintf() call, but really, ignore them here :) > +} > + > +static ssize_t write_register(const char *buf, size_t count, > + u32 ioctl_id, u32 reg) > +{ > + char *kern_buff; > + char *inbuf; > + char *tok; > + long mask; > + long value; > + int ret; > + u32 ret_payload[PAYLOAD_ARG_CNT]; > + const struct zynqmp_eemi_ops *eemi_ops = get_eemi_ops(); > + > + if (!eemi_ops || !eemi_ops->ioctl) > + return -EFAULT; > + > + kern_buff = kzalloc(count, GFP_KERNEL); > + if (!kern_buff) > + return -ENOMEM; > + > + ret = strlcpy(kern_buff, buf, count); > + if (ret < 0) { > + ret = -EFAULT; > + goto err; > + } > + > + inbuf = kern_buff; > + > + /* Read the write mask */ > + tok = strsep(&inbuf, " "); > + if (!tok) { > + ret = -EFAULT; > + goto err; > + } > + > + ret = kstrtol(tok, 16, &mask); > + if (ret) { > + ret = -EFAULT; > + goto err; > + } > + > + /* Read the write value */ > + tok = strsep(&inbuf, " "); > + if (!tok) { > + ret = -EFAULT; > + goto err; > + } > + > + ret = kstrtol(tok, 16, &value); > + if (ret) { > + ret = -EFAULT; > + goto err; > + } What exactly is the format for the data to be written here? You do not document it in the ABI/ file above, and it looks to be non-trivial to understand from the code :( > + > + ret = eemi_ops->ioctl(0, ioctl_id, reg, 0, ret_payload); > + if (ret) { > + ret = -EFAULT; > + goto err; > + } > + ret_payload[1] &= ~mask; > + value &= mask; > + value |= ret_payload[1]; > + > + ret = eemi_ops->ioctl(0, ioctl_id, reg, value, NULL); > + if (ret) > + ret = -EFAULT; > + > +err: > + kfree(kern_buff); > + if (ret) > + return ret; > + > + return count; > +} > + > +/** > + * ggs_show - Show global general storage (ggs) sysfs attribute > + * @dev: Device structure > + * @attr: Device attribute structure > + * @buf: Requested available shutdown_scope attributes string > + * @reg: Register number > + * > + * Return:Number of bytes printed into the buffer. > + * > + * Helper function for viewing a ggs register value. > + * > + * User-space interface for viewing the content of the ggs0 register. > + * cat /sys/devices/platform/firmware/ggs0 > + */ > +static ssize_t ggs_show(struct device *dev, > + struct device_attribute *attr, > + char *buf, > + u32 reg) > +{ > + return read_register(buf, IOCTL_READ_GGS, reg); > +} > + > +/** > + * ggs_store - Store global general storage (ggs) sysfs attribute > + * @dev: Device structure > + * @attr: Device attribute structure > + * @buf: User entered shutdown_scope attribute string > + * @count: Size of buf > + * @reg: Register number > + * > + * Return: count argument if request succeeds, the corresponding > + * error code otherwise > + * > + * Helper function for storing a ggs register value. > + * > + * For example, the user-space interface for storing a value to the > + * ggs0 register: > + * echo 0xFFFFFFFF 0x1234ABCD > /sys/devices/platform/firmware/ggs0 > + */ > +static ssize_t ggs_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, > + size_t count, > + u32 reg) > +{ > + if (!dev || !attr || !buf || !count || reg >= GSS_NUM_REGS) > + return -EINVAL; > + > + return write_register(buf, count, IOCTL_WRITE_GGS, reg); > +} > + > +/* GGS register show functions */ > +#define GGS0_SHOW(N) \ > + ssize_t ggs##N##_show(struct device *dev, \ > + struct device_attribute *attr, \ > + char *buf) \ > + { \ > + return ggs_show(dev, attr, buf, N); \ > + } > + > +static GGS0_SHOW(0); > +static GGS0_SHOW(1); > +static GGS0_SHOW(2); > +static GGS0_SHOW(3); > + > +/* GGS register store function */ > +#define GGS0_STORE(N) \ > + ssize_t ggs##N##_store(struct device *dev, \ > + struct device_attribute *attr, \ > + const char *buf, \ > + size_t count) \ > + { \ > + return ggs_store(dev, attr, buf, count, N); \ > + } > + > +static GGS0_STORE(0); > +static GGS0_STORE(1); > +static GGS0_STORE(2); > +static GGS0_STORE(3); > + > +/* GGS register device attributes */ > +static DEVICE_ATTR_RW(ggs0); > +static DEVICE_ATTR_RW(ggs1); > +static DEVICE_ATTR_RW(ggs2); > +static DEVICE_ATTR_RW(ggs3); > + > +#define CREATE_GGS_DEVICE(dev, N) \ > +do { \ > + if (device_create_file(dev, &dev_attr_ggs##N)) \ > + dev_err(dev, "unable to create ggs%d attribute\n", N); \ > +} while (0) > + > +/** > + * pggs_show - Show persistent global general storage (pggs) sysfs attribute > + * @dev: Device structure > + * @attr: Device attribute structure > + * @buf: Requested available shutdown_scope attributes string > + * @reg: Register number > + * > + * Return:Number of bytes printed into the buffer. > + * > + * Helper function for viewing a pggs register value. > + */ > +static ssize_t pggs_show(struct device *dev, > + struct device_attribute *attr, > + char *buf, > + u32 reg) > +{ > + return read_register(buf, IOCTL_READ_GGS, reg); > +} > + > +/** > + * pggs_store - Store persistent global general storage (pggs) sysfs attribute > + * @dev: Device structure > + * @attr: Device attribute structure > + * @buf: User entered shutdown_scope attribute string > + * @count: Size of buf > + * @reg: Register number > + * > + * Return: count argument if request succeeds, the corresponding > + * error code otherwise > + * > + * Helper function for storing a pggs register value. > + */ > +static ssize_t pggs_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, > + size_t count, > + u32 reg) > +{ > + return write_register(buf, count, IOCTL_WRITE_PGGS, reg); > +} > + > +#define PGGS0_SHOW(N) \ > + ssize_t pggs##N##_show(struct device *dev, \ > + struct device_attribute *attr, \ > + char *buf) \ > + { \ > + return pggs_show(dev, attr, buf, N); \ > + } > + > +/* PGGS register show functions */ > +static PGGS0_SHOW(0); > +static PGGS0_SHOW(1); > +static PGGS0_SHOW(2); > +static PGGS0_SHOW(3); > + > +#define PGGS0_STORE(N) \ > + ssize_t pggs##N##_store(struct device *dev, \ > + struct device_attribute *attr, \ > + const char *buf, \ > + size_t count) \ > + { \ > + return pggs_store(dev, attr, buf, count, N); \ > + } > + > +/* PGGS register store functions */ > +static PGGS0_STORE(0); > +static PGGS0_STORE(1); > +static PGGS0_STORE(2); > +static PGGS0_STORE(3); > + > +/* PGGS register device attributes */ > +static DEVICE_ATTR_RW(pggs0); > +static DEVICE_ATTR_RW(pggs1); > +static DEVICE_ATTR_RW(pggs2); > +static DEVICE_ATTR_RW(pggs3); > + > +#define CREATE_PGGS_DEVICE(dev, N) \ > +do { \ > + if (device_create_file(dev, &dev_attr_pggs##N)) \ > + dev_err(dev, "unable to create pggs%d attribute\n", N); \ Ick, no, just use an attribute group please. Handles all of this mess for you automatically, and will unwind properly if you have an error (which this macro does not do.) thanks, greg k-h