diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/acpi/nfit/core.c | 93 | ||||
| -rw-r--r-- | drivers/acpi/nfit/nfit.h | 6 | ||||
| -rw-r--r-- | drivers/nvdimm/btt.c | 33 | ||||
| -rw-r--r-- | drivers/nvdimm/btt.h | 2 | ||||
| -rw-r--r-- | drivers/nvdimm/btt_devs.c | 8 | ||||
| -rw-r--r-- | drivers/nvdimm/dimm_devs.c | 7 | ||||
| -rw-r--r-- | drivers/nvdimm/label.c | 26 | ||||
| -rw-r--r-- | drivers/nvdimm/namespace_devs.c | 14 | ||||
| -rw-r--r-- | drivers/nvdimm/of_pmem.c | 1 | ||||
| -rw-r--r-- | drivers/nvdimm/region_devs.c | 7 |
10 files changed, 147 insertions, 50 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index c34c595d6bb0..c7afb1f223f7 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
| @@ -55,6 +55,10 @@ static bool no_init_ars; | |||
| 55 | module_param(no_init_ars, bool, 0644); | 55 | module_param(no_init_ars, bool, 0644); |
| 56 | MODULE_PARM_DESC(no_init_ars, "Skip ARS run at nfit init time"); | 56 | MODULE_PARM_DESC(no_init_ars, "Skip ARS run at nfit init time"); |
| 57 | 57 | ||
| 58 | static bool force_labels; | ||
| 59 | module_param(force_labels, bool, 0444); | ||
| 60 | MODULE_PARM_DESC(force_labels, "Opt-in to labels despite missing methods"); | ||
| 61 | |||
| 58 | LIST_HEAD(acpi_descs); | 62 | LIST_HEAD(acpi_descs); |
| 59 | DEFINE_MUTEX(acpi_desc_lock); | 63 | DEFINE_MUTEX(acpi_desc_lock); |
| 60 | 64 | ||
| @@ -556,6 +560,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | |||
| 556 | return -EINVAL; | 560 | return -EINVAL; |
| 557 | } | 561 | } |
| 558 | 562 | ||
| 563 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
| 564 | dev_dbg(dev, "%s unexpected output object type cmd: %s type: %d\n", | ||
| 565 | dimm_name, cmd_name, out_obj->type); | ||
| 566 | rc = -EINVAL; | ||
| 567 | goto out; | ||
| 568 | } | ||
| 569 | |||
| 559 | if (call_pkg) { | 570 | if (call_pkg) { |
| 560 | call_pkg->nd_fw_size = out_obj->buffer.length; | 571 | call_pkg->nd_fw_size = out_obj->buffer.length; |
| 561 | memcpy(call_pkg->nd_payload + call_pkg->nd_size_in, | 572 | memcpy(call_pkg->nd_payload + call_pkg->nd_size_in, |
| @@ -574,13 +585,6 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | |||
| 574 | return 0; | 585 | return 0; |
| 575 | } | 586 | } |
| 576 | 587 | ||
| 577 | if (out_obj->package.type != ACPI_TYPE_BUFFER) { | ||
| 578 | dev_dbg(dev, "%s unexpected output object type cmd: %s type: %d\n", | ||
| 579 | dimm_name, cmd_name, out_obj->type); | ||
| 580 | rc = -EINVAL; | ||
| 581 | goto out; | ||
| 582 | } | ||
| 583 | |||
| 584 | dev_dbg(dev, "%s cmd: %s output length: %d\n", dimm_name, | 588 | dev_dbg(dev, "%s cmd: %s output length: %d\n", dimm_name, |
| 585 | cmd_name, out_obj->buffer.length); | 589 | cmd_name, out_obj->buffer.length); |
| 586 | print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, 4, | 590 | print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, 4, |
| @@ -1761,14 +1765,14 @@ static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method) | |||
| 1761 | 1765 | ||
| 1762 | __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) | 1766 | __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) |
| 1763 | { | 1767 | { |
| 1768 | struct device *dev = &nfit_mem->adev->dev; | ||
| 1764 | struct nd_intel_smart smart = { 0 }; | 1769 | struct nd_intel_smart smart = { 0 }; |
| 1765 | union acpi_object in_buf = { | 1770 | union acpi_object in_buf = { |
| 1766 | .type = ACPI_TYPE_BUFFER, | 1771 | .buffer.type = ACPI_TYPE_BUFFER, |
| 1767 | .buffer.pointer = (char *) &smart, | 1772 | .buffer.length = 0, |
| 1768 | .buffer.length = sizeof(smart), | ||
| 1769 | }; | 1773 | }; |
| 1770 | union acpi_object in_obj = { | 1774 | union acpi_object in_obj = { |
| 1771 | .type = ACPI_TYPE_PACKAGE, | 1775 | .package.type = ACPI_TYPE_PACKAGE, |
| 1772 | .package.count = 1, | 1776 | .package.count = 1, |
| 1773 | .package.elements = &in_buf, | 1777 | .package.elements = &in_buf, |
| 1774 | }; | 1778 | }; |
| @@ -1783,8 +1787,15 @@ __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) | |||
| 1783 | return; | 1787 | return; |
| 1784 | 1788 | ||
| 1785 | out_obj = acpi_evaluate_dsm(handle, guid, revid, func, &in_obj); | 1789 | out_obj = acpi_evaluate_dsm(handle, guid, revid, func, &in_obj); |
| 1786 | if (!out_obj) | 1790 | if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER |
| 1791 | || out_obj->buffer.length < sizeof(smart)) { | ||
| 1792 | dev_dbg(dev->parent, "%s: failed to retrieve initial health\n", | ||
| 1793 | dev_name(dev)); | ||
| 1794 | ACPI_FREE(out_obj); | ||
| 1787 | return; | 1795 | return; |
| 1796 | } | ||
| 1797 | memcpy(&smart, out_obj->buffer.pointer, sizeof(smart)); | ||
| 1798 | ACPI_FREE(out_obj); | ||
| 1788 | 1799 | ||
| 1789 | if (smart.flags & ND_INTEL_SMART_SHUTDOWN_VALID) { | 1800 | if (smart.flags & ND_INTEL_SMART_SHUTDOWN_VALID) { |
| 1790 | if (smart.shutdown_state) | 1801 | if (smart.shutdown_state) |
| @@ -1795,7 +1806,6 @@ __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) | |||
| 1795 | set_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags); | 1806 | set_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags); |
| 1796 | nfit_mem->dirty_shutdown = smart.shutdown_count; | 1807 | nfit_mem->dirty_shutdown = smart.shutdown_count; |
| 1797 | } | 1808 | } |
| 1798 | ACPI_FREE(out_obj); | ||
| 1799 | } | 1809 | } |
| 1800 | 1810 | ||
| 1801 | static void populate_shutdown_status(struct nfit_mem *nfit_mem) | 1811 | static void populate_shutdown_status(struct nfit_mem *nfit_mem) |
| @@ -1863,9 +1873,17 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
| 1863 | dev_set_drvdata(&adev_dimm->dev, nfit_mem); | 1873 | dev_set_drvdata(&adev_dimm->dev, nfit_mem); |
| 1864 | 1874 | ||
| 1865 | /* | 1875 | /* |
| 1866 | * Until standardization materializes we need to consider 4 | 1876 | * There are 4 "legacy" NVDIMM command sets |
| 1867 | * different command sets. Note, that checking for function0 (bit0) | 1877 | * (NVDIMM_FAMILY_{INTEL,MSFT,HPE1,HPE2}) that were created before |
| 1868 | * tells us if any commands are reachable through this GUID. | 1878 | * an EFI working group was established to constrain this |
| 1879 | * proliferation. The nfit driver probes for the supported command | ||
| 1880 | * set by GUID. Note, if you're a platform developer looking to add | ||
| 1881 | * a new command set to this probe, consider using an existing set, | ||
| 1882 | * or otherwise seek approval to publish the command set at | ||
| 1883 | * http://www.uefi.org/RFIC_LIST. | ||
| 1884 | * | ||
| 1885 | * Note, that checking for function0 (bit0) tells us if any commands | ||
| 1886 | * are reachable through this GUID. | ||
| 1869 | */ | 1887 | */ |
| 1870 | for (i = 0; i <= NVDIMM_FAMILY_MAX; i++) | 1888 | for (i = 0; i <= NVDIMM_FAMILY_MAX; i++) |
| 1871 | if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1)) | 1889 | if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1)) |
| @@ -1888,6 +1906,8 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
| 1888 | dsm_mask &= ~(1 << 8); | 1906 | dsm_mask &= ~(1 << 8); |
| 1889 | } else if (nfit_mem->family == NVDIMM_FAMILY_MSFT) { | 1907 | } else if (nfit_mem->family == NVDIMM_FAMILY_MSFT) { |
| 1890 | dsm_mask = 0xffffffff; | 1908 | dsm_mask = 0xffffffff; |
| 1909 | } else if (nfit_mem->family == NVDIMM_FAMILY_HYPERV) { | ||
| 1910 | dsm_mask = 0x1f; | ||
| 1891 | } else { | 1911 | } else { |
| 1892 | dev_dbg(dev, "unknown dimm command family\n"); | 1912 | dev_dbg(dev, "unknown dimm command family\n"); |
| 1893 | nfit_mem->family = -1; | 1913 | nfit_mem->family = -1; |
| @@ -1917,18 +1937,32 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
| 1917 | | 1 << ND_CMD_SET_CONFIG_DATA; | 1937 | | 1 << ND_CMD_SET_CONFIG_DATA; |
| 1918 | if (family == NVDIMM_FAMILY_INTEL | 1938 | if (family == NVDIMM_FAMILY_INTEL |
| 1919 | && (dsm_mask & label_mask) == label_mask) | 1939 | && (dsm_mask & label_mask) == label_mask) |
| 1920 | return 0; | 1940 | /* skip _LS{I,R,W} enabling */; |
| 1941 | else { | ||
| 1942 | if (acpi_nvdimm_has_method(adev_dimm, "_LSI") | ||
| 1943 | && acpi_nvdimm_has_method(adev_dimm, "_LSR")) { | ||
| 1944 | dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev)); | ||
| 1945 | set_bit(NFIT_MEM_LSR, &nfit_mem->flags); | ||
| 1946 | } | ||
| 1921 | 1947 | ||
| 1922 | if (acpi_nvdimm_has_method(adev_dimm, "_LSI") | 1948 | if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags) |
| 1923 | && acpi_nvdimm_has_method(adev_dimm, "_LSR")) { | 1949 | && acpi_nvdimm_has_method(adev_dimm, "_LSW")) { |
| 1924 | dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev)); | 1950 | dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev)); |
| 1925 | set_bit(NFIT_MEM_LSR, &nfit_mem->flags); | 1951 | set_bit(NFIT_MEM_LSW, &nfit_mem->flags); |
| 1926 | } | 1952 | } |
| 1927 | 1953 | ||
| 1928 | if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags) | 1954 | /* |
| 1929 | && acpi_nvdimm_has_method(adev_dimm, "_LSW")) { | 1955 | * Quirk read-only label configurations to preserve |
| 1930 | dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev)); | 1956 | * access to label-less namespaces by default. |
| 1931 | set_bit(NFIT_MEM_LSW, &nfit_mem->flags); | 1957 | */ |
| 1958 | if (!test_bit(NFIT_MEM_LSW, &nfit_mem->flags) | ||
| 1959 | && !force_labels) { | ||
| 1960 | dev_dbg(dev, "%s: No _LSW, disable labels\n", | ||
| 1961 | dev_name(&adev_dimm->dev)); | ||
| 1962 | clear_bit(NFIT_MEM_LSR, &nfit_mem->flags); | ||
| 1963 | } else | ||
| 1964 | dev_dbg(dev, "%s: Force enable labels\n", | ||
| 1965 | dev_name(&adev_dimm->dev)); | ||
| 1932 | } | 1966 | } |
| 1933 | 1967 | ||
| 1934 | populate_shutdown_status(nfit_mem); | 1968 | populate_shutdown_status(nfit_mem); |
| @@ -2029,6 +2063,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
| 2029 | cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK; | 2063 | cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK; |
| 2030 | } | 2064 | } |
| 2031 | 2065 | ||
| 2066 | /* Quirk to ignore LOCAL for labels on HYPERV DIMMs */ | ||
| 2067 | if (nfit_mem->family == NVDIMM_FAMILY_HYPERV) | ||
| 2068 | set_bit(NDD_NOBLK, &flags); | ||
| 2069 | |||
| 2032 | if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) { | 2070 | if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) { |
| 2033 | set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask); | 2071 | set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask); |
| 2034 | set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask); | 2072 | set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask); |
| @@ -2052,7 +2090,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
| 2052 | if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0) | 2090 | if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0) |
| 2053 | continue; | 2091 | continue; |
| 2054 | 2092 | ||
| 2055 | dev_info(acpi_desc->dev, "%s flags:%s%s%s%s%s\n", | 2093 | dev_err(acpi_desc->dev, "Error found in NVDIMM %s flags:%s%s%s%s%s\n", |
| 2056 | nvdimm_name(nvdimm), | 2094 | nvdimm_name(nvdimm), |
| 2057 | mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "", | 2095 | mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "", |
| 2058 | mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"", | 2096 | mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"", |
| @@ -3731,6 +3769,7 @@ static __init int nfit_init(void) | |||
| 3731 | guid_parse(UUID_NFIT_DIMM_N_HPE1, &nfit_uuid[NFIT_DEV_DIMM_N_HPE1]); | 3769 | guid_parse(UUID_NFIT_DIMM_N_HPE1, &nfit_uuid[NFIT_DEV_DIMM_N_HPE1]); |
| 3732 | guid_parse(UUID_NFIT_DIMM_N_HPE2, &nfit_uuid[NFIT_DEV_DIMM_N_HPE2]); | 3770 | guid_parse(UUID_NFIT_DIMM_N_HPE2, &nfit_uuid[NFIT_DEV_DIMM_N_HPE2]); |
| 3733 | guid_parse(UUID_NFIT_DIMM_N_MSFT, &nfit_uuid[NFIT_DEV_DIMM_N_MSFT]); | 3771 | guid_parse(UUID_NFIT_DIMM_N_MSFT, &nfit_uuid[NFIT_DEV_DIMM_N_MSFT]); |
| 3772 | guid_parse(UUID_NFIT_DIMM_N_HYPERV, &nfit_uuid[NFIT_DEV_DIMM_N_HYPERV]); | ||
| 3734 | 3773 | ||
| 3735 | nfit_wq = create_singlethread_workqueue("nfit"); | 3774 | nfit_wq = create_singlethread_workqueue("nfit"); |
| 3736 | if (!nfit_wq) | 3775 | if (!nfit_wq) |
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index 33691aecfcee..4de167b4f76f 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h | |||
| @@ -34,11 +34,14 @@ | |||
| 34 | /* https://msdn.microsoft.com/library/windows/hardware/mt604741 */ | 34 | /* https://msdn.microsoft.com/library/windows/hardware/mt604741 */ |
| 35 | #define UUID_NFIT_DIMM_N_MSFT "1ee68b36-d4bd-4a1a-9a16-4f8e53d46e05" | 35 | #define UUID_NFIT_DIMM_N_MSFT "1ee68b36-d4bd-4a1a-9a16-4f8e53d46e05" |
| 36 | 36 | ||
| 37 | /* http://www.uefi.org/RFIC_LIST (see "Virtual NVDIMM 0x1901") */ | ||
| 38 | #define UUID_NFIT_DIMM_N_HYPERV "5746c5f2-a9a2-4264-ad0e-e4ddc9e09e80" | ||
| 39 | |||
| 37 | #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \ | 40 | #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \ |
| 38 | | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \ | 41 | | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \ |
| 39 | | ACPI_NFIT_MEM_NOT_ARMED | ACPI_NFIT_MEM_MAP_FAILED) | 42 | | ACPI_NFIT_MEM_NOT_ARMED | ACPI_NFIT_MEM_MAP_FAILED) |
| 40 | 43 | ||
| 41 | #define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_MSFT | 44 | #define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_HYPERV |
| 42 | 45 | ||
| 43 | #define NVDIMM_STANDARD_CMDMASK \ | 46 | #define NVDIMM_STANDARD_CMDMASK \ |
| 44 | (1 << ND_CMD_SMART | 1 << ND_CMD_SMART_THRESHOLD | 1 << ND_CMD_DIMM_FLAGS \ | 47 | (1 << ND_CMD_SMART | 1 << ND_CMD_SMART_THRESHOLD | 1 << ND_CMD_DIMM_FLAGS \ |
| @@ -94,6 +97,7 @@ enum nfit_uuids { | |||
| 94 | NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1, | 97 | NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1, |
| 95 | NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2, | 98 | NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2, |
| 96 | NFIT_DEV_DIMM_N_MSFT = NVDIMM_FAMILY_MSFT, | 99 | NFIT_DEV_DIMM_N_MSFT = NVDIMM_FAMILY_MSFT, |
| 100 | NFIT_DEV_DIMM_N_HYPERV = NVDIMM_FAMILY_HYPERV, | ||
| 97 | NFIT_SPA_VOLATILE, | 101 | NFIT_SPA_VOLATILE, |
| 98 | NFIT_SPA_PM, | 102 | NFIT_SPA_PM, |
| 99 | NFIT_SPA_DCR, | 103 | NFIT_SPA_DCR, |
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index b123b0dcf274..4671776f5623 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c | |||
| @@ -541,9 +541,9 @@ static int arena_clear_freelist_error(struct arena_info *arena, u32 lane) | |||
| 541 | 541 | ||
| 542 | static int btt_freelist_init(struct arena_info *arena) | 542 | static int btt_freelist_init(struct arena_info *arena) |
| 543 | { | 543 | { |
| 544 | int old, new, ret; | 544 | int new, ret; |
| 545 | u32 i, map_entry; | 545 | struct log_entry log_new; |
| 546 | struct log_entry log_new, log_old; | 546 | u32 i, map_entry, log_oldmap, log_newmap; |
| 547 | 547 | ||
| 548 | arena->freelist = kcalloc(arena->nfree, sizeof(struct free_entry), | 548 | arena->freelist = kcalloc(arena->nfree, sizeof(struct free_entry), |
| 549 | GFP_KERNEL); | 549 | GFP_KERNEL); |
| @@ -551,24 +551,26 @@ static int btt_freelist_init(struct arena_info *arena) | |||
| 551 | return -ENOMEM; | 551 | return -ENOMEM; |
| 552 | 552 | ||
| 553 | for (i = 0; i < arena->nfree; i++) { | 553 | for (i = 0; i < arena->nfree; i++) { |
| 554 | old = btt_log_read(arena, i, &log_old, LOG_OLD_ENT); | ||
| 555 | if (old < 0) | ||
| 556 | return old; | ||
| 557 | |||
| 558 | new = btt_log_read(arena, i, &log_new, LOG_NEW_ENT); | 554 | new = btt_log_read(arena, i, &log_new, LOG_NEW_ENT); |
| 559 | if (new < 0) | 555 | if (new < 0) |
| 560 | return new; | 556 | return new; |
| 561 | 557 | ||
| 558 | /* old and new map entries with any flags stripped out */ | ||
| 559 | log_oldmap = ent_lba(le32_to_cpu(log_new.old_map)); | ||
| 560 | log_newmap = ent_lba(le32_to_cpu(log_new.new_map)); | ||
| 561 | |||
| 562 | /* sub points to the next one to be overwritten */ | 562 | /* sub points to the next one to be overwritten */ |
| 563 | arena->freelist[i].sub = 1 - new; | 563 | arena->freelist[i].sub = 1 - new; |
| 564 | arena->freelist[i].seq = nd_inc_seq(le32_to_cpu(log_new.seq)); | 564 | arena->freelist[i].seq = nd_inc_seq(le32_to_cpu(log_new.seq)); |
| 565 | arena->freelist[i].block = le32_to_cpu(log_new.old_map); | 565 | arena->freelist[i].block = log_oldmap; |
| 566 | 566 | ||
| 567 | /* | 567 | /* |
| 568 | * FIXME: if error clearing fails during init, we want to make | 568 | * FIXME: if error clearing fails during init, we want to make |
| 569 | * the BTT read-only | 569 | * the BTT read-only |
| 570 | */ | 570 | */ |
| 571 | if (ent_e_flag(log_new.old_map)) { | 571 | if (ent_e_flag(log_new.old_map) && |
| 572 | !ent_normal(log_new.old_map)) { | ||
| 573 | arena->freelist[i].has_err = 1; | ||
| 572 | ret = arena_clear_freelist_error(arena, i); | 574 | ret = arena_clear_freelist_error(arena, i); |
| 573 | if (ret) | 575 | if (ret) |
| 574 | dev_err_ratelimited(to_dev(arena), | 576 | dev_err_ratelimited(to_dev(arena), |
| @@ -576,7 +578,7 @@ static int btt_freelist_init(struct arena_info *arena) | |||
| 576 | } | 578 | } |
| 577 | 579 | ||
| 578 | /* This implies a newly created or untouched flog entry */ | 580 | /* This implies a newly created or untouched flog entry */ |
| 579 | if (log_new.old_map == log_new.new_map) | 581 | if (log_oldmap == log_newmap) |
| 580 | continue; | 582 | continue; |
| 581 | 583 | ||
| 582 | /* Check if map recovery is needed */ | 584 | /* Check if map recovery is needed */ |
| @@ -584,8 +586,15 @@ static int btt_freelist_init(struct arena_info *arena) | |||
| 584 | NULL, NULL, 0); | 586 | NULL, NULL, 0); |
| 585 | if (ret) | 587 | if (ret) |
| 586 | return ret; | 588 | return ret; |
| 587 | if ((le32_to_cpu(log_new.new_map) != map_entry) && | 589 | |
| 588 | (le32_to_cpu(log_new.old_map) == map_entry)) { | 590 | /* |
| 591 | * The map_entry from btt_read_map is stripped of any flag bits, | ||
| 592 | * so use the stripped out versions from the log as well for | ||
| 593 | * testing whether recovery is needed. For restoration, use the | ||
| 594 | * 'raw' version of the log entries as that captured what we | ||
| 595 | * were going to write originally. | ||
| 596 | */ | ||
| 597 | if ((log_newmap != map_entry) && (log_oldmap == map_entry)) { | ||
| 589 | /* | 598 | /* |
| 590 | * Last transaction wrote the flog, but wasn't able | 599 | * Last transaction wrote the flog, but wasn't able |
| 591 | * to complete the map write. So fix up the map. | 600 | * to complete the map write. So fix up the map. |
diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h index db3cb6d4d0d4..ddff49c707b0 100644 --- a/drivers/nvdimm/btt.h +++ b/drivers/nvdimm/btt.h | |||
| @@ -44,6 +44,8 @@ | |||
| 44 | #define ent_e_flag(ent) (!!(ent & MAP_ERR_MASK)) | 44 | #define ent_e_flag(ent) (!!(ent & MAP_ERR_MASK)) |
| 45 | #define ent_z_flag(ent) (!!(ent & MAP_TRIM_MASK)) | 45 | #define ent_z_flag(ent) (!!(ent & MAP_TRIM_MASK)) |
| 46 | #define set_e_flag(ent) (ent |= MAP_ERR_MASK) | 46 | #define set_e_flag(ent) (ent |= MAP_ERR_MASK) |
| 47 | /* 'normal' is both e and z flags set */ | ||
| 48 | #define ent_normal(ent) (ent_e_flag(ent) && ent_z_flag(ent)) | ||
| 47 | 49 | ||
| 48 | enum btt_init_state { | 50 | enum btt_init_state { |
| 49 | INIT_UNCHECKED = 0, | 51 | INIT_UNCHECKED = 0, |
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c index 795ad4ff35ca..b72a303176c7 100644 --- a/drivers/nvdimm/btt_devs.c +++ b/drivers/nvdimm/btt_devs.c | |||
| @@ -159,11 +159,19 @@ static ssize_t size_show(struct device *dev, | |||
| 159 | } | 159 | } |
| 160 | static DEVICE_ATTR_RO(size); | 160 | static DEVICE_ATTR_RO(size); |
| 161 | 161 | ||
| 162 | static ssize_t log_zero_flags_show(struct device *dev, | ||
| 163 | struct device_attribute *attr, char *buf) | ||
| 164 | { | ||
| 165 | return sprintf(buf, "Y\n"); | ||
| 166 | } | ||
| 167 | static DEVICE_ATTR_RO(log_zero_flags); | ||
| 168 | |||
| 162 | static struct attribute *nd_btt_attributes[] = { | 169 | static struct attribute *nd_btt_attributes[] = { |
| 163 | &dev_attr_sector_size.attr, | 170 | &dev_attr_sector_size.attr, |
| 164 | &dev_attr_namespace.attr, | 171 | &dev_attr_namespace.attr, |
| 165 | &dev_attr_uuid.attr, | 172 | &dev_attr_uuid.attr, |
| 166 | &dev_attr_size.attr, | 173 | &dev_attr_size.attr, |
| 174 | &dev_attr_log_zero_flags.attr, | ||
| 167 | NULL, | 175 | NULL, |
| 168 | }; | 176 | }; |
| 169 | 177 | ||
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index efe412a6b5b9..91b9abbf689c 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | * General Public License for more details. | 11 | * General Public License for more details. |
| 12 | */ | 12 | */ |
| 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 14 | #include <linux/moduleparam.h> | ||
| 14 | #include <linux/vmalloc.h> | 15 | #include <linux/vmalloc.h> |
| 15 | #include <linux/device.h> | 16 | #include <linux/device.h> |
| 16 | #include <linux/ndctl.h> | 17 | #include <linux/ndctl.h> |
| @@ -25,6 +26,10 @@ | |||
| 25 | 26 | ||
| 26 | static DEFINE_IDA(dimm_ida); | 27 | static DEFINE_IDA(dimm_ida); |
| 27 | 28 | ||
| 29 | static bool noblk; | ||
| 30 | module_param(noblk, bool, 0444); | ||
| 31 | MODULE_PARM_DESC(noblk, "force disable BLK / local alias support"); | ||
| 32 | |||
| 28 | /* | 33 | /* |
| 29 | * Retrieve bus and dimm handle and return if this bus supports | 34 | * Retrieve bus and dimm handle and return if this bus supports |
| 30 | * get_config_data commands | 35 | * get_config_data commands |
| @@ -551,6 +556,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, | |||
| 551 | 556 | ||
| 552 | nvdimm->dimm_id = dimm_id; | 557 | nvdimm->dimm_id = dimm_id; |
| 553 | nvdimm->provider_data = provider_data; | 558 | nvdimm->provider_data = provider_data; |
| 559 | if (noblk) | ||
| 560 | flags |= 1 << NDD_NOBLK; | ||
| 554 | nvdimm->flags = flags; | 561 | nvdimm->flags = flags; |
| 555 | nvdimm->cmd_mask = cmd_mask; | 562 | nvdimm->cmd_mask = cmd_mask; |
| 556 | nvdimm->num_flush = num_flush; | 563 | nvdimm->num_flush = num_flush; |
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index a11bf4e6b451..f3d753d3169c 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c | |||
| @@ -392,6 +392,7 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) | |||
| 392 | return 0; /* no label, nothing to reserve */ | 392 | return 0; /* no label, nothing to reserve */ |
| 393 | 393 | ||
| 394 | for_each_clear_bit_le(slot, free, nslot) { | 394 | for_each_clear_bit_le(slot, free, nslot) { |
| 395 | struct nvdimm *nvdimm = to_nvdimm(ndd->dev); | ||
| 395 | struct nd_namespace_label *nd_label; | 396 | struct nd_namespace_label *nd_label; |
| 396 | struct nd_region *nd_region = NULL; | 397 | struct nd_region *nd_region = NULL; |
| 397 | u8 label_uuid[NSLABEL_UUID_LEN]; | 398 | u8 label_uuid[NSLABEL_UUID_LEN]; |
| @@ -406,6 +407,8 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) | |||
| 406 | 407 | ||
| 407 | memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN); | 408 | memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN); |
| 408 | flags = __le32_to_cpu(nd_label->flags); | 409 | flags = __le32_to_cpu(nd_label->flags); |
| 410 | if (test_bit(NDD_NOBLK, &nvdimm->flags)) | ||
| 411 | flags &= ~NSLABEL_FLAG_LOCAL; | ||
| 409 | nd_label_gen_id(&label_id, label_uuid, flags); | 412 | nd_label_gen_id(&label_id, label_uuid, flags); |
| 410 | res = nvdimm_allocate_dpa(ndd, &label_id, | 413 | res = nvdimm_allocate_dpa(ndd, &label_id, |
| 411 | __le64_to_cpu(nd_label->dpa), | 414 | __le64_to_cpu(nd_label->dpa), |
| @@ -755,7 +758,7 @@ static const guid_t *to_abstraction_guid(enum nvdimm_claim_class claim_class, | |||
| 755 | 758 | ||
| 756 | static int __pmem_label_update(struct nd_region *nd_region, | 759 | static int __pmem_label_update(struct nd_region *nd_region, |
| 757 | struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm, | 760 | struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm, |
| 758 | int pos) | 761 | int pos, unsigned long flags) |
| 759 | { | 762 | { |
| 760 | struct nd_namespace_common *ndns = &nspm->nsio.common; | 763 | struct nd_namespace_common *ndns = &nspm->nsio.common; |
| 761 | struct nd_interleave_set *nd_set = nd_region->nd_set; | 764 | struct nd_interleave_set *nd_set = nd_region->nd_set; |
| @@ -796,7 +799,7 @@ static int __pmem_label_update(struct nd_region *nd_region, | |||
| 796 | memcpy(nd_label->uuid, nspm->uuid, NSLABEL_UUID_LEN); | 799 | memcpy(nd_label->uuid, nspm->uuid, NSLABEL_UUID_LEN); |
| 797 | if (nspm->alt_name) | 800 | if (nspm->alt_name) |
| 798 | memcpy(nd_label->name, nspm->alt_name, NSLABEL_NAME_LEN); | 801 | memcpy(nd_label->name, nspm->alt_name, NSLABEL_NAME_LEN); |
| 799 | nd_label->flags = __cpu_to_le32(NSLABEL_FLAG_UPDATING); | 802 | nd_label->flags = __cpu_to_le32(flags); |
| 800 | nd_label->nlabel = __cpu_to_le16(nd_region->ndr_mappings); | 803 | nd_label->nlabel = __cpu_to_le16(nd_region->ndr_mappings); |
| 801 | nd_label->position = __cpu_to_le16(pos); | 804 | nd_label->position = __cpu_to_le16(pos); |
| 802 | nd_label->isetcookie = __cpu_to_le64(cookie); | 805 | nd_label->isetcookie = __cpu_to_le64(cookie); |
| @@ -1249,13 +1252,13 @@ static int del_labels(struct nd_mapping *nd_mapping, u8 *uuid) | |||
| 1249 | int nd_pmem_namespace_label_update(struct nd_region *nd_region, | 1252 | int nd_pmem_namespace_label_update(struct nd_region *nd_region, |
| 1250 | struct nd_namespace_pmem *nspm, resource_size_t size) | 1253 | struct nd_namespace_pmem *nspm, resource_size_t size) |
| 1251 | { | 1254 | { |
| 1252 | int i; | 1255 | int i, rc; |
| 1253 | 1256 | ||
| 1254 | for (i = 0; i < nd_region->ndr_mappings; i++) { | 1257 | for (i = 0; i < nd_region->ndr_mappings; i++) { |
| 1255 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; | 1258 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; |
| 1256 | struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); | 1259 | struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); |
| 1257 | struct resource *res; | 1260 | struct resource *res; |
| 1258 | int rc, count = 0; | 1261 | int count = 0; |
| 1259 | 1262 | ||
| 1260 | if (size == 0) { | 1263 | if (size == 0) { |
| 1261 | rc = del_labels(nd_mapping, nspm->uuid); | 1264 | rc = del_labels(nd_mapping, nspm->uuid); |
| @@ -1273,7 +1276,20 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region, | |||
| 1273 | if (rc < 0) | 1276 | if (rc < 0) |
| 1274 | return rc; | 1277 | return rc; |
| 1275 | 1278 | ||
| 1276 | rc = __pmem_label_update(nd_region, nd_mapping, nspm, i); | 1279 | rc = __pmem_label_update(nd_region, nd_mapping, nspm, i, |
| 1280 | NSLABEL_FLAG_UPDATING); | ||
| 1281 | if (rc) | ||
| 1282 | return rc; | ||
| 1283 | } | ||
| 1284 | |||
| 1285 | if (size == 0) | ||
| 1286 | return 0; | ||
| 1287 | |||
| 1288 | /* Clear the UPDATING flag per UEFI 2.7 expectations */ | ||
| 1289 | for (i = 0; i < nd_region->ndr_mappings; i++) { | ||
| 1290 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; | ||
| 1291 | |||
| 1292 | rc = __pmem_label_update(nd_region, nd_mapping, nspm, i, 0); | ||
| 1277 | if (rc) | 1293 | if (rc) |
| 1278 | return rc; | 1294 | return rc; |
| 1279 | } | 1295 | } |
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 4b077555ac70..17fb7f931f0c 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c | |||
| @@ -1506,13 +1506,13 @@ static ssize_t __holder_class_store(struct device *dev, const char *buf) | |||
| 1506 | if (dev->driver || ndns->claim) | 1506 | if (dev->driver || ndns->claim) |
| 1507 | return -EBUSY; | 1507 | return -EBUSY; |
| 1508 | 1508 | ||
| 1509 | if (strcmp(buf, "btt") == 0 || strcmp(buf, "btt\n") == 0) | 1509 | if (sysfs_streq(buf, "btt")) |
| 1510 | ndns->claim_class = btt_claim_class(dev); | 1510 | ndns->claim_class = btt_claim_class(dev); |
| 1511 | else if (strcmp(buf, "pfn") == 0 || strcmp(buf, "pfn\n") == 0) | 1511 | else if (sysfs_streq(buf, "pfn")) |
| 1512 | ndns->claim_class = NVDIMM_CCLASS_PFN; | 1512 | ndns->claim_class = NVDIMM_CCLASS_PFN; |
| 1513 | else if (strcmp(buf, "dax") == 0 || strcmp(buf, "dax\n") == 0) | 1513 | else if (sysfs_streq(buf, "dax")) |
| 1514 | ndns->claim_class = NVDIMM_CCLASS_DAX; | 1514 | ndns->claim_class = NVDIMM_CCLASS_DAX; |
| 1515 | else if (strcmp(buf, "") == 0 || strcmp(buf, "\n") == 0) | 1515 | else if (sysfs_streq(buf, "")) |
| 1516 | ndns->claim_class = NVDIMM_CCLASS_NONE; | 1516 | ndns->claim_class = NVDIMM_CCLASS_NONE; |
| 1517 | else | 1517 | else |
| 1518 | return -EINVAL; | 1518 | return -EINVAL; |
| @@ -2492,6 +2492,12 @@ static int init_active_labels(struct nd_region *nd_region) | |||
| 2492 | if (!label_ent) | 2492 | if (!label_ent) |
| 2493 | break; | 2493 | break; |
| 2494 | label = nd_label_active(ndd, j); | 2494 | label = nd_label_active(ndd, j); |
| 2495 | if (test_bit(NDD_NOBLK, &nvdimm->flags)) { | ||
| 2496 | u32 flags = __le32_to_cpu(label->flags); | ||
| 2497 | |||
| 2498 | flags &= ~NSLABEL_FLAG_LOCAL; | ||
| 2499 | label->flags = __cpu_to_le32(flags); | ||
| 2500 | } | ||
| 2495 | label_ent->label = label; | 2501 | label_ent->label = label; |
| 2496 | 2502 | ||
| 2497 | mutex_lock(&nd_mapping->lock); | 2503 | mutex_lock(&nd_mapping->lock); |
diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c index 0a701837dfc0..11b9821eba85 100644 --- a/drivers/nvdimm/of_pmem.c +++ b/drivers/nvdimm/of_pmem.c | |||
| @@ -108,7 +108,6 @@ static struct platform_driver of_pmem_region_driver = { | |||
| 108 | .remove = of_pmem_region_remove, | 108 | .remove = of_pmem_region_remove, |
| 109 | .driver = { | 109 | .driver = { |
| 110 | .name = "of_pmem", | 110 | .name = "of_pmem", |
| 111 | .owner = THIS_MODULE, | ||
| 112 | .of_match_table = of_pmem_region_match, | 111 | .of_match_table = of_pmem_region_match, |
| 113 | }, | 112 | }, |
| 114 | }; | 113 | }; |
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index e2818f94f292..3b58baa44b5c 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c | |||
| @@ -1003,6 +1003,13 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, | |||
| 1003 | 1003 | ||
| 1004 | if (test_bit(NDD_UNARMED, &nvdimm->flags)) | 1004 | if (test_bit(NDD_UNARMED, &nvdimm->flags)) |
| 1005 | ro = 1; | 1005 | ro = 1; |
| 1006 | |||
| 1007 | if (test_bit(NDD_NOBLK, &nvdimm->flags) | ||
| 1008 | && dev_type == &nd_blk_device_type) { | ||
| 1009 | dev_err(&nvdimm_bus->dev, "%s: %s mapping%d is not BLK capable\n", | ||
| 1010 | caller, dev_name(&nvdimm->dev), i); | ||
| 1011 | return NULL; | ||
| 1012 | } | ||
| 1006 | } | 1013 | } |
| 1007 | 1014 | ||
| 1008 | if (dev_type == &nd_blk_device_type) { | 1015 | if (dev_type == &nd_blk_device_type) { |
