summaryrefslogtreecommitdiffstats
path: root/tools/testing
diff options
context:
space:
mode:
authorDave Jiang <dave.jiang@intel.com>2017-10-30 16:22:20 -0400
committerDan Williams <dan.j.williams@intel.com>2017-11-02 13:42:30 -0400
commit9fb1a1903345fea598f48277576a3589a972b72e (patch)
treef531856064348bfdb55e256a988e6b3d411ad026 /tools/testing
parentaa9ad44a42b4cf4387f8ecddaf8e51707fdcda5a (diff)
nfit_test: add error injection DSMs
Add nfit_test emulation for the new ACPI 6.2 error injectino DSMs. This will allow unit tests to selectively inject the errors they wish to test for. Signed-off-by: Dave Jiang <dave.jiang@intel.com> [vishal: Move injection functions to ND_CMD_CALL] [vishal: Add support for the notification option] [vishal: move an nfit_test private definition into a local header] Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/nvdimm/test/nfit.c187
-rw-r--r--tools/testing/nvdimm/test/nfit_test.h5
2 files changed, 168 insertions, 24 deletions
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 3a3bad348d56..788b1a5d6c5a 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -168,8 +168,12 @@ struct nfit_test {
168 spinlock_t lock; 168 spinlock_t lock;
169 } ars_state; 169 } ars_state;
170 struct device *dimm_dev[NUM_DCR]; 170 struct device *dimm_dev[NUM_DCR];
171 struct badrange badrange;
172 struct work_struct work;
171}; 173};
172 174
175static struct workqueue_struct *nfit_wq;
176
173static struct nfit_test *to_nfit_test(struct device *dev) 177static struct nfit_test *to_nfit_test(struct device *dev)
174{ 178{
175 struct platform_device *pdev = to_platform_device(dev); 179 struct platform_device *pdev = to_platform_device(dev);
@@ -234,48 +238,68 @@ static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd,
234 return rc; 238 return rc;
235} 239}
236 240
237#define NFIT_TEST_ARS_RECORDS 4
238#define NFIT_TEST_CLEAR_ERR_UNIT 256 241#define NFIT_TEST_CLEAR_ERR_UNIT 256
239 242
240static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, 243static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd,
241 unsigned int buf_len) 244 unsigned int buf_len)
242{ 245{
246 int ars_recs;
247
243 if (buf_len < sizeof(*nd_cmd)) 248 if (buf_len < sizeof(*nd_cmd))
244 return -EINVAL; 249 return -EINVAL;
245 250
251 /* for testing, only store up to n records that fit within 4k */
252 ars_recs = SZ_4K / sizeof(struct nd_ars_record);
253
246 nd_cmd->max_ars_out = sizeof(struct nd_cmd_ars_status) 254 nd_cmd->max_ars_out = sizeof(struct nd_cmd_ars_status)
247 + NFIT_TEST_ARS_RECORDS * sizeof(struct nd_ars_record); 255 + ars_recs * sizeof(struct nd_ars_record);
248 nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16; 256 nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16;
249 nd_cmd->clear_err_unit = NFIT_TEST_CLEAR_ERR_UNIT; 257 nd_cmd->clear_err_unit = NFIT_TEST_CLEAR_ERR_UNIT;
250 258
251 return 0; 259 return 0;
252} 260}
253 261
254/* 262static void post_ars_status(struct ars_state *ars_state,
255 * Initialize the ars_state to return an ars_result 1 second in the future with 263 struct badrange *badrange, u64 addr, u64 len)
256 * a 4K error range in the middle of the requested address range.
257 */
258static void post_ars_status(struct ars_state *ars_state, u64 addr, u64 len)
259{ 264{
260 struct nd_cmd_ars_status *ars_status; 265 struct nd_cmd_ars_status *ars_status;
261 struct nd_ars_record *ars_record; 266 struct nd_ars_record *ars_record;
267 struct badrange_entry *be;
268 u64 end = addr + len - 1;
269 int i = 0;
262 270
263 ars_state->deadline = jiffies + 1*HZ; 271 ars_state->deadline = jiffies + 1*HZ;
264 ars_status = ars_state->ars_status; 272 ars_status = ars_state->ars_status;
265 ars_status->status = 0; 273 ars_status->status = 0;
266 ars_status->out_length = sizeof(struct nd_cmd_ars_status)
267 + sizeof(struct nd_ars_record);
268 ars_status->address = addr; 274 ars_status->address = addr;
269 ars_status->length = len; 275 ars_status->length = len;
270 ars_status->type = ND_ARS_PERSISTENT; 276 ars_status->type = ND_ARS_PERSISTENT;
271 ars_status->num_records = 1; 277
272 ars_record = &ars_status->records[0]; 278 spin_lock(&badrange->lock);
273 ars_record->handle = 0; 279 list_for_each_entry(be, &badrange->list, list) {
274 ars_record->err_address = addr + len / 2; 280 u64 be_end = be->start + be->length - 1;
275 ars_record->length = SZ_4K; 281 u64 rstart, rend;
282
283 /* skip entries outside the range */
284 if (be_end < addr || be->start > end)
285 continue;
286
287 rstart = (be->start < addr) ? addr : be->start;
288 rend = (be_end < end) ? be_end : end;
289 ars_record = &ars_status->records[i];
290 ars_record->handle = 0;
291 ars_record->err_address = rstart;
292 ars_record->length = rend - rstart + 1;
293 i++;
294 }
295 spin_unlock(&badrange->lock);
296 ars_status->num_records = i;
297 ars_status->out_length = sizeof(struct nd_cmd_ars_status)
298 + i * sizeof(struct nd_ars_record);
276} 299}
277 300
278static int nfit_test_cmd_ars_start(struct ars_state *ars_state, 301static int nfit_test_cmd_ars_start(struct nfit_test *t,
302 struct ars_state *ars_state,
279 struct nd_cmd_ars_start *ars_start, unsigned int buf_len, 303 struct nd_cmd_ars_start *ars_start, unsigned int buf_len,
280 int *cmd_rc) 304 int *cmd_rc)
281{ 305{
@@ -289,7 +313,7 @@ static int nfit_test_cmd_ars_start(struct ars_state *ars_state,
289 } else { 313 } else {
290 ars_start->status = 0; 314 ars_start->status = 0;
291 ars_start->scrub_time = 1; 315 ars_start->scrub_time = 1;
292 post_ars_status(ars_state, ars_start->address, 316 post_ars_status(ars_state, &t->badrange, ars_start->address,
293 ars_start->length); 317 ars_start->length);
294 *cmd_rc = 0; 318 *cmd_rc = 0;
295 } 319 }
@@ -456,6 +480,93 @@ static int nfit_test_cmd_smart_threshold(struct nd_cmd_smart_threshold *smart_t,
456 return 0; 480 return 0;
457} 481}
458 482
483static void uc_error_notify(struct work_struct *work)
484{
485 struct nfit_test *t = container_of(work, typeof(*t), work);
486
487 __acpi_nfit_notify(&t->pdev.dev, t, NFIT_NOTIFY_UC_MEMORY_ERROR);
488}
489
490static int nfit_test_cmd_ars_error_inject(struct nfit_test *t,
491 struct nd_cmd_ars_err_inj *err_inj, unsigned int buf_len)
492{
493 int rc;
494
495 if (buf_len < sizeof(*err_inj)) {
496 rc = -EINVAL;
497 goto err;
498 }
499
500 if (err_inj->err_inj_spa_range_length <= 0) {
501 rc = -EINVAL;
502 goto err;
503 }
504
505 rc = badrange_add(&t->badrange, err_inj->err_inj_spa_range_base,
506 err_inj->err_inj_spa_range_length);
507 if (rc < 0)
508 goto err;
509
510 if (err_inj->err_inj_options & (1 << ND_ARS_ERR_INJ_OPT_NOTIFY))
511 queue_work(nfit_wq, &t->work);
512
513 err_inj->status = 0;
514 return 0;
515
516err:
517 err_inj->status = NFIT_ARS_INJECT_INVALID;
518 return rc;
519}
520
521static int nfit_test_cmd_ars_inject_clear(struct nfit_test *t,
522 struct nd_cmd_ars_err_inj_clr *err_clr, unsigned int buf_len)
523{
524 int rc;
525
526 if (buf_len < sizeof(*err_clr)) {
527 rc = -EINVAL;
528 goto err;
529 }
530
531 if (err_clr->err_inj_clr_spa_range_length <= 0) {
532 rc = -EINVAL;
533 goto err;
534 }
535
536 badrange_forget(&t->badrange, err_clr->err_inj_clr_spa_range_base,
537 err_clr->err_inj_clr_spa_range_length);
538
539 err_clr->status = 0;
540 return 0;
541
542err:
543 err_clr->status = NFIT_ARS_INJECT_INVALID;
544 return rc;
545}
546
547static int nfit_test_cmd_ars_inject_status(struct nfit_test *t,
548 struct nd_cmd_ars_err_inj_stat *err_stat,
549 unsigned int buf_len)
550{
551 struct badrange_entry *be;
552 int max = SZ_4K / sizeof(struct nd_error_stat_query_record);
553 int i = 0;
554
555 err_stat->status = 0;
556 spin_lock(&t->badrange.lock);
557 list_for_each_entry(be, &t->badrange.list, list) {
558 err_stat->record[i].err_inj_stat_spa_range_base = be->start;
559 err_stat->record[i].err_inj_stat_spa_range_length = be->length;
560 i++;
561 if (i > max)
562 break;
563 }
564 spin_unlock(&t->badrange.lock);
565 err_stat->inj_err_rec_count = i;
566
567 return 0;
568}
569
459static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, 570static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
460 struct nvdimm *nvdimm, unsigned int cmd, void *buf, 571 struct nvdimm *nvdimm, unsigned int cmd, void *buf,
461 unsigned int buf_len, int *cmd_rc) 572 unsigned int buf_len, int *cmd_rc)
@@ -543,6 +654,18 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
543 rc = nfit_test_cmd_translate_spa( 654 rc = nfit_test_cmd_translate_spa(
544 acpi_desc->nvdimm_bus, buf, buf_len); 655 acpi_desc->nvdimm_bus, buf, buf_len);
545 return rc; 656 return rc;
657 case NFIT_CMD_ARS_INJECT_SET:
658 rc = nfit_test_cmd_ars_error_inject(t, buf,
659 buf_len);
660 return rc;
661 case NFIT_CMD_ARS_INJECT_CLEAR:
662 rc = nfit_test_cmd_ars_inject_clear(t, buf,
663 buf_len);
664 return rc;
665 case NFIT_CMD_ARS_INJECT_GET:
666 rc = nfit_test_cmd_ars_inject_status(t, buf,
667 buf_len);
668 return rc;
546 default: 669 default:
547 return -ENOTTY; 670 return -ENOTTY;
548 } 671 }
@@ -556,8 +679,8 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
556 rc = nfit_test_cmd_ars_cap(buf, buf_len); 679 rc = nfit_test_cmd_ars_cap(buf, buf_len);
557 break; 680 break;
558 case ND_CMD_ARS_START: 681 case ND_CMD_ARS_START:
559 rc = nfit_test_cmd_ars_start(ars_state, buf, buf_len, 682 rc = nfit_test_cmd_ars_start(t, ars_state, buf,
560 cmd_rc); 683 buf_len, cmd_rc);
561 break; 684 break;
562 case ND_CMD_ARS_STATUS: 685 case ND_CMD_ARS_STATUS:
563 rc = nfit_test_cmd_ars_status(ars_state, buf, buf_len, 686 rc = nfit_test_cmd_ars_status(ars_state, buf, buf_len,
@@ -664,10 +787,9 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
664 787
665static int ars_state_init(struct device *dev, struct ars_state *ars_state) 788static int ars_state_init(struct device *dev, struct ars_state *ars_state)
666{ 789{
790 /* for testing, only store up to n records that fit within 4k */
667 ars_state->ars_status = devm_kzalloc(dev, 791 ars_state->ars_status = devm_kzalloc(dev,
668 sizeof(struct nd_cmd_ars_status) 792 sizeof(struct nd_cmd_ars_status) + SZ_4K, GFP_KERNEL);
669 + sizeof(struct nd_ars_record) * NFIT_TEST_ARS_RECORDS,
670 GFP_KERNEL);
671 if (!ars_state->ars_status) 793 if (!ars_state->ars_status)
672 return -ENOMEM; 794 return -ENOMEM;
673 spin_lock_init(&ars_state->lock); 795 spin_lock_init(&ars_state->lock);
@@ -1517,7 +1639,8 @@ static void nfit_test0_setup(struct nfit_test *t)
1517 + i * sizeof(u64); 1639 + i * sizeof(u64);
1518 } 1640 }
1519 1641
1520 post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE); 1642 post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0],
1643 SPA0_SIZE);
1521 1644
1522 acpi_desc = &t->acpi_desc; 1645 acpi_desc = &t->acpi_desc;
1523 set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); 1646 set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en);
@@ -1531,6 +1654,9 @@ static void nfit_test0_setup(struct nfit_test *t)
1531 set_bit(ND_CMD_CALL, &acpi_desc->bus_cmd_force_en); 1654 set_bit(ND_CMD_CALL, &acpi_desc->bus_cmd_force_en);
1532 set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); 1655 set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en);
1533 set_bit(NFIT_CMD_TRANSLATE_SPA, &acpi_desc->bus_nfit_cmd_force_en); 1656 set_bit(NFIT_CMD_TRANSLATE_SPA, &acpi_desc->bus_nfit_cmd_force_en);
1657 set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_nfit_cmd_force_en);
1658 set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_nfit_cmd_force_en);
1659 set_bit(NFIT_CMD_ARS_INJECT_GET, &acpi_desc->bus_nfit_cmd_force_en);
1534} 1660}
1535 1661
1536static void nfit_test1_setup(struct nfit_test *t) 1662static void nfit_test1_setup(struct nfit_test *t)
@@ -1620,7 +1746,8 @@ static void nfit_test1_setup(struct nfit_test *t)
1620 dcr->code = NFIT_FIC_BYTE; 1746 dcr->code = NFIT_FIC_BYTE;
1621 dcr->windows = 0; 1747 dcr->windows = 0;
1622 1748
1623 post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); 1749 post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0],
1750 SPA2_SIZE);
1624 1751
1625 acpi_desc = &t->acpi_desc; 1752 acpi_desc = &t->acpi_desc;
1626 set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); 1753 set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en);
@@ -1718,7 +1845,10 @@ static int nfit_ctl_test(struct device *dev)
1718 .module = THIS_MODULE, 1845 .module = THIS_MODULE,
1719 .provider_name = "ACPI.NFIT", 1846 .provider_name = "ACPI.NFIT",
1720 .ndctl = acpi_nfit_ctl, 1847 .ndctl = acpi_nfit_ctl,
1721 .bus_dsm_mask = 1UL << NFIT_CMD_TRANSLATE_SPA, 1848 .bus_dsm_mask = 1UL << NFIT_CMD_TRANSLATE_SPA
1849 | 1UL << NFIT_CMD_ARS_INJECT_SET
1850 | 1UL << NFIT_CMD_ARS_INJECT_CLEAR
1851 | 1UL << NFIT_CMD_ARS_INJECT_GET,
1722 }, 1852 },
1723 .dev = &adev->dev, 1853 .dev = &adev->dev,
1724 }; 1854 };
@@ -2017,6 +2147,10 @@ static __init int nfit_test_init(void)
2017 2147
2018 nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm); 2148 nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm);
2019 2149
2150 nfit_wq = create_singlethread_workqueue("nfit");
2151 if (!nfit_wq)
2152 return -ENOMEM;
2153
2020 nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm"); 2154 nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm");
2021 if (IS_ERR(nfit_test_dimm)) { 2155 if (IS_ERR(nfit_test_dimm)) {
2022 rc = PTR_ERR(nfit_test_dimm); 2156 rc = PTR_ERR(nfit_test_dimm);
@@ -2033,6 +2167,7 @@ static __init int nfit_test_init(void)
2033 goto err_register; 2167 goto err_register;
2034 } 2168 }
2035 INIT_LIST_HEAD(&nfit_test->resources); 2169 INIT_LIST_HEAD(&nfit_test->resources);
2170 badrange_init(&nfit_test->badrange);
2036 switch (i) { 2171 switch (i) {
2037 case 0: 2172 case 0:
2038 nfit_test->num_pm = NUM_PM; 2173 nfit_test->num_pm = NUM_PM;
@@ -2068,6 +2203,7 @@ static __init int nfit_test_init(void)
2068 goto err_register; 2203 goto err_register;
2069 2204
2070 instances[i] = nfit_test; 2205 instances[i] = nfit_test;
2206 INIT_WORK(&nfit_test->work, uc_error_notify);
2071 } 2207 }
2072 2208
2073 rc = platform_driver_register(&nfit_test_driver); 2209 rc = platform_driver_register(&nfit_test_driver);
@@ -2076,6 +2212,7 @@ static __init int nfit_test_init(void)
2076 return 0; 2212 return 0;
2077 2213
2078 err_register: 2214 err_register:
2215 destroy_workqueue(nfit_wq);
2079 for (i = 0; i < NUM_NFITS; i++) 2216 for (i = 0; i < NUM_NFITS; i++)
2080 if (instances[i]) 2217 if (instances[i])
2081 platform_device_unregister(&instances[i]->pdev); 2218 platform_device_unregister(&instances[i]->pdev);
@@ -2091,6 +2228,8 @@ static __exit void nfit_test_exit(void)
2091{ 2228{
2092 int i; 2229 int i;
2093 2230
2231 flush_workqueue(nfit_wq);
2232 destroy_workqueue(nfit_wq);
2094 for (i = 0; i < NUM_NFITS; i++) 2233 for (i = 0; i < NUM_NFITS; i++)
2095 platform_device_unregister(&instances[i]->pdev); 2234 platform_device_unregister(&instances[i]->pdev);
2096 platform_driver_unregister(&nfit_test_driver); 2235 platform_driver_unregister(&nfit_test_driver);
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h
index 52c83be9dcfa..113b44675a71 100644
--- a/tools/testing/nvdimm/test/nfit_test.h
+++ b/tools/testing/nvdimm/test/nfit_test.h
@@ -33,6 +33,11 @@ struct nfit_test_resource {
33}; 33};
34 34
35#define ND_TRANSLATE_SPA_STATUS_INVALID_SPA 2 35#define ND_TRANSLATE_SPA_STATUS_INVALID_SPA 2
36#define NFIT_ARS_INJECT_INVALID 2
37
38enum err_inj_options {
39 ND_ARS_ERR_INJ_OPT_NOTIFY = 0,
40};
36 41
37/* nfit commands */ 42/* nfit commands */
38enum nfit_cmd_num { 43enum nfit_cmd_num {