Message ID | 20201106194221.59353-1-stuart.w.hayes@gmail.com (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | Expose PCIe SSD Status LED Management DSM in sysfs | expand |
Hi Stuart, I love your patch! Perhaps something to improve: [auto build test WARNING on pci/next] [also build test WARNING on linus/master v5.10-rc3 next-20201109] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Stuart-Hayes/Expose-PCIe-SSD-Status-LED-Management-DSM-in-sysfs/20201109-100709 base: https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git next config: i386-randconfig-r015-20201109 (attached as .config) compiler: gcc-9 (Debian 9.3.0-15) 9.3.0 reproduce (this is a W=1 build): # https://github.com/0day-ci/linux/commit/71fa2ed2b9ac8be92eb60fb757e0333dd6788d2f git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Stuart-Hayes/Expose-PCIe-SSD-Status-LED-Management-DSM-in-sysfs/20201109-100709 git checkout 71fa2ed2b9ac8be92eb60fb757e0333dd6788d2f # save the attached .config to linux build tree make W=1 ARCH=i386 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): >> drivers/pci/pci-ssdleds.c:184:6: warning: no previous prototype for 'pci_create_ssdleds_files' [-Wmissing-prototypes] 184 | void pci_create_ssdleds_files(struct pci_dev *pdev) | ^~~~~~~~~~~~~~~~~~~~~~~~ drivers/pci/pci-ssdleds.c: In function 'pci_create_ssdleds_files': >> drivers/pci/pci-ssdleds.c:186:6: warning: variable 'ret' set but not used [-Wunused-but-set-variable] 186 | int ret; | ^~~ drivers/pci/pci-ssdleds.c: At top level: >> drivers/pci/pci-ssdleds.c:191:6: warning: no previous prototype for 'pci_remove_ssdleds_files' [-Wmissing-prototypes] 191 | void pci_remove_ssdleds_files(struct pci_dev *pdev) | ^~~~~~~~~~~~~~~~~~~~~~~~ vim +/pci_create_ssdleds_files +184 drivers/pci/pci-ssdleds.c 183 > 184 void pci_create_ssdleds_files(struct pci_dev *pdev) 185 { > 186 int ret; 187 188 ret = sysfs_create_group(&pdev->dev.kobj, &ssdleds_attr_group); 189 } 190 > 191 void pci_remove_ssdleds_files(struct pci_dev *pdev) --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Stuart, I love your patch! Perhaps something to improve: [auto build test WARNING on pci/next] [also build test WARNING on linus/master v5.10-rc3 next-20201109] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Stuart-Hayes/Expose-PCIe-SSD-Status-LED-Management-DSM-in-sysfs/20201109-100709 base: https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git next config: arm64-randconfig-r024-20201109 (attached as .config) compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 09ec07827b1128504457a93dee80b2ceee1af600) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install arm64 cross compiling tool for clang build # apt-get install binutils-aarch64-linux-gnu # https://github.com/0day-ci/linux/commit/71fa2ed2b9ac8be92eb60fb757e0333dd6788d2f git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Stuart-Hayes/Expose-PCIe-SSD-Status-LED-Management-DSM-in-sysfs/20201109-100709 git checkout 71fa2ed2b9ac8be92eb60fb757e0333dd6788d2f # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=arm64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): >> drivers/pci/pci-ssdleds.c:126:48: warning: use of logical '||' with constant operand [-Wconstant-logical-operand] 1 << SSDLEDS_GET_SUPPORTED_STATES_DSM || ^ drivers/pci/pci-ssdleds.c:126:48: note: use '|' for a bitwise operation 1 << SSDLEDS_GET_SUPPORTED_STATES_DSM || ^~ | drivers/pci/pci-ssdleds.c:127:37: warning: use of logical '||' with constant operand [-Wconstant-logical-operand] 1 << SSDLEDS_GET_STATE_DSM || ^ drivers/pci/pci-ssdleds.c:127:37: note: use '|' for a bitwise operation 1 << SSDLEDS_GET_STATE_DSM || ^~ | >> drivers/pci/pci-ssdleds.c:128:12: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare] 1 << SSDLEDS_SET_STATE_DSM); ^ drivers/pci/pci-ssdleds.c:126:12: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare] 1 << SSDLEDS_GET_SUPPORTED_STATES_DSM || ^ drivers/pci/pci-ssdleds.c:127:12: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare] 1 << SSDLEDS_GET_STATE_DSM || ^ >> drivers/pci/pci-ssdleds.c:184:6: warning: no previous prototype for function 'pci_create_ssdleds_files' [-Wmissing-prototypes] void pci_create_ssdleds_files(struct pci_dev *pdev) ^ drivers/pci/pci-ssdleds.c:184:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void pci_create_ssdleds_files(struct pci_dev *pdev) ^ static >> drivers/pci/pci-ssdleds.c:191:6: warning: no previous prototype for function 'pci_remove_ssdleds_files' [-Wmissing-prototypes] void pci_remove_ssdleds_files(struct pci_dev *pdev) ^ drivers/pci/pci-ssdleds.c:191:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void pci_remove_ssdleds_files(struct pci_dev *pdev) ^ static 7 warnings generated. vim +126 drivers/pci/pci-ssdleds.c 116 117 static bool device_has_dsm(struct device *dev) 118 { 119 acpi_handle handle; 120 121 handle = ACPI_HANDLE(dev); 122 if (!handle) 123 return false; 124 125 return !!acpi_check_dsm(handle, &pci_ssdleds_dsm_guid, 0x1, > 126 1 << SSDLEDS_GET_SUPPORTED_STATES_DSM || 127 1 << SSDLEDS_GET_STATE_DSM || > 128 1 << SSDLEDS_SET_STATE_DSM); 129 } 130 131 static ssize_t ssdleds_current_store(struct device *dev, 132 struct device_attribute *attr, 133 const char *buf, size_t count) 134 { 135 int ret; 136 137 ret = ssdleds_dsm_set(dev, buf, SSDLEDS_SET_STATE_DSM); 138 return (ret < 0) ? ret : count; 139 } 140 141 static ssize_t ssdleds_current_show(struct device *dev, 142 struct device_attribute *attr, char *buf) 143 { 144 return ssdleds_dsm_get(dev, buf, SSDLEDS_GET_STATE_DSM); 145 } 146 147 static ssize_t ssdleds_supported_show(struct device *dev, 148 struct device_attribute *attr, char *buf) 149 { 150 return ssdleds_dsm_get(dev, buf, SSDLEDS_GET_SUPPORTED_STATES_DSM); 151 } 152 153 static umode_t ssdleds_attr_visible(struct kobject *kobj, 154 struct attribute *attr, int n) 155 { 156 struct device *dev = kobj_to_dev(kobj); 157 umode_t mode = attr->mode; 158 159 return device_has_dsm(dev) ? mode : 0; 160 } 161 162 static struct device_attribute ssdleds_attr_current = { 163 .attr = {.name = "ssdleds_current_state", .mode = 0644}, 164 .show = ssdleds_current_show, 165 .store = ssdleds_current_store, 166 }; 167 168 static struct device_attribute ssdleds_attr_supported = { 169 .attr = {.name = "ssdleds_supported_states", .mode = 0444}, 170 .show = ssdleds_supported_show, 171 }; 172 173 static struct attribute *ssdleds_attributes[] = { 174 &ssdleds_attr_current.attr, 175 &ssdleds_attr_supported.attr, 176 NULL, 177 }; 178 179 static const struct attribute_group ssdleds_attr_group = { 180 .attrs = ssdleds_attributes, 181 .is_visible = ssdleds_attr_visible, 182 }; 183 > 184 void pci_create_ssdleds_files(struct pci_dev *pdev) 185 { 186 int ret; 187 188 ret = sysfs_create_group(&pdev->dev.kobj, &ssdleds_attr_group); 189 } 190 > 191 void pci_remove_ssdleds_files(struct pci_dev *pdev) --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 450296cc7948..bee7855e408a 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -360,3 +360,17 @@ Contact: Heiner Kallweit <hkallweit1@gmail.com> Description: If ASPM is supported for an endpoint, these files can be used to disable or enable the individual power management states. Write y/1/on to enable, n/0/off to disable. + +What: /sys/bus/pci/devices/.../ssdleds_supported_states +Date: October 2020 +Contact: Stuart Hayes <stuart.w.hayes@gmail.com> +Description: If the device supports the ACPI _DSM method to control the + PCIe SSD LED states, ssdleds_supported_states (read only) + will show the LED states that are supported by the _DSM. + +What: /sys/bus/pci/devices/.../ssdleds_current_state +Date: October 2020 +Contact: Stuart Hayes <stuart.w.hayes@gmail.com> +Description: If the device supports the ACPI _DSM method to control the + PCIe SSD LED states, ssdleds_current_state will show or set + the current LED states that are active. diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 0c473d75e625..a56b94764182 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -182,6 +182,13 @@ config PCI_LABEL def_bool y if (DMI || ACPI) select NLS +config PCI_SSDLEDS + def_bool y if (ACPI) + depends on ACPI + help + Enables userspace access to PCIe SSD LED management interface via + sysfs. + config PCI_HYPERV tristate "Hyper-V PCI Frontend" depends on X86_64 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && SYSFS diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 522d2b974e91..75d3d5a3b1ed 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PCI_ATS) += ats.o obj-$(CONFIG_PCI_IOV) += iov.o obj-$(CONFIG_PCI_BRIDGE_EMUL) += pci-bridge-emul.o obj-$(CONFIG_PCI_LABEL) += pci-label.o +obj-$(CONFIG_PCI_SSDLEDS) += pci-ssdleds.o obj-$(CONFIG_X86_INTEL_MID) += pci-mid.o obj-$(CONFIG_PCI_SYSCALL) += syscall.o obj-$(CONFIG_PCI_STUB) += pci-stub.o diff --git a/drivers/pci/pci-ssdleds.c b/drivers/pci/pci-ssdleds.c new file mode 100644 index 000000000000..7b9afd3d0ccb --- /dev/null +++ b/drivers/pci/pci-ssdleds.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Provide userspace access to PCIe SSD Status LED Management + * + * The PCIe spec defines an ACPI _DSM method to allow PCIe SSD status LED + * management (see "_DSM additions for PCIe SSD Status LED Management" ECN, + * February 12, 2020). This code provides a sysfs interface to this _DSM. + * + * Copyright (C) 2020 Dell Inc. + * + */ + +#include <linux/sysfs.h> +#include <linux/pci.h> +#include <linux/device.h> +#include <linux/acpi.h> + +const guid_t pci_ssdleds_dsm_guid = + GUID_INIT(0x5d524d9d, 0xfff9, 0x4d4b, + 0x8c, 0xb7, 0x74, 0x7e, 0xd5, 0x1e, 0x19, 0x4d); + +#define SSDLEDS_GET_SUPPORTED_STATES_DSM 0x01 +#define SSDLEDS_GET_STATE_DSM 0x02 +#define SSDLEDS_SET_STATE_DSM 0x03 + +struct pci_ssdleds_dsm_output { + u16 status; + u8 function_specific_err; + u8 vendor_specific_err; + u32 state; +}; + +static int ssdleds_dsm_set(struct device *dev, const char *buf, u64 dsm_func) +{ + acpi_handle handle; + union acpi_object *out_obj, arg3[2]; + struct pci_ssdleds_dsm_output *dsm_output; + u32 val; + int err; + + handle = ACPI_HANDLE(dev); + if (!handle) + return -ENODEV; + + err = kstrtou32(buf, 0, &val); + if (err || val > U32_MAX) + return -EINVAL; + + arg3[0].type = ACPI_TYPE_PACKAGE; + arg3[0].package.count = 1; + arg3[0].package.elements = &arg3[1]; + + arg3[1].type = ACPI_TYPE_BUFFER; + arg3[1].buffer.length = 4; + arg3[1].buffer.pointer = (u8 *)&val; + + out_obj = acpi_evaluate_dsm_typed(handle, &pci_ssdleds_dsm_guid, 0x1, + dsm_func, &arg3[0], ACPI_TYPE_BUFFER); + if (!out_obj) + return -EIO; + + if (out_obj->buffer.length < 8) { + ACPI_FREE(out_obj); + return -EIO; + } + + dsm_output = (struct pci_ssdleds_dsm_output *)out_obj->buffer.pointer; + /* + * Ignore function specific error bit 1 (some LED state bits weren't + * set), since write was done. User can read current state to see which + * bits were set. + */ + if (dsm_output->status != 0 && + !(dsm_output->status == 4 && dsm_output->function_specific_err == 1)) { + ACPI_FREE(out_obj); + return -EIO; + } + + ACPI_FREE(out_obj); + + return 0; +} + +static int ssdleds_dsm_get(struct device *dev, char *buf, u64 dsm_func) +{ + acpi_handle handle; + union acpi_object *out_obj; + struct pci_ssdleds_dsm_output *dsm_output; + + handle = ACPI_HANDLE(dev); + if (!handle) + return -ENODEV; + + out_obj = acpi_evaluate_dsm_typed(handle, &pci_ssdleds_dsm_guid, 0x1, + dsm_func, NULL, ACPI_TYPE_BUFFER); + if (!out_obj) + return -EIO; + + if (out_obj->buffer.length < 8) { + ACPI_FREE(out_obj); + return -EIO; + } + + dsm_output = (struct pci_ssdleds_dsm_output *)out_obj->buffer.pointer; + if (dsm_output->status != 0) { + ACPI_FREE(out_obj); + return -EIO; + } + + scnprintf(buf, PAGE_SIZE, "%#x\n", dsm_output->state); + + ACPI_FREE(out_obj); + + return strlen(buf) > 0 ? strlen(buf) : -EIO; +} + +static bool device_has_dsm(struct device *dev) +{ + acpi_handle handle; + + handle = ACPI_HANDLE(dev); + if (!handle) + return false; + + return !!acpi_check_dsm(handle, &pci_ssdleds_dsm_guid, 0x1, + 1 << SSDLEDS_GET_SUPPORTED_STATES_DSM || + 1 << SSDLEDS_GET_STATE_DSM || + 1 << SSDLEDS_SET_STATE_DSM); +} + +static ssize_t ssdleds_current_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + + ret = ssdleds_dsm_set(dev, buf, SSDLEDS_SET_STATE_DSM); + return (ret < 0) ? ret : count; +} + +static ssize_t ssdleds_current_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return ssdleds_dsm_get(dev, buf, SSDLEDS_GET_STATE_DSM); +} + +static ssize_t ssdleds_supported_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return ssdleds_dsm_get(dev, buf, SSDLEDS_GET_SUPPORTED_STATES_DSM); +} + +static umode_t ssdleds_attr_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + umode_t mode = attr->mode; + + return device_has_dsm(dev) ? mode : 0; +} + +static struct device_attribute ssdleds_attr_current = { + .attr = {.name = "ssdleds_current_state", .mode = 0644}, + .show = ssdleds_current_show, + .store = ssdleds_current_store, +}; + +static struct device_attribute ssdleds_attr_supported = { + .attr = {.name = "ssdleds_supported_states", .mode = 0444}, + .show = ssdleds_supported_show, +}; + +static struct attribute *ssdleds_attributes[] = { + &ssdleds_attr_current.attr, + &ssdleds_attr_supported.attr, + NULL, +}; + +static const struct attribute_group ssdleds_attr_group = { + .attrs = ssdleds_attributes, + .is_visible = ssdleds_attr_visible, +}; + +void pci_create_ssdleds_files(struct pci_dev *pdev) +{ + int ret; + + ret = sysfs_create_group(&pdev->dev.kobj, &ssdleds_attr_group); +} + +void pci_remove_ssdleds_files(struct pci_dev *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &ssdleds_attr_group); +} diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index d15c881e2e7e..820f32956971 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1377,6 +1377,7 @@ int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev) goto err_rom_file; pci_create_firmware_label_files(pdev); + pci_create_ssdleds_files(pdev); return 0; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index f86cae9aa1f4..8e6883a1b701 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -30,6 +30,17 @@ static inline void pci_remove_firmware_label_files(struct pci_dev *pdev) void pci_create_firmware_label_files(struct pci_dev *pdev); void pci_remove_firmware_label_files(struct pci_dev *pdev); #endif + +#if !defined(CONFIG_PCI_SSDLEDS) +static inline void pci_create_ssdleds_files(struct pci_dev *pdev) +{ return; } +static inline void pci_remove_ssdleds_files(struct pci_dev *pdev) +{ return; } +#else +void pci_create_ssdleds_files(struct pci_dev *pdev); +void pci_remove_ssdleds_files(struct pci_dev *pdev); +#endif + void pci_cleanup_rom(struct pci_dev *dev); enum pci_mmap_api {
This patch will expose the PCIe SSD Status LED Management interface in sysfs for devices that have the relevant _DSM method, per the "_DSM additions for PCIe SSD Status LED Management" ECN to the PCI Firmware Specification revision 3.2. The interface is exposed in two sysfs files, ssdleds_supported_states (RO) and ssdleds_current_state (RW). Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com> --- Documentation/ABI/testing/sysfs-bus-pci | 14 ++ drivers/pci/Kconfig | 7 + drivers/pci/Makefile | 1 + drivers/pci/pci-ssdleds.c | 194 ++++++++++++++++++++++++ drivers/pci/pci-sysfs.c | 1 + drivers/pci/pci.h | 11 ++ 6 files changed, 228 insertions(+) create mode 100644 drivers/pci/pci-ssdleds.c