···4545MODULE_PARM_DESC(scrub_overflow_abort,4646 "Number of times we overflow ARS results before abort");47474848+static bool disable_vendor_specific;4949+module_param(disable_vendor_specific, bool, S_IRUGO);5050+MODULE_PARM_DESC(disable_vendor_specific,5151+ "Limit commands to the publicly specified set\n");5252+4853static struct workqueue_struct *nfit_wq;49545055struct nfit_table_prev {···176171 unsigned int buf_len, int *cmd_rc)177172{178173 struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);179179- const struct nd_cmd_desc *desc = NULL;180174 union acpi_object in_obj, in_buf, *out_obj;175175+ const struct nd_cmd_desc *desc = NULL;181176 struct device *dev = acpi_desc->dev;177177+ struct nd_cmd_pkg *call_pkg = NULL;182178 const char *cmd_name, *dimm_name;183183- unsigned long dsm_mask;179179+ unsigned long cmd_mask, dsm_mask;184180 acpi_handle handle;181181+ unsigned int func;185182 const u8 *uuid;186183 u32 offset;187184 int rc, i;185185+186186+ func = cmd;187187+ if (cmd == ND_CMD_CALL) {188188+ call_pkg = buf;189189+ func = call_pkg->nd_command;190190+ }188191189192 if (nvdimm) {190193 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);···200187201188 if (!adev)202189 return -ENOTTY;190190+ if (call_pkg && nfit_mem->family != call_pkg->nd_family)191191+ return -ENOTTY;192192+203193 dimm_name = nvdimm_name(nvdimm);204194 cmd_name = nvdimm_cmd_name(cmd);195195+ cmd_mask = nvdimm_cmd_mask(nvdimm);205196 dsm_mask = nfit_mem->dsm_mask;206197 desc = nd_cmd_dimm_desc(cmd);207207- uuid = to_nfit_uuid(NFIT_DEV_DIMM);198198+ uuid = to_nfit_uuid(nfit_mem->family);208199 handle = adev->handle;209200 } else {210201 struct acpi_device *adev = to_acpi_dev(acpi_desc);211202212203 cmd_name = nvdimm_bus_cmd_name(cmd);213213- dsm_mask = nd_desc->dsm_mask;204204+ cmd_mask = nd_desc->cmd_mask;205205+ dsm_mask = cmd_mask;214206 desc = nd_cmd_bus_desc(cmd);215207 uuid = to_nfit_uuid(NFIT_DEV_BUS);216208 handle = adev->handle;···225207 if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))226208 return -ENOTTY;227209228228- if (!test_bit(cmd, &dsm_mask))210210+ if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask))229211 return -ENOTTY;230212231213 in_obj.type = ACPI_TYPE_PACKAGE;···240222 in_buf.buffer.length += nd_cmd_in_size(nvdimm, cmd, desc,241223 i, buf);242224243243- if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {244244- dev_dbg(dev, "%s:%s cmd: %s input length: %d\n", __func__,245245- dimm_name, cmd_name, in_buf.buffer.length);246246- print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4,247247- 4, in_buf.buffer.pointer, min_t(u32, 128,248248- in_buf.buffer.length), true);225225+ if (call_pkg) {226226+ /* skip over package wrapper */227227+ in_buf.buffer.pointer = (void *) &call_pkg->nd_payload;228228+ in_buf.buffer.length = call_pkg->nd_size_in;249229 }250230251251- out_obj = acpi_evaluate_dsm(handle, uuid, 1, cmd, &in_obj);231231+ if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) {232232+ dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n",233233+ __func__, dimm_name, cmd, func,234234+ in_buf.buffer.length);235235+ print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4,236236+ in_buf.buffer.pointer,237237+ min_t(u32, 256, in_buf.buffer.length), true);238238+ }239239+240240+ out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj);252241 if (!out_obj) {253242 dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name,254243 cmd_name);255244 return -EINVAL;245245+ }246246+247247+ if (call_pkg) {248248+ call_pkg->nd_fw_size = out_obj->buffer.length;249249+ memcpy(call_pkg->nd_payload + call_pkg->nd_size_in,250250+ out_obj->buffer.pointer,251251+ min(call_pkg->nd_fw_size, call_pkg->nd_size_out));252252+253253+ ACPI_FREE(out_obj);254254+ /*255255+ * Need to support FW function w/o known size in advance.256256+ * Caller can determine required size based upon nd_fw_size.257257+ * If we return an error (like elsewhere) then caller wouldn't258258+ * be able to rely upon data returned to make calculation.259259+ */260260+ return 0;256261 }257262258263 if (out_obj->package.type != ACPI_TYPE_BUFFER) {···962921}963922static DEVICE_ATTR_RO(serial);964923924924+static ssize_t family_show(struct device *dev,925925+ struct device_attribute *attr, char *buf)926926+{927927+ struct nvdimm *nvdimm = to_nvdimm(dev);928928+ struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);929929+930930+ if (nfit_mem->family < 0)931931+ return -ENXIO;932932+ return sprintf(buf, "%d\n", nfit_mem->family);933933+}934934+static DEVICE_ATTR_RO(family);935935+936936+static ssize_t dsm_mask_show(struct device *dev,937937+ struct device_attribute *attr, char *buf)938938+{939939+ struct nvdimm *nvdimm = to_nvdimm(dev);940940+ struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);941941+942942+ if (nfit_mem->family < 0)943943+ return -ENXIO;944944+ return sprintf(buf, "%#lx\n", nfit_mem->dsm_mask);945945+}946946+static DEVICE_ATTR_RO(dsm_mask);947947+965948static ssize_t flags_show(struct device *dev,966949 struct device_attribute *attr, char *buf)967950{···1011946 &dev_attr_serial.attr,1012947 &dev_attr_rev_id.attr,1013948 &dev_attr_flags.attr,949949+ &dev_attr_family.attr,950950+ &dev_attr_dsm_mask.attr,1014951 NULL,1015952};1016953···1059992{1060993 struct acpi_device *adev, *adev_dimm;1061994 struct device *dev = acpi_desc->dev;10621062- const u8 *uuid = to_nfit_uuid(NFIT_DEV_DIMM);995995+ unsigned long dsm_mask;996996+ const u8 *uuid;1063997 int i;106499810651065- nfit_mem->dsm_mask = acpi_desc->dimm_dsm_force_en;999999+ /* nfit test assumes 1:1 relationship between commands and dsms */10001000+ nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en;10011001+ nfit_mem->family = NVDIMM_FAMILY_INTEL;10661002 adev = to_acpi_dev(acpi_desc);10671003 if (!adev)10681004 return 0;···10781008 return force_enable_dimms ? 0 : -ENODEV;10791009 }1080101010811081- for (i = ND_CMD_SMART; i <= ND_CMD_VENDOR; i++)10111011+ /*10121012+ * Until standardization materializes we need to consider up to 310131013+ * different command sets. Note, that checking for function0 (bit0)10141014+ * tells us if any commands are reachable through this uuid.10151015+ */10161016+ for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_HPE2; i++)10171017+ if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))10181018+ break;10191019+10201020+ /* limit the supported commands to those that are publicly documented */10211021+ nfit_mem->family = i;10221022+ if (nfit_mem->family == NVDIMM_FAMILY_INTEL) {10231023+ dsm_mask = 0x3fe;10241024+ if (disable_vendor_specific)10251025+ dsm_mask &= ~(1 << ND_CMD_VENDOR);10261026+ } else if (nfit_mem->family == NVDIMM_FAMILY_HPE1)10271027+ dsm_mask = 0x1c3c76;10281028+ else if (nfit_mem->family == NVDIMM_FAMILY_HPE2) {10291029+ dsm_mask = 0x1fe;10301030+ if (disable_vendor_specific)10311031+ dsm_mask &= ~(1 << 8);10321032+ } else {10331033+ dev_err(dev, "unknown dimm command family\n");10341034+ nfit_mem->family = -1;10351035+ return force_enable_dimms ? 0 : -ENODEV;10361036+ }10371037+10381038+ uuid = to_nfit_uuid(nfit_mem->family);10391039+ for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)10821040 if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i))10831041 set_bit(i, &nfit_mem->dsm_mask);10841042···11191021 int dimm_count = 0;1120102211211023 list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {10241024+ unsigned long flags = 0, cmd_mask;11221025 struct nvdimm *nvdimm;11231123- unsigned long flags = 0;11241026 u32 device_handle;11251027 u16 mem_flags;11261028 int rc;···11431045 if (rc)11441046 continue;1145104710481048+ /*10491049+ * TODO: provide translation for non-NVDIMM_FAMILY_INTEL10501050+ * devices (i.e. from nd_cmd to acpi_dsm) to standardize the10511051+ * userspace interface.10521052+ */10531053+ cmd_mask = 1UL << ND_CMD_CALL;10541054+ if (nfit_mem->family == NVDIMM_FAMILY_INTEL)10551055+ cmd_mask |= nfit_mem->dsm_mask;10561056+11461057 nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,11471058 acpi_nfit_dimm_attribute_groups,11481148- flags, &nfit_mem->dsm_mask);10591059+ flags, cmd_mask);11491060 if (!nvdimm)11501061 return -ENOMEM;11511062···11831076 struct acpi_device *adev;11841077 int i;1185107811861186- nd_desc->dsm_mask = acpi_desc->bus_dsm_force_en;10791079+ nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en;11871080 adev = to_acpi_dev(acpi_desc);11881081 if (!adev)11891082 return;1190108311911084 for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)11921085 if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i))11931193- set_bit(i, &nd_desc->dsm_mask);10861086+ set_bit(i, &nd_desc->cmd_mask);11941087}1195108811961089static ssize_t range_index_show(struct device *dev,···26392532 acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]);26402533 acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);26412534 acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);25352535+ acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);25362536+ acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);2642253726432538 nfit_wq = create_singlethread_workqueue("nfit");26442539 if (!nfit_wq)
+15-3
drivers/acpi/nfit.h
···2121#include <linux/acpi.h>2222#include <acpi/acuuid.h>23232424+/* ACPI 6.1 */2425#define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"2626+2727+/* http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf */2528#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"2929+3030+/* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */3131+#define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6"3232+#define UUID_NFIT_DIMM_N_HPE2 "5008664b-b758-41a0-a03c-27c2f2d04f7e"3333+2634#define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \2735 | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \2836 | ACPI_NFIT_MEM_NOT_ARMED)29373038enum nfit_uuids {3939+ /* for simplicity alias the uuid index with the family id */4040+ NFIT_DEV_DIMM = NVDIMM_FAMILY_INTEL,4141+ NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1,4242+ NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,3143 NFIT_SPA_VOLATILE,3244 NFIT_SPA_PM,3345 NFIT_SPA_DCR,···4937 NFIT_SPA_PDISK,5038 NFIT_SPA_PCD,5139 NFIT_DEV_BUS,5252- NFIT_DEV_DIMM,5340 NFIT_UUID_MAX,5441};5542···122111 struct acpi_device *adev;123112 struct acpi_nfit_desc *acpi_desc;124113 unsigned long dsm_mask;114114+ int family;125115};126116127117struct acpi_nfit_desc {···145133 size_t ars_status_size;146134 struct work_struct work;147135 unsigned int cancel:1;148148- unsigned long dimm_dsm_force_en;149149- unsigned long bus_dsm_force_en;136136+ unsigned long dimm_cmd_force_en;137137+ unsigned long bus_cmd_force_en;150138 int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,151139 void *iobuf, u64 len, int rw);152140};
+2-2
drivers/acpi/utils.c
···625625 * some old BIOSes do expect a buffer or an integer etc.626626 */627627union acpi_object *628628-acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func,628628+acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 func,629629 union acpi_object *argv4)630630{631631 acpi_status ret;···674674 * functions. Currently only support 64 functions at maximum, should be675675 * enough for now.676676 */677677-bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)677677+bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs)678678{679679 int i;680680 u64 mask = 0;
···37373838 nvdimm = to_nvdimm(ndd->dev);39394040- if (!nvdimm->dsm_mask)4040+ if (!nvdimm->cmd_mask)4141 return -ENXIO;4242- if (!test_bit(ND_CMD_GET_CONFIG_DATA, nvdimm->dsm_mask))4242+ if (!test_bit(ND_CMD_GET_CONFIG_DATA, &nvdimm->cmd_mask))4343 return -ENXIO;44444545 return 0;···263263}264264EXPORT_SYMBOL_GPL(nvdimm_name);265265266266+unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm)267267+{268268+ return nvdimm->cmd_mask;269269+}270270+EXPORT_SYMBOL_GPL(nvdimm_cmd_mask);271271+266272void *nvdimm_provider_data(struct nvdimm *nvdimm)267273{268274 if (nvdimm)···283277 struct nvdimm *nvdimm = to_nvdimm(dev);284278 int cmd, len = 0;285279286286- if (!nvdimm->dsm_mask)280280+ if (!nvdimm->cmd_mask)287281 return sprintf(buf, "\n");288282289289- for_each_set_bit(cmd, nvdimm->dsm_mask, BITS_PER_LONG)283283+ for_each_set_bit(cmd, &nvdimm->cmd_mask, BITS_PER_LONG)290284 len += sprintf(buf + len, "%s ", nvdimm_cmd_name(cmd));291285 len += sprintf(buf + len, "\n");292286 return len;···346340347341struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,348342 const struct attribute_group **groups, unsigned long flags,349349- unsigned long *dsm_mask)343343+ unsigned long cmd_mask)350344{351345 struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL);352346 struct device *dev;···361355 }362356 nvdimm->provider_data = provider_data;363357 nvdimm->flags = flags;364364- nvdimm->dsm_mask = dsm_mask;358358+ nvdimm->cmd_mask = cmd_mask;365359 atomic_set(&nvdimm->busy, 0);366360 dev = &nvdimm->dev;367361 dev_set_name(dev, "nmem%d", nvdimm->id);
+1-1
drivers/nvdimm/nd-core.h
···3737struct nvdimm {3838 unsigned long flags;3939 void *provider_data;4040- unsigned long *dsm_mask;4040+ unsigned long cmd_mask;4141 struct device dev;4242 atomic_t busy;4343 int id;
+3-3
include/acpi/acpi_bus.h
···6161bool acpi_bay_match(acpi_handle handle);6262bool acpi_dock_match(acpi_handle handle);63636464-bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs);6464+bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs);6565union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid,6666- int rev, int func, union acpi_object *argv4);6666+ u64 rev, u64 func, union acpi_object *argv4);67676868static inline union acpi_object *6969-acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, int rev, int func,6969+acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, u64 rev, u64 func,7070 union acpi_object *argv4, acpi_object_type type)7171{7272 union acpi_object *obj;
+4-3
include/linux/libnvdimm.h
···2727 /* need to set a limit somewhere, but yes, this is likely overkill */2828 ND_IOCTL_MAX_BUFLEN = SZ_4M,2929 ND_CMD_MAX_ELEM = 5,3030- ND_CMD_MAX_ENVELOPE = 16,3030+ ND_CMD_MAX_ENVELOPE = 256,3131 ND_MAX_MAPPINGS = 32,32323333 /* region flag indicating to direct-map persistent memory by default */···68686969struct nvdimm_bus_descriptor {7070 const struct attribute_group **attr_groups;7171- unsigned long dsm_mask;7171+ unsigned long cmd_mask;7272 char *provider_name;7373 ndctl_fn ndctl;7474 int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc);···130130struct nd_blk_region *to_nd_blk_region(struct device *dev);131131struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus);132132const char *nvdimm_name(struct nvdimm *nvdimm);133133+unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm);133134void *nvdimm_provider_data(struct nvdimm *nvdimm);134135struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,135136 const struct attribute_group **groups, unsigned long flags,136136- unsigned long *dsm_mask);137137+ unsigned long cmd_mask);137138const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);138139const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);139140u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
+42
include/uapi/linux/ndctl.h
···159159 ND_CMD_VENDOR_EFFECT_LOG_SIZE = 7,160160 ND_CMD_VENDOR_EFFECT_LOG = 8,161161 ND_CMD_VENDOR = 9,162162+ ND_CMD_CALL = 10,162163};163164164165enum {···193192 [ND_CMD_VENDOR_EFFECT_LOG_SIZE] = "effect_size",194193 [ND_CMD_VENDOR_EFFECT_LOG] = "effect_log",195194 [ND_CMD_VENDOR] = "vendor",195195+ [ND_CMD_CALL] = "cmd_call",196196 };197197198198 if (cmd < ARRAY_SIZE(names) && names[cmd])···262260 ARS_STATUS_MASK = 0x0000FFFF,263261 ARS_EXT_STATUS_SHIFT = 16,264262};263263+264264+/*265265+ * struct nd_cmd_pkg266266+ *267267+ * is a wrapper to a quasi pass thru interface for invoking firmware268268+ * associated with nvdimms.269269+ *270270+ * INPUT PARAMETERS271271+ *272272+ * nd_family corresponds to the firmware (e.g. DSM) interface.273273+ *274274+ * nd_command are the function index advertised by the firmware.275275+ *276276+ * nd_size_in is the size of the input parameters being passed to firmware277277+ *278278+ * OUTPUT PARAMETERS279279+ *280280+ * nd_fw_size is the size of the data firmware wants to return for281281+ * the call. If nd_fw_size is greater than size of nd_size_out, only282282+ * the first nd_size_out bytes are returned.283283+ */284284+285285+struct nd_cmd_pkg {286286+ __u64 nd_family; /* family of commands */287287+ __u64 nd_command;288288+ __u32 nd_size_in; /* INPUT: size of input args */289289+ __u32 nd_size_out; /* INPUT: size of payload */290290+ __u32 nd_reserved2[9]; /* reserved must be zero */291291+ __u32 nd_fw_size; /* OUTPUT: size fw wants to return */292292+ unsigned char nd_payload[]; /* Contents of call */293293+};294294+295295+/* These NVDIMM families represent pre-standardization command sets */296296+#define NVDIMM_FAMILY_INTEL 0297297+#define NVDIMM_FAMILY_HPE1 1298298+#define NVDIMM_FAMILY_HPE2 2299299+300300+#define ND_IOCTL_CALL _IOWR(ND_IOCTL, ND_CMD_CALL,\301301+ struct nd_cmd_pkg)302302+265303#endif /* __NDCTL_H__ */