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, |