Add necessary scaffolding in libndctl for dimms that support papr_scm specification[1]. Since there can be platforms that support Open-Firmware[2] but not the papr_scm specification, hence the changes proposed first add support for probing if the dimm bus supports Open-Firmware. This is done via querying for sysfs attribute 'of_node' in dimm device sysfs directory. If available newly introduced member 'struct ndctl_bus.has_of_node' is set. During the probe of the dimm and execution of add_dimm(), the newly introduced add_papr_dimm() is called if dimm bus reports supports Open-Firmware.
Function add_papr_dimm() queries the 'compatible' device tree attribute via newly introduced ndctl_bus_is_papr_scm() and based on its value assign NVDIMM_FAMILY_PAPR to the dimm command family. In future, based on the contents of 'compatible' attribute more of_pmem dimm families can be queried. We also add support for parsing the dimm flags for NVDIMM_FAMILY_PAPR supporting nvdimms as described at [3]. A newly introduced function parse_papr_flags() reads the contents of this flag file and sets appropriate flag bits in 'struct ndctl_dimm.flags'. Also we advertise support for monitor mode by allocating a file descriptor to the dimm 'flags' file and assigning it to 'struct ndctl_dimm.health_event_fd'. The dimm-ops implementation for NVDIMM_FAMILY_PAPR is available in global variable 'papr_dimm_ops' which points to skeleton implementation in newly introduced file 'lib/papr.c'. References: [1] Documentation/powerpc/papr_hcalls.rst https://lore.kernel.org/linux-nvdimm/20200529214719.223344-2-vaib...@linux.ibm.com [2] https://en.wikipedia.org/wiki/Open_Firmware [3] Documentation/ABI/testing/sysfs-bus-papr-pmem https://lore.kernel.org/linux-nvdimm/20200529214719.223344-4-vaib...@linux.ibm.com Signed-off-by: Vaibhav Jain <vaib...@linux.ibm.com> --- Changelog: v5..v6: * Updated various dbg messages to use consistent dimm device name rather than dimm-id. [Vishal] * Minor changes to log messages in add_papr_dimm() [ Vishal ] * Minor change in parse_papr_flags() to aid in code readability [Vishal] * Added ndctl_bus_has_of_node() and ndctl_bus_is_papr_scm to library ld version script. [Vishal] * Added new library function ndctl_bus_is_papr_scm() that checks the device tree compatible field [Vishal] * Updated add_papr_dimm() to use ndctl_bus_is_papr_scm() [Vishal] * Updated the license header of 'papr.c' to LGPL 2.1 v4..v5: * Renamed file 'papr_scm.c' to 'papr.c' * s/NVDIMM_FAMILY_PAPR_SCM/NVDIMM_FAMILY_PAPR/g * s/papr_scm_dimm_ops/papr_dimm_ops/g * s/parse_papr_scm_flags()/parse_papr_flags()/g * Updated patch description & title to reflect new command family name and file-names. v3..v4: * None v2..v3: * Renamed add_of_pmem() to add_papr_dimm() [ Aneesh ] v1..v2: * Squashed the patch to parse dimm flags * Updated the dimm flags parsing to add case for 'restore_fail' and 'flush_fail'. * Renamed parse_of_pmem_flags() to parse_papr_scm_flags(). * Updated the path to dimm flags file to 'papr/flags'. * Introduced 'papr_scm.c' file in this patch rather than later in the patch series. * Update add_of_pmem_dimm() to parse dimm flags and enable monitoring only if 'ibm,pmemory' compatible nvdimm is found. --- ndctl/lib/Makefile.am | 1 + ndctl/lib/libndctl.c | 84 ++++++++++++++++++++++++++++++++++++++++++ ndctl/lib/libndctl.sym | 5 +++ ndctl/lib/papr.c | 22 +++++++++++ ndctl/lib/private.h | 2 + ndctl/libndctl.h | 2 + ndctl/ndctl.h | 1 + 7 files changed, 117 insertions(+) create mode 100644 ndctl/lib/papr.c diff --git a/ndctl/lib/Makefile.am b/ndctl/lib/Makefile.am index d6be5c3acd26..e15bb2288575 100644 --- a/ndctl/lib/Makefile.am +++ b/ndctl/lib/Makefile.am @@ -23,6 +23,7 @@ libndctl_la_SOURCES =\ hpe1.c \ msft.c \ hyperv.c \ + papr.c \ ars.c \ firmware.c \ libndctl.c \ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c index 85c4d5b34548..2851d16b9f24 100644 --- a/ndctl/lib/libndctl.c +++ b/ndctl/lib/libndctl.c @@ -799,6 +799,28 @@ static void parse_nfit_mem_flags(struct ndctl_dimm *dimm, char *flags) ndctl_dimm_get_devname(dimm), flags); } +static void parse_papr_flags(struct ndctl_dimm *dimm, char *flags) +{ + struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm); + char *start, *end; + + start = flags; + while ((end = strchr(start, ' '))) { + *end = '\0'; + if (strcmp(start, "not_armed") == 0) + dimm->flags.f_arm = 1; + else if (strcmp(start, "flush_fail") == 0) + dimm->flags.f_flush = 1; + else if (strcmp(start, "restore_fail") == 0) + dimm->flags.f_restore = 1; + else if (strcmp(start, "smart_notify") == 0) + dimm->flags.f_smart = 1; + start = end + 1; + } + if (end != start) + dbg(ctx, "%s: Flags:%s\n", ndctl_dimm_get_devname(dimm), flags); +} + static void parse_dimm_flags(struct ndctl_dimm *dimm, char *flags) { char *start, *end; @@ -856,6 +878,12 @@ static void *add_bus(void *parent, int id, const char *ctl_base) bus->revision = strtoul(buf, NULL, 0); } + sprintf(path, "%s/device/of_node/compatible", ctl_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + bus->has_of_node = 0; + else + bus->has_of_node = 1; + sprintf(path, "%s/device/nfit/dsm_mask", ctl_base); if (sysfs_read_attr(ctx, path, buf) < 0) bus->nfit_dsm_mask = 0; @@ -964,6 +992,23 @@ NDCTL_EXPORT int ndctl_bus_has_nfit(struct ndctl_bus *bus) return bus->has_nfit; } +NDCTL_EXPORT int ndctl_bus_has_of_node(struct ndctl_bus *bus) +{ + return bus->has_of_node; +} + +NDCTL_EXPORT int ndctl_bus_is_papr_scm(struct ndctl_bus *bus) +{ + char buf[SYSFS_ATTR_SIZE]; + + snprintf(bus->bus_buf, bus->buf_len, + "%s/of_node/compatible", bus->bus_path); + if (sysfs_read_attr(bus->ctx, bus->bus_buf, buf) < 0) + return 0; + + return (strcmp(buf, "ibm,pmemory") == 0); +} + /** * ndctl_bus_get_major - nd bus character device major number * @bus: ndctl_bus instance returned from ndctl_bus_get_{first|next} @@ -1441,6 +1486,40 @@ static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module, static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath); static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias); +static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base) +{ + int rc = -ENODEV; + char buf[SYSFS_ATTR_SIZE]; + struct ndctl_ctx *ctx = dimm->bus->ctx; + char *path = calloc(1, strlen(dimm_base) + 100); + const char * const devname = ndctl_dimm_get_devname(dimm); + + dbg(ctx, "%s: Probing of_pmem dimm at %s\n", devname, dimm_base); + + if (!path) + return -ENOMEM; + + /* construct path to the papr compatible dimm flags file */ + sprintf(path, "%s/papr/flags", dimm_base); + + if (ndctl_bus_is_papr_scm(dimm->bus) && + sysfs_read_attr(ctx, path, buf) == 0) { + + dbg(ctx, "%s: Adding papr-scm dimm flags:\"%s\"\n", devname, buf); + dimm->cmd_family = NVDIMM_FAMILY_PAPR; + + /* Parse dimm flags */ + parse_papr_flags(dimm, buf); + + /* Allocate monitor mode fd */ + dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC); + rc = 0; + } + + free(path); + return rc; +} + static int add_nfit_dimm(struct ndctl_dimm *dimm, const char *dimm_base) { int i, rc = -1; @@ -1619,6 +1698,8 @@ static void *add_dimm(void *parent, int id, const char *dimm_base) if (ndctl_bus_has_nfit(bus)) { dimm->formats = formats; rc = add_nfit_dimm(dimm, dimm_base); + } else if (ndctl_bus_has_of_node(bus)) { + rc = add_papr_dimm(dimm, dimm_base); } if (rc == -ENODEV) { @@ -1636,6 +1717,9 @@ static void *add_dimm(void *parent, int id, const char *dimm_base) dimm->ops = msft_dimm_ops; if (dimm->cmd_family == NVDIMM_FAMILY_HYPERV) dimm->ops = hyperv_dimm_ops; + if (dimm->cmd_family == NVDIMM_FAMILY_PAPR) + dimm->ops = papr_dimm_ops; + out: if (rc) { /* Ensure dimm_uninit() is not called during free_dimm() */ diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index ac575a23d035..9cfaccf5d3b7 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -431,3 +431,8 @@ LIBNDCTL_23 { ndctl_region_get_align; ndctl_region_set_align; } LIBNDCTL_22; + +LIBNDCTL_24 { + ndctl_bus_has_of_node; + ndctl_bus_is_papr_scm; +} LIBNDCTL_23; diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c new file mode 100644 index 000000000000..4b6ce8beccab --- /dev/null +++ b/ndctl/lib/papr.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: LGPL-2.1 + +#include <stdint.h> +#include <stdlib.h> +#include <limits.h> +#include <util/log.h> +#include <ndctl.h> +#include <ndctl/libndctl.h> +#include <lib/private.h> + +static bool papr_cmd_is_supported(struct ndctl_dimm *dimm, int cmd) +{ + /* Handle this separately to support monitor mode */ + if (cmd == ND_CMD_SMART) + return true; + + return !!(dimm->cmd_mask & (1ULL << cmd)); +} + +struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) { + .cmd_is_supported = papr_cmd_is_supported, +}; diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h index 2e537f0a8649..d90236b1f98b 100644 --- a/ndctl/lib/private.h +++ b/ndctl/lib/private.h @@ -167,6 +167,7 @@ struct ndctl_bus { int dimms_init; int regions_init; int has_nfit; + int has_of_node; char *bus_path; char *bus_buf; size_t buf_len; @@ -352,6 +353,7 @@ extern struct ndctl_dimm_ops * const intel_dimm_ops; extern struct ndctl_dimm_ops * const hpe1_dimm_ops; extern struct ndctl_dimm_ops * const msft_dimm_ops; extern struct ndctl_dimm_ops * const hyperv_dimm_ops; +extern struct ndctl_dimm_ops * const papr_dimm_ops; static inline struct ndctl_bus *cmd_to_bus(struct ndctl_cmd *cmd) { diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index 2580f433ade8..e16fb7eaf34b 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -119,6 +119,8 @@ struct ndctl_bus *ndctl_bus_get_next(struct ndctl_bus *bus); bus = ndctl_bus_get_next(bus)) struct ndctl_ctx *ndctl_bus_get_ctx(struct ndctl_bus *bus); int ndctl_bus_has_nfit(struct ndctl_bus *bus); +int ndctl_bus_has_of_node(struct ndctl_bus *bus); +int ndctl_bus_is_papr_scm(struct ndctl_bus *bus); unsigned int ndctl_bus_get_major(struct ndctl_bus *bus); unsigned int ndctl_bus_get_minor(struct ndctl_bus *bus); const char *ndctl_bus_get_devname(struct ndctl_bus *bus); diff --git a/ndctl/ndctl.h b/ndctl/ndctl.h index 008f81cdeb9f..3b64f66d58cc 100644 --- a/ndctl/ndctl.h +++ b/ndctl/ndctl.h @@ -263,6 +263,7 @@ struct nd_cmd_pkg { #define NVDIMM_FAMILY_HPE2 2 #define NVDIMM_FAMILY_MSFT 3 #define NVDIMM_FAMILY_HYPERV 4 +#define NVDIMM_FAMILY_PAPR 5 #define ND_IOCTL_CALL _IOWR(ND_IOCTL, ND_CMD_CALL,\ struct nd_cmd_pkg) -- 2.26.2 _______________________________________________ Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org To unsubscribe send an email to linux-nvdimm-le...@lists.01.org