diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2016-02-20 18:12:47 -0500 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2016-03-05 15:24:06 -0500 |
| commit | f471f1a7d0aa58c609e665514010650b2afa24b6 (patch) | |
| tree | 42cfb19d94e1d5ce43d6939f91aa1f5c536e19aa /tools/testing/nvdimm | |
| parent | 87bf572e19a092cc9cc77d5a00d543a2b628c142 (diff) | |
tools/testing/nvdimm: expand ars unit testing
Simulate platform-firmware-initiated and asynchronous scrub results.
This injects poison in the middle of all nfit_test pmem address ranges.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'tools/testing/nvdimm')
| -rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 112 |
1 files changed, 90 insertions, 22 deletions
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index a66842e61bbc..1555c09efba1 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
| @@ -151,6 +151,11 @@ struct nfit_test { | |||
| 151 | int (*alloc)(struct nfit_test *t); | 151 | int (*alloc)(struct nfit_test *t); |
| 152 | void (*setup)(struct nfit_test *t); | 152 | void (*setup)(struct nfit_test *t); |
| 153 | int setup_hotplug; | 153 | int setup_hotplug; |
| 154 | struct ars_state { | ||
| 155 | struct nd_cmd_ars_status *ars_status; | ||
| 156 | unsigned long deadline; | ||
| 157 | spinlock_t lock; | ||
| 158 | } ars_state; | ||
| 154 | }; | 159 | }; |
| 155 | 160 | ||
| 156 | static struct nfit_test *to_nfit_test(struct device *dev) | 161 | static struct nfit_test *to_nfit_test(struct device *dev) |
| @@ -232,30 +237,72 @@ static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, | |||
| 232 | return 0; | 237 | return 0; |
| 233 | } | 238 | } |
| 234 | 239 | ||
| 235 | static int nfit_test_cmd_ars_start(struct nd_cmd_ars_start *nd_cmd, | 240 | /* |
| 236 | unsigned int buf_len) | 241 | * Initialize the ars_state to return an ars_result 1 second in the future with |
| 242 | * a 4K error range in the middle of the requested address range. | ||
| 243 | */ | ||
| 244 | static void post_ars_status(struct ars_state *ars_state, u64 addr, u64 len) | ||
| 237 | { | 245 | { |
| 238 | if (buf_len < sizeof(*nd_cmd)) | 246 | struct nd_cmd_ars_status *ars_status; |
| 247 | struct nd_ars_record *ars_record; | ||
| 248 | |||
| 249 | ars_state->deadline = jiffies + 1*HZ; | ||
| 250 | ars_status = ars_state->ars_status; | ||
| 251 | ars_status->status = 0; | ||
| 252 | ars_status->out_length = sizeof(struct nd_cmd_ars_status) | ||
| 253 | + sizeof(struct nd_ars_record); | ||
| 254 | ars_status->address = addr; | ||
| 255 | ars_status->length = len; | ||
| 256 | ars_status->type = ND_ARS_PERSISTENT; | ||
| 257 | ars_status->num_records = 1; | ||
| 258 | ars_record = &ars_status->records[0]; | ||
| 259 | ars_record->handle = 0; | ||
| 260 | ars_record->err_address = addr + len / 2; | ||
| 261 | ars_record->length = SZ_4K; | ||
| 262 | } | ||
| 263 | |||
| 264 | static int nfit_test_cmd_ars_start(struct ars_state *ars_state, | ||
| 265 | struct nd_cmd_ars_start *ars_start, unsigned int buf_len, | ||
| 266 | int *cmd_rc) | ||
| 267 | { | ||
| 268 | if (buf_len < sizeof(*ars_start)) | ||
| 239 | return -EINVAL; | 269 | return -EINVAL; |
| 240 | 270 | ||
| 241 | nd_cmd->status = 0; | 271 | spin_lock(&ars_state->lock); |
| 272 | if (time_before(jiffies, ars_state->deadline)) { | ||
| 273 | ars_start->status = NFIT_ARS_START_BUSY; | ||
| 274 | *cmd_rc = -EBUSY; | ||
| 275 | } else { | ||
| 276 | ars_start->status = 0; | ||
| 277 | ars_start->scrub_time = 1; | ||
| 278 | post_ars_status(ars_state, ars_start->address, | ||
| 279 | ars_start->length); | ||
| 280 | *cmd_rc = 0; | ||
| 281 | } | ||
| 282 | spin_unlock(&ars_state->lock); | ||
| 242 | 283 | ||
| 243 | return 0; | 284 | return 0; |
| 244 | } | 285 | } |
| 245 | 286 | ||
| 246 | static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd, | 287 | static int nfit_test_cmd_ars_status(struct ars_state *ars_state, |
| 247 | unsigned int buf_len) | 288 | struct nd_cmd_ars_status *ars_status, unsigned int buf_len, |
| 289 | int *cmd_rc) | ||
| 248 | { | 290 | { |
| 249 | if (buf_len < sizeof(*nd_cmd)) | 291 | if (buf_len < ars_state->ars_status->out_length) |
| 250 | return -EINVAL; | 292 | return -EINVAL; |
| 251 | 293 | ||
| 252 | nd_cmd->out_length = sizeof(struct nd_cmd_ars_status); | 294 | spin_lock(&ars_state->lock); |
| 253 | /* TODO: emit error records */ | 295 | if (time_before(jiffies, ars_state->deadline)) { |
| 254 | nd_cmd->num_records = 0; | 296 | memset(ars_status, 0, buf_len); |
| 255 | nd_cmd->address = 0; | 297 | ars_status->status = NFIT_ARS_STATUS_BUSY; |
| 256 | nd_cmd->length = -1ULL; | 298 | ars_status->out_length = sizeof(*ars_status); |
| 257 | nd_cmd->status = 0; | 299 | *cmd_rc = -EBUSY; |
| 258 | 300 | } else { | |
| 301 | memcpy(ars_status, ars_state->ars_status, | ||
| 302 | ars_state->ars_status->out_length); | ||
| 303 | *cmd_rc = 0; | ||
| 304 | } | ||
| 305 | spin_unlock(&ars_state->lock); | ||
| 259 | return 0; | 306 | return 0; |
| 260 | } | 307 | } |
| 261 | 308 | ||
| @@ -265,7 +312,11 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 265 | { | 312 | { |
| 266 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); | 313 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); |
| 267 | struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); | 314 | struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); |
| 268 | int i, rc = 0; | 315 | int i, rc = 0, __cmd_rc; |
| 316 | |||
| 317 | if (!cmd_rc) | ||
| 318 | cmd_rc = &__cmd_rc; | ||
| 319 | *cmd_rc = 0; | ||
| 269 | 320 | ||
| 270 | if (nvdimm) { | 321 | if (nvdimm) { |
| 271 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | 322 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); |
| @@ -297,6 +348,8 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 297 | return -ENOTTY; | 348 | return -ENOTTY; |
| 298 | } | 349 | } |
| 299 | } else { | 350 | } else { |
| 351 | struct ars_state *ars_state = &t->ars_state; | ||
| 352 | |||
| 300 | if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask)) | 353 | if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask)) |
| 301 | return -ENOTTY; | 354 | return -ENOTTY; |
| 302 | 355 | ||
| @@ -305,19 +358,18 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 305 | rc = nfit_test_cmd_ars_cap(buf, buf_len); | 358 | rc = nfit_test_cmd_ars_cap(buf, buf_len); |
| 306 | break; | 359 | break; |
| 307 | case ND_CMD_ARS_START: | 360 | case ND_CMD_ARS_START: |
| 308 | rc = nfit_test_cmd_ars_start(buf, buf_len); | 361 | rc = nfit_test_cmd_ars_start(ars_state, buf, buf_len, |
| 362 | cmd_rc); | ||
| 309 | break; | 363 | break; |
| 310 | case ND_CMD_ARS_STATUS: | 364 | case ND_CMD_ARS_STATUS: |
| 311 | rc = nfit_test_cmd_ars_status(buf, buf_len); | 365 | rc = nfit_test_cmd_ars_status(ars_state, buf, buf_len, |
| 366 | cmd_rc); | ||
| 312 | break; | 367 | break; |
| 313 | default: | 368 | default: |
| 314 | return -ENOTTY; | 369 | return -ENOTTY; |
| 315 | } | 370 | } |
| 316 | } | 371 | } |
| 317 | 372 | ||
| 318 | /* TODO: error status tests */ | ||
| 319 | if (cmd_rc) | ||
| 320 | *cmd_rc = 0; | ||
| 321 | return rc; | 373 | return rc; |
| 322 | } | 374 | } |
| 323 | 375 | ||
| @@ -427,6 +479,18 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr) | |||
| 427 | return NULL; | 479 | return NULL; |
| 428 | } | 480 | } |
| 429 | 481 | ||
| 482 | static int ars_state_init(struct device *dev, struct ars_state *ars_state) | ||
| 483 | { | ||
| 484 | ars_state->ars_status = devm_kzalloc(dev, | ||
| 485 | sizeof(struct nd_cmd_ars_status) | ||
| 486 | + sizeof(struct nd_ars_record) * NFIT_TEST_ARS_RECORDS, | ||
| 487 | GFP_KERNEL); | ||
| 488 | if (!ars_state->ars_status) | ||
| 489 | return -ENOMEM; | ||
| 490 | spin_lock_init(&ars_state->lock); | ||
| 491 | return 0; | ||
| 492 | } | ||
| 493 | |||
| 430 | static int nfit_test0_alloc(struct nfit_test *t) | 494 | static int nfit_test0_alloc(struct nfit_test *t) |
| 431 | { | 495 | { |
| 432 | size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA | 496 | size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA |
| @@ -476,7 +540,7 @@ static int nfit_test0_alloc(struct nfit_test *t) | |||
| 476 | return -ENOMEM; | 540 | return -ENOMEM; |
| 477 | } | 541 | } |
| 478 | 542 | ||
| 479 | return 0; | 543 | return ars_state_init(&t->pdev.dev, &t->ars_state); |
| 480 | } | 544 | } |
| 481 | 545 | ||
| 482 | static int nfit_test1_alloc(struct nfit_test *t) | 546 | static int nfit_test1_alloc(struct nfit_test *t) |
| @@ -494,7 +558,7 @@ static int nfit_test1_alloc(struct nfit_test *t) | |||
| 494 | if (!t->spa_set[0]) | 558 | if (!t->spa_set[0]) |
| 495 | return -ENOMEM; | 559 | return -ENOMEM; |
| 496 | 560 | ||
| 497 | return 0; | 561 | return ars_state_init(&t->pdev.dev, &t->ars_state); |
| 498 | } | 562 | } |
| 499 | 563 | ||
| 500 | static void nfit_test0_setup(struct nfit_test *t) | 564 | static void nfit_test0_setup(struct nfit_test *t) |
| @@ -1157,6 +1221,8 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
| 1157 | flush->hint_address[0] = t->flush_dma[4]; | 1221 | flush->hint_address[0] = t->flush_dma[4]; |
| 1158 | } | 1222 | } |
| 1159 | 1223 | ||
| 1224 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE); | ||
| 1225 | |||
| 1160 | acpi_desc = &t->acpi_desc; | 1226 | acpi_desc = &t->acpi_desc; |
| 1161 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); | 1227 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); |
| 1162 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); | 1228 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); |
| @@ -1218,6 +1284,8 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
| 1218 | dcr->code = NFIT_FIC_BYTE; | 1284 | dcr->code = NFIT_FIC_BYTE; |
| 1219 | dcr->windows = 0; | 1285 | dcr->windows = 0; |
| 1220 | 1286 | ||
| 1287 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); | ||
| 1288 | |||
| 1221 | acpi_desc = &t->acpi_desc; | 1289 | acpi_desc = &t->acpi_desc; |
| 1222 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); | 1290 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); |
| 1223 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); | 1291 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); |
