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