[PATCH v2 06/20] libnd: ndctl.h, the nd ioctl abi
Most configuration of the nd-subsystem is done via nd-sysfs attributes. However, some nd buses, particularly the ACPI.NFIT bus, define a small set of messages that can be passed to the platform. For convenience we derivce the initial nd-ioctl-command formats directly from the NFIT DSM formats. ND_CMD_SMART: media health and diagnostics ND_CMD_GET_CONFIG_SIZE: size of the label space ND_CMD_GET_CONFIG_DATA: read label space ND_CMD_SET_CONFIG_DATA: write label space ND_CMD_VENDOR: vendor-specific command passthrough ND_CMD_ARS_CAP: report address-range-scrubbing capabilities ND_CMD_START_ARS: initiate scrubbing ND_CMD_QUERY_ARS: report on scrubbing state ND_CMD_SMART_THRESHOLD: configure alarm thresholds for smart events If a platform later defines different commands than this set it is straightforward to extend support to those formats. Most of the commands target a specific dimm. However, the address-range-scrubbing commands target the bus. The 'commands' attribute in sysfs of an nd-bus, or an nd-dimm enumerate the supported commands for that object. Cc: Cc: Robert Moore Cc: Rafael J. Wysocki Reported-by: Nicholas Moulin Signed-off-by: Dan Williams --- drivers/block/nd/Kconfig | 12 ++ drivers/block/nd/acpi.c | 237 ++ drivers/block/nd/acpi_nfit.h |3 drivers/block/nd/bus.c| 324 - drivers/block/nd/core.c | 16 ++ drivers/block/nd/dimm_devs.c | 38 - drivers/block/nd/libnd.h | 25 +++ drivers/block/nd/nd-private.h |3 drivers/block/nd/test/nfit.c | 78 ++ include/uapi/linux/Kbuild |1 include/uapi/linux/ndctl.h| 178 +++ 11 files changed, 903 insertions(+), 12 deletions(-) create mode 100644 include/uapi/linux/ndctl.h diff --git a/drivers/block/nd/Kconfig b/drivers/block/nd/Kconfig index 09f0135147ca..d2d84451e82c 100644 --- a/drivers/block/nd/Kconfig +++ b/drivers/block/nd/Kconfig @@ -37,6 +37,18 @@ config ND_ACPI addition to storage devices this also enables libnd craft ACPI._DSM messages for platform/dimm configuration. +config ND_ACPI_DEBUG + bool "ACPI: Extra nd_acpi debugging" + depends on ND_ACPI + depends on DYNAMIC_DEBUG + default n + help + Enabling this option causes the nd_acpi driver to dump the + input and output buffers of _DSM operations on the ACPI0012 + device and its children. This can be very verbose, so leave + it disabled unless you are debugging a hardware / firmware + issue. + config NFIT_TEST tristate "NFIT TEST: Manufactured NFIT for interface testing" depends on DMA_CMA diff --git a/drivers/block/nd/acpi.c b/drivers/block/nd/acpi.c index af6684341c9b..c46e166695f7 100644 --- a/drivers/block/nd/acpi.c +++ b/drivers/block/nd/acpi.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include "acpi_nfit.h" @@ -25,11 +26,160 @@ enum { NFIT_ACPI_NOTIFY_TABLE = 0x80, }; +static u8 nd_acpi_uuids[2][16]; /* initialized at nd_acpi_init */ + +static u8 *nd_acpi_bus_uuid(void) +{ + return nd_acpi_uuids[0]; +} + +static u8 *nd_acpi_dimm_uuid(void) +{ + return nd_acpi_uuids[1]; +} + +static struct acpi_nfit_desc *to_acpi_nfit_desc(struct nd_bus_descriptor *nd_desc) +{ + return container_of(nd_desc, struct acpi_nfit_desc, nd_desc); +} + +static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc) +{ + struct nd_bus_descriptor *nd_desc = _desc->nd_desc; + + /* +* If provider == 'ACPI.NFIT' we can assume 'dev' is a struct +* acpi_device. +*/ + if (!nd_desc->provider_name + || strcmp(nd_desc->provider_name, "ACPI.NFIT") != 0) + return NULL; + + return to_acpi_device(acpi_desc->dev); +} + static int nd_acpi_ctl(struct nd_bus_descriptor *nd_desc, struct nd_dimm *nd_dimm, unsigned int cmd, void *buf, unsigned int buf_len) { - return -ENOTTY; + struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); + const struct nd_cmd_desc const *desc = NULL; + union acpi_object in_obj, in_buf, *out_obj; + struct device *dev = acpi_desc->dev; + const char *cmd_name, *dimm_name; + unsigned long dsm_mask; + acpi_handle handle; + u32 offset; + int rc, i; + u8 *uuid; + + if (nd_dimm) { + struct nfit_mem *nfit_mem = nd_dimm_provider_data(nd_dimm); + struct acpi_device *adev = nfit_mem->adev; + + if (!adev) + return -ENOTTY; + dimm_name = dev_name(>dev); + cmd_name = nd_dimm_cmd_name(cmd); + dsm_mask = nfit_mem->dsm_mask; + desc = nd_cmd_dimm_desc(cmd); + uuid = nd_acpi_dimm_uuid(); +
[PATCH v2 06/20] libnd: ndctl.h, the nd ioctl abi
Most configuration of the nd-subsystem is done via nd-sysfs attributes. However, some nd buses, particularly the ACPI.NFIT bus, define a small set of messages that can be passed to the platform. For convenience we derivce the initial nd-ioctl-command formats directly from the NFIT DSM formats. ND_CMD_SMART: media health and diagnostics ND_CMD_GET_CONFIG_SIZE: size of the label space ND_CMD_GET_CONFIG_DATA: read label space ND_CMD_SET_CONFIG_DATA: write label space ND_CMD_VENDOR: vendor-specific command passthrough ND_CMD_ARS_CAP: report address-range-scrubbing capabilities ND_CMD_START_ARS: initiate scrubbing ND_CMD_QUERY_ARS: report on scrubbing state ND_CMD_SMART_THRESHOLD: configure alarm thresholds for smart events If a platform later defines different commands than this set it is straightforward to extend support to those formats. Most of the commands target a specific dimm. However, the address-range-scrubbing commands target the bus. The 'commands' attribute in sysfs of an nd-bus, or an nd-dimm enumerate the supported commands for that object. Cc: linux-a...@vger.kernel.org Cc: Robert Moore robert.mo...@intel.com Cc: Rafael J. Wysocki rafael.j.wyso...@intel.com Reported-by: Nicholas Moulin nicholas.w.mou...@linux.intel.com Signed-off-by: Dan Williams dan.j.willi...@intel.com --- drivers/block/nd/Kconfig | 12 ++ drivers/block/nd/acpi.c | 237 ++ drivers/block/nd/acpi_nfit.h |3 drivers/block/nd/bus.c| 324 - drivers/block/nd/core.c | 16 ++ drivers/block/nd/dimm_devs.c | 38 - drivers/block/nd/libnd.h | 25 +++ drivers/block/nd/nd-private.h |3 drivers/block/nd/test/nfit.c | 78 ++ include/uapi/linux/Kbuild |1 include/uapi/linux/ndctl.h| 178 +++ 11 files changed, 903 insertions(+), 12 deletions(-) create mode 100644 include/uapi/linux/ndctl.h diff --git a/drivers/block/nd/Kconfig b/drivers/block/nd/Kconfig index 09f0135147ca..d2d84451e82c 100644 --- a/drivers/block/nd/Kconfig +++ b/drivers/block/nd/Kconfig @@ -37,6 +37,18 @@ config ND_ACPI addition to storage devices this also enables libnd craft ACPI._DSM messages for platform/dimm configuration. +config ND_ACPI_DEBUG + bool ACPI: Extra nd_acpi debugging + depends on ND_ACPI + depends on DYNAMIC_DEBUG + default n + help + Enabling this option causes the nd_acpi driver to dump the + input and output buffers of _DSM operations on the ACPI0012 + device and its children. This can be very verbose, so leave + it disabled unless you are debugging a hardware / firmware + issue. + config NFIT_TEST tristate NFIT TEST: Manufactured NFIT for interface testing depends on DMA_CMA diff --git a/drivers/block/nd/acpi.c b/drivers/block/nd/acpi.c index af6684341c9b..c46e166695f7 100644 --- a/drivers/block/nd/acpi.c +++ b/drivers/block/nd/acpi.c @@ -12,6 +12,7 @@ */ #include linux/list_sort.h #include linux/module.h +#include linux/ndctl.h #include linux/list.h #include linux/acpi.h #include acpi_nfit.h @@ -25,11 +26,160 @@ enum { NFIT_ACPI_NOTIFY_TABLE = 0x80, }; +static u8 nd_acpi_uuids[2][16]; /* initialized at nd_acpi_init */ + +static u8 *nd_acpi_bus_uuid(void) +{ + return nd_acpi_uuids[0]; +} + +static u8 *nd_acpi_dimm_uuid(void) +{ + return nd_acpi_uuids[1]; +} + +static struct acpi_nfit_desc *to_acpi_nfit_desc(struct nd_bus_descriptor *nd_desc) +{ + return container_of(nd_desc, struct acpi_nfit_desc, nd_desc); +} + +static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc) +{ + struct nd_bus_descriptor *nd_desc = acpi_desc-nd_desc; + + /* +* If provider == 'ACPI.NFIT' we can assume 'dev' is a struct +* acpi_device. +*/ + if (!nd_desc-provider_name + || strcmp(nd_desc-provider_name, ACPI.NFIT) != 0) + return NULL; + + return to_acpi_device(acpi_desc-dev); +} + static int nd_acpi_ctl(struct nd_bus_descriptor *nd_desc, struct nd_dimm *nd_dimm, unsigned int cmd, void *buf, unsigned int buf_len) { - return -ENOTTY; + struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); + const struct nd_cmd_desc const *desc = NULL; + union acpi_object in_obj, in_buf, *out_obj; + struct device *dev = acpi_desc-dev; + const char *cmd_name, *dimm_name; + unsigned long dsm_mask; + acpi_handle handle; + u32 offset; + int rc, i; + u8 *uuid; + + if (nd_dimm) { + struct nfit_mem *nfit_mem = nd_dimm_provider_data(nd_dimm); + struct acpi_device *adev = nfit_mem-adev; + + if (!adev) + return -ENOTTY; + dimm_name = dev_name(adev-dev); +