Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libnvdimm/nfit_test: add firmware download emulation

Adding support in nfit_test for DSM v1.6 firmware update sequence. The test
will simulate the flashing of firmware to the DIMM. A bogus version string
will be returned as the test has no idea how to parse the firmware binary.
Any bogus binary can be used to "update" as the actual binary is not copied
into the kernel.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Vishal Verma <vishal.l.verma@intel.com>
[ vishal: also move smart calls into the nd_cmd_call block ]
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

authored by

Dave Jiang and committed by
Dan Williams
bfbaa952 1c47a645

+360 -28
+297 -25
tools/testing/nvdimm/test/nfit.c
··· 137 137 138 138 static unsigned long dimm_fail_cmd_flags[NUM_DCR]; 139 139 140 + struct nfit_test_fw { 141 + enum intel_fw_update_state state; 142 + u32 context; 143 + u64 version; 144 + u32 size_received; 145 + u64 end_time; 146 + }; 147 + 140 148 struct nfit_test { 141 149 struct acpi_nfit_desc acpi_desc; 142 150 struct platform_device pdev; ··· 180 172 struct nd_intel_smart_threshold *smart_threshold; 181 173 struct badrange badrange; 182 174 struct work_struct work; 175 + struct nfit_test_fw *fw; 183 176 }; 184 177 185 178 static struct workqueue_struct *nfit_wq; ··· 190 181 struct platform_device *pdev = to_platform_device(dev); 191 182 192 183 return container_of(pdev, struct nfit_test, pdev); 184 + } 185 + 186 + static int nd_intel_test_get_fw_info(struct nfit_test *t, 187 + struct nd_intel_fw_info *nd_cmd, unsigned int buf_len, 188 + int idx) 189 + { 190 + struct device *dev = &t->pdev.dev; 191 + struct nfit_test_fw *fw = &t->fw[idx]; 192 + 193 + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p, buf_len: %u, idx: %d\n", 194 + __func__, t, nd_cmd, buf_len, idx); 195 + 196 + if (buf_len < sizeof(*nd_cmd)) 197 + return -EINVAL; 198 + 199 + nd_cmd->status = 0; 200 + nd_cmd->storage_size = INTEL_FW_STORAGE_SIZE; 201 + nd_cmd->max_send_len = INTEL_FW_MAX_SEND_LEN; 202 + nd_cmd->query_interval = INTEL_FW_QUERY_INTERVAL; 203 + nd_cmd->max_query_time = INTEL_FW_QUERY_MAX_TIME; 204 + nd_cmd->update_cap = 0; 205 + nd_cmd->fis_version = INTEL_FW_FIS_VERSION; 206 + nd_cmd->run_version = 0; 207 + nd_cmd->updated_version = fw->version; 208 + 209 + return 0; 210 + } 211 + 212 + static int nd_intel_test_start_update(struct nfit_test *t, 213 + struct nd_intel_fw_start *nd_cmd, unsigned int buf_len, 214 + int idx) 215 + { 216 + struct device *dev = &t->pdev.dev; 217 + struct nfit_test_fw *fw = &t->fw[idx]; 218 + 219 + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n", 220 + __func__, t, nd_cmd, buf_len, idx); 221 + 222 + if (buf_len < sizeof(*nd_cmd)) 223 + return -EINVAL; 224 + 225 + if (fw->state != FW_STATE_NEW) { 226 + /* extended status, FW update in progress */ 227 + nd_cmd->status = 0x10007; 228 + return 0; 229 + } 230 + 231 + fw->state = FW_STATE_IN_PROGRESS; 232 + fw->context++; 233 + fw->size_received = 0; 234 + nd_cmd->status = 0; 235 + nd_cmd->context = fw->context; 236 + 237 + dev_dbg(dev, "%s: context issued: %#x\n", __func__, nd_cmd->context); 238 + 239 + return 0; 240 + } 241 + 242 + static int nd_intel_test_send_data(struct nfit_test *t, 243 + struct nd_intel_fw_send_data *nd_cmd, unsigned int buf_len, 244 + int idx) 245 + { 246 + struct device *dev = &t->pdev.dev; 247 + struct nfit_test_fw *fw = &t->fw[idx]; 248 + u32 *status = (u32 *)&nd_cmd->data[nd_cmd->length]; 249 + 250 + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n", 251 + __func__, t, nd_cmd, buf_len, idx); 252 + 253 + if (buf_len < sizeof(*nd_cmd)) 254 + return -EINVAL; 255 + 256 + 257 + dev_dbg(dev, "%s: cmd->status: %#x\n", __func__, *status); 258 + dev_dbg(dev, "%s: cmd->data[0]: %#x\n", __func__, nd_cmd->data[0]); 259 + dev_dbg(dev, "%s: cmd->data[%u]: %#x\n", __func__, nd_cmd->length-1, 260 + nd_cmd->data[nd_cmd->length-1]); 261 + 262 + if (fw->state != FW_STATE_IN_PROGRESS) { 263 + dev_dbg(dev, "%s: not in IN_PROGRESS state\n", __func__); 264 + *status = 0x5; 265 + return 0; 266 + } 267 + 268 + if (nd_cmd->context != fw->context) { 269 + dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n", 270 + __func__, nd_cmd->context, fw->context); 271 + *status = 0x10007; 272 + return 0; 273 + } 274 + 275 + /* 276 + * check offset + len > size of fw storage 277 + * check length is > max send length 278 + */ 279 + if (nd_cmd->offset + nd_cmd->length > INTEL_FW_STORAGE_SIZE || 280 + nd_cmd->length > INTEL_FW_MAX_SEND_LEN) { 281 + *status = 0x3; 282 + dev_dbg(dev, "%s: buffer boundary violation\n", __func__); 283 + return 0; 284 + } 285 + 286 + fw->size_received += nd_cmd->length; 287 + dev_dbg(dev, "%s: copying %u bytes, %u bytes so far\n", 288 + __func__, nd_cmd->length, fw->size_received); 289 + *status = 0; 290 + return 0; 291 + } 292 + 293 + static int nd_intel_test_finish_fw(struct nfit_test *t, 294 + struct nd_intel_fw_finish_update *nd_cmd, 295 + unsigned int buf_len, int idx) 296 + { 297 + struct device *dev = &t->pdev.dev; 298 + struct nfit_test_fw *fw = &t->fw[idx]; 299 + 300 + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n", 301 + __func__, t, nd_cmd, buf_len, idx); 302 + 303 + if (fw->state == FW_STATE_UPDATED) { 304 + /* update already done, need cold boot */ 305 + nd_cmd->status = 0x20007; 306 + return 0; 307 + } 308 + 309 + dev_dbg(dev, "%s: context: %#x ctrl_flags: %#x\n", 310 + __func__, nd_cmd->context, nd_cmd->ctrl_flags); 311 + 312 + switch (nd_cmd->ctrl_flags) { 313 + case 0: /* finish */ 314 + if (nd_cmd->context != fw->context) { 315 + dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n", 316 + __func__, nd_cmd->context, 317 + fw->context); 318 + nd_cmd->status = 0x10007; 319 + return 0; 320 + } 321 + nd_cmd->status = 0; 322 + fw->state = FW_STATE_VERIFY; 323 + /* set 1 second of time for firmware "update" */ 324 + fw->end_time = jiffies + HZ; 325 + break; 326 + 327 + case 1: /* abort */ 328 + fw->size_received = 0; 329 + /* successfully aborted status */ 330 + nd_cmd->status = 0x40007; 331 + fw->state = FW_STATE_NEW; 332 + dev_dbg(dev, "%s: abort successful\n", __func__); 333 + break; 334 + 335 + default: /* bad control flag */ 336 + dev_warn(dev, "%s: unknown control flag: %#x\n", 337 + __func__, nd_cmd->ctrl_flags); 338 + return -EINVAL; 339 + } 340 + 341 + return 0; 342 + } 343 + 344 + static int nd_intel_test_finish_query(struct nfit_test *t, 345 + struct nd_intel_fw_finish_query *nd_cmd, 346 + unsigned int buf_len, int idx) 347 + { 348 + struct device *dev = &t->pdev.dev; 349 + struct nfit_test_fw *fw = &t->fw[idx]; 350 + 351 + dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n", 352 + __func__, t, nd_cmd, buf_len, idx); 353 + 354 + if (buf_len < sizeof(*nd_cmd)) 355 + return -EINVAL; 356 + 357 + if (nd_cmd->context != fw->context) { 358 + dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n", 359 + __func__, nd_cmd->context, fw->context); 360 + nd_cmd->status = 0x10007; 361 + return 0; 362 + } 363 + 364 + dev_dbg(dev, "%s context: %#x\n", __func__, nd_cmd->context); 365 + 366 + switch (fw->state) { 367 + case FW_STATE_NEW: 368 + nd_cmd->updated_fw_rev = 0; 369 + nd_cmd->status = 0; 370 + dev_dbg(dev, "%s: new state\n", __func__); 371 + break; 372 + 373 + case FW_STATE_IN_PROGRESS: 374 + /* sequencing error */ 375 + nd_cmd->status = 0x40007; 376 + nd_cmd->updated_fw_rev = 0; 377 + dev_dbg(dev, "%s: sequence error\n", __func__); 378 + break; 379 + 380 + case FW_STATE_VERIFY: 381 + if (time_is_after_jiffies64(fw->end_time)) { 382 + nd_cmd->updated_fw_rev = 0; 383 + nd_cmd->status = 0x20007; 384 + dev_dbg(dev, "%s: still verifying\n", __func__); 385 + break; 386 + } 387 + 388 + dev_dbg(dev, "%s: transition out verify\n", __func__); 389 + fw->state = FW_STATE_UPDATED; 390 + /* we are going to fall through if it's "done" */ 391 + case FW_STATE_UPDATED: 392 + nd_cmd->status = 0; 393 + /* bogus test version */ 394 + fw->version = nd_cmd->updated_fw_rev = 395 + INTEL_FW_FAKE_VERSION; 396 + dev_dbg(dev, "%s: updated\n", __func__); 397 + break; 398 + 399 + default: /* we should never get here */ 400 + return -EINVAL; 401 + } 402 + 403 + return 0; 193 404 } 194 405 195 406 static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd, ··· 821 592 return 0; 822 593 } 823 594 595 + static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) 596 + { 597 + int i; 598 + 599 + /* lookup per-dimm data */ 600 + for (i = 0; i < ARRAY_SIZE(handle); i++) 601 + if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i]) 602 + break; 603 + if (i >= ARRAY_SIZE(handle)) 604 + return -ENXIO; 605 + 606 + if ((1 << func) & dimm_fail_cmd_flags[i]) 607 + return -EIO; 608 + 609 + return i; 610 + } 611 + 824 612 static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, 825 613 struct nvdimm *nvdimm, unsigned int cmd, void *buf, 826 614 unsigned int buf_len, int *cmd_rc) ··· 866 620 func = call_pkg->nd_command; 867 621 if (call_pkg->nd_family != nfit_mem->family) 868 622 return -ENOTTY; 623 + 624 + i = get_dimm(nfit_mem, func); 625 + if (i < 0) 626 + return i; 627 + 628 + switch (func) { 629 + case ND_INTEL_FW_GET_INFO: 630 + return nd_intel_test_get_fw_info(t, buf, 631 + buf_len, i - t->dcr_idx); 632 + case ND_INTEL_FW_START_UPDATE: 633 + return nd_intel_test_start_update(t, buf, 634 + buf_len, i - t->dcr_idx); 635 + case ND_INTEL_FW_SEND_DATA: 636 + return nd_intel_test_send_data(t, buf, 637 + buf_len, i - t->dcr_idx); 638 + case ND_INTEL_FW_FINISH_UPDATE: 639 + return nd_intel_test_finish_fw(t, buf, 640 + buf_len, i - t->dcr_idx); 641 + case ND_INTEL_FW_FINISH_QUERY: 642 + return nd_intel_test_finish_query(t, buf, 643 + buf_len, i - t->dcr_idx); 644 + case ND_INTEL_SMART: 645 + return nfit_test_cmd_smart(buf, buf_len, 646 + &t->smart[i - t->dcr_idx]); 647 + case ND_INTEL_SMART_THRESHOLD: 648 + return nfit_test_cmd_smart_threshold(buf, 649 + buf_len, 650 + &t->smart_threshold[i - 651 + t->dcr_idx]); 652 + case ND_INTEL_SMART_SET_THRESHOLD: 653 + return nfit_test_cmd_smart_set_threshold(buf, 654 + buf_len, 655 + &t->smart_threshold[i - 656 + t->dcr_idx], 657 + &t->smart[i - t->dcr_idx], 658 + &t->pdev.dev, t->dimm_dev[i]); 659 + default: 660 + return -ENOTTY; 661 + } 869 662 } 870 663 871 664 if (!test_bit(cmd, &cmd_mask) 872 665 || !test_bit(func, &nfit_mem->dsm_mask)) 873 666 return -ENOTTY; 874 667 875 - /* lookup per-dimm data */ 876 - for (i = 0; i < ARRAY_SIZE(handle); i++) 877 - if (__to_nfit_memdev(nfit_mem)->device_handle == 878 - handle[i]) 879 - break; 880 - if (i >= ARRAY_SIZE(handle)) 881 - return -ENXIO; 882 - 883 - if ((1 << func) & dimm_fail_cmd_flags[i]) 884 - return -EIO; 668 + i = get_dimm(nfit_mem, func); 669 + if (i < 0) 670 + return i; 885 671 886 672 switch (func) { 887 673 case ND_CMD_GET_CONFIG_SIZE: ··· 926 648 case ND_CMD_SET_CONFIG_DATA: 927 649 rc = nfit_test_cmd_set_config_data(buf, buf_len, 928 650 t->label[i - t->dcr_idx]); 929 - break; 930 - case ND_INTEL_SMART: 931 - rc = nfit_test_cmd_smart(buf, buf_len, 932 - &t->smart[i - t->dcr_idx]); 933 - break; 934 - case ND_INTEL_SMART_THRESHOLD: 935 - rc = nfit_test_cmd_smart_threshold(buf, buf_len, 936 - &t->smart_threshold[i - t->dcr_idx]); 937 - break; 938 - case ND_INTEL_SMART_SET_THRESHOLD: 939 - rc = nfit_test_cmd_smart_set_threshold(buf, buf_len, 940 - &t->smart_threshold[i - t->dcr_idx], 941 - &t->smart[i - t->dcr_idx], 942 - &t->pdev.dev, t->dimm_dev[i]); 943 651 break; 944 652 default: 945 653 return -ENOTTY; ··· 1992 1728 set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_nfit_cmd_force_en); 1993 1729 set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_nfit_cmd_force_en); 1994 1730 set_bit(NFIT_CMD_ARS_INJECT_GET, &acpi_desc->bus_nfit_cmd_force_en); 1731 + set_bit(ND_INTEL_FW_GET_INFO, &acpi_desc->dimm_cmd_force_en); 1732 + set_bit(ND_INTEL_FW_START_UPDATE, &acpi_desc->dimm_cmd_force_en); 1733 + set_bit(ND_INTEL_FW_SEND_DATA, &acpi_desc->dimm_cmd_force_en); 1734 + set_bit(ND_INTEL_FW_FINISH_UPDATE, &acpi_desc->dimm_cmd_force_en); 1735 + set_bit(ND_INTEL_FW_FINISH_QUERY, &acpi_desc->dimm_cmd_force_en); 1995 1736 } 1996 1737 1997 1738 static void nfit_test1_setup(struct nfit_test *t) ··· 2403 2134 nfit_test->smart_threshold = devm_kcalloc(dev, num, 2404 2135 sizeof(struct nd_intel_smart_threshold), 2405 2136 GFP_KERNEL); 2137 + nfit_test->fw = devm_kcalloc(dev, num, 2138 + sizeof(struct nfit_test_fw), GFP_KERNEL); 2406 2139 if (nfit_test->dimm && nfit_test->dimm_dma && nfit_test->label 2407 2140 && nfit_test->label_dma && nfit_test->dcr 2408 2141 && nfit_test->dcr_dma && nfit_test->flush 2409 - && nfit_test->flush_dma) 2142 + && nfit_test->flush_dma 2143 + && nfit_test->fw) 2410 2144 /* pass */; 2411 2145 else 2412 2146 return -ENOMEM;
+63 -3
tools/testing/nvdimm/test/nfit_test.h
··· 84 84 } __packed record[0]; 85 85 } __packed; 86 86 87 - #define ND_INTEL_SMART 1 88 - #define ND_INTEL_SMART_THRESHOLD 2 89 - #define ND_INTEL_SMART_SET_THRESHOLD 17 87 + #define ND_INTEL_SMART 1 88 + #define ND_INTEL_SMART_THRESHOLD 2 89 + #define ND_INTEL_FW_GET_INFO 12 90 + #define ND_INTEL_FW_START_UPDATE 13 91 + #define ND_INTEL_FW_SEND_DATA 14 92 + #define ND_INTEL_FW_FINISH_UPDATE 15 93 + #define ND_INTEL_FW_FINISH_QUERY 16 94 + #define ND_INTEL_SMART_SET_THRESHOLD 17 90 95 91 96 #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) 92 97 #define ND_INTEL_SMART_SPARES_VALID (1 << 1) ··· 155 150 __u16 media_temperature; 156 151 __u16 ctrl_temperature; 157 152 __u32 status; 153 + } __packed; 154 + 155 + #define INTEL_FW_STORAGE_SIZE 0x100000 156 + #define INTEL_FW_MAX_SEND_LEN 0xFFEC 157 + #define INTEL_FW_QUERY_INTERVAL 250000 158 + #define INTEL_FW_QUERY_MAX_TIME 3000000 159 + #define INTEL_FW_FIS_VERSION 0x0105 160 + #define INTEL_FW_FAKE_VERSION 0xffffffffabcd 161 + 162 + enum intel_fw_update_state { 163 + FW_STATE_NEW = 0, 164 + FW_STATE_IN_PROGRESS, 165 + FW_STATE_VERIFY, 166 + FW_STATE_UPDATED, 167 + }; 168 + 169 + struct nd_intel_fw_info { 170 + __u32 status; 171 + __u32 storage_size; 172 + __u32 max_send_len; 173 + __u32 query_interval; 174 + __u32 max_query_time; 175 + __u8 update_cap; 176 + __u8 reserved[3]; 177 + __u32 fis_version; 178 + __u64 run_version; 179 + __u64 updated_version; 180 + } __packed; 181 + 182 + struct nd_intel_fw_start { 183 + __u32 status; 184 + __u32 context; 185 + } __packed; 186 + 187 + /* this one has the output first because the variable input data size */ 188 + struct nd_intel_fw_send_data { 189 + __u32 context; 190 + __u32 offset; 191 + __u32 length; 192 + __u8 data[0]; 193 + /* this field is not declared due ot variable data from input */ 194 + /* __u32 status; */ 195 + } __packed; 196 + 197 + struct nd_intel_fw_finish_update { 198 + __u8 ctrl_flags; 199 + __u8 reserved[3]; 200 + __u32 context; 201 + __u32 status; 202 + } __packed; 203 + 204 + struct nd_intel_fw_finish_query { 205 + __u32 context; 206 + __u32 status; 207 + __u64 updated_fw_rev; 158 208 } __packed; 159 209 160 210 union acpi_object;