diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2016-05-18 13:06:59 -0400 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2016-05-18 13:06:59 -0400 |
| commit | 1f716d05f8daee4f393dc568ea7a53c7ecfd0bfc (patch) | |
| tree | 3ba46ef65cd2fb1766934769c1d4a7fc16c3fe61 | |
| parent | 2159669f581917c4d197d3ea183d3d85b47faf66 (diff) | |
| parent | a94e3fbe4d53d4e512c4ea88a475e605b8d8dccb (diff) | |
Merge branch 'for-4.7/dsm' into libnvdimm-for-next
| -rw-r--r-- | drivers/acpi/nfit.c | 145 | ||||
| -rw-r--r-- | drivers/acpi/nfit.h | 18 | ||||
| -rw-r--r-- | drivers/acpi/utils.c | 4 | ||||
| -rw-r--r-- | drivers/nvdimm/bus.c | 47 | ||||
| -rw-r--r-- | drivers/nvdimm/core.c | 2 | ||||
| -rw-r--r-- | drivers/nvdimm/dimm_devs.c | 18 | ||||
| -rw-r--r-- | drivers/nvdimm/nd-core.h | 2 | ||||
| -rw-r--r-- | include/acpi/acpi_bus.h | 6 | ||||
| -rw-r--r-- | include/linux/libnvdimm.h | 7 | ||||
| -rw-r--r-- | include/uapi/linux/ndctl.h | 42 | ||||
| -rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 50 |
11 files changed, 283 insertions, 58 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index d60f73a63c3c..2564f330a93e 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c | |||
| @@ -45,6 +45,11 @@ module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR); | |||
| 45 | MODULE_PARM_DESC(scrub_overflow_abort, | 45 | MODULE_PARM_DESC(scrub_overflow_abort, |
| 46 | "Number of times we overflow ARS results before abort"); | 46 | "Number of times we overflow ARS results before abort"); |
| 47 | 47 | ||
| 48 | static bool disable_vendor_specific; | ||
| 49 | module_param(disable_vendor_specific, bool, S_IRUGO); | ||
| 50 | MODULE_PARM_DESC(disable_vendor_specific, | ||
| 51 | "Limit commands to the publicly specified set\n"); | ||
| 52 | |||
| 48 | static struct workqueue_struct *nfit_wq; | 53 | static struct workqueue_struct *nfit_wq; |
| 49 | 54 | ||
| 50 | struct nfit_table_prev { | 55 | struct nfit_table_prev { |
| @@ -171,33 +176,46 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 171 | unsigned int buf_len, int *cmd_rc) | 176 | unsigned int buf_len, int *cmd_rc) |
| 172 | { | 177 | { |
| 173 | struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); | 178 | struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); |
| 174 | const struct nd_cmd_desc *desc = NULL; | ||
| 175 | union acpi_object in_obj, in_buf, *out_obj; | 179 | union acpi_object in_obj, in_buf, *out_obj; |
| 180 | const struct nd_cmd_desc *desc = NULL; | ||
| 176 | struct device *dev = acpi_desc->dev; | 181 | struct device *dev = acpi_desc->dev; |
| 182 | struct nd_cmd_pkg *call_pkg = NULL; | ||
| 177 | const char *cmd_name, *dimm_name; | 183 | const char *cmd_name, *dimm_name; |
| 178 | unsigned long dsm_mask; | 184 | unsigned long cmd_mask, dsm_mask; |
| 179 | acpi_handle handle; | 185 | acpi_handle handle; |
| 186 | unsigned int func; | ||
| 180 | const u8 *uuid; | 187 | const u8 *uuid; |
| 181 | u32 offset; | 188 | u32 offset; |
| 182 | int rc, i; | 189 | int rc, i; |
| 183 | 190 | ||
| 191 | func = cmd; | ||
| 192 | if (cmd == ND_CMD_CALL) { | ||
| 193 | call_pkg = buf; | ||
| 194 | func = call_pkg->nd_command; | ||
| 195 | } | ||
| 196 | |||
| 184 | if (nvdimm) { | 197 | if (nvdimm) { |
| 185 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | 198 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); |
| 186 | struct acpi_device *adev = nfit_mem->adev; | 199 | struct acpi_device *adev = nfit_mem->adev; |
| 187 | 200 | ||
| 188 | if (!adev) | 201 | if (!adev) |
| 189 | return -ENOTTY; | 202 | return -ENOTTY; |
| 203 | if (call_pkg && nfit_mem->family != call_pkg->nd_family) | ||
| 204 | return -ENOTTY; | ||
| 205 | |||
| 190 | dimm_name = nvdimm_name(nvdimm); | 206 | dimm_name = nvdimm_name(nvdimm); |
| 191 | cmd_name = nvdimm_cmd_name(cmd); | 207 | cmd_name = nvdimm_cmd_name(cmd); |
| 208 | cmd_mask = nvdimm_cmd_mask(nvdimm); | ||
| 192 | dsm_mask = nfit_mem->dsm_mask; | 209 | dsm_mask = nfit_mem->dsm_mask; |
| 193 | desc = nd_cmd_dimm_desc(cmd); | 210 | desc = nd_cmd_dimm_desc(cmd); |
| 194 | uuid = to_nfit_uuid(NFIT_DEV_DIMM); | 211 | uuid = to_nfit_uuid(nfit_mem->family); |
| 195 | handle = adev->handle; | 212 | handle = adev->handle; |
| 196 | } else { | 213 | } else { |
| 197 | struct acpi_device *adev = to_acpi_dev(acpi_desc); | 214 | struct acpi_device *adev = to_acpi_dev(acpi_desc); |
| 198 | 215 | ||
| 199 | cmd_name = nvdimm_bus_cmd_name(cmd); | 216 | cmd_name = nvdimm_bus_cmd_name(cmd); |
| 200 | dsm_mask = nd_desc->dsm_mask; | 217 | cmd_mask = nd_desc->cmd_mask; |
| 218 | dsm_mask = cmd_mask; | ||
| 201 | desc = nd_cmd_bus_desc(cmd); | 219 | desc = nd_cmd_bus_desc(cmd); |
| 202 | uuid = to_nfit_uuid(NFIT_DEV_BUS); | 220 | uuid = to_nfit_uuid(NFIT_DEV_BUS); |
| 203 | handle = adev->handle; | 221 | handle = adev->handle; |
| @@ -207,7 +225,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 207 | if (!desc || (cmd && (desc->out_num + desc->in_num == 0))) | 225 | if (!desc || (cmd && (desc->out_num + desc->in_num == 0))) |
| 208 | return -ENOTTY; | 226 | return -ENOTTY; |
| 209 | 227 | ||
| 210 | if (!test_bit(cmd, &dsm_mask)) | 228 | if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask)) |
| 211 | return -ENOTTY; | 229 | return -ENOTTY; |
| 212 | 230 | ||
| 213 | in_obj.type = ACPI_TYPE_PACKAGE; | 231 | in_obj.type = ACPI_TYPE_PACKAGE; |
| @@ -222,21 +240,44 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 222 | in_buf.buffer.length += nd_cmd_in_size(nvdimm, cmd, desc, | 240 | in_buf.buffer.length += nd_cmd_in_size(nvdimm, cmd, desc, |
| 223 | i, buf); | 241 | i, buf); |
| 224 | 242 | ||
| 243 | if (call_pkg) { | ||
| 244 | /* skip over package wrapper */ | ||
| 245 | in_buf.buffer.pointer = (void *) &call_pkg->nd_payload; | ||
| 246 | in_buf.buffer.length = call_pkg->nd_size_in; | ||
| 247 | } | ||
| 248 | |||
| 225 | if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) { | 249 | if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) { |
| 226 | dev_dbg(dev, "%s:%s cmd: %s input length: %d\n", __func__, | 250 | dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n", |
| 227 | dimm_name, cmd_name, in_buf.buffer.length); | 251 | __func__, dimm_name, cmd, func, |
| 228 | print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, | 252 | in_buf.buffer.length); |
| 229 | 4, in_buf.buffer.pointer, min_t(u32, 128, | 253 | print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4, |
| 230 | in_buf.buffer.length), true); | 254 | in_buf.buffer.pointer, |
| 255 | min_t(u32, 256, in_buf.buffer.length), true); | ||
| 231 | } | 256 | } |
| 232 | 257 | ||
| 233 | out_obj = acpi_evaluate_dsm(handle, uuid, 1, cmd, &in_obj); | 258 | out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj); |
| 234 | if (!out_obj) { | 259 | if (!out_obj) { |
| 235 | dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name, | 260 | dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name, |
| 236 | cmd_name); | 261 | cmd_name); |
| 237 | return -EINVAL; | 262 | return -EINVAL; |
| 238 | } | 263 | } |
| 239 | 264 | ||
| 265 | if (call_pkg) { | ||
| 266 | call_pkg->nd_fw_size = out_obj->buffer.length; | ||
| 267 | memcpy(call_pkg->nd_payload + call_pkg->nd_size_in, | ||
| 268 | out_obj->buffer.pointer, | ||
| 269 | min(call_pkg->nd_fw_size, call_pkg->nd_size_out)); | ||
| 270 | |||
| 271 | ACPI_FREE(out_obj); | ||
| 272 | /* | ||
| 273 | * Need to support FW function w/o known size in advance. | ||
| 274 | * Caller can determine required size based upon nd_fw_size. | ||
| 275 | * If we return an error (like elsewhere) then caller wouldn't | ||
| 276 | * be able to rely upon data returned to make calculation. | ||
| 277 | */ | ||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | |||
| 240 | if (out_obj->package.type != ACPI_TYPE_BUFFER) { | 281 | if (out_obj->package.type != ACPI_TYPE_BUFFER) { |
| 241 | dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n", | 282 | dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n", |
| 242 | __func__, dimm_name, cmd_name, out_obj->type); | 283 | __func__, dimm_name, cmd_name, out_obj->type); |
| @@ -921,6 +962,30 @@ static ssize_t serial_show(struct device *dev, | |||
| 921 | } | 962 | } |
| 922 | static DEVICE_ATTR_RO(serial); | 963 | static DEVICE_ATTR_RO(serial); |
| 923 | 964 | ||
| 965 | static ssize_t family_show(struct device *dev, | ||
| 966 | struct device_attribute *attr, char *buf) | ||
| 967 | { | ||
| 968 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
| 969 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 970 | |||
| 971 | if (nfit_mem->family < 0) | ||
| 972 | return -ENXIO; | ||
| 973 | return sprintf(buf, "%d\n", nfit_mem->family); | ||
| 974 | } | ||
| 975 | static DEVICE_ATTR_RO(family); | ||
| 976 | |||
| 977 | static ssize_t dsm_mask_show(struct device *dev, | ||
| 978 | struct device_attribute *attr, char *buf) | ||
| 979 | { | ||
| 980 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
| 981 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 982 | |||
| 983 | if (nfit_mem->family < 0) | ||
| 984 | return -ENXIO; | ||
| 985 | return sprintf(buf, "%#lx\n", nfit_mem->dsm_mask); | ||
| 986 | } | ||
| 987 | static DEVICE_ATTR_RO(dsm_mask); | ||
| 988 | |||
| 924 | static ssize_t flags_show(struct device *dev, | 989 | static ssize_t flags_show(struct device *dev, |
| 925 | struct device_attribute *attr, char *buf) | 990 | struct device_attribute *attr, char *buf) |
| 926 | { | 991 | { |
| @@ -946,6 +1011,8 @@ static struct attribute *acpi_nfit_dimm_attributes[] = { | |||
| 946 | &dev_attr_serial.attr, | 1011 | &dev_attr_serial.attr, |
| 947 | &dev_attr_rev_id.attr, | 1012 | &dev_attr_rev_id.attr, |
| 948 | &dev_attr_flags.attr, | 1013 | &dev_attr_flags.attr, |
| 1014 | &dev_attr_family.attr, | ||
| 1015 | &dev_attr_dsm_mask.attr, | ||
| 949 | NULL, | 1016 | NULL, |
| 950 | }; | 1017 | }; |
| 951 | 1018 | ||
| @@ -992,10 +1059,13 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
| 992 | { | 1059 | { |
| 993 | struct acpi_device *adev, *adev_dimm; | 1060 | struct acpi_device *adev, *adev_dimm; |
| 994 | struct device *dev = acpi_desc->dev; | 1061 | struct device *dev = acpi_desc->dev; |
| 995 | const u8 *uuid = to_nfit_uuid(NFIT_DEV_DIMM); | 1062 | unsigned long dsm_mask; |
| 1063 | const u8 *uuid; | ||
| 996 | int i; | 1064 | int i; |
| 997 | 1065 | ||
| 998 | nfit_mem->dsm_mask = acpi_desc->dimm_dsm_force_en; | 1066 | /* nfit test assumes 1:1 relationship between commands and dsms */ |
| 1067 | nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en; | ||
| 1068 | nfit_mem->family = NVDIMM_FAMILY_INTEL; | ||
| 999 | adev = to_acpi_dev(acpi_desc); | 1069 | adev = to_acpi_dev(acpi_desc); |
| 1000 | if (!adev) | 1070 | if (!adev) |
| 1001 | return 0; | 1071 | return 0; |
| @@ -1008,7 +1078,35 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
| 1008 | return force_enable_dimms ? 0 : -ENODEV; | 1078 | return force_enable_dimms ? 0 : -ENODEV; |
| 1009 | } | 1079 | } |
| 1010 | 1080 | ||
| 1011 | for (i = ND_CMD_SMART; i <= ND_CMD_VENDOR; i++) | 1081 | /* |
| 1082 | * Until standardization materializes we need to consider up to 3 | ||
| 1083 | * different command sets. Note, that checking for function0 (bit0) | ||
| 1084 | * tells us if any commands are reachable through this uuid. | ||
| 1085 | */ | ||
| 1086 | for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_HPE2; i++) | ||
| 1087 | if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1)) | ||
| 1088 | break; | ||
| 1089 | |||
| 1090 | /* limit the supported commands to those that are publicly documented */ | ||
| 1091 | nfit_mem->family = i; | ||
| 1092 | if (nfit_mem->family == NVDIMM_FAMILY_INTEL) { | ||
| 1093 | dsm_mask = 0x3fe; | ||
| 1094 | if (disable_vendor_specific) | ||
| 1095 | dsm_mask &= ~(1 << ND_CMD_VENDOR); | ||
| 1096 | } else if (nfit_mem->family == NVDIMM_FAMILY_HPE1) | ||
| 1097 | dsm_mask = 0x1c3c76; | ||
| 1098 | else if (nfit_mem->family == NVDIMM_FAMILY_HPE2) { | ||
| 1099 | dsm_mask = 0x1fe; | ||
| 1100 | if (disable_vendor_specific) | ||
| 1101 | dsm_mask &= ~(1 << 8); | ||
| 1102 | } else { | ||
| 1103 | dev_err(dev, "unknown dimm command family\n"); | ||
| 1104 | nfit_mem->family = -1; | ||
| 1105 | return force_enable_dimms ? 0 : -ENODEV; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | uuid = to_nfit_uuid(nfit_mem->family); | ||
| 1109 | for_each_set_bit(i, &dsm_mask, BITS_PER_LONG) | ||
| 1012 | if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i)) | 1110 | if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i)) |
| 1013 | set_bit(i, &nfit_mem->dsm_mask); | 1111 | set_bit(i, &nfit_mem->dsm_mask); |
| 1014 | 1112 | ||
| @@ -1021,8 +1119,8 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
| 1021 | int dimm_count = 0; | 1119 | int dimm_count = 0; |
| 1022 | 1120 | ||
| 1023 | list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) { | 1121 | list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) { |
| 1122 | unsigned long flags = 0, cmd_mask; | ||
| 1024 | struct nvdimm *nvdimm; | 1123 | struct nvdimm *nvdimm; |
| 1025 | unsigned long flags = 0; | ||
| 1026 | u32 device_handle; | 1124 | u32 device_handle; |
| 1027 | u16 mem_flags; | 1125 | u16 mem_flags; |
| 1028 | int rc; | 1126 | int rc; |
| @@ -1045,9 +1143,18 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
| 1045 | if (rc) | 1143 | if (rc) |
| 1046 | continue; | 1144 | continue; |
| 1047 | 1145 | ||
| 1146 | /* | ||
| 1147 | * TODO: provide translation for non-NVDIMM_FAMILY_INTEL | ||
| 1148 | * devices (i.e. from nd_cmd to acpi_dsm) to standardize the | ||
| 1149 | * userspace interface. | ||
| 1150 | */ | ||
| 1151 | cmd_mask = 1UL << ND_CMD_CALL; | ||
| 1152 | if (nfit_mem->family == NVDIMM_FAMILY_INTEL) | ||
| 1153 | cmd_mask |= nfit_mem->dsm_mask; | ||
| 1154 | |||
| 1048 | nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem, | 1155 | nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem, |
| 1049 | acpi_nfit_dimm_attribute_groups, | 1156 | acpi_nfit_dimm_attribute_groups, |
| 1050 | flags, &nfit_mem->dsm_mask); | 1157 | flags, cmd_mask); |
| 1051 | if (!nvdimm) | 1158 | if (!nvdimm) |
| 1052 | return -ENOMEM; | 1159 | return -ENOMEM; |
| 1053 | 1160 | ||
| @@ -1076,14 +1183,14 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc) | |||
| 1076 | struct acpi_device *adev; | 1183 | struct acpi_device *adev; |
| 1077 | int i; | 1184 | int i; |
| 1078 | 1185 | ||
| 1079 | nd_desc->dsm_mask = acpi_desc->bus_dsm_force_en; | 1186 | nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en; |
| 1080 | adev = to_acpi_dev(acpi_desc); | 1187 | adev = to_acpi_dev(acpi_desc); |
| 1081 | if (!adev) | 1188 | if (!adev) |
| 1082 | return; | 1189 | return; |
| 1083 | 1190 | ||
| 1084 | for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++) | 1191 | for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++) |
| 1085 | if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i)) | 1192 | if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i)) |
| 1086 | set_bit(i, &nd_desc->dsm_mask); | 1193 | set_bit(i, &nd_desc->cmd_mask); |
| 1087 | } | 1194 | } |
| 1088 | 1195 | ||
| 1089 | static ssize_t range_index_show(struct device *dev, | 1196 | static ssize_t range_index_show(struct device *dev, |
| @@ -2532,6 +2639,8 @@ static __init int nfit_init(void) | |||
| 2532 | acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]); | 2639 | acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]); |
| 2533 | acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]); | 2640 | acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]); |
| 2534 | acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]); | 2641 | acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]); |
| 2642 | acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]); | ||
| 2643 | acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]); | ||
| 2535 | 2644 | ||
| 2536 | nfit_wq = create_singlethread_workqueue("nfit"); | 2645 | nfit_wq = create_singlethread_workqueue("nfit"); |
| 2537 | if (!nfit_wq) | 2646 | if (!nfit_wq) |
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 5201840c1147..46c50148e4b7 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h | |||
| @@ -21,13 +21,25 @@ | |||
| 21 | #include <linux/acpi.h> | 21 | #include <linux/acpi.h> |
| 22 | #include <acpi/acuuid.h> | 22 | #include <acpi/acuuid.h> |
| 23 | 23 | ||
| 24 | /* ACPI 6.1 */ | ||
| 24 | #define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba" | 25 | #define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba" |
| 26 | |||
| 27 | /* http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf */ | ||
| 25 | #define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66" | 28 | #define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66" |
| 29 | |||
| 30 | /* https://github.com/HewlettPackard/hpe-nvm/blob/master/Documentation/ */ | ||
| 31 | #define UUID_NFIT_DIMM_N_HPE1 "9002c334-acf3-4c0e-9642-a235f0d53bc6" | ||
| 32 | #define UUID_NFIT_DIMM_N_HPE2 "5008664b-b758-41a0-a03c-27c2f2d04f7e" | ||
| 33 | |||
| 26 | #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \ | 34 | #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \ |
| 27 | | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \ | 35 | | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \ |
| 28 | | ACPI_NFIT_MEM_NOT_ARMED) | 36 | | ACPI_NFIT_MEM_NOT_ARMED) |
| 29 | 37 | ||
| 30 | enum nfit_uuids { | 38 | enum nfit_uuids { |
| 39 | /* for simplicity alias the uuid index with the family id */ | ||
| 40 | NFIT_DEV_DIMM = NVDIMM_FAMILY_INTEL, | ||
| 41 | NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1, | ||
| 42 | NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2, | ||
| 31 | NFIT_SPA_VOLATILE, | 43 | NFIT_SPA_VOLATILE, |
| 32 | NFIT_SPA_PM, | 44 | NFIT_SPA_PM, |
| 33 | NFIT_SPA_DCR, | 45 | NFIT_SPA_DCR, |
| @@ -37,7 +49,6 @@ enum nfit_uuids { | |||
| 37 | NFIT_SPA_PDISK, | 49 | NFIT_SPA_PDISK, |
| 38 | NFIT_SPA_PCD, | 50 | NFIT_SPA_PCD, |
| 39 | NFIT_DEV_BUS, | 51 | NFIT_DEV_BUS, |
| 40 | NFIT_DEV_DIMM, | ||
| 41 | NFIT_UUID_MAX, | 52 | NFIT_UUID_MAX, |
| 42 | }; | 53 | }; |
| 43 | 54 | ||
| @@ -111,6 +122,7 @@ struct nfit_mem { | |||
| 111 | struct acpi_device *adev; | 122 | struct acpi_device *adev; |
| 112 | struct acpi_nfit_desc *acpi_desc; | 123 | struct acpi_nfit_desc *acpi_desc; |
| 113 | unsigned long dsm_mask; | 124 | unsigned long dsm_mask; |
| 125 | int family; | ||
| 114 | }; | 126 | }; |
| 115 | 127 | ||
| 116 | struct acpi_nfit_desc { | 128 | struct acpi_nfit_desc { |
| @@ -133,8 +145,8 @@ struct acpi_nfit_desc { | |||
| 133 | size_t ars_status_size; | 145 | size_t ars_status_size; |
| 134 | struct work_struct work; | 146 | struct work_struct work; |
| 135 | unsigned int cancel:1; | 147 | unsigned int cancel:1; |
| 136 | unsigned long dimm_dsm_force_en; | 148 | unsigned long dimm_cmd_force_en; |
| 137 | unsigned long bus_dsm_force_en; | 149 | unsigned long bus_cmd_force_en; |
| 138 | int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, | 150 | int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, |
| 139 | void *iobuf, u64 len, int rw); | 151 | void *iobuf, u64 len, int rw); |
| 140 | }; | 152 | }; |
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 050673f0c0b3..e854dea7d5fe 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c | |||
| @@ -625,7 +625,7 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) | |||
| 625 | * some old BIOSes do expect a buffer or an integer etc. | 625 | * some old BIOSes do expect a buffer or an integer etc. |
| 626 | */ | 626 | */ |
| 627 | union acpi_object * | 627 | union acpi_object * |
| 628 | acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func, | 628 | acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 func, |
| 629 | union acpi_object *argv4) | 629 | union acpi_object *argv4) |
| 630 | { | 630 | { |
| 631 | acpi_status ret; | 631 | acpi_status ret; |
| @@ -674,7 +674,7 @@ EXPORT_SYMBOL(acpi_evaluate_dsm); | |||
| 674 | * functions. Currently only support 64 functions at maximum, should be | 674 | * functions. Currently only support 64 functions at maximum, should be |
| 675 | * enough for now. | 675 | * enough for now. |
| 676 | */ | 676 | */ |
| 677 | bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs) | 677 | bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs) |
| 678 | { | 678 | { |
| 679 | int i; | 679 | int i; |
| 680 | u64 mask = 0; | 680 | u64 mask = 0; |
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index dcaefe229887..04c2c3fda1ab 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c | |||
| @@ -443,6 +443,12 @@ static const struct nd_cmd_desc __nd_cmd_dimm_descs[] = { | |||
| 443 | .out_num = 3, | 443 | .out_num = 3, |
| 444 | .out_sizes = { 4, 4, UINT_MAX, }, | 444 | .out_sizes = { 4, 4, UINT_MAX, }, |
| 445 | }, | 445 | }, |
| 446 | [ND_CMD_CALL] = { | ||
| 447 | .in_num = 2, | ||
| 448 | .in_sizes = { sizeof(struct nd_cmd_pkg), UINT_MAX, }, | ||
| 449 | .out_num = 1, | ||
| 450 | .out_sizes = { UINT_MAX, }, | ||
| 451 | }, | ||
| 446 | }; | 452 | }; |
| 447 | 453 | ||
| 448 | const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd) | 454 | const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd) |
| @@ -477,6 +483,12 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = { | |||
| 477 | .out_num = 3, | 483 | .out_num = 3, |
| 478 | .out_sizes = { 4, 4, 8, }, | 484 | .out_sizes = { 4, 4, 8, }, |
| 479 | }, | 485 | }, |
| 486 | [ND_CMD_CALL] = { | ||
| 487 | .in_num = 2, | ||
| 488 | .in_sizes = { sizeof(struct nd_cmd_pkg), UINT_MAX, }, | ||
| 489 | .out_num = 1, | ||
| 490 | .out_sizes = { UINT_MAX, }, | ||
| 491 | }, | ||
| 480 | }; | 492 | }; |
| 481 | 493 | ||
| 482 | const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd) | 494 | const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd) |
| @@ -504,6 +516,10 @@ u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, | |||
| 504 | struct nd_cmd_vendor_hdr *hdr = buf; | 516 | struct nd_cmd_vendor_hdr *hdr = buf; |
| 505 | 517 | ||
| 506 | return hdr->in_length; | 518 | return hdr->in_length; |
| 519 | } else if (cmd == ND_CMD_CALL) { | ||
| 520 | struct nd_cmd_pkg *pkg = buf; | ||
| 521 | |||
| 522 | return pkg->nd_size_in; | ||
| 507 | } | 523 | } |
| 508 | 524 | ||
| 509 | return UINT_MAX; | 525 | return UINT_MAX; |
| @@ -526,6 +542,12 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd, | |||
| 526 | return out_field[1]; | 542 | return out_field[1]; |
| 527 | else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2) | 543 | else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2) |
| 528 | return out_field[1] - 8; | 544 | return out_field[1] - 8; |
| 545 | else if (cmd == ND_CMD_CALL) { | ||
| 546 | struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field; | ||
| 547 | |||
| 548 | return pkg->nd_size_out; | ||
| 549 | } | ||
| 550 | |||
| 529 | 551 | ||
| 530 | return UINT_MAX; | 552 | return UINT_MAX; |
| 531 | } | 553 | } |
| @@ -592,25 +614,31 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
| 592 | unsigned int cmd = _IOC_NR(ioctl_cmd); | 614 | unsigned int cmd = _IOC_NR(ioctl_cmd); |
| 593 | void __user *p = (void __user *) arg; | 615 | void __user *p = (void __user *) arg; |
| 594 | struct device *dev = &nvdimm_bus->dev; | 616 | struct device *dev = &nvdimm_bus->dev; |
| 617 | struct nd_cmd_pkg pkg; | ||
| 595 | const char *cmd_name, *dimm_name; | 618 | const char *cmd_name, *dimm_name; |
| 596 | unsigned long dsm_mask; | 619 | unsigned long cmd_mask; |
| 597 | void *buf; | 620 | void *buf; |
| 598 | int rc, i; | 621 | int rc, i; |
| 599 | 622 | ||
| 600 | if (nvdimm) { | 623 | if (nvdimm) { |
| 601 | desc = nd_cmd_dimm_desc(cmd); | 624 | desc = nd_cmd_dimm_desc(cmd); |
| 602 | cmd_name = nvdimm_cmd_name(cmd); | 625 | cmd_name = nvdimm_cmd_name(cmd); |
| 603 | dsm_mask = nvdimm->dsm_mask ? *(nvdimm->dsm_mask) : 0; | 626 | cmd_mask = nvdimm->cmd_mask; |
| 604 | dimm_name = dev_name(&nvdimm->dev); | 627 | dimm_name = dev_name(&nvdimm->dev); |
| 605 | } else { | 628 | } else { |
| 606 | desc = nd_cmd_bus_desc(cmd); | 629 | desc = nd_cmd_bus_desc(cmd); |
| 607 | cmd_name = nvdimm_bus_cmd_name(cmd); | 630 | cmd_name = nvdimm_bus_cmd_name(cmd); |
| 608 | dsm_mask = nd_desc->dsm_mask; | 631 | cmd_mask = nd_desc->cmd_mask; |
| 609 | dimm_name = "bus"; | 632 | dimm_name = "bus"; |
| 610 | } | 633 | } |
| 611 | 634 | ||
| 635 | if (cmd == ND_CMD_CALL) { | ||
| 636 | if (copy_from_user(&pkg, p, sizeof(pkg))) | ||
| 637 | return -EFAULT; | ||
| 638 | } | ||
| 639 | |||
| 612 | if (!desc || (desc->out_num + desc->in_num == 0) || | 640 | if (!desc || (desc->out_num + desc->in_num == 0) || |
| 613 | !test_bit(cmd, &dsm_mask)) | 641 | !test_bit(cmd, &cmd_mask)) |
| 614 | return -ENOTTY; | 642 | return -ENOTTY; |
| 615 | 643 | ||
| 616 | /* fail write commands (when read-only) */ | 644 | /* fail write commands (when read-only) */ |
| @@ -620,6 +648,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
| 620 | case ND_CMD_SET_CONFIG_DATA: | 648 | case ND_CMD_SET_CONFIG_DATA: |
| 621 | case ND_CMD_ARS_START: | 649 | case ND_CMD_ARS_START: |
| 622 | case ND_CMD_CLEAR_ERROR: | 650 | case ND_CMD_CLEAR_ERROR: |
| 651 | case ND_CMD_CALL: | ||
| 623 | dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n", | 652 | dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n", |
| 624 | nvdimm ? nvdimm_cmd_name(cmd) | 653 | nvdimm ? nvdimm_cmd_name(cmd) |
| 625 | : nvdimm_bus_cmd_name(cmd)); | 654 | : nvdimm_bus_cmd_name(cmd)); |
| @@ -647,6 +676,16 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
| 647 | in_len += in_size; | 676 | in_len += in_size; |
| 648 | } | 677 | } |
| 649 | 678 | ||
| 679 | if (cmd == ND_CMD_CALL) { | ||
| 680 | dev_dbg(dev, "%s:%s, idx: %llu, in: %zu, out: %zu, len %zu\n", | ||
| 681 | __func__, dimm_name, pkg.nd_command, | ||
| 682 | in_len, out_len, buf_len); | ||
| 683 | |||
| 684 | for (i = 0; i < ARRAY_SIZE(pkg.nd_reserved2); i++) | ||
| 685 | if (pkg.nd_reserved2[i]) | ||
| 686 | return -EINVAL; | ||
| 687 | } | ||
| 688 | |||
| 650 | /* process an output envelope */ | 689 | /* process an output envelope */ |
| 651 | for (i = 0; i < desc->out_num; i++) { | 690 | for (i = 0; i < desc->out_num; i++) { |
| 652 | u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, | 691 | u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, |
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index 182a93fe3712..e8688a13cf4f 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c | |||
| @@ -251,7 +251,7 @@ static ssize_t commands_show(struct device *dev, | |||
| 251 | struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev); | 251 | struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev); |
| 252 | struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc; | 252 | struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc; |
| 253 | 253 | ||
| 254 | for_each_set_bit(cmd, &nd_desc->dsm_mask, BITS_PER_LONG) | 254 | for_each_set_bit(cmd, &nd_desc->cmd_mask, BITS_PER_LONG) |
| 255 | len += sprintf(buf + len, "%s ", nvdimm_bus_cmd_name(cmd)); | 255 | len += sprintf(buf + len, "%s ", nvdimm_bus_cmd_name(cmd)); |
| 256 | len += sprintf(buf + len, "\n"); | 256 | len += sprintf(buf + len, "\n"); |
| 257 | return len; | 257 | return len; |
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index c56f88217924..79a35a02053c 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c | |||
| @@ -37,9 +37,9 @@ static int __validate_dimm(struct nvdimm_drvdata *ndd) | |||
| 37 | 37 | ||
| 38 | nvdimm = to_nvdimm(ndd->dev); | 38 | nvdimm = to_nvdimm(ndd->dev); |
| 39 | 39 | ||
| 40 | if (!nvdimm->dsm_mask) | 40 | if (!nvdimm->cmd_mask) |
| 41 | return -ENXIO; | 41 | return -ENXIO; |
| 42 | if (!test_bit(ND_CMD_GET_CONFIG_DATA, nvdimm->dsm_mask)) | 42 | if (!test_bit(ND_CMD_GET_CONFIG_DATA, &nvdimm->cmd_mask)) |
| 43 | return -ENXIO; | 43 | return -ENXIO; |
| 44 | 44 | ||
| 45 | return 0; | 45 | return 0; |
| @@ -263,6 +263,12 @@ const char *nvdimm_name(struct nvdimm *nvdimm) | |||
| 263 | } | 263 | } |
| 264 | EXPORT_SYMBOL_GPL(nvdimm_name); | 264 | EXPORT_SYMBOL_GPL(nvdimm_name); |
| 265 | 265 | ||
| 266 | unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm) | ||
| 267 | { | ||
| 268 | return nvdimm->cmd_mask; | ||
| 269 | } | ||
| 270 | EXPORT_SYMBOL_GPL(nvdimm_cmd_mask); | ||
| 271 | |||
| 266 | void *nvdimm_provider_data(struct nvdimm *nvdimm) | 272 | void *nvdimm_provider_data(struct nvdimm *nvdimm) |
| 267 | { | 273 | { |
| 268 | if (nvdimm) | 274 | if (nvdimm) |
| @@ -277,10 +283,10 @@ static ssize_t commands_show(struct device *dev, | |||
| 277 | struct nvdimm *nvdimm = to_nvdimm(dev); | 283 | struct nvdimm *nvdimm = to_nvdimm(dev); |
| 278 | int cmd, len = 0; | 284 | int cmd, len = 0; |
| 279 | 285 | ||
| 280 | if (!nvdimm->dsm_mask) | 286 | if (!nvdimm->cmd_mask) |
| 281 | return sprintf(buf, "\n"); | 287 | return sprintf(buf, "\n"); |
| 282 | 288 | ||
| 283 | for_each_set_bit(cmd, nvdimm->dsm_mask, BITS_PER_LONG) | 289 | for_each_set_bit(cmd, &nvdimm->cmd_mask, BITS_PER_LONG) |
| 284 | len += sprintf(buf + len, "%s ", nvdimm_cmd_name(cmd)); | 290 | len += sprintf(buf + len, "%s ", nvdimm_cmd_name(cmd)); |
| 285 | len += sprintf(buf + len, "\n"); | 291 | len += sprintf(buf + len, "\n"); |
| 286 | return len; | 292 | return len; |
| @@ -340,7 +346,7 @@ EXPORT_SYMBOL_GPL(nvdimm_attribute_group); | |||
| 340 | 346 | ||
| 341 | struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, | 347 | struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, |
| 342 | const struct attribute_group **groups, unsigned long flags, | 348 | const struct attribute_group **groups, unsigned long flags, |
| 343 | unsigned long *dsm_mask) | 349 | unsigned long cmd_mask) |
| 344 | { | 350 | { |
| 345 | struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL); | 351 | struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL); |
| 346 | struct device *dev; | 352 | struct device *dev; |
| @@ -355,7 +361,7 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, | |||
| 355 | } | 361 | } |
| 356 | nvdimm->provider_data = provider_data; | 362 | nvdimm->provider_data = provider_data; |
| 357 | nvdimm->flags = flags; | 363 | nvdimm->flags = flags; |
| 358 | nvdimm->dsm_mask = dsm_mask; | 364 | nvdimm->cmd_mask = cmd_mask; |
| 359 | atomic_set(&nvdimm->busy, 0); | 365 | atomic_set(&nvdimm->busy, 0); |
| 360 | dev = &nvdimm->dev; | 366 | dev = &nvdimm->dev; |
| 361 | dev_set_name(dev, "nmem%d", nvdimm->id); | 367 | dev_set_name(dev, "nmem%d", nvdimm->id); |
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index cb65308c0329..86d985ccce82 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h | |||
| @@ -37,7 +37,7 @@ struct nvdimm_bus { | |||
| 37 | struct nvdimm { | 37 | struct nvdimm { |
| 38 | unsigned long flags; | 38 | unsigned long flags; |
| 39 | void *provider_data; | 39 | void *provider_data; |
| 40 | unsigned long *dsm_mask; | 40 | unsigned long cmd_mask; |
| 41 | struct device dev; | 41 | struct device dev; |
| 42 | atomic_t busy; | 42 | atomic_t busy; |
| 43 | int id; | 43 | int id; |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 14362a84c78e..f092cc6eb1fb 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
| @@ -61,12 +61,12 @@ bool acpi_ata_match(acpi_handle handle); | |||
| 61 | bool acpi_bay_match(acpi_handle handle); | 61 | bool acpi_bay_match(acpi_handle handle); |
| 62 | bool acpi_dock_match(acpi_handle handle); | 62 | bool acpi_dock_match(acpi_handle handle); |
| 63 | 63 | ||
| 64 | bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs); | 64 | bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs); |
| 65 | union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, | 65 | union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, |
| 66 | int rev, int func, union acpi_object *argv4); | 66 | u64 rev, u64 func, union acpi_object *argv4); |
| 67 | 67 | ||
| 68 | static inline union acpi_object * | 68 | static inline union acpi_object * |
| 69 | acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, int rev, int func, | 69 | acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, u64 rev, u64 func, |
| 70 | union acpi_object *argv4, acpi_object_type type) | 70 | union acpi_object *argv4, acpi_object_type type) |
| 71 | { | 71 | { |
| 72 | union acpi_object *obj; | 72 | union acpi_object *obj; |
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 833867b9ddc2..0c3c30cbbea5 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h | |||
| @@ -27,7 +27,7 @@ enum { | |||
| 27 | /* need to set a limit somewhere, but yes, this is likely overkill */ | 27 | /* need to set a limit somewhere, but yes, this is likely overkill */ |
| 28 | ND_IOCTL_MAX_BUFLEN = SZ_4M, | 28 | ND_IOCTL_MAX_BUFLEN = SZ_4M, |
| 29 | ND_CMD_MAX_ELEM = 5, | 29 | ND_CMD_MAX_ELEM = 5, |
| 30 | ND_CMD_MAX_ENVELOPE = 16, | 30 | ND_CMD_MAX_ENVELOPE = 256, |
| 31 | ND_MAX_MAPPINGS = 32, | 31 | ND_MAX_MAPPINGS = 32, |
| 32 | 32 | ||
| 33 | /* region flag indicating to direct-map persistent memory by default */ | 33 | /* region flag indicating to direct-map persistent memory by default */ |
| @@ -68,7 +68,7 @@ struct nd_mapping { | |||
| 68 | 68 | ||
| 69 | struct nvdimm_bus_descriptor { | 69 | struct nvdimm_bus_descriptor { |
| 70 | const struct attribute_group **attr_groups; | 70 | const struct attribute_group **attr_groups; |
| 71 | unsigned long dsm_mask; | 71 | unsigned long cmd_mask; |
| 72 | char *provider_name; | 72 | char *provider_name; |
| 73 | ndctl_fn ndctl; | 73 | ndctl_fn ndctl; |
| 74 | int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc); | 74 | int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc); |
| @@ -130,10 +130,11 @@ struct nd_region *to_nd_region(struct device *dev); | |||
| 130 | struct nd_blk_region *to_nd_blk_region(struct device *dev); | 130 | struct nd_blk_region *to_nd_blk_region(struct device *dev); |
| 131 | struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus); | 131 | struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus); |
| 132 | const char *nvdimm_name(struct nvdimm *nvdimm); | 132 | const char *nvdimm_name(struct nvdimm *nvdimm); |
| 133 | unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm); | ||
| 133 | void *nvdimm_provider_data(struct nvdimm *nvdimm); | 134 | void *nvdimm_provider_data(struct nvdimm *nvdimm); |
| 134 | struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, | 135 | struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, |
| 135 | const struct attribute_group **groups, unsigned long flags, | 136 | const struct attribute_group **groups, unsigned long flags, |
| 136 | unsigned long *dsm_mask); | 137 | unsigned long cmd_mask); |
| 137 | const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); | 138 | const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); |
| 138 | const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); | 139 | const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); |
| 139 | u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, | 140 | u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, |
diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index 1eac426aead5..309915f74492 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h | |||
| @@ -159,6 +159,7 @@ enum { | |||
| 159 | ND_CMD_VENDOR_EFFECT_LOG_SIZE = 7, | 159 | ND_CMD_VENDOR_EFFECT_LOG_SIZE = 7, |
| 160 | ND_CMD_VENDOR_EFFECT_LOG = 8, | 160 | ND_CMD_VENDOR_EFFECT_LOG = 8, |
| 161 | ND_CMD_VENDOR = 9, | 161 | ND_CMD_VENDOR = 9, |
| 162 | ND_CMD_CALL = 10, | ||
| 162 | }; | 163 | }; |
| 163 | 164 | ||
| 164 | enum { | 165 | enum { |
| @@ -192,6 +193,7 @@ static inline const char *nvdimm_cmd_name(unsigned cmd) | |||
| 192 | [ND_CMD_VENDOR_EFFECT_LOG_SIZE] = "effect_size", | 193 | [ND_CMD_VENDOR_EFFECT_LOG_SIZE] = "effect_size", |
| 193 | [ND_CMD_VENDOR_EFFECT_LOG] = "effect_log", | 194 | [ND_CMD_VENDOR_EFFECT_LOG] = "effect_log", |
| 194 | [ND_CMD_VENDOR] = "vendor", | 195 | [ND_CMD_VENDOR] = "vendor", |
| 196 | [ND_CMD_CALL] = "cmd_call", | ||
| 195 | }; | 197 | }; |
| 196 | 198 | ||
| 197 | if (cmd < ARRAY_SIZE(names) && names[cmd]) | 199 | if (cmd < ARRAY_SIZE(names) && names[cmd]) |
| @@ -260,4 +262,44 @@ enum ars_masks { | |||
| 260 | ARS_STATUS_MASK = 0x0000FFFF, | 262 | ARS_STATUS_MASK = 0x0000FFFF, |
| 261 | ARS_EXT_STATUS_SHIFT = 16, | 263 | ARS_EXT_STATUS_SHIFT = 16, |
| 262 | }; | 264 | }; |
| 265 | |||
| 266 | /* | ||
| 267 | * struct nd_cmd_pkg | ||
| 268 | * | ||
| 269 | * is a wrapper to a quasi pass thru interface for invoking firmware | ||
| 270 | * associated with nvdimms. | ||
| 271 | * | ||
| 272 | * INPUT PARAMETERS | ||
| 273 | * | ||
| 274 | * nd_family corresponds to the firmware (e.g. DSM) interface. | ||
| 275 | * | ||
| 276 | * nd_command are the function index advertised by the firmware. | ||
| 277 | * | ||
| 278 | * nd_size_in is the size of the input parameters being passed to firmware | ||
| 279 | * | ||
| 280 | * OUTPUT PARAMETERS | ||
| 281 | * | ||
| 282 | * nd_fw_size is the size of the data firmware wants to return for | ||
| 283 | * the call. If nd_fw_size is greater than size of nd_size_out, only | ||
| 284 | * the first nd_size_out bytes are returned. | ||
| 285 | */ | ||
| 286 | |||
| 287 | struct nd_cmd_pkg { | ||
| 288 | __u64 nd_family; /* family of commands */ | ||
| 289 | __u64 nd_command; | ||
| 290 | __u32 nd_size_in; /* INPUT: size of input args */ | ||
| 291 | __u32 nd_size_out; /* INPUT: size of payload */ | ||
| 292 | __u32 nd_reserved2[9]; /* reserved must be zero */ | ||
| 293 | __u32 nd_fw_size; /* OUTPUT: size fw wants to return */ | ||
| 294 | unsigned char nd_payload[]; /* Contents of call */ | ||
| 295 | }; | ||
| 296 | |||
| 297 | /* These NVDIMM families represent pre-standardization command sets */ | ||
| 298 | #define NVDIMM_FAMILY_INTEL 0 | ||
| 299 | #define NVDIMM_FAMILY_HPE1 1 | ||
| 300 | #define NVDIMM_FAMILY_HPE2 2 | ||
| 301 | |||
| 302 | #define ND_IOCTL_CALL _IOWR(ND_IOCTL, ND_CMD_CALL,\ | ||
| 303 | struct nd_cmd_pkg) | ||
| 304 | |||
| 263 | #endif /* __NDCTL_H__ */ | 305 | #endif /* __NDCTL_H__ */ |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index d1c98d4386d4..c919866853a0 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
| @@ -372,6 +372,7 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 372 | { | 372 | { |
| 373 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); | 373 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); |
| 374 | struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); | 374 | struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); |
| 375 | unsigned int func = cmd; | ||
| 375 | int i, rc = 0, __cmd_rc; | 376 | int i, rc = 0, __cmd_rc; |
| 376 | 377 | ||
| 377 | if (!cmd_rc) | 378 | if (!cmd_rc) |
| @@ -380,8 +381,23 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 380 | 381 | ||
| 381 | if (nvdimm) { | 382 | if (nvdimm) { |
| 382 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | 383 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); |
| 384 | unsigned long cmd_mask = nvdimm_cmd_mask(nvdimm); | ||
| 383 | 385 | ||
| 384 | if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) | 386 | if (!nfit_mem) |
| 387 | return -ENOTTY; | ||
| 388 | |||
| 389 | if (cmd == ND_CMD_CALL) { | ||
| 390 | struct nd_cmd_pkg *call_pkg = buf; | ||
| 391 | |||
| 392 | buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out; | ||
| 393 | buf = (void *) call_pkg->nd_payload; | ||
| 394 | func = call_pkg->nd_command; | ||
| 395 | if (call_pkg->nd_family != nfit_mem->family) | ||
| 396 | return -ENOTTY; | ||
| 397 | } | ||
| 398 | |||
| 399 | if (!test_bit(cmd, &cmd_mask) | ||
| 400 | || !test_bit(func, &nfit_mem->dsm_mask)) | ||
| 385 | return -ENOTTY; | 401 | return -ENOTTY; |
| 386 | 402 | ||
| 387 | /* lookup label space for the given dimm */ | 403 | /* lookup label space for the given dimm */ |
| @@ -392,7 +408,7 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 392 | if (i >= ARRAY_SIZE(handle)) | 408 | if (i >= ARRAY_SIZE(handle)) |
| 393 | return -ENXIO; | 409 | return -ENXIO; |
| 394 | 410 | ||
| 395 | switch (cmd) { | 411 | switch (func) { |
| 396 | case ND_CMD_GET_CONFIG_SIZE: | 412 | case ND_CMD_GET_CONFIG_SIZE: |
| 397 | rc = nfit_test_cmd_get_config_size(buf, buf_len); | 413 | rc = nfit_test_cmd_get_config_size(buf, buf_len); |
| 398 | break; | 414 | break; |
| @@ -416,10 +432,10 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 416 | } else { | 432 | } else { |
| 417 | struct ars_state *ars_state = &t->ars_state; | 433 | struct ars_state *ars_state = &t->ars_state; |
| 418 | 434 | ||
| 419 | if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask)) | 435 | if (!nd_desc || !test_bit(cmd, &nd_desc->cmd_mask)) |
| 420 | return -ENOTTY; | 436 | return -ENOTTY; |
| 421 | 437 | ||
| 422 | switch (cmd) { | 438 | switch (func) { |
| 423 | case ND_CMD_ARS_CAP: | 439 | case ND_CMD_ARS_CAP: |
| 424 | rc = nfit_test_cmd_ars_cap(buf, buf_len); | 440 | rc = nfit_test_cmd_ars_cap(buf, buf_len); |
| 425 | break; | 441 | break; |
| @@ -1293,15 +1309,15 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
| 1293 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE); | 1309 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE); |
| 1294 | 1310 | ||
| 1295 | acpi_desc = &t->acpi_desc; | 1311 | acpi_desc = &t->acpi_desc; |
| 1296 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); | 1312 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); |
| 1297 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); | 1313 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); |
| 1298 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); | 1314 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); |
| 1299 | set_bit(ND_CMD_SMART, &acpi_desc->dimm_dsm_force_en); | 1315 | set_bit(ND_CMD_SMART, &acpi_desc->dimm_cmd_force_en); |
| 1300 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); | 1316 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); |
| 1301 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); | 1317 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
| 1302 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); | 1318 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
| 1303 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_dsm_force_en); | 1319 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); |
| 1304 | set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_dsm_force_en); | 1320 | set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); |
| 1305 | } | 1321 | } |
| 1306 | 1322 | ||
| 1307 | static void nfit_test1_setup(struct nfit_test *t) | 1323 | static void nfit_test1_setup(struct nfit_test *t) |
| @@ -1359,10 +1375,10 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
| 1359 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); | 1375 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); |
| 1360 | 1376 | ||
| 1361 | acpi_desc = &t->acpi_desc; | 1377 | acpi_desc = &t->acpi_desc; |
| 1362 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); | 1378 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); |
| 1363 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); | 1379 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
| 1364 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); | 1380 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
| 1365 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_dsm_force_en); | 1381 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); |
| 1366 | } | 1382 | } |
| 1367 | 1383 | ||
| 1368 | static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, | 1384 | static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, |
