diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2017-11-24 17:32:27 -0500 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2017-12-04 13:19:31 -0500 |
| commit | ed07c4338dd5ceadb5ffed0a5be03488ac54f5d2 (patch) | |
| tree | 636c810caed24b852f53624c80096f300c195163 | |
| parent | cdd77d3e193031cc67426cd671d8aa370f7dfee4 (diff) | |
tools/testing/nvdimm: smart alarm/threshold control
Allow the smart_threshold values to be changed via the 'set smart
threshold command' and trigger notifications when the thresholds are
met.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
| -rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 157 | ||||
| -rw-r--r-- | tools/testing/nvdimm/test/nfit_test.h | 9 |
2 files changed, 122 insertions, 44 deletions
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 640c02b08a50..2b57254342aa 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
| @@ -168,6 +168,8 @@ 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 nd_intel_smart *smart; | ||
| 172 | struct nd_intel_smart_threshold *smart_threshold; | ||
| 171 | struct badrange badrange; | 173 | struct badrange badrange; |
| 172 | struct work_struct work; | 174 | struct work_struct work; |
| 173 | }; | 175 | }; |
| @@ -440,50 +442,66 @@ static int nfit_test_cmd_translate_spa(struct nvdimm_bus *bus, | |||
| 440 | return 0; | 442 | return 0; |
| 441 | } | 443 | } |
| 442 | 444 | ||
| 443 | static int nfit_test_cmd_smart(struct nd_intel_smart *smart, unsigned int buf_len) | 445 | static int nfit_test_cmd_smart(struct nd_intel_smart *smart, unsigned int buf_len, |
| 446 | struct nd_intel_smart *smart_data) | ||
| 444 | { | 447 | { |
| 445 | static const struct nd_intel_smart smart_data = { | ||
| 446 | .flags = ND_INTEL_SMART_HEALTH_VALID | ||
| 447 | | ND_INTEL_SMART_SPARES_VALID | ||
| 448 | | ND_INTEL_SMART_ALARM_VALID | ||
| 449 | | ND_INTEL_SMART_USED_VALID | ||
| 450 | | ND_INTEL_SMART_SHUTDOWN_VALID | ||
| 451 | | ND_INTEL_SMART_MTEMP_VALID, | ||
| 452 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, | ||
| 453 | .media_temperature = 23 * 16, | ||
| 454 | .ctrl_temperature = 30 * 16, | ||
| 455 | .pmic_temperature = 40 * 16, | ||
| 456 | .spares = 75, | ||
| 457 | .alarm_flags = ND_INTEL_SMART_SPARE_TRIP | ||
| 458 | | ND_INTEL_SMART_TEMP_TRIP, | ||
| 459 | .ait_status = 1, | ||
| 460 | .life_used = 5, | ||
| 461 | .shutdown_state = 0, | ||
| 462 | .vendor_size = 0, | ||
| 463 | .shutdown_count = 100, | ||
| 464 | }; | ||
| 465 | |||
| 466 | if (buf_len < sizeof(*smart)) | 448 | if (buf_len < sizeof(*smart)) |
| 467 | return -EINVAL; | 449 | return -EINVAL; |
| 468 | memcpy(smart, &smart_data, sizeof(smart_data)); | 450 | memcpy(smart, smart_data, sizeof(*smart)); |
| 469 | return 0; | 451 | return 0; |
| 470 | } | 452 | } |
| 471 | 453 | ||
| 472 | static int nfit_test_cmd_smart_threshold( | 454 | static int nfit_test_cmd_smart_threshold( |
| 473 | struct nd_intel_smart_threshold *smart_t, | 455 | struct nd_intel_smart_threshold *out, |
| 474 | unsigned int buf_len) | 456 | unsigned int buf_len, |
| 457 | struct nd_intel_smart_threshold *smart_t) | ||
| 475 | { | 458 | { |
| 476 | static const struct nd_intel_smart_threshold smart_t_data = { | ||
| 477 | .alarm_control = ND_INTEL_SMART_SPARE_TRIP | ||
| 478 | | ND_INTEL_SMART_TEMP_TRIP, | ||
| 479 | .media_temperature = 40 * 16, | ||
| 480 | .ctrl_temperature = 30 * 16, | ||
| 481 | .spares = 5, | ||
| 482 | }; | ||
| 483 | |||
| 484 | if (buf_len < sizeof(*smart_t)) | 459 | if (buf_len < sizeof(*smart_t)) |
| 485 | return -EINVAL; | 460 | return -EINVAL; |
| 486 | memcpy(smart_t, &smart_t_data, sizeof(smart_t_data)); | 461 | memcpy(out, smart_t, sizeof(*smart_t)); |
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | static void smart_notify(struct device *bus_dev, | ||
| 466 | struct device *dimm_dev, struct nd_intel_smart *smart, | ||
| 467 | struct nd_intel_smart_threshold *thresh) | ||
| 468 | { | ||
| 469 | dev_dbg(dimm_dev, "%s: alarm: %#x spares: %d (%d) mtemp: %d (%d) ctemp: %d (%d)\n", | ||
| 470 | __func__, thresh->alarm_control, thresh->spares, | ||
| 471 | smart->spares, thresh->media_temperature, | ||
| 472 | smart->media_temperature, thresh->ctrl_temperature, | ||
| 473 | smart->ctrl_temperature); | ||
| 474 | if (((thresh->alarm_control & ND_INTEL_SMART_SPARE_TRIP) | ||
| 475 | && smart->spares | ||
| 476 | <= thresh->spares) | ||
| 477 | || ((thresh->alarm_control & ND_INTEL_SMART_TEMP_TRIP) | ||
| 478 | && smart->media_temperature | ||
| 479 | >= thresh->media_temperature) | ||
| 480 | || ((thresh->alarm_control & ND_INTEL_SMART_CTEMP_TRIP) | ||
| 481 | && smart->ctrl_temperature | ||
| 482 | >= thresh->ctrl_temperature)) { | ||
| 483 | device_lock(bus_dev); | ||
| 484 | __acpi_nvdimm_notify(dimm_dev, 0x81); | ||
| 485 | device_unlock(bus_dev); | ||
| 486 | } | ||
| 487 | } | ||
| 488 | |||
| 489 | static int nfit_test_cmd_smart_set_threshold( | ||
| 490 | struct nd_intel_smart_set_threshold *in, | ||
| 491 | unsigned int buf_len, | ||
| 492 | struct nd_intel_smart_threshold *thresh, | ||
| 493 | struct nd_intel_smart *smart, | ||
| 494 | struct device *bus_dev, struct device *dimm_dev) | ||
| 495 | { | ||
| 496 | unsigned int size; | ||
| 497 | |||
| 498 | size = sizeof(*in) - 4; | ||
| 499 | if (buf_len < size) | ||
| 500 | return -EINVAL; | ||
| 501 | memcpy(thresh->data, in, size); | ||
| 502 | in->status = 0; | ||
| 503 | smart_notify(bus_dev, dimm_dev, smart, thresh); | ||
| 504 | |||
| 487 | return 0; | 505 | return 0; |
| 488 | } | 506 | } |
| 489 | 507 | ||
| @@ -608,7 +626,7 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 608 | || !test_bit(func, &nfit_mem->dsm_mask)) | 626 | || !test_bit(func, &nfit_mem->dsm_mask)) |
| 609 | return -ENOTTY; | 627 | return -ENOTTY; |
| 610 | 628 | ||
| 611 | /* lookup label space for the given dimm */ | 629 | /* lookup per-dimm data */ |
| 612 | for (i = 0; i < ARRAY_SIZE(handle); i++) | 630 | for (i = 0; i < ARRAY_SIZE(handle); i++) |
| 613 | if (__to_nfit_memdev(nfit_mem)->device_handle == | 631 | if (__to_nfit_memdev(nfit_mem)->device_handle == |
| 614 | handle[i]) | 632 | handle[i]) |
| @@ -631,14 +649,19 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 631 | rc = nfit_test_cmd_set_config_data(buf, buf_len, | 649 | rc = nfit_test_cmd_set_config_data(buf, buf_len, |
| 632 | t->label[i - t->dcr_idx]); | 650 | t->label[i - t->dcr_idx]); |
| 633 | break; | 651 | break; |
| 634 | case ND_CMD_SMART: | 652 | case ND_INTEL_SMART: |
| 635 | rc = nfit_test_cmd_smart(buf, buf_len); | 653 | rc = nfit_test_cmd_smart(buf, buf_len, |
| 654 | &t->smart[i - t->dcr_idx]); | ||
| 655 | break; | ||
| 656 | case ND_INTEL_SMART_THRESHOLD: | ||
| 657 | rc = nfit_test_cmd_smart_threshold(buf, buf_len, | ||
| 658 | &t->smart_threshold[i - t->dcr_idx]); | ||
| 636 | break; | 659 | break; |
| 637 | case ND_CMD_SMART_THRESHOLD: | 660 | case ND_INTEL_SMART_SET_THRESHOLD: |
| 638 | rc = nfit_test_cmd_smart_threshold(buf, buf_len); | 661 | rc = nfit_test_cmd_smart_set_threshold(buf, buf_len, |
| 639 | device_lock(&t->pdev.dev); | 662 | &t->smart_threshold[i - t->dcr_idx], |
| 640 | __acpi_nvdimm_notify(t->dimm_dev[i], 0x81); | 663 | &t->smart[i - t->dcr_idx], |
| 641 | device_unlock(&t->pdev.dev); | 664 | &t->pdev.dev, t->dimm_dev[i]); |
| 642 | break; | 665 | break; |
| 643 | default: | 666 | default: |
| 644 | return -ENOTTY; | 667 | return -ENOTTY; |
| @@ -883,6 +906,44 @@ static const struct attribute_group *nfit_test_dimm_attribute_groups[] = { | |||
| 883 | NULL, | 906 | NULL, |
| 884 | }; | 907 | }; |
| 885 | 908 | ||
| 909 | static void smart_init(struct nfit_test *t) | ||
| 910 | { | ||
| 911 | int i; | ||
| 912 | const struct nd_intel_smart_threshold smart_t_data = { | ||
| 913 | .alarm_control = ND_INTEL_SMART_SPARE_TRIP | ||
| 914 | | ND_INTEL_SMART_TEMP_TRIP, | ||
| 915 | .media_temperature = 40 * 16, | ||
| 916 | .ctrl_temperature = 30 * 16, | ||
| 917 | .spares = 5, | ||
| 918 | }; | ||
| 919 | const struct nd_intel_smart smart_data = { | ||
| 920 | .flags = ND_INTEL_SMART_HEALTH_VALID | ||
| 921 | | ND_INTEL_SMART_SPARES_VALID | ||
| 922 | | ND_INTEL_SMART_ALARM_VALID | ||
| 923 | | ND_INTEL_SMART_USED_VALID | ||
| 924 | | ND_INTEL_SMART_SHUTDOWN_VALID | ||
| 925 | | ND_INTEL_SMART_MTEMP_VALID, | ||
| 926 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, | ||
| 927 | .media_temperature = 23 * 16, | ||
| 928 | .ctrl_temperature = 30 * 16, | ||
| 929 | .pmic_temperature = 40 * 16, | ||
| 930 | .spares = 75, | ||
| 931 | .alarm_flags = ND_INTEL_SMART_SPARE_TRIP | ||
| 932 | | ND_INTEL_SMART_TEMP_TRIP, | ||
| 933 | .ait_status = 1, | ||
| 934 | .life_used = 5, | ||
| 935 | .shutdown_state = 0, | ||
| 936 | .vendor_size = 0, | ||
| 937 | .shutdown_count = 100, | ||
| 938 | }; | ||
| 939 | |||
| 940 | for (i = 0; i < t->num_dcr; i++) { | ||
| 941 | memcpy(&t->smart[i], &smart_data, sizeof(smart_data)); | ||
| 942 | memcpy(&t->smart_threshold[i], &smart_t_data, | ||
| 943 | sizeof(smart_t_data)); | ||
| 944 | } | ||
| 945 | } | ||
| 946 | |||
| 886 | static int nfit_test0_alloc(struct nfit_test *t) | 947 | static int nfit_test0_alloc(struct nfit_test *t) |
| 887 | { | 948 | { |
| 888 | size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA | 949 | size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA |
| @@ -950,6 +1011,7 @@ static int nfit_test0_alloc(struct nfit_test *t) | |||
| 950 | return -ENOMEM; | 1011 | return -ENOMEM; |
| 951 | } | 1012 | } |
| 952 | 1013 | ||
| 1014 | smart_init(t); | ||
| 953 | return ars_state_init(&t->pdev.dev, &t->ars_state); | 1015 | return ars_state_init(&t->pdev.dev, &t->ars_state); |
| 954 | } | 1016 | } |
| 955 | 1017 | ||
| @@ -980,6 +1042,7 @@ static int nfit_test1_alloc(struct nfit_test *t) | |||
| 980 | if (!t->spa_set[1]) | 1042 | if (!t->spa_set[1]) |
| 981 | return -ENOMEM; | 1043 | return -ENOMEM; |
| 982 | 1044 | ||
| 1045 | smart_init(t); | ||
| 983 | return ars_state_init(&t->pdev.dev, &t->ars_state); | 1046 | return ars_state_init(&t->pdev.dev, &t->ars_state); |
| 984 | } | 1047 | } |
| 985 | 1048 | ||
| @@ -1653,13 +1716,14 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
| 1653 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); | 1716 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); |
| 1654 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); | 1717 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); |
| 1655 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); | 1718 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); |
| 1656 | set_bit(ND_CMD_SMART, &acpi_desc->dimm_cmd_force_en); | 1719 | set_bit(ND_INTEL_SMART, &acpi_desc->dimm_cmd_force_en); |
| 1720 | set_bit(ND_INTEL_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | ||
| 1721 | set_bit(ND_INTEL_SMART_SET_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | ||
| 1657 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); | 1722 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); |
| 1658 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); | 1723 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
| 1659 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); | 1724 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
| 1660 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); | 1725 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); |
| 1661 | set_bit(ND_CMD_CALL, &acpi_desc->bus_cmd_force_en); | 1726 | set_bit(ND_CMD_CALL, &acpi_desc->bus_cmd_force_en); |
| 1662 | set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | ||
| 1663 | set_bit(NFIT_CMD_TRANSLATE_SPA, &acpi_desc->bus_nfit_cmd_force_en); | 1727 | set_bit(NFIT_CMD_TRANSLATE_SPA, &acpi_desc->bus_nfit_cmd_force_en); |
| 1664 | set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_nfit_cmd_force_en); | 1728 | set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_nfit_cmd_force_en); |
| 1665 | set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_nfit_cmd_force_en); | 1729 | set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_nfit_cmd_force_en); |
| @@ -2065,6 +2129,11 @@ static int nfit_test_probe(struct platform_device *pdev) | |||
| 2065 | sizeof(struct nfit_test_dcr *), GFP_KERNEL); | 2129 | sizeof(struct nfit_test_dcr *), GFP_KERNEL); |
| 2066 | nfit_test->dcr_dma = devm_kcalloc(dev, num, | 2130 | nfit_test->dcr_dma = devm_kcalloc(dev, num, |
| 2067 | sizeof(dma_addr_t), GFP_KERNEL); | 2131 | sizeof(dma_addr_t), GFP_KERNEL); |
| 2132 | nfit_test->smart = devm_kcalloc(dev, num, | ||
| 2133 | sizeof(struct nd_intel_smart), GFP_KERNEL); | ||
| 2134 | nfit_test->smart_threshold = devm_kcalloc(dev, num, | ||
| 2135 | sizeof(struct nd_intel_smart_threshold), | ||
| 2136 | GFP_KERNEL); | ||
| 2068 | if (nfit_test->dimm && nfit_test->dimm_dma && nfit_test->label | 2137 | if (nfit_test->dimm && nfit_test->dimm_dma && nfit_test->label |
| 2069 | && nfit_test->label_dma && nfit_test->dcr | 2138 | && nfit_test->label_dma && nfit_test->dcr |
| 2070 | && nfit_test->dcr_dma && nfit_test->flush | 2139 | && nfit_test->dcr_dma && nfit_test->flush |
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index b85fba2856c7..ba230f6f7676 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h | |||
| @@ -86,6 +86,7 @@ struct nd_cmd_ars_err_inj_stat { | |||
| 86 | 86 | ||
| 87 | #define ND_INTEL_SMART 1 | 87 | #define ND_INTEL_SMART 1 |
| 88 | #define ND_INTEL_SMART_THRESHOLD 2 | 88 | #define ND_INTEL_SMART_THRESHOLD 2 |
| 89 | #define ND_INTEL_SMART_SET_THRESHOLD 17 | ||
| 89 | 90 | ||
| 90 | #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) | 91 | #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) |
| 91 | #define ND_INTEL_SMART_SPARES_VALID (1 << 1) | 92 | #define ND_INTEL_SMART_SPARES_VALID (1 << 1) |
| @@ -143,6 +144,14 @@ struct nd_intel_smart_threshold { | |||
| 143 | }; | 144 | }; |
| 144 | } __packed; | 145 | } __packed; |
| 145 | 146 | ||
| 147 | struct nd_intel_smart_set_threshold { | ||
| 148 | __u16 alarm_control; | ||
| 149 | __u8 spares; | ||
| 150 | __u16 media_temperature; | ||
| 151 | __u16 ctrl_temperature; | ||
| 152 | __u32 status; | ||
| 153 | } __packed; | ||
| 154 | |||
| 146 | union acpi_object; | 155 | union acpi_object; |
| 147 | typedef void *acpi_handle; | 156 | typedef void *acpi_handle; |
| 148 | 157 | ||
