diff options
50 files changed, 1217 insertions, 788 deletions
diff --git a/Documentation/devicetree/bindings/pmem/pmem-region.txt b/Documentation/devicetree/bindings/pmem/pmem-region.txt new file mode 100644 index 000000000000..5cfa4f016a00 --- /dev/null +++ b/Documentation/devicetree/bindings/pmem/pmem-region.txt | |||
@@ -0,0 +1,65 @@ | |||
1 | Device-tree bindings for persistent memory regions | ||
2 | ----------------------------------------------------- | ||
3 | |||
4 | Persistent memory refers to a class of memory devices that are: | ||
5 | |||
6 | a) Usable as main system memory (i.e. cacheable), and | ||
7 | b) Retain their contents across power failure. | ||
8 | |||
9 | Given b) it is best to think of persistent memory as a kind of memory mapped | ||
10 | storage device. To ensure data integrity the operating system needs to manage | ||
11 | persistent regions separately to the normal memory pool. To aid with that this | ||
12 | binding provides a standardised interface for discovering where persistent | ||
13 | memory regions exist inside the physical address space. | ||
14 | |||
15 | Bindings for the region nodes: | ||
16 | ----------------------------- | ||
17 | |||
18 | Required properties: | ||
19 | - compatible = "pmem-region" | ||
20 | |||
21 | - reg = <base, size>; | ||
22 | The reg property should specificy an address range that is | ||
23 | translatable to a system physical address range. This address | ||
24 | range should be mappable as normal system memory would be | ||
25 | (i.e cacheable). | ||
26 | |||
27 | If the reg property contains multiple address ranges | ||
28 | each address range will be treated as though it was specified | ||
29 | in a separate device node. Having multiple address ranges in a | ||
30 | node implies no special relationship between the two ranges. | ||
31 | |||
32 | Optional properties: | ||
33 | - Any relevant NUMA assocativity properties for the target platform. | ||
34 | |||
35 | - volatile; This property indicates that this region is actually | ||
36 | backed by non-persistent memory. This lets the OS know that it | ||
37 | may skip the cache flushes required to ensure data is made | ||
38 | persistent after a write. | ||
39 | |||
40 | If this property is absent then the OS must assume that the region | ||
41 | is backed by non-volatile memory. | ||
42 | |||
43 | Examples: | ||
44 | -------------------- | ||
45 | |||
46 | /* | ||
47 | * This node specifies one 4KB region spanning from | ||
48 | * 0x5000 to 0x5fff that is backed by non-volatile memory. | ||
49 | */ | ||
50 | pmem@5000 { | ||
51 | compatible = "pmem-region"; | ||
52 | reg = <0x00005000 0x00001000>; | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * This node specifies two 4KB regions that are backed by | ||
57 | * volatile (normal) memory. | ||
58 | */ | ||
59 | pmem@6000 { | ||
60 | compatible = "pmem-region"; | ||
61 | reg = < 0x00006000 0x00001000 | ||
62 | 0x00008000 0x00001000 >; | ||
63 | volatile; | ||
64 | }; | ||
65 | |||
diff --git a/MAINTAINERS b/MAINTAINERS index dd7ce9171ac0..00855ffc8de9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -8048,6 +8048,14 @@ Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ | |||
8048 | S: Supported | 8048 | S: Supported |
8049 | F: drivers/nvdimm/pmem* | 8049 | F: drivers/nvdimm/pmem* |
8050 | 8050 | ||
8051 | LIBNVDIMM: DEVICETREE BINDINGS | ||
8052 | M: Oliver O'Halloran <oohall@gmail.com> | ||
8053 | L: linux-nvdimm@lists.01.org | ||
8054 | Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ | ||
8055 | S: Supported | ||
8056 | F: drivers/nvdimm/of_pmem.c | ||
8057 | F: Documentation/devicetree/bindings/pmem/pmem-region.txt | ||
8058 | |||
8051 | LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM | 8059 | LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM |
8052 | M: Dan Williams <dan.j.williams@intel.com> | 8060 | M: Dan Williams <dan.j.williams@intel.com> |
8053 | L: linux-nvdimm@lists.01.org | 8061 | L: linux-nvdimm@lists.01.org |
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 516e23de5a3d..48fbb41af5d1 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c | |||
@@ -824,6 +824,9 @@ static int __init opal_init(void) | |||
824 | /* Create i2c platform devices */ | 824 | /* Create i2c platform devices */ |
825 | opal_pdev_init("ibm,opal-i2c"); | 825 | opal_pdev_init("ibm,opal-i2c"); |
826 | 826 | ||
827 | /* Handle non-volatile memory devices */ | ||
828 | opal_pdev_init("pmem-region"); | ||
829 | |||
827 | /* Setup a heatbeat thread if requested by OPAL */ | 830 | /* Setup a heatbeat thread if requested by OPAL */ |
828 | opal_init_heartbeat(); | 831 | opal_init_heartbeat(); |
829 | 832 | ||
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 22a112b4f4d8..e2235ed3e4be 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
@@ -36,16 +36,6 @@ static bool force_enable_dimms; | |||
36 | module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR); | 36 | module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR); |
37 | MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status"); | 37 | MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status"); |
38 | 38 | ||
39 | static unsigned int scrub_timeout = NFIT_ARS_TIMEOUT; | ||
40 | module_param(scrub_timeout, uint, S_IRUGO|S_IWUSR); | ||
41 | MODULE_PARM_DESC(scrub_timeout, "Initial scrub timeout in seconds"); | ||
42 | |||
43 | /* after three payloads of overflow, it's dead jim */ | ||
44 | static unsigned int scrub_overflow_abort = 3; | ||
45 | module_param(scrub_overflow_abort, uint, S_IRUGO|S_IWUSR); | ||
46 | MODULE_PARM_DESC(scrub_overflow_abort, | ||
47 | "Number of times we overflow ARS results before abort"); | ||
48 | |||
49 | static bool disable_vendor_specific; | 39 | static bool disable_vendor_specific; |
50 | module_param(disable_vendor_specific, bool, S_IRUGO); | 40 | module_param(disable_vendor_specific, bool, S_IRUGO); |
51 | MODULE_PARM_DESC(disable_vendor_specific, | 41 | MODULE_PARM_DESC(disable_vendor_specific, |
@@ -60,6 +50,10 @@ module_param(default_dsm_family, int, S_IRUGO); | |||
60 | MODULE_PARM_DESC(default_dsm_family, | 50 | MODULE_PARM_DESC(default_dsm_family, |
61 | "Try this DSM type first when identifying NVDIMM family"); | 51 | "Try this DSM type first when identifying NVDIMM family"); |
62 | 52 | ||
53 | static bool no_init_ars; | ||
54 | module_param(no_init_ars, bool, 0644); | ||
55 | MODULE_PARM_DESC(no_init_ars, "Skip ARS run at nfit init time"); | ||
56 | |||
63 | LIST_HEAD(acpi_descs); | 57 | LIST_HEAD(acpi_descs); |
64 | DEFINE_MUTEX(acpi_desc_lock); | 58 | DEFINE_MUTEX(acpi_desc_lock); |
65 | 59 | ||
@@ -197,7 +191,7 @@ static int xlat_nvdimm_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd | |||
197 | * In the _LSI, _LSR, _LSW case the locked status is | 191 | * In the _LSI, _LSR, _LSW case the locked status is |
198 | * communicated via the read/write commands | 192 | * communicated via the read/write commands |
199 | */ | 193 | */ |
200 | if (nfit_mem->has_lsi) | 194 | if (nfit_mem->has_lsr) |
201 | break; | 195 | break; |
202 | 196 | ||
203 | if (status >> 16 & ND_CONFIG_LOCKED) | 197 | if (status >> 16 & ND_CONFIG_LOCKED) |
@@ -477,14 +471,14 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | |||
477 | in_buf.buffer.length = call_pkg->nd_size_in; | 471 | in_buf.buffer.length = call_pkg->nd_size_in; |
478 | } | 472 | } |
479 | 473 | ||
480 | dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n", | 474 | dev_dbg(dev, "%s cmd: %d: func: %d input length: %d\n", |
481 | __func__, dimm_name, cmd, func, in_buf.buffer.length); | 475 | dimm_name, cmd, func, in_buf.buffer.length); |
482 | print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4, | 476 | print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4, |
483 | in_buf.buffer.pointer, | 477 | in_buf.buffer.pointer, |
484 | min_t(u32, 256, in_buf.buffer.length), true); | 478 | min_t(u32, 256, in_buf.buffer.length), true); |
485 | 479 | ||
486 | /* call the BIOS, prefer the named methods over _DSM if available */ | 480 | /* call the BIOS, prefer the named methods over _DSM if available */ |
487 | if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE && nfit_mem->has_lsi) | 481 | if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE && nfit_mem->has_lsr) |
488 | out_obj = acpi_label_info(handle); | 482 | out_obj = acpi_label_info(handle); |
489 | else if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && nfit_mem->has_lsr) { | 483 | else if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && nfit_mem->has_lsr) { |
490 | struct nd_cmd_get_config_data_hdr *p = buf; | 484 | struct nd_cmd_get_config_data_hdr *p = buf; |
@@ -507,8 +501,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | |||
507 | } | 501 | } |
508 | 502 | ||
509 | if (!out_obj) { | 503 | if (!out_obj) { |
510 | dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name, | 504 | dev_dbg(dev, "%s _DSM failed cmd: %s\n", dimm_name, cmd_name); |
511 | cmd_name); | ||
512 | return -EINVAL; | 505 | return -EINVAL; |
513 | } | 506 | } |
514 | 507 | ||
@@ -529,13 +522,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | |||
529 | } | 522 | } |
530 | 523 | ||
531 | if (out_obj->package.type != ACPI_TYPE_BUFFER) { | 524 | if (out_obj->package.type != ACPI_TYPE_BUFFER) { |
532 | dev_dbg(dev, "%s:%s unexpected output object type cmd: %s type: %d\n", | 525 | dev_dbg(dev, "%s unexpected output object type cmd: %s type: %d\n", |
533 | __func__, dimm_name, cmd_name, out_obj->type); | 526 | dimm_name, cmd_name, out_obj->type); |
534 | rc = -EINVAL; | 527 | rc = -EINVAL; |
535 | goto out; | 528 | goto out; |
536 | } | 529 | } |
537 | 530 | ||
538 | dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__, dimm_name, | 531 | dev_dbg(dev, "%s cmd: %s output length: %d\n", dimm_name, |
539 | cmd_name, out_obj->buffer.length); | 532 | cmd_name, out_obj->buffer.length); |
540 | print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, 4, | 533 | print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, 4, |
541 | out_obj->buffer.pointer, | 534 | out_obj->buffer.pointer, |
@@ -547,14 +540,14 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | |||
547 | out_obj->buffer.length - offset); | 540 | out_obj->buffer.length - offset); |
548 | 541 | ||
549 | if (offset + out_size > out_obj->buffer.length) { | 542 | if (offset + out_size > out_obj->buffer.length) { |
550 | dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n", | 543 | dev_dbg(dev, "%s output object underflow cmd: %s field: %d\n", |
551 | __func__, dimm_name, cmd_name, i); | 544 | dimm_name, cmd_name, i); |
552 | break; | 545 | break; |
553 | } | 546 | } |
554 | 547 | ||
555 | if (in_buf.buffer.length + offset + out_size > buf_len) { | 548 | if (in_buf.buffer.length + offset + out_size > buf_len) { |
556 | dev_dbg(dev, "%s:%s output overrun cmd: %s field: %d\n", | 549 | dev_dbg(dev, "%s output overrun cmd: %s field: %d\n", |
557 | __func__, dimm_name, cmd_name, i); | 550 | dimm_name, cmd_name, i); |
558 | rc = -ENXIO; | 551 | rc = -ENXIO; |
559 | goto out; | 552 | goto out; |
560 | } | 553 | } |
@@ -656,7 +649,7 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc, | |||
656 | INIT_LIST_HEAD(&nfit_spa->list); | 649 | INIT_LIST_HEAD(&nfit_spa->list); |
657 | memcpy(nfit_spa->spa, spa, sizeof(*spa)); | 650 | memcpy(nfit_spa->spa, spa, sizeof(*spa)); |
658 | list_add_tail(&nfit_spa->list, &acpi_desc->spas); | 651 | list_add_tail(&nfit_spa->list, &acpi_desc->spas); |
659 | dev_dbg(dev, "%s: spa index: %d type: %s\n", __func__, | 652 | dev_dbg(dev, "spa index: %d type: %s\n", |
660 | spa->range_index, | 653 | spa->range_index, |
661 | spa_type_name(nfit_spa_type(spa))); | 654 | spa_type_name(nfit_spa_type(spa))); |
662 | return true; | 655 | return true; |
@@ -685,8 +678,8 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc, | |||
685 | INIT_LIST_HEAD(&nfit_memdev->list); | 678 | INIT_LIST_HEAD(&nfit_memdev->list); |
686 | memcpy(nfit_memdev->memdev, memdev, sizeof(*memdev)); | 679 | memcpy(nfit_memdev->memdev, memdev, sizeof(*memdev)); |
687 | list_add_tail(&nfit_memdev->list, &acpi_desc->memdevs); | 680 | list_add_tail(&nfit_memdev->list, &acpi_desc->memdevs); |
688 | dev_dbg(dev, "%s: memdev handle: %#x spa: %d dcr: %d flags: %#x\n", | 681 | dev_dbg(dev, "memdev handle: %#x spa: %d dcr: %d flags: %#x\n", |
689 | __func__, memdev->device_handle, memdev->range_index, | 682 | memdev->device_handle, memdev->range_index, |
690 | memdev->region_index, memdev->flags); | 683 | memdev->region_index, memdev->flags); |
691 | return true; | 684 | return true; |
692 | } | 685 | } |
@@ -754,7 +747,7 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc, | |||
754 | INIT_LIST_HEAD(&nfit_dcr->list); | 747 | INIT_LIST_HEAD(&nfit_dcr->list); |
755 | memcpy(nfit_dcr->dcr, dcr, sizeof_dcr(dcr)); | 748 | memcpy(nfit_dcr->dcr, dcr, sizeof_dcr(dcr)); |
756 | list_add_tail(&nfit_dcr->list, &acpi_desc->dcrs); | 749 | list_add_tail(&nfit_dcr->list, &acpi_desc->dcrs); |
757 | dev_dbg(dev, "%s: dcr index: %d windows: %d\n", __func__, | 750 | dev_dbg(dev, "dcr index: %d windows: %d\n", |
758 | dcr->region_index, dcr->windows); | 751 | dcr->region_index, dcr->windows); |
759 | return true; | 752 | return true; |
760 | } | 753 | } |
@@ -781,7 +774,7 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc, | |||
781 | INIT_LIST_HEAD(&nfit_bdw->list); | 774 | INIT_LIST_HEAD(&nfit_bdw->list); |
782 | memcpy(nfit_bdw->bdw, bdw, sizeof(*bdw)); | 775 | memcpy(nfit_bdw->bdw, bdw, sizeof(*bdw)); |
783 | list_add_tail(&nfit_bdw->list, &acpi_desc->bdws); | 776 | list_add_tail(&nfit_bdw->list, &acpi_desc->bdws); |
784 | dev_dbg(dev, "%s: bdw dcr: %d windows: %d\n", __func__, | 777 | dev_dbg(dev, "bdw dcr: %d windows: %d\n", |
785 | bdw->region_index, bdw->windows); | 778 | bdw->region_index, bdw->windows); |
786 | return true; | 779 | return true; |
787 | } | 780 | } |
@@ -820,7 +813,7 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc, | |||
820 | INIT_LIST_HEAD(&nfit_idt->list); | 813 | INIT_LIST_HEAD(&nfit_idt->list); |
821 | memcpy(nfit_idt->idt, idt, sizeof_idt(idt)); | 814 | memcpy(nfit_idt->idt, idt, sizeof_idt(idt)); |
822 | list_add_tail(&nfit_idt->list, &acpi_desc->idts); | 815 | list_add_tail(&nfit_idt->list, &acpi_desc->idts); |
823 | dev_dbg(dev, "%s: idt index: %d num_lines: %d\n", __func__, | 816 | dev_dbg(dev, "idt index: %d num_lines: %d\n", |
824 | idt->interleave_index, idt->line_count); | 817 | idt->interleave_index, idt->line_count); |
825 | return true; | 818 | return true; |
826 | } | 819 | } |
@@ -860,7 +853,7 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc, | |||
860 | INIT_LIST_HEAD(&nfit_flush->list); | 853 | INIT_LIST_HEAD(&nfit_flush->list); |
861 | memcpy(nfit_flush->flush, flush, sizeof_flush(flush)); | 854 | memcpy(nfit_flush->flush, flush, sizeof_flush(flush)); |
862 | list_add_tail(&nfit_flush->list, &acpi_desc->flushes); | 855 | list_add_tail(&nfit_flush->list, &acpi_desc->flushes); |
863 | dev_dbg(dev, "%s: nfit_flush handle: %d hint_count: %d\n", __func__, | 856 | dev_dbg(dev, "nfit_flush handle: %d hint_count: %d\n", |
864 | flush->device_handle, flush->hint_count); | 857 | flush->device_handle, flush->hint_count); |
865 | return true; | 858 | return true; |
866 | } | 859 | } |
@@ -873,7 +866,7 @@ static bool add_platform_cap(struct acpi_nfit_desc *acpi_desc, | |||
873 | 866 | ||
874 | mask = (1 << (pcap->highest_capability + 1)) - 1; | 867 | mask = (1 << (pcap->highest_capability + 1)) - 1; |
875 | acpi_desc->platform_cap = pcap->capabilities & mask; | 868 | acpi_desc->platform_cap = pcap->capabilities & mask; |
876 | dev_dbg(dev, "%s: cap: %#x\n", __func__, acpi_desc->platform_cap); | 869 | dev_dbg(dev, "cap: %#x\n", acpi_desc->platform_cap); |
877 | return true; | 870 | return true; |
878 | } | 871 | } |
879 | 872 | ||
@@ -920,7 +913,7 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc, | |||
920 | return err; | 913 | return err; |
921 | break; | 914 | break; |
922 | case ACPI_NFIT_TYPE_SMBIOS: | 915 | case ACPI_NFIT_TYPE_SMBIOS: |
923 | dev_dbg(dev, "%s: smbios\n", __func__); | 916 | dev_dbg(dev, "smbios\n"); |
924 | break; | 917 | break; |
925 | case ACPI_NFIT_TYPE_CAPABILITIES: | 918 | case ACPI_NFIT_TYPE_CAPABILITIES: |
926 | if (!add_platform_cap(acpi_desc, table)) | 919 | if (!add_platform_cap(acpi_desc, table)) |
@@ -1277,8 +1270,11 @@ static ssize_t scrub_show(struct device *dev, | |||
1277 | if (nd_desc) { | 1270 | if (nd_desc) { |
1278 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); | 1271 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); |
1279 | 1272 | ||
1273 | mutex_lock(&acpi_desc->init_mutex); | ||
1280 | rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, | 1274 | rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, |
1281 | (work_busy(&acpi_desc->work)) ? "+\n" : "\n"); | 1275 | work_busy(&acpi_desc->dwork.work) |
1276 | && !acpi_desc->cancel ? "+\n" : "\n"); | ||
1277 | mutex_unlock(&acpi_desc->init_mutex); | ||
1282 | } | 1278 | } |
1283 | device_unlock(dev); | 1279 | device_unlock(dev); |
1284 | return rc; | 1280 | return rc; |
@@ -1648,7 +1644,7 @@ void __acpi_nvdimm_notify(struct device *dev, u32 event) | |||
1648 | struct nfit_mem *nfit_mem; | 1644 | struct nfit_mem *nfit_mem; |
1649 | struct acpi_nfit_desc *acpi_desc; | 1645 | struct acpi_nfit_desc *acpi_desc; |
1650 | 1646 | ||
1651 | dev_dbg(dev->parent, "%s: %s: event: %d\n", dev_name(dev), __func__, | 1647 | dev_dbg(dev->parent, "%s: event: %d\n", dev_name(dev), |
1652 | event); | 1648 | event); |
1653 | 1649 | ||
1654 | if (event != NFIT_NOTIFY_DIMM_HEALTH) { | 1650 | if (event != NFIT_NOTIFY_DIMM_HEALTH) { |
@@ -1681,12 +1677,23 @@ static void acpi_nvdimm_notify(acpi_handle handle, u32 event, void *data) | |||
1681 | device_unlock(dev->parent); | 1677 | device_unlock(dev->parent); |
1682 | } | 1678 | } |
1683 | 1679 | ||
1680 | static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method) | ||
1681 | { | ||
1682 | acpi_handle handle; | ||
1683 | acpi_status status; | ||
1684 | |||
1685 | status = acpi_get_handle(adev->handle, method, &handle); | ||
1686 | |||
1687 | if (ACPI_SUCCESS(status)) | ||
1688 | return true; | ||
1689 | return false; | ||
1690 | } | ||
1691 | |||
1684 | static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | 1692 | static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, |
1685 | struct nfit_mem *nfit_mem, u32 device_handle) | 1693 | struct nfit_mem *nfit_mem, u32 device_handle) |
1686 | { | 1694 | { |
1687 | struct acpi_device *adev, *adev_dimm; | 1695 | struct acpi_device *adev, *adev_dimm; |
1688 | struct device *dev = acpi_desc->dev; | 1696 | struct device *dev = acpi_desc->dev; |
1689 | union acpi_object *obj; | ||
1690 | unsigned long dsm_mask; | 1697 | unsigned long dsm_mask; |
1691 | const guid_t *guid; | 1698 | const guid_t *guid; |
1692 | int i; | 1699 | int i; |
@@ -1759,25 +1766,15 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
1759 | 1ULL << i)) | 1766 | 1ULL << i)) |
1760 | set_bit(i, &nfit_mem->dsm_mask); | 1767 | set_bit(i, &nfit_mem->dsm_mask); |
1761 | 1768 | ||
1762 | obj = acpi_label_info(adev_dimm->handle); | 1769 | if (acpi_nvdimm_has_method(adev_dimm, "_LSI") |
1763 | if (obj) { | 1770 | && acpi_nvdimm_has_method(adev_dimm, "_LSR")) { |
1764 | ACPI_FREE(obj); | ||
1765 | nfit_mem->has_lsi = 1; | ||
1766 | dev_dbg(dev, "%s: has _LSI\n", dev_name(&adev_dimm->dev)); | ||
1767 | } | ||
1768 | |||
1769 | obj = acpi_label_read(adev_dimm->handle, 0, 0); | ||
1770 | if (obj) { | ||
1771 | ACPI_FREE(obj); | ||
1772 | nfit_mem->has_lsr = 1; | ||
1773 | dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev)); | 1771 | dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev)); |
1772 | nfit_mem->has_lsr = true; | ||
1774 | } | 1773 | } |
1775 | 1774 | ||
1776 | obj = acpi_label_write(adev_dimm->handle, 0, 0, NULL); | 1775 | if (nfit_mem->has_lsr && acpi_nvdimm_has_method(adev_dimm, "_LSW")) { |
1777 | if (obj) { | ||
1778 | ACPI_FREE(obj); | ||
1779 | nfit_mem->has_lsw = 1; | ||
1780 | dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev)); | 1776 | dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev)); |
1777 | nfit_mem->has_lsw = true; | ||
1781 | } | 1778 | } |
1782 | 1779 | ||
1783 | return 0; | 1780 | return 0; |
@@ -1866,10 +1863,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
1866 | cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK; | 1863 | cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK; |
1867 | } | 1864 | } |
1868 | 1865 | ||
1869 | if (nfit_mem->has_lsi) | 1866 | if (nfit_mem->has_lsr) { |
1870 | set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask); | 1867 | set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask); |
1871 | if (nfit_mem->has_lsr) | ||
1872 | set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask); | 1868 | set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask); |
1869 | } | ||
1873 | if (nfit_mem->has_lsw) | 1870 | if (nfit_mem->has_lsw) |
1874 | set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask); | 1871 | set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask); |
1875 | 1872 | ||
@@ -2365,7 +2362,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, | |||
2365 | nvdimm = nd_blk_region_to_dimm(ndbr); | 2362 | nvdimm = nd_blk_region_to_dimm(ndbr); |
2366 | nfit_mem = nvdimm_provider_data(nvdimm); | 2363 | nfit_mem = nvdimm_provider_data(nvdimm); |
2367 | if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) { | 2364 | if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) { |
2368 | dev_dbg(dev, "%s: missing%s%s%s\n", __func__, | 2365 | dev_dbg(dev, "missing%s%s%s\n", |
2369 | nfit_mem ? "" : " nfit_mem", | 2366 | nfit_mem ? "" : " nfit_mem", |
2370 | (nfit_mem && nfit_mem->dcr) ? "" : " dcr", | 2367 | (nfit_mem && nfit_mem->dcr) ? "" : " dcr", |
2371 | (nfit_mem && nfit_mem->bdw) ? "" : " bdw"); | 2368 | (nfit_mem && nfit_mem->bdw) ? "" : " bdw"); |
@@ -2384,7 +2381,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, | |||
2384 | mmio->addr.base = devm_nvdimm_memremap(dev, nfit_mem->spa_bdw->address, | 2381 | mmio->addr.base = devm_nvdimm_memremap(dev, nfit_mem->spa_bdw->address, |
2385 | nfit_mem->spa_bdw->length, nd_blk_memremap_flags(ndbr)); | 2382 | nfit_mem->spa_bdw->length, nd_blk_memremap_flags(ndbr)); |
2386 | if (!mmio->addr.base) { | 2383 | if (!mmio->addr.base) { |
2387 | dev_dbg(dev, "%s: %s failed to map bdw\n", __func__, | 2384 | dev_dbg(dev, "%s failed to map bdw\n", |
2388 | nvdimm_name(nvdimm)); | 2385 | nvdimm_name(nvdimm)); |
2389 | return -ENOMEM; | 2386 | return -ENOMEM; |
2390 | } | 2387 | } |
@@ -2395,8 +2392,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, | |||
2395 | rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_bdw, | 2392 | rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_bdw, |
2396 | nfit_mem->memdev_bdw->interleave_ways); | 2393 | nfit_mem->memdev_bdw->interleave_ways); |
2397 | if (rc) { | 2394 | if (rc) { |
2398 | dev_dbg(dev, "%s: %s failed to init bdw interleave\n", | 2395 | dev_dbg(dev, "%s failed to init bdw interleave\n", |
2399 | __func__, nvdimm_name(nvdimm)); | 2396 | nvdimm_name(nvdimm)); |
2400 | return rc; | 2397 | return rc; |
2401 | } | 2398 | } |
2402 | 2399 | ||
@@ -2407,7 +2404,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, | |||
2407 | mmio->addr.base = devm_nvdimm_ioremap(dev, nfit_mem->spa_dcr->address, | 2404 | mmio->addr.base = devm_nvdimm_ioremap(dev, nfit_mem->spa_dcr->address, |
2408 | nfit_mem->spa_dcr->length); | 2405 | nfit_mem->spa_dcr->length); |
2409 | if (!mmio->addr.base) { | 2406 | if (!mmio->addr.base) { |
2410 | dev_dbg(dev, "%s: %s failed to map dcr\n", __func__, | 2407 | dev_dbg(dev, "%s failed to map dcr\n", |
2411 | nvdimm_name(nvdimm)); | 2408 | nvdimm_name(nvdimm)); |
2412 | return -ENOMEM; | 2409 | return -ENOMEM; |
2413 | } | 2410 | } |
@@ -2418,15 +2415,15 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, | |||
2418 | rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_dcr, | 2415 | rc = nfit_blk_init_interleave(mmio, nfit_mem->idt_dcr, |
2419 | nfit_mem->memdev_dcr->interleave_ways); | 2416 | nfit_mem->memdev_dcr->interleave_ways); |
2420 | if (rc) { | 2417 | if (rc) { |
2421 | dev_dbg(dev, "%s: %s failed to init dcr interleave\n", | 2418 | dev_dbg(dev, "%s failed to init dcr interleave\n", |
2422 | __func__, nvdimm_name(nvdimm)); | 2419 | nvdimm_name(nvdimm)); |
2423 | return rc; | 2420 | return rc; |
2424 | } | 2421 | } |
2425 | 2422 | ||
2426 | rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk); | 2423 | rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk); |
2427 | if (rc < 0) { | 2424 | if (rc < 0) { |
2428 | dev_dbg(dev, "%s: %s failed get DIMM flags\n", | 2425 | dev_dbg(dev, "%s failed get DIMM flags\n", |
2429 | __func__, nvdimm_name(nvdimm)); | 2426 | nvdimm_name(nvdimm)); |
2430 | return rc; | 2427 | return rc; |
2431 | } | 2428 | } |
2432 | 2429 | ||
@@ -2476,7 +2473,8 @@ static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa | |||
2476 | memset(&ars_start, 0, sizeof(ars_start)); | 2473 | memset(&ars_start, 0, sizeof(ars_start)); |
2477 | ars_start.address = spa->address; | 2474 | ars_start.address = spa->address; |
2478 | ars_start.length = spa->length; | 2475 | ars_start.length = spa->length; |
2479 | ars_start.flags = acpi_desc->ars_start_flags; | 2476 | if (test_bit(ARS_SHORT, &nfit_spa->ars_state)) |
2477 | ars_start.flags = ND_ARS_RETURN_PREV_DATA; | ||
2480 | if (nfit_spa_type(spa) == NFIT_SPA_PM) | 2478 | if (nfit_spa_type(spa) == NFIT_SPA_PM) |
2481 | ars_start.type = ND_ARS_PERSISTENT; | 2479 | ars_start.type = ND_ARS_PERSISTENT; |
2482 | else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) | 2480 | else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) |
@@ -2518,16 +2516,62 @@ static int ars_get_status(struct acpi_nfit_desc *acpi_desc) | |||
2518 | int rc, cmd_rc; | 2516 | int rc, cmd_rc; |
2519 | 2517 | ||
2520 | rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, ars_status, | 2518 | rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, ars_status, |
2521 | acpi_desc->ars_status_size, &cmd_rc); | 2519 | acpi_desc->max_ars, &cmd_rc); |
2522 | if (rc < 0) | 2520 | if (rc < 0) |
2523 | return rc; | 2521 | return rc; |
2524 | return cmd_rc; | 2522 | return cmd_rc; |
2525 | } | 2523 | } |
2526 | 2524 | ||
2527 | static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc, | 2525 | static void ars_complete(struct acpi_nfit_desc *acpi_desc, |
2528 | struct nd_cmd_ars_status *ars_status) | 2526 | struct nfit_spa *nfit_spa) |
2527 | { | ||
2528 | struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status; | ||
2529 | struct acpi_nfit_system_address *spa = nfit_spa->spa; | ||
2530 | struct nd_region *nd_region = nfit_spa->nd_region; | ||
2531 | struct device *dev; | ||
2532 | |||
2533 | if ((ars_status->address >= spa->address && ars_status->address | ||
2534 | < spa->address + spa->length) | ||
2535 | || (ars_status->address < spa->address)) { | ||
2536 | /* | ||
2537 | * Assume that if a scrub starts at an offset from the | ||
2538 | * start of nfit_spa that we are in the continuation | ||
2539 | * case. | ||
2540 | * | ||
2541 | * Otherwise, if the scrub covers the spa range, mark | ||
2542 | * any pending request complete. | ||
2543 | */ | ||
2544 | if (ars_status->address + ars_status->length | ||
2545 | >= spa->address + spa->length) | ||
2546 | /* complete */; | ||
2547 | else | ||
2548 | return; | ||
2549 | } else | ||
2550 | return; | ||
2551 | |||
2552 | if (test_bit(ARS_DONE, &nfit_spa->ars_state)) | ||
2553 | return; | ||
2554 | |||
2555 | if (!test_and_clear_bit(ARS_REQ, &nfit_spa->ars_state)) | ||
2556 | return; | ||
2557 | |||
2558 | if (nd_region) { | ||
2559 | dev = nd_region_dev(nd_region); | ||
2560 | nvdimm_region_notify(nd_region, NVDIMM_REVALIDATE_POISON); | ||
2561 | } else | ||
2562 | dev = acpi_desc->dev; | ||
2563 | |||
2564 | dev_dbg(dev, "ARS: range %d %s complete\n", spa->range_index, | ||
2565 | test_bit(ARS_SHORT, &nfit_spa->ars_state) | ||
2566 | ? "short" : "long"); | ||
2567 | clear_bit(ARS_SHORT, &nfit_spa->ars_state); | ||
2568 | set_bit(ARS_DONE, &nfit_spa->ars_state); | ||
2569 | } | ||
2570 | |||
2571 | static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc) | ||
2529 | { | 2572 | { |
2530 | struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus; | 2573 | struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus; |
2574 | struct nd_cmd_ars_status *ars_status = acpi_desc->ars_status; | ||
2531 | int rc; | 2575 | int rc; |
2532 | u32 i; | 2576 | u32 i; |
2533 | 2577 | ||
@@ -2606,7 +2650,7 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc, | |||
2606 | struct acpi_nfit_system_address *spa = nfit_spa->spa; | 2650 | struct acpi_nfit_system_address *spa = nfit_spa->spa; |
2607 | struct nd_blk_region_desc *ndbr_desc; | 2651 | struct nd_blk_region_desc *ndbr_desc; |
2608 | struct nfit_mem *nfit_mem; | 2652 | struct nfit_mem *nfit_mem; |
2609 | int blk_valid = 0, rc; | 2653 | int rc; |
2610 | 2654 | ||
2611 | if (!nvdimm) { | 2655 | if (!nvdimm) { |
2612 | dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n", | 2656 | dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n", |
@@ -2626,15 +2670,14 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc, | |||
2626 | if (!nfit_mem || !nfit_mem->bdw) { | 2670 | if (!nfit_mem || !nfit_mem->bdw) { |
2627 | dev_dbg(acpi_desc->dev, "spa%d %s missing bdw\n", | 2671 | dev_dbg(acpi_desc->dev, "spa%d %s missing bdw\n", |
2628 | spa->range_index, nvdimm_name(nvdimm)); | 2672 | spa->range_index, nvdimm_name(nvdimm)); |
2629 | } else { | 2673 | break; |
2630 | mapping->size = nfit_mem->bdw->capacity; | ||
2631 | mapping->start = nfit_mem->bdw->start_address; | ||
2632 | ndr_desc->num_lanes = nfit_mem->bdw->windows; | ||
2633 | blk_valid = 1; | ||
2634 | } | 2674 | } |
2635 | 2675 | ||
2676 | mapping->size = nfit_mem->bdw->capacity; | ||
2677 | mapping->start = nfit_mem->bdw->start_address; | ||
2678 | ndr_desc->num_lanes = nfit_mem->bdw->windows; | ||
2636 | ndr_desc->mapping = mapping; | 2679 | ndr_desc->mapping = mapping; |
2637 | ndr_desc->num_mappings = blk_valid; | 2680 | ndr_desc->num_mappings = 1; |
2638 | ndbr_desc = to_blk_region_desc(ndr_desc); | 2681 | ndbr_desc = to_blk_region_desc(ndr_desc); |
2639 | ndbr_desc->enable = acpi_nfit_blk_region_enable; | 2682 | ndbr_desc->enable = acpi_nfit_blk_region_enable; |
2640 | ndbr_desc->do_io = acpi_desc->blk_do_io; | 2683 | ndbr_desc->do_io = acpi_desc->blk_do_io; |
@@ -2682,8 +2725,7 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc, | |||
2682 | return 0; | 2725 | return 0; |
2683 | 2726 | ||
2684 | if (spa->range_index == 0 && !nfit_spa_is_virtual(spa)) { | 2727 | if (spa->range_index == 0 && !nfit_spa_is_virtual(spa)) { |
2685 | dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n", | 2728 | dev_dbg(acpi_desc->dev, "detected invalid spa index\n"); |
2686 | __func__); | ||
2687 | return 0; | 2729 | return 0; |
2688 | } | 2730 | } |
2689 | 2731 | ||
@@ -2769,301 +2811,243 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc, | |||
2769 | return rc; | 2811 | return rc; |
2770 | } | 2812 | } |
2771 | 2813 | ||
2772 | static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc, | 2814 | static int ars_status_alloc(struct acpi_nfit_desc *acpi_desc) |
2773 | u32 max_ars) | ||
2774 | { | 2815 | { |
2775 | struct device *dev = acpi_desc->dev; | 2816 | struct device *dev = acpi_desc->dev; |
2776 | struct nd_cmd_ars_status *ars_status; | 2817 | struct nd_cmd_ars_status *ars_status; |
2777 | 2818 | ||
2778 | if (acpi_desc->ars_status && acpi_desc->ars_status_size >= max_ars) { | 2819 | if (acpi_desc->ars_status) { |
2779 | memset(acpi_desc->ars_status, 0, acpi_desc->ars_status_size); | 2820 | memset(acpi_desc->ars_status, 0, acpi_desc->max_ars); |
2780 | return 0; | 2821 | return 0; |
2781 | } | 2822 | } |
2782 | 2823 | ||
2783 | if (acpi_desc->ars_status) | 2824 | ars_status = devm_kzalloc(dev, acpi_desc->max_ars, GFP_KERNEL); |
2784 | devm_kfree(dev, acpi_desc->ars_status); | ||
2785 | acpi_desc->ars_status = NULL; | ||
2786 | ars_status = devm_kzalloc(dev, max_ars, GFP_KERNEL); | ||
2787 | if (!ars_status) | 2825 | if (!ars_status) |
2788 | return -ENOMEM; | 2826 | return -ENOMEM; |
2789 | acpi_desc->ars_status = ars_status; | 2827 | acpi_desc->ars_status = ars_status; |
2790 | acpi_desc->ars_status_size = max_ars; | ||
2791 | return 0; | 2828 | return 0; |
2792 | } | 2829 | } |
2793 | 2830 | ||
2794 | static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc, | 2831 | static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc) |
2795 | struct nfit_spa *nfit_spa) | ||
2796 | { | 2832 | { |
2797 | struct acpi_nfit_system_address *spa = nfit_spa->spa; | ||
2798 | int rc; | 2833 | int rc; |
2799 | 2834 | ||
2800 | if (!nfit_spa->max_ars) { | 2835 | if (ars_status_alloc(acpi_desc)) |
2801 | struct nd_cmd_ars_cap ars_cap; | ||
2802 | |||
2803 | memset(&ars_cap, 0, sizeof(ars_cap)); | ||
2804 | rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa); | ||
2805 | if (rc < 0) | ||
2806 | return rc; | ||
2807 | nfit_spa->max_ars = ars_cap.max_ars_out; | ||
2808 | nfit_spa->clear_err_unit = ars_cap.clear_err_unit; | ||
2809 | /* check that the supported scrub types match the spa type */ | ||
2810 | if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE && | ||
2811 | ((ars_cap.status >> 16) & ND_ARS_VOLATILE) == 0) | ||
2812 | return -ENOTTY; | ||
2813 | else if (nfit_spa_type(spa) == NFIT_SPA_PM && | ||
2814 | ((ars_cap.status >> 16) & ND_ARS_PERSISTENT) == 0) | ||
2815 | return -ENOTTY; | ||
2816 | } | ||
2817 | |||
2818 | if (ars_status_alloc(acpi_desc, nfit_spa->max_ars)) | ||
2819 | return -ENOMEM; | 2836 | return -ENOMEM; |
2820 | 2837 | ||
2821 | rc = ars_get_status(acpi_desc); | 2838 | rc = ars_get_status(acpi_desc); |
2839 | |||
2822 | if (rc < 0 && rc != -ENOSPC) | 2840 | if (rc < 0 && rc != -ENOSPC) |
2823 | return rc; | 2841 | return rc; |
2824 | 2842 | ||
2825 | if (ars_status_process_records(acpi_desc, acpi_desc->ars_status)) | 2843 | if (ars_status_process_records(acpi_desc)) |
2826 | return -ENOMEM; | 2844 | return -ENOMEM; |
2827 | 2845 | ||
2828 | return 0; | 2846 | return 0; |
2829 | } | 2847 | } |
2830 | 2848 | ||
2831 | static void acpi_nfit_async_scrub(struct acpi_nfit_desc *acpi_desc, | 2849 | static int ars_register(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa, |
2832 | struct nfit_spa *nfit_spa) | 2850 | int *query_rc) |
2833 | { | 2851 | { |
2834 | struct acpi_nfit_system_address *spa = nfit_spa->spa; | 2852 | int rc = *query_rc; |
2835 | unsigned int overflow_retry = scrub_overflow_abort; | ||
2836 | u64 init_ars_start = 0, init_ars_len = 0; | ||
2837 | struct device *dev = acpi_desc->dev; | ||
2838 | unsigned int tmo = scrub_timeout; | ||
2839 | int rc; | ||
2840 | 2853 | ||
2841 | if (!nfit_spa->ars_required || !nfit_spa->nd_region) | 2854 | if (no_init_ars) |
2842 | return; | 2855 | return acpi_nfit_register_region(acpi_desc, nfit_spa); |
2843 | 2856 | ||
2844 | rc = ars_start(acpi_desc, nfit_spa); | 2857 | set_bit(ARS_REQ, &nfit_spa->ars_state); |
2845 | /* | 2858 | set_bit(ARS_SHORT, &nfit_spa->ars_state); |
2846 | * If we timed out the initial scan we'll still be busy here, | ||
2847 | * and will wait another timeout before giving up permanently. | ||
2848 | */ | ||
2849 | if (rc < 0 && rc != -EBUSY) | ||
2850 | return; | ||
2851 | |||
2852 | do { | ||
2853 | u64 ars_start, ars_len; | ||
2854 | |||
2855 | if (acpi_desc->cancel) | ||
2856 | break; | ||
2857 | rc = acpi_nfit_query_poison(acpi_desc, nfit_spa); | ||
2858 | if (rc == -ENOTTY) | ||
2859 | break; | ||
2860 | if (rc == -EBUSY && !tmo) { | ||
2861 | dev_warn(dev, "range %d ars timeout, aborting\n", | ||
2862 | spa->range_index); | ||
2863 | break; | ||
2864 | } | ||
2865 | 2859 | ||
2860 | switch (rc) { | ||
2861 | case 0: | ||
2862 | case -EAGAIN: | ||
2863 | rc = ars_start(acpi_desc, nfit_spa); | ||
2866 | if (rc == -EBUSY) { | 2864 | if (rc == -EBUSY) { |
2867 | /* | 2865 | *query_rc = rc; |
2868 | * Note, entries may be appended to the list | ||
2869 | * while the lock is dropped, but the workqueue | ||
2870 | * being active prevents entries being deleted / | ||
2871 | * freed. | ||
2872 | */ | ||
2873 | mutex_unlock(&acpi_desc->init_mutex); | ||
2874 | ssleep(1); | ||
2875 | tmo--; | ||
2876 | mutex_lock(&acpi_desc->init_mutex); | ||
2877 | continue; | ||
2878 | } | ||
2879 | |||
2880 | /* we got some results, but there are more pending... */ | ||
2881 | if (rc == -ENOSPC && overflow_retry--) { | ||
2882 | if (!init_ars_len) { | ||
2883 | init_ars_len = acpi_desc->ars_status->length; | ||
2884 | init_ars_start = acpi_desc->ars_status->address; | ||
2885 | } | ||
2886 | rc = ars_continue(acpi_desc); | ||
2887 | } | ||
2888 | |||
2889 | if (rc < 0) { | ||
2890 | dev_warn(dev, "range %d ars continuation failed\n", | ||
2891 | spa->range_index); | ||
2892 | break; | 2866 | break; |
2893 | } | 2867 | } else if (rc == 0) { |
2894 | 2868 | rc = acpi_nfit_query_poison(acpi_desc); | |
2895 | if (init_ars_len) { | ||
2896 | ars_start = init_ars_start; | ||
2897 | ars_len = init_ars_len; | ||
2898 | } else { | 2869 | } else { |
2899 | ars_start = acpi_desc->ars_status->address; | 2870 | set_bit(ARS_FAILED, &nfit_spa->ars_state); |
2900 | ars_len = acpi_desc->ars_status->length; | 2871 | break; |
2901 | } | 2872 | } |
2902 | dev_dbg(dev, "spa range: %d ars from %#llx + %#llx complete\n", | 2873 | if (rc == -EAGAIN) |
2903 | spa->range_index, ars_start, ars_len); | 2874 | clear_bit(ARS_SHORT, &nfit_spa->ars_state); |
2904 | /* notify the region about new poison entries */ | 2875 | else if (rc == 0) |
2905 | nvdimm_region_notify(nfit_spa->nd_region, | 2876 | ars_complete(acpi_desc, nfit_spa); |
2906 | NVDIMM_REVALIDATE_POISON); | ||
2907 | break; | 2877 | break; |
2908 | } while (1); | 2878 | case -EBUSY: |
2879 | case -ENOSPC: | ||
2880 | break; | ||
2881 | default: | ||
2882 | set_bit(ARS_FAILED, &nfit_spa->ars_state); | ||
2883 | break; | ||
2884 | } | ||
2885 | |||
2886 | if (test_and_clear_bit(ARS_DONE, &nfit_spa->ars_state)) | ||
2887 | set_bit(ARS_REQ, &nfit_spa->ars_state); | ||
2888 | |||
2889 | return acpi_nfit_register_region(acpi_desc, nfit_spa); | ||
2909 | } | 2890 | } |
2910 | 2891 | ||
2911 | static void acpi_nfit_scrub(struct work_struct *work) | 2892 | static void ars_complete_all(struct acpi_nfit_desc *acpi_desc) |
2912 | { | 2893 | { |
2913 | struct device *dev; | ||
2914 | u64 init_scrub_length = 0; | ||
2915 | struct nfit_spa *nfit_spa; | 2894 | struct nfit_spa *nfit_spa; |
2916 | u64 init_scrub_address = 0; | ||
2917 | bool init_ars_done = false; | ||
2918 | struct acpi_nfit_desc *acpi_desc; | ||
2919 | unsigned int tmo = scrub_timeout; | ||
2920 | unsigned int overflow_retry = scrub_overflow_abort; | ||
2921 | |||
2922 | acpi_desc = container_of(work, typeof(*acpi_desc), work); | ||
2923 | dev = acpi_desc->dev; | ||
2924 | |||
2925 | /* | ||
2926 | * We scrub in 2 phases. The first phase waits for any platform | ||
2927 | * firmware initiated scrubs to complete and then we go search for the | ||
2928 | * affected spa regions to mark them scanned. In the second phase we | ||
2929 | * initiate a directed scrub for every range that was not scrubbed in | ||
2930 | * phase 1. If we're called for a 'rescan', we harmlessly pass through | ||
2931 | * the first phase, but really only care about running phase 2, where | ||
2932 | * regions can be notified of new poison. | ||
2933 | */ | ||
2934 | 2895 | ||
2935 | /* process platform firmware initiated scrubs */ | ||
2936 | retry: | ||
2937 | mutex_lock(&acpi_desc->init_mutex); | ||
2938 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { | 2896 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { |
2939 | struct nd_cmd_ars_status *ars_status; | 2897 | if (test_bit(ARS_FAILED, &nfit_spa->ars_state)) |
2940 | struct acpi_nfit_system_address *spa; | ||
2941 | u64 ars_start, ars_len; | ||
2942 | int rc; | ||
2943 | |||
2944 | if (acpi_desc->cancel) | ||
2945 | break; | ||
2946 | |||
2947 | if (nfit_spa->nd_region) | ||
2948 | continue; | 2898 | continue; |
2899 | ars_complete(acpi_desc, nfit_spa); | ||
2900 | } | ||
2901 | } | ||
2949 | 2902 | ||
2950 | if (init_ars_done) { | 2903 | static unsigned int __acpi_nfit_scrub(struct acpi_nfit_desc *acpi_desc, |
2951 | /* | 2904 | int query_rc) |
2952 | * No need to re-query, we're now just | 2905 | { |
2953 | * reconciling all the ranges covered by the | 2906 | unsigned int tmo = acpi_desc->scrub_tmo; |
2954 | * initial scrub | 2907 | struct device *dev = acpi_desc->dev; |
2955 | */ | 2908 | struct nfit_spa *nfit_spa; |
2956 | rc = 0; | ||
2957 | } else | ||
2958 | rc = acpi_nfit_query_poison(acpi_desc, nfit_spa); | ||
2959 | |||
2960 | if (rc == -ENOTTY) { | ||
2961 | /* no ars capability, just register spa and move on */ | ||
2962 | acpi_nfit_register_region(acpi_desc, nfit_spa); | ||
2963 | continue; | ||
2964 | } | ||
2965 | |||
2966 | if (rc == -EBUSY && !tmo) { | ||
2967 | /* fallthrough to directed scrub in phase 2 */ | ||
2968 | dev_warn(dev, "timeout awaiting ars results, continuing...\n"); | ||
2969 | break; | ||
2970 | } else if (rc == -EBUSY) { | ||
2971 | mutex_unlock(&acpi_desc->init_mutex); | ||
2972 | ssleep(1); | ||
2973 | tmo--; | ||
2974 | goto retry; | ||
2975 | } | ||
2976 | |||
2977 | /* we got some results, but there are more pending... */ | ||
2978 | if (rc == -ENOSPC && overflow_retry--) { | ||
2979 | ars_status = acpi_desc->ars_status; | ||
2980 | /* | ||
2981 | * Record the original scrub range, so that we | ||
2982 | * can recall all the ranges impacted by the | ||
2983 | * initial scrub. | ||
2984 | */ | ||
2985 | if (!init_scrub_length) { | ||
2986 | init_scrub_length = ars_status->length; | ||
2987 | init_scrub_address = ars_status->address; | ||
2988 | } | ||
2989 | rc = ars_continue(acpi_desc); | ||
2990 | if (rc == 0) { | ||
2991 | mutex_unlock(&acpi_desc->init_mutex); | ||
2992 | goto retry; | ||
2993 | } | ||
2994 | } | ||
2995 | 2909 | ||
2996 | if (rc < 0) { | 2910 | if (acpi_desc->cancel) |
2997 | /* | 2911 | return 0; |
2998 | * Initial scrub failed, we'll give it one more | ||
2999 | * try below... | ||
3000 | */ | ||
3001 | break; | ||
3002 | } | ||
3003 | 2912 | ||
3004 | /* We got some final results, record completed ranges */ | 2913 | if (query_rc == -EBUSY) { |
3005 | ars_status = acpi_desc->ars_status; | 2914 | dev_dbg(dev, "ARS: ARS busy\n"); |
3006 | if (init_scrub_length) { | 2915 | return min(30U * 60U, tmo * 2); |
3007 | ars_start = init_scrub_address; | 2916 | } |
3008 | ars_len = ars_start + init_scrub_length; | 2917 | if (query_rc == -ENOSPC) { |
3009 | } else { | 2918 | dev_dbg(dev, "ARS: ARS continue\n"); |
3010 | ars_start = ars_status->address; | 2919 | ars_continue(acpi_desc); |
3011 | ars_len = ars_status->length; | 2920 | return 1; |
3012 | } | 2921 | } |
3013 | spa = nfit_spa->spa; | 2922 | if (query_rc && query_rc != -EAGAIN) { |
2923 | unsigned long long addr, end; | ||
3014 | 2924 | ||
3015 | if (!init_ars_done) { | 2925 | addr = acpi_desc->ars_status->address; |
3016 | init_ars_done = true; | 2926 | end = addr + acpi_desc->ars_status->length; |
3017 | dev_dbg(dev, "init scrub %#llx + %#llx complete\n", | 2927 | dev_dbg(dev, "ARS: %llx-%llx failed (%d)\n", addr, end, |
3018 | ars_start, ars_len); | 2928 | query_rc); |
3019 | } | ||
3020 | if (ars_start <= spa->address && ars_start + ars_len | ||
3021 | >= spa->address + spa->length) | ||
3022 | acpi_nfit_register_region(acpi_desc, nfit_spa); | ||
3023 | } | 2929 | } |
3024 | 2930 | ||
3025 | /* | 2931 | ars_complete_all(acpi_desc); |
3026 | * For all the ranges not covered by an initial scrub we still | ||
3027 | * want to see if there are errors, but it's ok to discover them | ||
3028 | * asynchronously. | ||
3029 | */ | ||
3030 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { | 2932 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { |
3031 | /* | 2933 | if (test_bit(ARS_FAILED, &nfit_spa->ars_state)) |
3032 | * Flag all the ranges that still need scrubbing, but | 2934 | continue; |
3033 | * register them now to make data available. | 2935 | if (test_bit(ARS_REQ, &nfit_spa->ars_state)) { |
3034 | */ | 2936 | int rc = ars_start(acpi_desc, nfit_spa); |
3035 | if (!nfit_spa->nd_region) { | 2937 | |
3036 | nfit_spa->ars_required = 1; | 2938 | clear_bit(ARS_DONE, &nfit_spa->ars_state); |
3037 | acpi_nfit_register_region(acpi_desc, nfit_spa); | 2939 | dev = nd_region_dev(nfit_spa->nd_region); |
2940 | dev_dbg(dev, "ARS: range %d ARS start (%d)\n", | ||
2941 | nfit_spa->spa->range_index, rc); | ||
2942 | if (rc == 0 || rc == -EBUSY) | ||
2943 | return 1; | ||
2944 | dev_err(dev, "ARS: range %d ARS failed (%d)\n", | ||
2945 | nfit_spa->spa->range_index, rc); | ||
2946 | set_bit(ARS_FAILED, &nfit_spa->ars_state); | ||
3038 | } | 2947 | } |
3039 | } | 2948 | } |
3040 | acpi_desc->init_complete = 1; | 2949 | return 0; |
2950 | } | ||
3041 | 2951 | ||
3042 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) | 2952 | static void acpi_nfit_scrub(struct work_struct *work) |
3043 | acpi_nfit_async_scrub(acpi_desc, nfit_spa); | 2953 | { |
3044 | acpi_desc->scrub_count++; | 2954 | struct acpi_nfit_desc *acpi_desc; |
3045 | acpi_desc->ars_start_flags = 0; | 2955 | unsigned int tmo; |
3046 | if (acpi_desc->scrub_count_state) | 2956 | int query_rc; |
3047 | sysfs_notify_dirent(acpi_desc->scrub_count_state); | 2957 | |
2958 | acpi_desc = container_of(work, typeof(*acpi_desc), dwork.work); | ||
2959 | mutex_lock(&acpi_desc->init_mutex); | ||
2960 | query_rc = acpi_nfit_query_poison(acpi_desc); | ||
2961 | tmo = __acpi_nfit_scrub(acpi_desc, query_rc); | ||
2962 | if (tmo) { | ||
2963 | queue_delayed_work(nfit_wq, &acpi_desc->dwork, tmo * HZ); | ||
2964 | acpi_desc->scrub_tmo = tmo; | ||
2965 | } else { | ||
2966 | acpi_desc->scrub_count++; | ||
2967 | if (acpi_desc->scrub_count_state) | ||
2968 | sysfs_notify_dirent(acpi_desc->scrub_count_state); | ||
2969 | } | ||
2970 | memset(acpi_desc->ars_status, 0, acpi_desc->max_ars); | ||
3048 | mutex_unlock(&acpi_desc->init_mutex); | 2971 | mutex_unlock(&acpi_desc->init_mutex); |
3049 | } | 2972 | } |
3050 | 2973 | ||
2974 | static void acpi_nfit_init_ars(struct acpi_nfit_desc *acpi_desc, | ||
2975 | struct nfit_spa *nfit_spa) | ||
2976 | { | ||
2977 | int type = nfit_spa_type(nfit_spa->spa); | ||
2978 | struct nd_cmd_ars_cap ars_cap; | ||
2979 | int rc; | ||
2980 | |||
2981 | memset(&ars_cap, 0, sizeof(ars_cap)); | ||
2982 | rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa); | ||
2983 | if (rc < 0) | ||
2984 | return; | ||
2985 | /* check that the supported scrub types match the spa type */ | ||
2986 | if (type == NFIT_SPA_VOLATILE && ((ars_cap.status >> 16) | ||
2987 | & ND_ARS_VOLATILE) == 0) | ||
2988 | return; | ||
2989 | if (type == NFIT_SPA_PM && ((ars_cap.status >> 16) | ||
2990 | & ND_ARS_PERSISTENT) == 0) | ||
2991 | return; | ||
2992 | |||
2993 | nfit_spa->max_ars = ars_cap.max_ars_out; | ||
2994 | nfit_spa->clear_err_unit = ars_cap.clear_err_unit; | ||
2995 | acpi_desc->max_ars = max(nfit_spa->max_ars, acpi_desc->max_ars); | ||
2996 | clear_bit(ARS_FAILED, &nfit_spa->ars_state); | ||
2997 | set_bit(ARS_REQ, &nfit_spa->ars_state); | ||
2998 | } | ||
2999 | |||
3051 | static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) | 3000 | static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) |
3052 | { | 3001 | { |
3053 | struct nfit_spa *nfit_spa; | 3002 | struct nfit_spa *nfit_spa; |
3054 | int rc; | 3003 | int rc, query_rc; |
3004 | |||
3005 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { | ||
3006 | set_bit(ARS_FAILED, &nfit_spa->ars_state); | ||
3007 | switch (nfit_spa_type(nfit_spa->spa)) { | ||
3008 | case NFIT_SPA_VOLATILE: | ||
3009 | case NFIT_SPA_PM: | ||
3010 | acpi_nfit_init_ars(acpi_desc, nfit_spa); | ||
3011 | break; | ||
3012 | } | ||
3013 | } | ||
3014 | |||
3015 | /* | ||
3016 | * Reap any results that might be pending before starting new | ||
3017 | * short requests. | ||
3018 | */ | ||
3019 | query_rc = acpi_nfit_query_poison(acpi_desc); | ||
3020 | if (query_rc == 0) | ||
3021 | ars_complete_all(acpi_desc); | ||
3055 | 3022 | ||
3056 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) | 3023 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) |
3057 | if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) { | 3024 | switch (nfit_spa_type(nfit_spa->spa)) { |
3058 | /* BLK regions don't need to wait for ars results */ | 3025 | case NFIT_SPA_VOLATILE: |
3026 | case NFIT_SPA_PM: | ||
3027 | /* register regions and kick off initial ARS run */ | ||
3028 | rc = ars_register(acpi_desc, nfit_spa, &query_rc); | ||
3029 | if (rc) | ||
3030 | return rc; | ||
3031 | break; | ||
3032 | case NFIT_SPA_BDW: | ||
3033 | /* nothing to register */ | ||
3034 | break; | ||
3035 | case NFIT_SPA_DCR: | ||
3036 | case NFIT_SPA_VDISK: | ||
3037 | case NFIT_SPA_VCD: | ||
3038 | case NFIT_SPA_PDISK: | ||
3039 | case NFIT_SPA_PCD: | ||
3040 | /* register known regions that don't support ARS */ | ||
3059 | rc = acpi_nfit_register_region(acpi_desc, nfit_spa); | 3041 | rc = acpi_nfit_register_region(acpi_desc, nfit_spa); |
3060 | if (rc) | 3042 | if (rc) |
3061 | return rc; | 3043 | return rc; |
3044 | break; | ||
3045 | default: | ||
3046 | /* don't register unknown regions */ | ||
3047 | break; | ||
3062 | } | 3048 | } |
3063 | 3049 | ||
3064 | acpi_desc->ars_start_flags = 0; | 3050 | queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0); |
3065 | if (!acpi_desc->cancel) | ||
3066 | queue_work(nfit_wq, &acpi_desc->work); | ||
3067 | return 0; | 3051 | return 0; |
3068 | } | 3052 | } |
3069 | 3053 | ||
@@ -3173,8 +3157,7 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz) | |||
3173 | data = add_table(acpi_desc, &prev, data, end); | 3157 | data = add_table(acpi_desc, &prev, data, end); |
3174 | 3158 | ||
3175 | if (IS_ERR(data)) { | 3159 | if (IS_ERR(data)) { |
3176 | dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__, | 3160 | dev_dbg(dev, "nfit table parsing error: %ld\n", PTR_ERR(data)); |
3177 | PTR_ERR(data)); | ||
3178 | rc = PTR_ERR(data); | 3161 | rc = PTR_ERR(data); |
3179 | goto out_unlock; | 3162 | goto out_unlock; |
3180 | } | 3163 | } |
@@ -3199,49 +3182,20 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz) | |||
3199 | } | 3182 | } |
3200 | EXPORT_SYMBOL_GPL(acpi_nfit_init); | 3183 | EXPORT_SYMBOL_GPL(acpi_nfit_init); |
3201 | 3184 | ||
3202 | struct acpi_nfit_flush_work { | ||
3203 | struct work_struct work; | ||
3204 | struct completion cmp; | ||
3205 | }; | ||
3206 | |||
3207 | static void flush_probe(struct work_struct *work) | ||
3208 | { | ||
3209 | struct acpi_nfit_flush_work *flush; | ||
3210 | |||
3211 | flush = container_of(work, typeof(*flush), work); | ||
3212 | complete(&flush->cmp); | ||
3213 | } | ||
3214 | |||
3215 | static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) | 3185 | static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) |
3216 | { | 3186 | { |
3217 | struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); | 3187 | struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); |
3218 | struct device *dev = acpi_desc->dev; | 3188 | struct device *dev = acpi_desc->dev; |
3219 | struct acpi_nfit_flush_work flush; | ||
3220 | int rc; | ||
3221 | 3189 | ||
3222 | /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */ | 3190 | /* Bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */ |
3223 | device_lock(dev); | 3191 | device_lock(dev); |
3224 | device_unlock(dev); | 3192 | device_unlock(dev); |
3225 | 3193 | ||
3226 | /* bounce the init_mutex to make init_complete valid */ | 3194 | /* Bounce the init_mutex to complete initial registration */ |
3227 | mutex_lock(&acpi_desc->init_mutex); | 3195 | mutex_lock(&acpi_desc->init_mutex); |
3228 | if (acpi_desc->cancel || acpi_desc->init_complete) { | ||
3229 | mutex_unlock(&acpi_desc->init_mutex); | ||
3230 | return 0; | ||
3231 | } | ||
3232 | |||
3233 | /* | ||
3234 | * Scrub work could take 10s of seconds, userspace may give up so we | ||
3235 | * need to be interruptible while waiting. | ||
3236 | */ | ||
3237 | INIT_WORK_ONSTACK(&flush.work, flush_probe); | ||
3238 | init_completion(&flush.cmp); | ||
3239 | queue_work(nfit_wq, &flush.work); | ||
3240 | mutex_unlock(&acpi_desc->init_mutex); | 3196 | mutex_unlock(&acpi_desc->init_mutex); |
3241 | 3197 | ||
3242 | rc = wait_for_completion_interruptible(&flush.cmp); | 3198 | return 0; |
3243 | cancel_work_sync(&flush.work); | ||
3244 | return rc; | ||
3245 | } | 3199 | } |
3246 | 3200 | ||
3247 | static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, | 3201 | static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, |
@@ -3260,20 +3214,18 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, | |||
3260 | * just needs guarantees that any ars it initiates are not | 3214 | * just needs guarantees that any ars it initiates are not |
3261 | * interrupted by any intervening start reqeusts from userspace. | 3215 | * interrupted by any intervening start reqeusts from userspace. |
3262 | */ | 3216 | */ |
3263 | if (work_busy(&acpi_desc->work)) | 3217 | if (work_busy(&acpi_desc->dwork.work)) |
3264 | return -EBUSY; | 3218 | return -EBUSY; |
3265 | 3219 | ||
3266 | return 0; | 3220 | return 0; |
3267 | } | 3221 | } |
3268 | 3222 | ||
3269 | int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags) | 3223 | int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags) |
3270 | { | 3224 | { |
3271 | struct device *dev = acpi_desc->dev; | 3225 | struct device *dev = acpi_desc->dev; |
3226 | int scheduled = 0, busy = 0; | ||
3272 | struct nfit_spa *nfit_spa; | 3227 | struct nfit_spa *nfit_spa; |
3273 | 3228 | ||
3274 | if (work_busy(&acpi_desc->work)) | ||
3275 | return -EBUSY; | ||
3276 | |||
3277 | mutex_lock(&acpi_desc->init_mutex); | 3229 | mutex_lock(&acpi_desc->init_mutex); |
3278 | if (acpi_desc->cancel) { | 3230 | if (acpi_desc->cancel) { |
3279 | mutex_unlock(&acpi_desc->init_mutex); | 3231 | mutex_unlock(&acpi_desc->init_mutex); |
@@ -3281,19 +3233,32 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags) | |||
3281 | } | 3233 | } |
3282 | 3234 | ||
3283 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { | 3235 | list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { |
3284 | struct acpi_nfit_system_address *spa = nfit_spa->spa; | 3236 | int type = nfit_spa_type(nfit_spa->spa); |
3285 | 3237 | ||
3286 | if (nfit_spa_type(spa) != NFIT_SPA_PM) | 3238 | if (type != NFIT_SPA_PM && type != NFIT_SPA_VOLATILE) |
3239 | continue; | ||
3240 | if (test_bit(ARS_FAILED, &nfit_spa->ars_state)) | ||
3287 | continue; | 3241 | continue; |
3288 | 3242 | ||
3289 | nfit_spa->ars_required = 1; | 3243 | if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state)) |
3244 | busy++; | ||
3245 | else { | ||
3246 | if (test_bit(ARS_SHORT, &flags)) | ||
3247 | set_bit(ARS_SHORT, &nfit_spa->ars_state); | ||
3248 | scheduled++; | ||
3249 | } | ||
3250 | } | ||
3251 | if (scheduled) { | ||
3252 | queue_delayed_work(nfit_wq, &acpi_desc->dwork, 0); | ||
3253 | dev_dbg(dev, "ars_scan triggered\n"); | ||
3290 | } | 3254 | } |
3291 | acpi_desc->ars_start_flags = flags; | ||
3292 | queue_work(nfit_wq, &acpi_desc->work); | ||
3293 | dev_dbg(dev, "%s: ars_scan triggered\n", __func__); | ||
3294 | mutex_unlock(&acpi_desc->init_mutex); | 3255 | mutex_unlock(&acpi_desc->init_mutex); |
3295 | 3256 | ||
3296 | return 0; | 3257 | if (scheduled) |
3258 | return 0; | ||
3259 | if (busy) | ||
3260 | return -EBUSY; | ||
3261 | return -ENOTTY; | ||
3297 | } | 3262 | } |
3298 | 3263 | ||
3299 | void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev) | 3264 | void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev) |
@@ -3320,7 +3285,8 @@ void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev) | |||
3320 | INIT_LIST_HEAD(&acpi_desc->dimms); | 3285 | INIT_LIST_HEAD(&acpi_desc->dimms); |
3321 | INIT_LIST_HEAD(&acpi_desc->list); | 3286 | INIT_LIST_HEAD(&acpi_desc->list); |
3322 | mutex_init(&acpi_desc->init_mutex); | 3287 | mutex_init(&acpi_desc->init_mutex); |
3323 | INIT_WORK(&acpi_desc->work, acpi_nfit_scrub); | 3288 | acpi_desc->scrub_tmo = 1; |
3289 | INIT_DELAYED_WORK(&acpi_desc->dwork, acpi_nfit_scrub); | ||
3324 | } | 3290 | } |
3325 | EXPORT_SYMBOL_GPL(acpi_nfit_desc_init); | 3291 | EXPORT_SYMBOL_GPL(acpi_nfit_desc_init); |
3326 | 3292 | ||
@@ -3344,6 +3310,7 @@ void acpi_nfit_shutdown(void *data) | |||
3344 | 3310 | ||
3345 | mutex_lock(&acpi_desc->init_mutex); | 3311 | mutex_lock(&acpi_desc->init_mutex); |
3346 | acpi_desc->cancel = 1; | 3312 | acpi_desc->cancel = 1; |
3313 | cancel_delayed_work_sync(&acpi_desc->dwork); | ||
3347 | mutex_unlock(&acpi_desc->init_mutex); | 3314 | mutex_unlock(&acpi_desc->init_mutex); |
3348 | 3315 | ||
3349 | /* | 3316 | /* |
@@ -3397,8 +3364,8 @@ static int acpi_nfit_add(struct acpi_device *adev) | |||
3397 | rc = acpi_nfit_init(acpi_desc, obj->buffer.pointer, | 3364 | rc = acpi_nfit_init(acpi_desc, obj->buffer.pointer, |
3398 | obj->buffer.length); | 3365 | obj->buffer.length); |
3399 | else | 3366 | else |
3400 | dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n", | 3367 | dev_dbg(dev, "invalid type %d, ignoring _FIT\n", |
3401 | __func__, (int) obj->type); | 3368 | (int) obj->type); |
3402 | kfree(buf.pointer); | 3369 | kfree(buf.pointer); |
3403 | } else | 3370 | } else |
3404 | /* skip over the lead-in header table */ | 3371 | /* skip over the lead-in header table */ |
@@ -3427,7 +3394,7 @@ static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle) | |||
3427 | 3394 | ||
3428 | if (!dev->driver) { | 3395 | if (!dev->driver) { |
3429 | /* dev->driver may be null if we're being removed */ | 3396 | /* dev->driver may be null if we're being removed */ |
3430 | dev_dbg(dev, "%s: no driver found for dev\n", __func__); | 3397 | dev_dbg(dev, "no driver found for dev\n"); |
3431 | return; | 3398 | return; |
3432 | } | 3399 | } |
3433 | 3400 | ||
@@ -3465,15 +3432,15 @@ static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle) | |||
3465 | static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle) | 3432 | static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle) |
3466 | { | 3433 | { |
3467 | struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev); | 3434 | struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev); |
3468 | u8 flags = (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON) ? | 3435 | unsigned long flags = (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON) ? |
3469 | 0 : ND_ARS_RETURN_PREV_DATA; | 3436 | 0 : 1 << ARS_SHORT; |
3470 | 3437 | ||
3471 | acpi_nfit_ars_rescan(acpi_desc, flags); | 3438 | acpi_nfit_ars_rescan(acpi_desc, flags); |
3472 | } | 3439 | } |
3473 | 3440 | ||
3474 | void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event) | 3441 | void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event) |
3475 | { | 3442 | { |
3476 | dev_dbg(dev, "%s: event: 0x%x\n", __func__, event); | 3443 | dev_dbg(dev, "event: 0x%x\n", event); |
3477 | 3444 | ||
3478 | switch (event) { | 3445 | switch (event) { |
3479 | case NFIT_NOTIFY_UPDATE: | 3446 | case NFIT_NOTIFY_UPDATE: |
diff --git a/drivers/acpi/nfit/mce.c b/drivers/acpi/nfit/mce.c index b92921439657..e9626bf6ca29 100644 --- a/drivers/acpi/nfit/mce.c +++ b/drivers/acpi/nfit/mce.c | |||
@@ -51,9 +51,8 @@ static int nfit_handle_mce(struct notifier_block *nb, unsigned long val, | |||
51 | if ((spa->address + spa->length - 1) < mce->addr) | 51 | if ((spa->address + spa->length - 1) < mce->addr) |
52 | continue; | 52 | continue; |
53 | found_match = 1; | 53 | found_match = 1; |
54 | dev_dbg(dev, "%s: addr in SPA %d (0x%llx, 0x%llx)\n", | 54 | dev_dbg(dev, "addr in SPA %d (0x%llx, 0x%llx)\n", |
55 | __func__, spa->range_index, spa->address, | 55 | spa->range_index, spa->address, spa->length); |
56 | spa->length); | ||
57 | /* | 56 | /* |
58 | * We can break at the first match because we're going | 57 | * We can break at the first match because we're going |
59 | * to rescan all the SPA ranges. There shouldn't be any | 58 | * to rescan all the SPA ranges. There shouldn't be any |
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index 50d36e166d70..7d15856a739f 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h | |||
@@ -117,10 +117,17 @@ enum nfit_dimm_notifiers { | |||
117 | NFIT_NOTIFY_DIMM_HEALTH = 0x81, | 117 | NFIT_NOTIFY_DIMM_HEALTH = 0x81, |
118 | }; | 118 | }; |
119 | 119 | ||
120 | enum nfit_ars_state { | ||
121 | ARS_REQ, | ||
122 | ARS_DONE, | ||
123 | ARS_SHORT, | ||
124 | ARS_FAILED, | ||
125 | }; | ||
126 | |||
120 | struct nfit_spa { | 127 | struct nfit_spa { |
121 | struct list_head list; | 128 | struct list_head list; |
122 | struct nd_region *nd_region; | 129 | struct nd_region *nd_region; |
123 | unsigned int ars_required:1; | 130 | unsigned long ars_state; |
124 | u32 clear_err_unit; | 131 | u32 clear_err_unit; |
125 | u32 max_ars; | 132 | u32 max_ars; |
126 | struct acpi_nfit_system_address spa[0]; | 133 | struct acpi_nfit_system_address spa[0]; |
@@ -171,9 +178,8 @@ struct nfit_mem { | |||
171 | struct resource *flush_wpq; | 178 | struct resource *flush_wpq; |
172 | unsigned long dsm_mask; | 179 | unsigned long dsm_mask; |
173 | int family; | 180 | int family; |
174 | u32 has_lsi:1; | 181 | bool has_lsr; |
175 | u32 has_lsr:1; | 182 | bool has_lsw; |
176 | u32 has_lsw:1; | ||
177 | }; | 183 | }; |
178 | 184 | ||
179 | struct acpi_nfit_desc { | 185 | struct acpi_nfit_desc { |
@@ -191,18 +197,18 @@ struct acpi_nfit_desc { | |||
191 | struct device *dev; | 197 | struct device *dev; |
192 | u8 ars_start_flags; | 198 | u8 ars_start_flags; |
193 | struct nd_cmd_ars_status *ars_status; | 199 | struct nd_cmd_ars_status *ars_status; |
194 | size_t ars_status_size; | 200 | struct delayed_work dwork; |
195 | struct work_struct work; | ||
196 | struct list_head list; | 201 | struct list_head list; |
197 | struct kernfs_node *scrub_count_state; | 202 | struct kernfs_node *scrub_count_state; |
203 | unsigned int max_ars; | ||
198 | unsigned int scrub_count; | 204 | unsigned int scrub_count; |
199 | unsigned int scrub_mode; | 205 | unsigned int scrub_mode; |
200 | unsigned int cancel:1; | 206 | unsigned int cancel:1; |
201 | unsigned int init_complete:1; | ||
202 | unsigned long dimm_cmd_force_en; | 207 | unsigned long dimm_cmd_force_en; |
203 | unsigned long bus_cmd_force_en; | 208 | unsigned long bus_cmd_force_en; |
204 | unsigned long bus_nfit_cmd_force_en; | 209 | unsigned long bus_nfit_cmd_force_en; |
205 | unsigned int platform_cap; | 210 | unsigned int platform_cap; |
211 | unsigned int scrub_tmo; | ||
206 | int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, | 212 | int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, |
207 | void *iobuf, u64 len, int rw); | 213 | void *iobuf, u64 len, int rw); |
208 | }; | 214 | }; |
@@ -244,7 +250,7 @@ struct nfit_blk { | |||
244 | 250 | ||
245 | extern struct list_head acpi_descs; | 251 | extern struct list_head acpi_descs; |
246 | extern struct mutex acpi_desc_lock; | 252 | extern struct mutex acpi_desc_lock; |
247 | int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags); | 253 | int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags); |
248 | 254 | ||
249 | #ifdef CONFIG_X86_MCE | 255 | #ifdef CONFIG_X86_MCE |
250 | void nfit_mce_register(void); | 256 | void nfit_mce_register(void); |
diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig index b79aa8f7a497..e0700bf4893a 100644 --- a/drivers/dax/Kconfig +++ b/drivers/dax/Kconfig | |||
@@ -1,3 +1,7 @@ | |||
1 | config DAX_DRIVER | ||
2 | select DAX | ||
3 | bool | ||
4 | |||
1 | menuconfig DAX | 5 | menuconfig DAX |
2 | tristate "DAX: direct access to differentiated memory" | 6 | tristate "DAX: direct access to differentiated memory" |
3 | select SRCU | 7 | select SRCU |
@@ -16,7 +20,6 @@ config DEV_DAX | |||
16 | baseline memory pool. Mappings of a /dev/daxX.Y device impose | 20 | baseline memory pool. Mappings of a /dev/daxX.Y device impose |
17 | restrictions that make the mapping behavior deterministic. | 21 | restrictions that make the mapping behavior deterministic. |
18 | 22 | ||
19 | |||
20 | config DEV_DAX_PMEM | 23 | config DEV_DAX_PMEM |
21 | tristate "PMEM DAX: direct access to persistent memory" | 24 | tristate "PMEM DAX: direct access to persistent memory" |
22 | depends on LIBNVDIMM && NVDIMM_DAX && DEV_DAX | 25 | depends on LIBNVDIMM && NVDIMM_DAX && DEV_DAX |
diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 0b61f48f21a6..be8606457f27 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c | |||
@@ -257,8 +257,8 @@ static int __dev_dax_pte_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) | |||
257 | 257 | ||
258 | dax_region = dev_dax->region; | 258 | dax_region = dev_dax->region; |
259 | if (dax_region->align > PAGE_SIZE) { | 259 | if (dax_region->align > PAGE_SIZE) { |
260 | dev_dbg(dev, "%s: alignment (%#x) > fault size (%#x)\n", | 260 | dev_dbg(dev, "alignment (%#x) > fault size (%#x)\n", |
261 | __func__, dax_region->align, fault_size); | 261 | dax_region->align, fault_size); |
262 | return VM_FAULT_SIGBUS; | 262 | return VM_FAULT_SIGBUS; |
263 | } | 263 | } |
264 | 264 | ||
@@ -267,8 +267,7 @@ static int __dev_dax_pte_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) | |||
267 | 267 | ||
268 | phys = dax_pgoff_to_phys(dev_dax, vmf->pgoff, PAGE_SIZE); | 268 | phys = dax_pgoff_to_phys(dev_dax, vmf->pgoff, PAGE_SIZE); |
269 | if (phys == -1) { | 269 | if (phys == -1) { |
270 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, | 270 | dev_dbg(dev, "pgoff_to_phys(%#lx) failed\n", vmf->pgoff); |
271 | vmf->pgoff); | ||
272 | return VM_FAULT_SIGBUS; | 271 | return VM_FAULT_SIGBUS; |
273 | } | 272 | } |
274 | 273 | ||
@@ -299,14 +298,14 @@ static int __dev_dax_pmd_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) | |||
299 | 298 | ||
300 | dax_region = dev_dax->region; | 299 | dax_region = dev_dax->region; |
301 | if (dax_region->align > PMD_SIZE) { | 300 | if (dax_region->align > PMD_SIZE) { |
302 | dev_dbg(dev, "%s: alignment (%#x) > fault size (%#x)\n", | 301 | dev_dbg(dev, "alignment (%#x) > fault size (%#x)\n", |
303 | __func__, dax_region->align, fault_size); | 302 | dax_region->align, fault_size); |
304 | return VM_FAULT_SIGBUS; | 303 | return VM_FAULT_SIGBUS; |
305 | } | 304 | } |
306 | 305 | ||
307 | /* dax pmd mappings require pfn_t_devmap() */ | 306 | /* dax pmd mappings require pfn_t_devmap() */ |
308 | if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) { | 307 | if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) { |
309 | dev_dbg(dev, "%s: region lacks devmap flags\n", __func__); | 308 | dev_dbg(dev, "region lacks devmap flags\n"); |
310 | return VM_FAULT_SIGBUS; | 309 | return VM_FAULT_SIGBUS; |
311 | } | 310 | } |
312 | 311 | ||
@@ -323,8 +322,7 @@ static int __dev_dax_pmd_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) | |||
323 | pgoff = linear_page_index(vmf->vma, pmd_addr); | 322 | pgoff = linear_page_index(vmf->vma, pmd_addr); |
324 | phys = dax_pgoff_to_phys(dev_dax, pgoff, PMD_SIZE); | 323 | phys = dax_pgoff_to_phys(dev_dax, pgoff, PMD_SIZE); |
325 | if (phys == -1) { | 324 | if (phys == -1) { |
326 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, | 325 | dev_dbg(dev, "pgoff_to_phys(%#lx) failed\n", pgoff); |
327 | pgoff); | ||
328 | return VM_FAULT_SIGBUS; | 326 | return VM_FAULT_SIGBUS; |
329 | } | 327 | } |
330 | 328 | ||
@@ -351,14 +349,14 @@ static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) | |||
351 | 349 | ||
352 | dax_region = dev_dax->region; | 350 | dax_region = dev_dax->region; |
353 | if (dax_region->align > PUD_SIZE) { | 351 | if (dax_region->align > PUD_SIZE) { |
354 | dev_dbg(dev, "%s: alignment (%#x) > fault size (%#x)\n", | 352 | dev_dbg(dev, "alignment (%#x) > fault size (%#x)\n", |
355 | __func__, dax_region->align, fault_size); | 353 | dax_region->align, fault_size); |
356 | return VM_FAULT_SIGBUS; | 354 | return VM_FAULT_SIGBUS; |
357 | } | 355 | } |
358 | 356 | ||
359 | /* dax pud mappings require pfn_t_devmap() */ | 357 | /* dax pud mappings require pfn_t_devmap() */ |
360 | if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) { | 358 | if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) { |
361 | dev_dbg(dev, "%s: region lacks devmap flags\n", __func__); | 359 | dev_dbg(dev, "region lacks devmap flags\n"); |
362 | return VM_FAULT_SIGBUS; | 360 | return VM_FAULT_SIGBUS; |
363 | } | 361 | } |
364 | 362 | ||
@@ -375,8 +373,7 @@ static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) | |||
375 | pgoff = linear_page_index(vmf->vma, pud_addr); | 373 | pgoff = linear_page_index(vmf->vma, pud_addr); |
376 | phys = dax_pgoff_to_phys(dev_dax, pgoff, PUD_SIZE); | 374 | phys = dax_pgoff_to_phys(dev_dax, pgoff, PUD_SIZE); |
377 | if (phys == -1) { | 375 | if (phys == -1) { |
378 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, | 376 | dev_dbg(dev, "pgoff_to_phys(%#lx) failed\n", pgoff); |
379 | pgoff); | ||
380 | return VM_FAULT_SIGBUS; | 377 | return VM_FAULT_SIGBUS; |
381 | } | 378 | } |
382 | 379 | ||
@@ -399,9 +396,8 @@ static int dev_dax_huge_fault(struct vm_fault *vmf, | |||
399 | struct file *filp = vmf->vma->vm_file; | 396 | struct file *filp = vmf->vma->vm_file; |
400 | struct dev_dax *dev_dax = filp->private_data; | 397 | struct dev_dax *dev_dax = filp->private_data; |
401 | 398 | ||
402 | dev_dbg(&dev_dax->dev, "%s: %s: %s (%#lx - %#lx) size = %d\n", __func__, | 399 | dev_dbg(&dev_dax->dev, "%s: %s (%#lx - %#lx) size = %d\n", current->comm, |
403 | current->comm, (vmf->flags & FAULT_FLAG_WRITE) | 400 | (vmf->flags & FAULT_FLAG_WRITE) ? "write" : "read", |
404 | ? "write" : "read", | ||
405 | vmf->vma->vm_start, vmf->vma->vm_end, pe_size); | 401 | vmf->vma->vm_start, vmf->vma->vm_end, pe_size); |
406 | 402 | ||
407 | id = dax_read_lock(); | 403 | id = dax_read_lock(); |
@@ -460,7 +456,7 @@ static int dax_mmap(struct file *filp, struct vm_area_struct *vma) | |||
460 | struct dev_dax *dev_dax = filp->private_data; | 456 | struct dev_dax *dev_dax = filp->private_data; |
461 | int rc, id; | 457 | int rc, id; |
462 | 458 | ||
463 | dev_dbg(&dev_dax->dev, "%s\n", __func__); | 459 | dev_dbg(&dev_dax->dev, "trace\n"); |
464 | 460 | ||
465 | /* | 461 | /* |
466 | * We lock to check dax_dev liveness and will re-check at | 462 | * We lock to check dax_dev liveness and will re-check at |
@@ -518,7 +514,7 @@ static int dax_open(struct inode *inode, struct file *filp) | |||
518 | struct inode *__dax_inode = dax_inode(dax_dev); | 514 | struct inode *__dax_inode = dax_inode(dax_dev); |
519 | struct dev_dax *dev_dax = dax_get_private(dax_dev); | 515 | struct dev_dax *dev_dax = dax_get_private(dax_dev); |
520 | 516 | ||
521 | dev_dbg(&dev_dax->dev, "%s\n", __func__); | 517 | dev_dbg(&dev_dax->dev, "trace\n"); |
522 | inode->i_mapping = __dax_inode->i_mapping; | 518 | inode->i_mapping = __dax_inode->i_mapping; |
523 | inode->i_mapping->host = __dax_inode; | 519 | inode->i_mapping->host = __dax_inode; |
524 | filp->f_mapping = inode->i_mapping; | 520 | filp->f_mapping = inode->i_mapping; |
@@ -533,7 +529,7 @@ static int dax_release(struct inode *inode, struct file *filp) | |||
533 | { | 529 | { |
534 | struct dev_dax *dev_dax = filp->private_data; | 530 | struct dev_dax *dev_dax = filp->private_data; |
535 | 531 | ||
536 | dev_dbg(&dev_dax->dev, "%s\n", __func__); | 532 | dev_dbg(&dev_dax->dev, "trace\n"); |
537 | return 0; | 533 | return 0; |
538 | } | 534 | } |
539 | 535 | ||
@@ -575,7 +571,7 @@ static void unregister_dev_dax(void *dev) | |||
575 | struct inode *inode = dax_inode(dax_dev); | 571 | struct inode *inode = dax_inode(dax_dev); |
576 | struct cdev *cdev = inode->i_cdev; | 572 | struct cdev *cdev = inode->i_cdev; |
577 | 573 | ||
578 | dev_dbg(dev, "%s\n", __func__); | 574 | dev_dbg(dev, "trace\n"); |
579 | 575 | ||
580 | kill_dev_dax(dev_dax); | 576 | kill_dev_dax(dev_dax); |
581 | cdev_device_del(cdev, dev); | 577 | cdev_device_del(cdev, dev); |
diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 31b6ecce4c64..fd49b24fd6af 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c | |||
@@ -34,7 +34,7 @@ static void dax_pmem_percpu_release(struct percpu_ref *ref) | |||
34 | { | 34 | { |
35 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); | 35 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); |
36 | 36 | ||
37 | dev_dbg(dax_pmem->dev, "%s\n", __func__); | 37 | dev_dbg(dax_pmem->dev, "trace\n"); |
38 | complete(&dax_pmem->cmp); | 38 | complete(&dax_pmem->cmp); |
39 | } | 39 | } |
40 | 40 | ||
@@ -43,7 +43,7 @@ static void dax_pmem_percpu_exit(void *data) | |||
43 | struct percpu_ref *ref = data; | 43 | struct percpu_ref *ref = data; |
44 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); | 44 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); |
45 | 45 | ||
46 | dev_dbg(dax_pmem->dev, "%s\n", __func__); | 46 | dev_dbg(dax_pmem->dev, "trace\n"); |
47 | wait_for_completion(&dax_pmem->cmp); | 47 | wait_for_completion(&dax_pmem->cmp); |
48 | percpu_ref_exit(ref); | 48 | percpu_ref_exit(ref); |
49 | } | 49 | } |
@@ -53,7 +53,7 @@ static void dax_pmem_percpu_kill(void *data) | |||
53 | struct percpu_ref *ref = data; | 53 | struct percpu_ref *ref = data; |
54 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); | 54 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); |
55 | 55 | ||
56 | dev_dbg(dax_pmem->dev, "%s\n", __func__); | 56 | dev_dbg(dax_pmem->dev, "trace\n"); |
57 | percpu_ref_kill(ref); | 57 | percpu_ref_kill(ref); |
58 | } | 58 | } |
59 | 59 | ||
@@ -150,17 +150,7 @@ static struct nd_device_driver dax_pmem_driver = { | |||
150 | .type = ND_DRIVER_DAX_PMEM, | 150 | .type = ND_DRIVER_DAX_PMEM, |
151 | }; | 151 | }; |
152 | 152 | ||
153 | static int __init dax_pmem_init(void) | 153 | module_nd_driver(dax_pmem_driver); |
154 | { | ||
155 | return nd_driver_register(&dax_pmem_driver); | ||
156 | } | ||
157 | module_init(dax_pmem_init); | ||
158 | |||
159 | static void __exit dax_pmem_exit(void) | ||
160 | { | ||
161 | driver_unregister(&dax_pmem_driver.drv); | ||
162 | } | ||
163 | module_exit(dax_pmem_exit); | ||
164 | 154 | ||
165 | MODULE_LICENSE("GPL v2"); | 155 | MODULE_LICENSE("GPL v2"); |
166 | MODULE_AUTHOR("Intel Corporation"); | 156 | MODULE_AUTHOR("Intel Corporation"); |
diff --git a/drivers/dax/super.c b/drivers/dax/super.c index ecdc292aa4e4..2b2332b605e4 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c | |||
@@ -124,10 +124,19 @@ int __bdev_dax_supported(struct super_block *sb, int blocksize) | |||
124 | return len < 0 ? len : -EIO; | 124 | return len < 0 ? len : -EIO; |
125 | } | 125 | } |
126 | 126 | ||
127 | if ((IS_ENABLED(CONFIG_FS_DAX_LIMITED) && pfn_t_special(pfn)) | 127 | if (IS_ENABLED(CONFIG_FS_DAX_LIMITED) && pfn_t_special(pfn)) { |
128 | || pfn_t_devmap(pfn)) | 128 | /* |
129 | * An arch that has enabled the pmem api should also | ||
130 | * have its drivers support pfn_t_devmap() | ||
131 | * | ||
132 | * This is a developer warning and should not trigger in | ||
133 | * production. dax_flush() will crash since it depends | ||
134 | * on being able to do (page_address(pfn_to_page())). | ||
135 | */ | ||
136 | WARN_ON(IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API)); | ||
137 | } else if (pfn_t_devmap(pfn)) { | ||
129 | /* pass */; | 138 | /* pass */; |
130 | else { | 139 | } else { |
131 | pr_debug("VFS (%s): error: dax support not enabled\n", | 140 | pr_debug("VFS (%s): error: dax support not enabled\n", |
132 | sb->s_id); | 141 | sb->s_id); |
133 | return -EOPNOTSUPP; | 142 | return -EOPNOTSUPP; |
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 2c8ac3688815..edff083f7c4e 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -201,7 +201,7 @@ config BLK_DEV_DM_BUILTIN | |||
201 | config BLK_DEV_DM | 201 | config BLK_DEV_DM |
202 | tristate "Device mapper support" | 202 | tristate "Device mapper support" |
203 | select BLK_DEV_DM_BUILTIN | 203 | select BLK_DEV_DM_BUILTIN |
204 | select DAX | 204 | depends on DAX || DAX=n |
205 | ---help--- | 205 | ---help--- |
206 | Device-mapper is a low level volume manager. It works by allowing | 206 | Device-mapper is a low level volume manager. It works by allowing |
207 | people to specify mappings for ranges of logical sectors. Various | 207 | people to specify mappings for ranges of logical sectors. Various |
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 99297212eeec..775c06d953b7 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c | |||
@@ -154,6 +154,7 @@ static int linear_iterate_devices(struct dm_target *ti, | |||
154 | return fn(ti, lc->dev, lc->start, ti->len, data); | 154 | return fn(ti, lc->dev, lc->start, ti->len, data); |
155 | } | 155 | } |
156 | 156 | ||
157 | #if IS_ENABLED(CONFIG_DAX_DRIVER) | ||
157 | static long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, | 158 | static long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, |
158 | long nr_pages, void **kaddr, pfn_t *pfn) | 159 | long nr_pages, void **kaddr, pfn_t *pfn) |
159 | { | 160 | { |
@@ -184,6 +185,11 @@ static size_t linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff, | |||
184 | return dax_copy_from_iter(dax_dev, pgoff, addr, bytes, i); | 185 | return dax_copy_from_iter(dax_dev, pgoff, addr, bytes, i); |
185 | } | 186 | } |
186 | 187 | ||
188 | #else | ||
189 | #define linear_dax_direct_access NULL | ||
190 | #define linear_dax_copy_from_iter NULL | ||
191 | #endif | ||
192 | |||
187 | static struct target_type linear_target = { | 193 | static struct target_type linear_target = { |
188 | .name = "linear", | 194 | .name = "linear", |
189 | .version = {1, 4, 0}, | 195 | .version = {1, 4, 0}, |
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index 9de072b7782a..c90c7c08a77f 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c | |||
@@ -611,51 +611,6 @@ static int log_mark(struct log_writes_c *lc, char *data) | |||
611 | return 0; | 611 | return 0; |
612 | } | 612 | } |
613 | 613 | ||
614 | static int log_dax(struct log_writes_c *lc, sector_t sector, size_t bytes, | ||
615 | struct iov_iter *i) | ||
616 | { | ||
617 | struct pending_block *block; | ||
618 | |||
619 | if (!bytes) | ||
620 | return 0; | ||
621 | |||
622 | block = kzalloc(sizeof(struct pending_block), GFP_KERNEL); | ||
623 | if (!block) { | ||
624 | DMERR("Error allocating dax pending block"); | ||
625 | return -ENOMEM; | ||
626 | } | ||
627 | |||
628 | block->data = kzalloc(bytes, GFP_KERNEL); | ||
629 | if (!block->data) { | ||
630 | DMERR("Error allocating dax data space"); | ||
631 | kfree(block); | ||
632 | return -ENOMEM; | ||
633 | } | ||
634 | |||
635 | /* write data provided via the iterator */ | ||
636 | if (!copy_from_iter(block->data, bytes, i)) { | ||
637 | DMERR("Error copying dax data"); | ||
638 | kfree(block->data); | ||
639 | kfree(block); | ||
640 | return -EIO; | ||
641 | } | ||
642 | |||
643 | /* rewind the iterator so that the block driver can use it */ | ||
644 | iov_iter_revert(i, bytes); | ||
645 | |||
646 | block->datalen = bytes; | ||
647 | block->sector = bio_to_dev_sectors(lc, sector); | ||
648 | block->nr_sectors = ALIGN(bytes, lc->sectorsize) >> lc->sectorshift; | ||
649 | |||
650 | atomic_inc(&lc->pending_blocks); | ||
651 | spin_lock_irq(&lc->blocks_lock); | ||
652 | list_add_tail(&block->list, &lc->unflushed_blocks); | ||
653 | spin_unlock_irq(&lc->blocks_lock); | ||
654 | wake_up_process(lc->log_kthread); | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | static void log_writes_dtr(struct dm_target *ti) | 614 | static void log_writes_dtr(struct dm_target *ti) |
660 | { | 615 | { |
661 | struct log_writes_c *lc = ti->private; | 616 | struct log_writes_c *lc = ti->private; |
@@ -925,6 +880,52 @@ static void log_writes_io_hints(struct dm_target *ti, struct queue_limits *limit | |||
925 | limits->io_min = limits->physical_block_size; | 880 | limits->io_min = limits->physical_block_size; |
926 | } | 881 | } |
927 | 882 | ||
883 | #if IS_ENABLED(CONFIG_DAX_DRIVER) | ||
884 | static int log_dax(struct log_writes_c *lc, sector_t sector, size_t bytes, | ||
885 | struct iov_iter *i) | ||
886 | { | ||
887 | struct pending_block *block; | ||
888 | |||
889 | if (!bytes) | ||
890 | return 0; | ||
891 | |||
892 | block = kzalloc(sizeof(struct pending_block), GFP_KERNEL); | ||
893 | if (!block) { | ||
894 | DMERR("Error allocating dax pending block"); | ||
895 | return -ENOMEM; | ||
896 | } | ||
897 | |||
898 | block->data = kzalloc(bytes, GFP_KERNEL); | ||
899 | if (!block->data) { | ||
900 | DMERR("Error allocating dax data space"); | ||
901 | kfree(block); | ||
902 | return -ENOMEM; | ||
903 | } | ||
904 | |||
905 | /* write data provided via the iterator */ | ||
906 | if (!copy_from_iter(block->data, bytes, i)) { | ||
907 | DMERR("Error copying dax data"); | ||
908 | kfree(block->data); | ||
909 | kfree(block); | ||
910 | return -EIO; | ||
911 | } | ||
912 | |||
913 | /* rewind the iterator so that the block driver can use it */ | ||
914 | iov_iter_revert(i, bytes); | ||
915 | |||
916 | block->datalen = bytes; | ||
917 | block->sector = bio_to_dev_sectors(lc, sector); | ||
918 | block->nr_sectors = ALIGN(bytes, lc->sectorsize) >> lc->sectorshift; | ||
919 | |||
920 | atomic_inc(&lc->pending_blocks); | ||
921 | spin_lock_irq(&lc->blocks_lock); | ||
922 | list_add_tail(&block->list, &lc->unflushed_blocks); | ||
923 | spin_unlock_irq(&lc->blocks_lock); | ||
924 | wake_up_process(lc->log_kthread); | ||
925 | |||
926 | return 0; | ||
927 | } | ||
928 | |||
928 | static long log_writes_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, | 929 | static long log_writes_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, |
929 | long nr_pages, void **kaddr, pfn_t *pfn) | 930 | long nr_pages, void **kaddr, pfn_t *pfn) |
930 | { | 931 | { |
@@ -961,6 +962,10 @@ static size_t log_writes_dax_copy_from_iter(struct dm_target *ti, | |||
961 | dax_copy: | 962 | dax_copy: |
962 | return dax_copy_from_iter(lc->dev->dax_dev, pgoff, addr, bytes, i); | 963 | return dax_copy_from_iter(lc->dev->dax_dev, pgoff, addr, bytes, i); |
963 | } | 964 | } |
965 | #else | ||
966 | #define log_writes_dax_direct_access NULL | ||
967 | #define log_writes_dax_copy_from_iter NULL | ||
968 | #endif | ||
964 | 969 | ||
965 | static struct target_type log_writes_target = { | 970 | static struct target_type log_writes_target = { |
966 | .name = "log-writes", | 971 | .name = "log-writes", |
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index bb907cb3e60d..fe7fb9b1aec3 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -313,6 +313,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio) | |||
313 | return DM_MAPIO_REMAPPED; | 313 | return DM_MAPIO_REMAPPED; |
314 | } | 314 | } |
315 | 315 | ||
316 | #if IS_ENABLED(CONFIG_DAX_DRIVER) | ||
316 | static long stripe_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, | 317 | static long stripe_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, |
317 | long nr_pages, void **kaddr, pfn_t *pfn) | 318 | long nr_pages, void **kaddr, pfn_t *pfn) |
318 | { | 319 | { |
@@ -353,6 +354,11 @@ static size_t stripe_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff, | |||
353 | return dax_copy_from_iter(dax_dev, pgoff, addr, bytes, i); | 354 | return dax_copy_from_iter(dax_dev, pgoff, addr, bytes, i); |
354 | } | 355 | } |
355 | 356 | ||
357 | #else | ||
358 | #define stripe_dax_direct_access NULL | ||
359 | #define stripe_dax_copy_from_iter NULL | ||
360 | #endif | ||
361 | |||
356 | /* | 362 | /* |
357 | * Stripe status: | 363 | * Stripe status: |
358 | * | 364 | * |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 5a81c47be4e4..4ea404dbcf0b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -1826,7 +1826,7 @@ static void cleanup_mapped_device(struct mapped_device *md) | |||
1826 | static struct mapped_device *alloc_dev(int minor) | 1826 | static struct mapped_device *alloc_dev(int minor) |
1827 | { | 1827 | { |
1828 | int r, numa_node_id = dm_get_numa_node(); | 1828 | int r, numa_node_id = dm_get_numa_node(); |
1829 | struct dax_device *dax_dev; | 1829 | struct dax_device *dax_dev = NULL; |
1830 | struct mapped_device *md; | 1830 | struct mapped_device *md; |
1831 | void *old_md; | 1831 | void *old_md; |
1832 | 1832 | ||
@@ -1892,9 +1892,11 @@ static struct mapped_device *alloc_dev(int minor) | |||
1892 | md->disk->private_data = md; | 1892 | md->disk->private_data = md; |
1893 | sprintf(md->disk->disk_name, "dm-%d", minor); | 1893 | sprintf(md->disk->disk_name, "dm-%d", minor); |
1894 | 1894 | ||
1895 | dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops); | 1895 | if (IS_ENABLED(CONFIG_DAX_DRIVER)) { |
1896 | if (!dax_dev) | 1896 | dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops); |
1897 | goto bad; | 1897 | if (!dax_dev) |
1898 | goto bad; | ||
1899 | } | ||
1898 | md->dax_dev = dax_dev; | 1900 | md->dax_dev = dax_dev; |
1899 | 1901 | ||
1900 | add_disk_no_queue_reg(md->disk); | 1902 | add_disk_no_queue_reg(md->disk); |
diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index a65f2e1d9f53..85997184e047 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig | |||
@@ -20,7 +20,7 @@ if LIBNVDIMM | |||
20 | config BLK_DEV_PMEM | 20 | config BLK_DEV_PMEM |
21 | tristate "PMEM: Persistent memory block device support" | 21 | tristate "PMEM: Persistent memory block device support" |
22 | default LIBNVDIMM | 22 | default LIBNVDIMM |
23 | select DAX | 23 | select DAX_DRIVER |
24 | select ND_BTT if BTT | 24 | select ND_BTT if BTT |
25 | select ND_PFN if NVDIMM_PFN | 25 | select ND_PFN if NVDIMM_PFN |
26 | help | 26 | help |
@@ -102,4 +102,15 @@ config NVDIMM_DAX | |||
102 | 102 | ||
103 | Select Y if unsure | 103 | Select Y if unsure |
104 | 104 | ||
105 | config OF_PMEM | ||
106 | # FIXME: make tristate once OF_NUMA dependency removed | ||
107 | bool "Device-tree support for persistent memory regions" | ||
108 | depends on OF | ||
109 | default LIBNVDIMM | ||
110 | help | ||
111 | Allows regions of persistent memory to be described in the | ||
112 | device-tree. | ||
113 | |||
114 | Select Y if unsure. | ||
115 | |||
105 | endif | 116 | endif |
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile index 70d5f3ad9909..e8847045dac0 100644 --- a/drivers/nvdimm/Makefile +++ b/drivers/nvdimm/Makefile | |||
@@ -4,6 +4,7 @@ obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o | |||
4 | obj-$(CONFIG_ND_BTT) += nd_btt.o | 4 | obj-$(CONFIG_ND_BTT) += nd_btt.o |
5 | obj-$(CONFIG_ND_BLK) += nd_blk.o | 5 | obj-$(CONFIG_ND_BLK) += nd_blk.o |
6 | obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o | 6 | obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o |
7 | obj-$(CONFIG_OF_PMEM) += of_pmem.o | ||
7 | 8 | ||
8 | nd_pmem-y := pmem.o | 9 | nd_pmem-y := pmem.o |
9 | 10 | ||
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c index d58925295aa7..795ad4ff35ca 100644 --- a/drivers/nvdimm/btt_devs.c +++ b/drivers/nvdimm/btt_devs.c | |||
@@ -26,7 +26,7 @@ static void nd_btt_release(struct device *dev) | |||
26 | struct nd_region *nd_region = to_nd_region(dev->parent); | 26 | struct nd_region *nd_region = to_nd_region(dev->parent); |
27 | struct nd_btt *nd_btt = to_nd_btt(dev); | 27 | struct nd_btt *nd_btt = to_nd_btt(dev); |
28 | 28 | ||
29 | dev_dbg(dev, "%s\n", __func__); | 29 | dev_dbg(dev, "trace\n"); |
30 | nd_detach_ndns(&nd_btt->dev, &nd_btt->ndns); | 30 | nd_detach_ndns(&nd_btt->dev, &nd_btt->ndns); |
31 | ida_simple_remove(&nd_region->btt_ida, nd_btt->id); | 31 | ida_simple_remove(&nd_region->btt_ida, nd_btt->id); |
32 | kfree(nd_btt->uuid); | 32 | kfree(nd_btt->uuid); |
@@ -74,8 +74,8 @@ static ssize_t sector_size_store(struct device *dev, | |||
74 | nvdimm_bus_lock(dev); | 74 | nvdimm_bus_lock(dev); |
75 | rc = nd_size_select_store(dev, buf, &nd_btt->lbasize, | 75 | rc = nd_size_select_store(dev, buf, &nd_btt->lbasize, |
76 | btt_lbasize_supported); | 76 | btt_lbasize_supported); |
77 | dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, | 77 | dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, |
78 | rc, buf, buf[len - 1] == '\n' ? "" : "\n"); | 78 | buf[len - 1] == '\n' ? "" : "\n"); |
79 | nvdimm_bus_unlock(dev); | 79 | nvdimm_bus_unlock(dev); |
80 | device_unlock(dev); | 80 | device_unlock(dev); |
81 | 81 | ||
@@ -101,8 +101,8 @@ static ssize_t uuid_store(struct device *dev, | |||
101 | 101 | ||
102 | device_lock(dev); | 102 | device_lock(dev); |
103 | rc = nd_uuid_store(dev, &nd_btt->uuid, buf, len); | 103 | rc = nd_uuid_store(dev, &nd_btt->uuid, buf, len); |
104 | dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, | 104 | dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, |
105 | rc, buf, buf[len - 1] == '\n' ? "" : "\n"); | 105 | buf[len - 1] == '\n' ? "" : "\n"); |
106 | device_unlock(dev); | 106 | device_unlock(dev); |
107 | 107 | ||
108 | return rc ? rc : len; | 108 | return rc ? rc : len; |
@@ -131,8 +131,8 @@ static ssize_t namespace_store(struct device *dev, | |||
131 | device_lock(dev); | 131 | device_lock(dev); |
132 | nvdimm_bus_lock(dev); | 132 | nvdimm_bus_lock(dev); |
133 | rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len); | 133 | rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len); |
134 | dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, | 134 | dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, |
135 | rc, buf, buf[len - 1] == '\n' ? "" : "\n"); | 135 | buf[len - 1] == '\n' ? "" : "\n"); |
136 | nvdimm_bus_unlock(dev); | 136 | nvdimm_bus_unlock(dev); |
137 | device_unlock(dev); | 137 | device_unlock(dev); |
138 | 138 | ||
@@ -206,8 +206,8 @@ static struct device *__nd_btt_create(struct nd_region *nd_region, | |||
206 | dev->groups = nd_btt_attribute_groups; | 206 | dev->groups = nd_btt_attribute_groups; |
207 | device_initialize(&nd_btt->dev); | 207 | device_initialize(&nd_btt->dev); |
208 | if (ndns && !__nd_attach_ndns(&nd_btt->dev, ndns, &nd_btt->ndns)) { | 208 | if (ndns && !__nd_attach_ndns(&nd_btt->dev, ndns, &nd_btt->ndns)) { |
209 | dev_dbg(&ndns->dev, "%s failed, already claimed by %s\n", | 209 | dev_dbg(&ndns->dev, "failed, already claimed by %s\n", |
210 | __func__, dev_name(ndns->claim)); | 210 | dev_name(ndns->claim)); |
211 | put_device(dev); | 211 | put_device(dev); |
212 | return NULL; | 212 | return NULL; |
213 | } | 213 | } |
@@ -346,8 +346,7 @@ int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns) | |||
346 | return -ENOMEM; | 346 | return -ENOMEM; |
347 | btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL); | 347 | btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL); |
348 | rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb); | 348 | rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb); |
349 | dev_dbg(dev, "%s: btt: %s\n", __func__, | 349 | dev_dbg(dev, "btt: %s\n", rc == 0 ? dev_name(btt_dev) : "<none>"); |
350 | rc == 0 ? dev_name(btt_dev) : "<none>"); | ||
351 | if (rc < 0) { | 350 | if (rc < 0) { |
352 | struct nd_btt *nd_btt = to_nd_btt(btt_dev); | 351 | struct nd_btt *nd_btt = to_nd_btt(btt_dev); |
353 | 352 | ||
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 78eabc3a1ab1..a64023690cad 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c | |||
@@ -358,6 +358,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent, | |||
358 | nvdimm_bus->dev.release = nvdimm_bus_release; | 358 | nvdimm_bus->dev.release = nvdimm_bus_release; |
359 | nvdimm_bus->dev.groups = nd_desc->attr_groups; | 359 | nvdimm_bus->dev.groups = nd_desc->attr_groups; |
360 | nvdimm_bus->dev.bus = &nvdimm_bus_type; | 360 | nvdimm_bus->dev.bus = &nvdimm_bus_type; |
361 | nvdimm_bus->dev.of_node = nd_desc->of_node; | ||
361 | dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id); | 362 | dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id); |
362 | rc = device_register(&nvdimm_bus->dev); | 363 | rc = device_register(&nvdimm_bus->dev); |
363 | if (rc) { | 364 | if (rc) { |
@@ -984,8 +985,8 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
984 | 985 | ||
985 | if (cmd == ND_CMD_CALL) { | 986 | if (cmd == ND_CMD_CALL) { |
986 | func = pkg.nd_command; | 987 | func = pkg.nd_command; |
987 | dev_dbg(dev, "%s:%s, idx: %llu, in: %u, out: %u, len %llu\n", | 988 | dev_dbg(dev, "%s, idx: %llu, in: %u, out: %u, len %llu\n", |
988 | __func__, dimm_name, pkg.nd_command, | 989 | dimm_name, pkg.nd_command, |
989 | in_len, out_len, buf_len); | 990 | in_len, out_len, buf_len); |
990 | } | 991 | } |
991 | 992 | ||
@@ -996,8 +997,8 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
996 | u32 copy; | 997 | u32 copy; |
997 | 998 | ||
998 | if (out_size == UINT_MAX) { | 999 | if (out_size == UINT_MAX) { |
999 | dev_dbg(dev, "%s:%s unknown output size cmd: %s field: %d\n", | 1000 | dev_dbg(dev, "%s unknown output size cmd: %s field: %d\n", |
1000 | __func__, dimm_name, cmd_name, i); | 1001 | dimm_name, cmd_name, i); |
1001 | return -EFAULT; | 1002 | return -EFAULT; |
1002 | } | 1003 | } |
1003 | if (out_len < sizeof(out_env)) | 1004 | if (out_len < sizeof(out_env)) |
@@ -1012,9 +1013,8 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
1012 | 1013 | ||
1013 | buf_len = (u64) out_len + (u64) in_len; | 1014 | buf_len = (u64) out_len + (u64) in_len; |
1014 | if (buf_len > ND_IOCTL_MAX_BUFLEN) { | 1015 | if (buf_len > ND_IOCTL_MAX_BUFLEN) { |
1015 | dev_dbg(dev, "%s:%s cmd: %s buf_len: %llu > %d\n", __func__, | 1016 | dev_dbg(dev, "%s cmd: %s buf_len: %llu > %d\n", dimm_name, |
1016 | dimm_name, cmd_name, buf_len, | 1017 | cmd_name, buf_len, ND_IOCTL_MAX_BUFLEN); |
1017 | ND_IOCTL_MAX_BUFLEN); | ||
1018 | return -EINVAL; | 1018 | return -EINVAL; |
1019 | } | 1019 | } |
1020 | 1020 | ||
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index b2fc29b8279b..30852270484f 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c | |||
@@ -148,7 +148,7 @@ ssize_t nd_namespace_store(struct device *dev, | |||
148 | char *name; | 148 | char *name; |
149 | 149 | ||
150 | if (dev->driver) { | 150 | if (dev->driver) { |
151 | dev_dbg(dev, "%s: -EBUSY\n", __func__); | 151 | dev_dbg(dev, "namespace already active\n"); |
152 | return -EBUSY; | 152 | return -EBUSY; |
153 | } | 153 | } |
154 | 154 | ||
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index 1dc527660637..acce050856a8 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c | |||
@@ -134,7 +134,7 @@ static void nvdimm_map_release(struct kref *kref) | |||
134 | nvdimm_map = container_of(kref, struct nvdimm_map, kref); | 134 | nvdimm_map = container_of(kref, struct nvdimm_map, kref); |
135 | nvdimm_bus = nvdimm_map->nvdimm_bus; | 135 | nvdimm_bus = nvdimm_map->nvdimm_bus; |
136 | 136 | ||
137 | dev_dbg(&nvdimm_bus->dev, "%s: %pa\n", __func__, &nvdimm_map->offset); | 137 | dev_dbg(&nvdimm_bus->dev, "%pa\n", &nvdimm_map->offset); |
138 | list_del(&nvdimm_map->list); | 138 | list_del(&nvdimm_map->list); |
139 | if (nvdimm_map->flags) | 139 | if (nvdimm_map->flags) |
140 | memunmap(nvdimm_map->mem); | 140 | memunmap(nvdimm_map->mem); |
@@ -230,8 +230,8 @@ static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf, | |||
230 | 230 | ||
231 | for (i = 0; i < 16; i++) { | 231 | for (i = 0; i < 16; i++) { |
232 | if (!isxdigit(str[0]) || !isxdigit(str[1])) { | 232 | if (!isxdigit(str[0]) || !isxdigit(str[1])) { |
233 | dev_dbg(dev, "%s: pos: %d buf[%zd]: %c buf[%zd]: %c\n", | 233 | dev_dbg(dev, "pos: %d buf[%zd]: %c buf[%zd]: %c\n", |
234 | __func__, i, str - buf, str[0], | 234 | i, str - buf, str[0], |
235 | str + 1 - buf, str[1]); | 235 | str + 1 - buf, str[1]); |
236 | return -EINVAL; | 236 | return -EINVAL; |
237 | } | 237 | } |
diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c index 1bf2bd318371..0453f49dc708 100644 --- a/drivers/nvdimm/dax_devs.c +++ b/drivers/nvdimm/dax_devs.c | |||
@@ -24,7 +24,7 @@ static void nd_dax_release(struct device *dev) | |||
24 | struct nd_dax *nd_dax = to_nd_dax(dev); | 24 | struct nd_dax *nd_dax = to_nd_dax(dev); |
25 | struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; | 25 | struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; |
26 | 26 | ||
27 | dev_dbg(dev, "%s\n", __func__); | 27 | dev_dbg(dev, "trace\n"); |
28 | nd_detach_ndns(dev, &nd_pfn->ndns); | 28 | nd_detach_ndns(dev, &nd_pfn->ndns); |
29 | ida_simple_remove(&nd_region->dax_ida, nd_pfn->id); | 29 | ida_simple_remove(&nd_region->dax_ida, nd_pfn->id); |
30 | kfree(nd_pfn->uuid); | 30 | kfree(nd_pfn->uuid); |
@@ -129,8 +129,7 @@ int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns) | |||
129 | pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); | 129 | pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); |
130 | nd_pfn->pfn_sb = pfn_sb; | 130 | nd_pfn->pfn_sb = pfn_sb; |
131 | rc = nd_pfn_validate(nd_pfn, DAX_SIG); | 131 | rc = nd_pfn_validate(nd_pfn, DAX_SIG); |
132 | dev_dbg(dev, "%s: dax: %s\n", __func__, | 132 | dev_dbg(dev, "dax: %s\n", rc == 0 ? dev_name(dax_dev) : "<none>"); |
133 | rc == 0 ? dev_name(dax_dev) : "<none>"); | ||
134 | if (rc < 0) { | 133 | if (rc < 0) { |
135 | nd_detach_ndns(dax_dev, &nd_pfn->ndns); | 134 | nd_detach_ndns(dax_dev, &nd_pfn->ndns); |
136 | put_device(dax_dev); | 135 | put_device(dax_dev); |
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index f8913b8124b6..233907889f96 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c | |||
@@ -67,9 +67,11 @@ static int nvdimm_probe(struct device *dev) | |||
67 | ndd->ns_next = nd_label_next_nsindex(ndd->ns_current); | 67 | ndd->ns_next = nd_label_next_nsindex(ndd->ns_current); |
68 | nd_label_copy(ndd, to_next_namespace_index(ndd), | 68 | nd_label_copy(ndd, to_next_namespace_index(ndd), |
69 | to_current_namespace_index(ndd)); | 69 | to_current_namespace_index(ndd)); |
70 | rc = nd_label_reserve_dpa(ndd); | 70 | if (ndd->ns_current >= 0) { |
71 | if (ndd->ns_current >= 0) | 71 | rc = nd_label_reserve_dpa(ndd); |
72 | nvdimm_set_aliasing(dev); | 72 | if (rc == 0) |
73 | nvdimm_set_aliasing(dev); | ||
74 | } | ||
73 | nvdimm_clear_locked(dev); | 75 | nvdimm_clear_locked(dev); |
74 | nvdimm_bus_unlock(dev); | 76 | nvdimm_bus_unlock(dev); |
75 | 77 | ||
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 097794d9f786..e00d45522b80 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c | |||
@@ -131,7 +131,7 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) | |||
131 | } | 131 | } |
132 | memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length); | 132 | memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length); |
133 | } | 133 | } |
134 | dev_dbg(ndd->dev, "%s: len: %zu rc: %d\n", __func__, offset, rc); | 134 | dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc); |
135 | kfree(cmd); | 135 | kfree(cmd); |
136 | 136 | ||
137 | return rc; | 137 | return rc; |
@@ -266,8 +266,7 @@ void nvdimm_drvdata_release(struct kref *kref) | |||
266 | struct device *dev = ndd->dev; | 266 | struct device *dev = ndd->dev; |
267 | struct resource *res, *_r; | 267 | struct resource *res, *_r; |
268 | 268 | ||
269 | dev_dbg(dev, "%s\n", __func__); | 269 | dev_dbg(dev, "trace\n"); |
270 | |||
271 | nvdimm_bus_lock(dev); | 270 | nvdimm_bus_lock(dev); |
272 | for_each_dpa_resource_safe(ndd, res, _r) | 271 | for_each_dpa_resource_safe(ndd, res, _r) |
273 | nvdimm_free_dpa(ndd, res); | 272 | nvdimm_free_dpa(ndd, res); |
@@ -660,7 +659,7 @@ int nvdimm_bus_check_dimm_count(struct nvdimm_bus *nvdimm_bus, int dimm_count) | |||
660 | nd_synchronize(); | 659 | nd_synchronize(); |
661 | 660 | ||
662 | device_for_each_child(&nvdimm_bus->dev, &count, count_dimms); | 661 | device_for_each_child(&nvdimm_bus->dev, &count, count_dimms); |
663 | dev_dbg(&nvdimm_bus->dev, "%s: count: %d\n", __func__, count); | 662 | dev_dbg(&nvdimm_bus->dev, "count: %d\n", count); |
664 | if (count != dimm_count) | 663 | if (count != dimm_count) |
665 | return -ENXIO; | 664 | return -ENXIO; |
666 | return 0; | 665 | return 0; |
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index de66c02f6140..1d28cd656536 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c | |||
@@ -45,9 +45,27 @@ unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd) | |||
45 | return ndd->nslabel_size; | 45 | return ndd->nslabel_size; |
46 | } | 46 | } |
47 | 47 | ||
48 | static size_t __sizeof_namespace_index(u32 nslot) | ||
49 | { | ||
50 | return ALIGN(sizeof(struct nd_namespace_index) + DIV_ROUND_UP(nslot, 8), | ||
51 | NSINDEX_ALIGN); | ||
52 | } | ||
53 | |||
54 | static int __nvdimm_num_label_slots(struct nvdimm_drvdata *ndd, | ||
55 | size_t index_size) | ||
56 | { | ||
57 | return (ndd->nsarea.config_size - index_size * 2) / | ||
58 | sizeof_namespace_label(ndd); | ||
59 | } | ||
60 | |||
48 | int nvdimm_num_label_slots(struct nvdimm_drvdata *ndd) | 61 | int nvdimm_num_label_slots(struct nvdimm_drvdata *ndd) |
49 | { | 62 | { |
50 | return ndd->nsarea.config_size / (sizeof_namespace_label(ndd) + 1); | 63 | u32 tmp_nslot, n; |
64 | |||
65 | tmp_nslot = ndd->nsarea.config_size / sizeof_namespace_label(ndd); | ||
66 | n = __sizeof_namespace_index(tmp_nslot) / NSINDEX_ALIGN; | ||
67 | |||
68 | return __nvdimm_num_label_slots(ndd, NSINDEX_ALIGN * n); | ||
51 | } | 69 | } |
52 | 70 | ||
53 | size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd) | 71 | size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd) |
@@ -55,18 +73,14 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd) | |||
55 | u32 nslot, space, size; | 73 | u32 nslot, space, size; |
56 | 74 | ||
57 | /* | 75 | /* |
58 | * The minimum index space is 512 bytes, with that amount of | 76 | * Per UEFI 2.7, the minimum size of the Label Storage Area is large |
59 | * index we can describe ~1400 labels which is less than a byte | 77 | * enough to hold 2 index blocks and 2 labels. The minimum index |
60 | * of overhead per label. Round up to a byte of overhead per | 78 | * block size is 256 bytes, and the minimum label size is 256 bytes. |
61 | * label and determine the size of the index region. Yes, this | ||
62 | * starts to waste space at larger config_sizes, but it's | ||
63 | * unlikely we'll ever see anything but 128K. | ||
64 | */ | 79 | */ |
65 | nslot = nvdimm_num_label_slots(ndd); | 80 | nslot = nvdimm_num_label_slots(ndd); |
66 | space = ndd->nsarea.config_size - nslot * sizeof_namespace_label(ndd); | 81 | space = ndd->nsarea.config_size - nslot * sizeof_namespace_label(ndd); |
67 | size = ALIGN(sizeof(struct nd_namespace_index) + DIV_ROUND_UP(nslot, 8), | 82 | size = __sizeof_namespace_index(nslot) * 2; |
68 | NSINDEX_ALIGN) * 2; | 83 | if (size <= space && nslot >= 2) |
69 | if (size <= space) | ||
70 | return size / 2; | 84 | return size / 2; |
71 | 85 | ||
72 | dev_err(ndd->dev, "label area (%d) too small to host (%d byte) labels\n", | 86 | dev_err(ndd->dev, "label area (%d) too small to host (%d byte) labels\n", |
@@ -121,8 +135,7 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd) | |||
121 | 135 | ||
122 | memcpy(sig, nsindex[i]->sig, NSINDEX_SIG_LEN); | 136 | memcpy(sig, nsindex[i]->sig, NSINDEX_SIG_LEN); |
123 | if (memcmp(sig, NSINDEX_SIGNATURE, NSINDEX_SIG_LEN) != 0) { | 137 | if (memcmp(sig, NSINDEX_SIGNATURE, NSINDEX_SIG_LEN) != 0) { |
124 | dev_dbg(dev, "%s: nsindex%d signature invalid\n", | 138 | dev_dbg(dev, "nsindex%d signature invalid\n", i); |
125 | __func__, i); | ||
126 | continue; | 139 | continue; |
127 | } | 140 | } |
128 | 141 | ||
@@ -135,8 +148,8 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd) | |||
135 | labelsize = 128; | 148 | labelsize = 128; |
136 | 149 | ||
137 | if (labelsize != sizeof_namespace_label(ndd)) { | 150 | if (labelsize != sizeof_namespace_label(ndd)) { |
138 | dev_dbg(dev, "%s: nsindex%d labelsize %d invalid\n", | 151 | dev_dbg(dev, "nsindex%d labelsize %d invalid\n", |
139 | __func__, i, nsindex[i]->labelsize); | 152 | i, nsindex[i]->labelsize); |
140 | continue; | 153 | continue; |
141 | } | 154 | } |
142 | 155 | ||
@@ -145,30 +158,28 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd) | |||
145 | sum = nd_fletcher64(nsindex[i], sizeof_namespace_index(ndd), 1); | 158 | sum = nd_fletcher64(nsindex[i], sizeof_namespace_index(ndd), 1); |
146 | nsindex[i]->checksum = __cpu_to_le64(sum_save); | 159 | nsindex[i]->checksum = __cpu_to_le64(sum_save); |
147 | if (sum != sum_save) { | 160 | if (sum != sum_save) { |
148 | dev_dbg(dev, "%s: nsindex%d checksum invalid\n", | 161 | dev_dbg(dev, "nsindex%d checksum invalid\n", i); |
149 | __func__, i); | ||
150 | continue; | 162 | continue; |
151 | } | 163 | } |
152 | 164 | ||
153 | seq = __le32_to_cpu(nsindex[i]->seq); | 165 | seq = __le32_to_cpu(nsindex[i]->seq); |
154 | if ((seq & NSINDEX_SEQ_MASK) == 0) { | 166 | if ((seq & NSINDEX_SEQ_MASK) == 0) { |
155 | dev_dbg(dev, "%s: nsindex%d sequence: %#x invalid\n", | 167 | dev_dbg(dev, "nsindex%d sequence: %#x invalid\n", i, seq); |
156 | __func__, i, seq); | ||
157 | continue; | 168 | continue; |
158 | } | 169 | } |
159 | 170 | ||
160 | /* sanity check the index against expected values */ | 171 | /* sanity check the index against expected values */ |
161 | if (__le64_to_cpu(nsindex[i]->myoff) | 172 | if (__le64_to_cpu(nsindex[i]->myoff) |
162 | != i * sizeof_namespace_index(ndd)) { | 173 | != i * sizeof_namespace_index(ndd)) { |
163 | dev_dbg(dev, "%s: nsindex%d myoff: %#llx invalid\n", | 174 | dev_dbg(dev, "nsindex%d myoff: %#llx invalid\n", |
164 | __func__, i, (unsigned long long) | 175 | i, (unsigned long long) |
165 | __le64_to_cpu(nsindex[i]->myoff)); | 176 | __le64_to_cpu(nsindex[i]->myoff)); |
166 | continue; | 177 | continue; |
167 | } | 178 | } |
168 | if (__le64_to_cpu(nsindex[i]->otheroff) | 179 | if (__le64_to_cpu(nsindex[i]->otheroff) |
169 | != (!i) * sizeof_namespace_index(ndd)) { | 180 | != (!i) * sizeof_namespace_index(ndd)) { |
170 | dev_dbg(dev, "%s: nsindex%d otheroff: %#llx invalid\n", | 181 | dev_dbg(dev, "nsindex%d otheroff: %#llx invalid\n", |
171 | __func__, i, (unsigned long long) | 182 | i, (unsigned long long) |
172 | __le64_to_cpu(nsindex[i]->otheroff)); | 183 | __le64_to_cpu(nsindex[i]->otheroff)); |
173 | continue; | 184 | continue; |
174 | } | 185 | } |
@@ -176,8 +187,7 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd) | |||
176 | size = __le64_to_cpu(nsindex[i]->mysize); | 187 | size = __le64_to_cpu(nsindex[i]->mysize); |
177 | if (size > sizeof_namespace_index(ndd) | 188 | if (size > sizeof_namespace_index(ndd) |
178 | || size < sizeof(struct nd_namespace_index)) { | 189 | || size < sizeof(struct nd_namespace_index)) { |
179 | dev_dbg(dev, "%s: nsindex%d mysize: %#llx invalid\n", | 190 | dev_dbg(dev, "nsindex%d mysize: %#llx invalid\n", i, size); |
180 | __func__, i, size); | ||
181 | continue; | 191 | continue; |
182 | } | 192 | } |
183 | 193 | ||
@@ -185,9 +195,8 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd) | |||
185 | if (nslot * sizeof_namespace_label(ndd) | 195 | if (nslot * sizeof_namespace_label(ndd) |
186 | + 2 * sizeof_namespace_index(ndd) | 196 | + 2 * sizeof_namespace_index(ndd) |
187 | > ndd->nsarea.config_size) { | 197 | > ndd->nsarea.config_size) { |
188 | dev_dbg(dev, "%s: nsindex%d nslot: %u invalid, config_size: %#x\n", | 198 | dev_dbg(dev, "nsindex%d nslot: %u invalid, config_size: %#x\n", |
189 | __func__, i, nslot, | 199 | i, nslot, ndd->nsarea.config_size); |
190 | ndd->nsarea.config_size); | ||
191 | continue; | 200 | continue; |
192 | } | 201 | } |
193 | valid[i] = true; | 202 | valid[i] = true; |
@@ -356,8 +365,8 @@ static bool slot_valid(struct nvdimm_drvdata *ndd, | |||
356 | sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); | 365 | sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); |
357 | nd_label->checksum = __cpu_to_le64(sum_save); | 366 | nd_label->checksum = __cpu_to_le64(sum_save); |
358 | if (sum != sum_save) { | 367 | if (sum != sum_save) { |
359 | dev_dbg(ndd->dev, "%s fail checksum. slot: %d expect: %#llx\n", | 368 | dev_dbg(ndd->dev, "fail checksum. slot: %d expect: %#llx\n", |
360 | __func__, slot, sum); | 369 | slot, sum); |
361 | return false; | 370 | return false; |
362 | } | 371 | } |
363 | } | 372 | } |
@@ -422,8 +431,8 @@ int nd_label_active_count(struct nvdimm_drvdata *ndd) | |||
422 | u64 dpa = __le64_to_cpu(nd_label->dpa); | 431 | u64 dpa = __le64_to_cpu(nd_label->dpa); |
423 | 432 | ||
424 | dev_dbg(ndd->dev, | 433 | dev_dbg(ndd->dev, |
425 | "%s: slot%d invalid slot: %d dpa: %llx size: %llx\n", | 434 | "slot%d invalid slot: %d dpa: %llx size: %llx\n", |
426 | __func__, slot, label_slot, dpa, size); | 435 | slot, label_slot, dpa, size); |
427 | continue; | 436 | continue; |
428 | } | 437 | } |
429 | count++; | 438 | count++; |
@@ -650,7 +659,7 @@ static int __pmem_label_update(struct nd_region *nd_region, | |||
650 | slot = nd_label_alloc_slot(ndd); | 659 | slot = nd_label_alloc_slot(ndd); |
651 | if (slot == UINT_MAX) | 660 | if (slot == UINT_MAX) |
652 | return -ENXIO; | 661 | return -ENXIO; |
653 | dev_dbg(ndd->dev, "%s: allocated: %d\n", __func__, slot); | 662 | dev_dbg(ndd->dev, "allocated: %d\n", slot); |
654 | 663 | ||
655 | nd_label = to_label(ndd, slot); | 664 | nd_label = to_label(ndd, slot); |
656 | memset(nd_label, 0, sizeof_namespace_label(ndd)); | 665 | memset(nd_label, 0, sizeof_namespace_label(ndd)); |
@@ -678,7 +687,7 @@ static int __pmem_label_update(struct nd_region *nd_region, | |||
678 | sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); | 687 | sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); |
679 | nd_label->checksum = __cpu_to_le64(sum); | 688 | nd_label->checksum = __cpu_to_le64(sum); |
680 | } | 689 | } |
681 | nd_dbg_dpa(nd_region, ndd, res, "%s\n", __func__); | 690 | nd_dbg_dpa(nd_region, ndd, res, "\n"); |
682 | 691 | ||
683 | /* update label */ | 692 | /* update label */ |
684 | offset = nd_label_offset(ndd, nd_label); | 693 | offset = nd_label_offset(ndd, nd_label); |
@@ -700,7 +709,7 @@ static int __pmem_label_update(struct nd_region *nd_region, | |||
700 | break; | 709 | break; |
701 | } | 710 | } |
702 | if (victim) { | 711 | if (victim) { |
703 | dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot); | 712 | dev_dbg(ndd->dev, "free: %d\n", slot); |
704 | slot = to_slot(ndd, victim->label); | 713 | slot = to_slot(ndd, victim->label); |
705 | nd_label_free_slot(ndd, slot); | 714 | nd_label_free_slot(ndd, slot); |
706 | victim->label = NULL; | 715 | victim->label = NULL; |
@@ -868,7 +877,7 @@ static int __blk_label_update(struct nd_region *nd_region, | |||
868 | slot = nd_label_alloc_slot(ndd); | 877 | slot = nd_label_alloc_slot(ndd); |
869 | if (slot == UINT_MAX) | 878 | if (slot == UINT_MAX) |
870 | goto abort; | 879 | goto abort; |
871 | dev_dbg(ndd->dev, "%s: allocated: %d\n", __func__, slot); | 880 | dev_dbg(ndd->dev, "allocated: %d\n", slot); |
872 | 881 | ||
873 | nd_label = to_label(ndd, slot); | 882 | nd_label = to_label(ndd, slot); |
874 | memset(nd_label, 0, sizeof_namespace_label(ndd)); | 883 | memset(nd_label, 0, sizeof_namespace_label(ndd)); |
@@ -928,7 +937,7 @@ static int __blk_label_update(struct nd_region *nd_region, | |||
928 | 937 | ||
929 | /* free up now unused slots in the new index */ | 938 | /* free up now unused slots in the new index */ |
930 | for_each_set_bit(slot, victim_map, victim_map ? nslot : 0) { | 939 | for_each_set_bit(slot, victim_map, victim_map ? nslot : 0) { |
931 | dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot); | 940 | dev_dbg(ndd->dev, "free: %d\n", slot); |
932 | nd_label_free_slot(ndd, slot); | 941 | nd_label_free_slot(ndd, slot); |
933 | } | 942 | } |
934 | 943 | ||
@@ -1092,7 +1101,7 @@ static int del_labels(struct nd_mapping *nd_mapping, u8 *uuid) | |||
1092 | active--; | 1101 | active--; |
1093 | slot = to_slot(ndd, nd_label); | 1102 | slot = to_slot(ndd, nd_label); |
1094 | nd_label_free_slot(ndd, slot); | 1103 | nd_label_free_slot(ndd, slot); |
1095 | dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot); | 1104 | dev_dbg(ndd->dev, "free: %d\n", slot); |
1096 | list_move_tail(&label_ent->list, &list); | 1105 | list_move_tail(&label_ent->list, &list); |
1097 | label_ent->label = NULL; | 1106 | label_ent->label = NULL; |
1098 | } | 1107 | } |
@@ -1100,7 +1109,7 @@ static int del_labels(struct nd_mapping *nd_mapping, u8 *uuid) | |||
1100 | 1109 | ||
1101 | if (active == 0) { | 1110 | if (active == 0) { |
1102 | nd_mapping_free_labels(nd_mapping); | 1111 | nd_mapping_free_labels(nd_mapping); |
1103 | dev_dbg(ndd->dev, "%s: no more active labels\n", __func__); | 1112 | dev_dbg(ndd->dev, "no more active labels\n"); |
1104 | } | 1113 | } |
1105 | mutex_unlock(&nd_mapping->lock); | 1114 | mutex_unlock(&nd_mapping->lock); |
1106 | 1115 | ||
diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h index 1ebf4d3d01ba..18bbe183b3a9 100644 --- a/drivers/nvdimm/label.h +++ b/drivers/nvdimm/label.h | |||
@@ -33,7 +33,7 @@ enum { | |||
33 | BTTINFO_UUID_LEN = 16, | 33 | BTTINFO_UUID_LEN = 16, |
34 | BTTINFO_FLAG_ERROR = 0x1, /* error state (read-only) */ | 34 | BTTINFO_FLAG_ERROR = 0x1, /* error state (read-only) */ |
35 | BTTINFO_MAJOR_VERSION = 1, | 35 | BTTINFO_MAJOR_VERSION = 1, |
36 | ND_LABEL_MIN_SIZE = 512 * 129, /* see sizeof_namespace_index() */ | 36 | ND_LABEL_MIN_SIZE = 256 * 4, /* see sizeof_namespace_index() */ |
37 | ND_LABEL_ID_SIZE = 50, | 37 | ND_LABEL_ID_SIZE = 50, |
38 | ND_NSINDEX_INIT = 0x1, | 38 | ND_NSINDEX_INIT = 0x1, |
39 | }; | 39 | }; |
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 658ada497be0..28afdd668905 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c | |||
@@ -421,7 +421,7 @@ static ssize_t alt_name_store(struct device *dev, | |||
421 | rc = __alt_name_store(dev, buf, len); | 421 | rc = __alt_name_store(dev, buf, len); |
422 | if (rc >= 0) | 422 | if (rc >= 0) |
423 | rc = nd_namespace_label_update(nd_region, dev); | 423 | rc = nd_namespace_label_update(nd_region, dev); |
424 | dev_dbg(dev, "%s: %s(%zd)\n", __func__, rc < 0 ? "fail " : "", rc); | 424 | dev_dbg(dev, "%s(%zd)\n", rc < 0 ? "fail " : "", rc); |
425 | nvdimm_bus_unlock(dev); | 425 | nvdimm_bus_unlock(dev); |
426 | device_unlock(dev); | 426 | device_unlock(dev); |
427 | 427 | ||
@@ -1007,7 +1007,7 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) | |||
1007 | if (uuid_not_set(uuid, dev, __func__)) | 1007 | if (uuid_not_set(uuid, dev, __func__)) |
1008 | return -ENXIO; | 1008 | return -ENXIO; |
1009 | if (nd_region->ndr_mappings == 0) { | 1009 | if (nd_region->ndr_mappings == 0) { |
1010 | dev_dbg(dev, "%s: not associated with dimm(s)\n", __func__); | 1010 | dev_dbg(dev, "not associated with dimm(s)\n"); |
1011 | return -ENXIO; | 1011 | return -ENXIO; |
1012 | } | 1012 | } |
1013 | 1013 | ||
@@ -1105,8 +1105,7 @@ static ssize_t size_store(struct device *dev, | |||
1105 | *uuid = NULL; | 1105 | *uuid = NULL; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | dev_dbg(dev, "%s: %llx %s (%d)\n", __func__, val, rc < 0 | 1108 | dev_dbg(dev, "%llx %s (%d)\n", val, rc < 0 ? "fail" : "success", rc); |
1109 | ? "fail" : "success", rc); | ||
1110 | 1109 | ||
1111 | nvdimm_bus_unlock(dev); | 1110 | nvdimm_bus_unlock(dev); |
1112 | device_unlock(dev); | 1111 | device_unlock(dev); |
@@ -1270,8 +1269,8 @@ static ssize_t uuid_store(struct device *dev, | |||
1270 | rc = nd_namespace_label_update(nd_region, dev); | 1269 | rc = nd_namespace_label_update(nd_region, dev); |
1271 | else | 1270 | else |
1272 | kfree(uuid); | 1271 | kfree(uuid); |
1273 | dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, | 1272 | dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, |
1274 | rc, buf, buf[len - 1] == '\n' ? "" : "\n"); | 1273 | buf[len - 1] == '\n' ? "" : "\n"); |
1275 | nvdimm_bus_unlock(dev); | 1274 | nvdimm_bus_unlock(dev); |
1276 | device_unlock(dev); | 1275 | device_unlock(dev); |
1277 | 1276 | ||
@@ -1355,9 +1354,8 @@ static ssize_t sector_size_store(struct device *dev, | |||
1355 | rc = nd_size_select_store(dev, buf, lbasize, supported); | 1354 | rc = nd_size_select_store(dev, buf, lbasize, supported); |
1356 | if (rc >= 0) | 1355 | if (rc >= 0) |
1357 | rc = nd_namespace_label_update(nd_region, dev); | 1356 | rc = nd_namespace_label_update(nd_region, dev); |
1358 | dev_dbg(dev, "%s: result: %zd %s: %s%s", __func__, | 1357 | dev_dbg(dev, "result: %zd %s: %s%s", rc, rc < 0 ? "tried" : "wrote", |
1359 | rc, rc < 0 ? "tried" : "wrote", buf, | 1358 | buf, buf[len - 1] == '\n' ? "" : "\n"); |
1360 | buf[len - 1] == '\n' ? "" : "\n"); | ||
1361 | nvdimm_bus_unlock(dev); | 1359 | nvdimm_bus_unlock(dev); |
1362 | device_unlock(dev); | 1360 | device_unlock(dev); |
1363 | 1361 | ||
@@ -1519,7 +1517,7 @@ static ssize_t holder_class_store(struct device *dev, | |||
1519 | rc = __holder_class_store(dev, buf); | 1517 | rc = __holder_class_store(dev, buf); |
1520 | if (rc >= 0) | 1518 | if (rc >= 0) |
1521 | rc = nd_namespace_label_update(nd_region, dev); | 1519 | rc = nd_namespace_label_update(nd_region, dev); |
1522 | dev_dbg(dev, "%s: %s(%zd)\n", __func__, rc < 0 ? "fail " : "", rc); | 1520 | dev_dbg(dev, "%s(%zd)\n", rc < 0 ? "fail " : "", rc); |
1523 | nvdimm_bus_unlock(dev); | 1521 | nvdimm_bus_unlock(dev); |
1524 | device_unlock(dev); | 1522 | device_unlock(dev); |
1525 | 1523 | ||
@@ -1717,8 +1715,7 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev) | |||
1717 | if (uuid_not_set(nsblk->uuid, &ndns->dev, __func__)) | 1715 | if (uuid_not_set(nsblk->uuid, &ndns->dev, __func__)) |
1718 | return ERR_PTR(-ENODEV); | 1716 | return ERR_PTR(-ENODEV); |
1719 | if (!nsblk->lbasize) { | 1717 | if (!nsblk->lbasize) { |
1720 | dev_dbg(&ndns->dev, "%s: sector size not set\n", | 1718 | dev_dbg(&ndns->dev, "sector size not set\n"); |
1721 | __func__); | ||
1722 | return ERR_PTR(-ENODEV); | 1719 | return ERR_PTR(-ENODEV); |
1723 | } | 1720 | } |
1724 | if (!nd_namespace_blk_validate(nsblk)) | 1721 | if (!nd_namespace_blk_validate(nsblk)) |
@@ -1798,9 +1795,7 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, | |||
1798 | } | 1795 | } |
1799 | 1796 | ||
1800 | if (found_uuid) { | 1797 | if (found_uuid) { |
1801 | dev_dbg(ndd->dev, | 1798 | dev_dbg(ndd->dev, "duplicate entry for uuid\n"); |
1802 | "%s duplicate entry for uuid\n", | ||
1803 | __func__); | ||
1804 | return false; | 1799 | return false; |
1805 | } | 1800 | } |
1806 | found_uuid = true; | 1801 | found_uuid = true; |
@@ -1926,7 +1921,7 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, | |||
1926 | } | 1921 | } |
1927 | 1922 | ||
1928 | if (i < nd_region->ndr_mappings) { | 1923 | if (i < nd_region->ndr_mappings) { |
1929 | struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]); | 1924 | struct nvdimm *nvdimm = nd_region->mapping[i].nvdimm; |
1930 | 1925 | ||
1931 | /* | 1926 | /* |
1932 | * Give up if we don't find an instance of a uuid at each | 1927 | * Give up if we don't find an instance of a uuid at each |
@@ -1934,7 +1929,7 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, | |||
1934 | * find a dimm with two instances of the same uuid. | 1929 | * find a dimm with two instances of the same uuid. |
1935 | */ | 1930 | */ |
1936 | dev_err(&nd_region->dev, "%s missing label for %pUb\n", | 1931 | dev_err(&nd_region->dev, "%s missing label for %pUb\n", |
1937 | dev_name(ndd->dev), nd_label->uuid); | 1932 | nvdimm_name(nvdimm), nd_label->uuid); |
1938 | rc = -EINVAL; | 1933 | rc = -EINVAL; |
1939 | goto err; | 1934 | goto err; |
1940 | } | 1935 | } |
@@ -1994,14 +1989,13 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, | |||
1994 | namespace_pmem_release(dev); | 1989 | namespace_pmem_release(dev); |
1995 | switch (rc) { | 1990 | switch (rc) { |
1996 | case -EINVAL: | 1991 | case -EINVAL: |
1997 | dev_dbg(&nd_region->dev, "%s: invalid label(s)\n", __func__); | 1992 | dev_dbg(&nd_region->dev, "invalid label(s)\n"); |
1998 | break; | 1993 | break; |
1999 | case -ENODEV: | 1994 | case -ENODEV: |
2000 | dev_dbg(&nd_region->dev, "%s: label not found\n", __func__); | 1995 | dev_dbg(&nd_region->dev, "label not found\n"); |
2001 | break; | 1996 | break; |
2002 | default: | 1997 | default: |
2003 | dev_dbg(&nd_region->dev, "%s: unexpected err: %d\n", | 1998 | dev_dbg(&nd_region->dev, "unexpected err: %d\n", rc); |
2004 | __func__, rc); | ||
2005 | break; | 1999 | break; |
2006 | } | 2000 | } |
2007 | return ERR_PTR(rc); | 2001 | return ERR_PTR(rc); |
@@ -2334,8 +2328,8 @@ static struct device **scan_labels(struct nd_region *nd_region) | |||
2334 | 2328 | ||
2335 | } | 2329 | } |
2336 | 2330 | ||
2337 | dev_dbg(&nd_region->dev, "%s: discovered %d %s namespace%s\n", | 2331 | dev_dbg(&nd_region->dev, "discovered %d %s namespace%s\n", |
2338 | __func__, count, is_nd_blk(&nd_region->dev) | 2332 | count, is_nd_blk(&nd_region->dev) |
2339 | ? "blk" : "pmem", count == 1 ? "" : "s"); | 2333 | ? "blk" : "pmem", count == 1 ? "" : "s"); |
2340 | 2334 | ||
2341 | if (count == 0) { | 2335 | if (count == 0) { |
@@ -2467,7 +2461,7 @@ static int init_active_labels(struct nd_region *nd_region) | |||
2467 | get_ndd(ndd); | 2461 | get_ndd(ndd); |
2468 | 2462 | ||
2469 | count = nd_label_active_count(ndd); | 2463 | count = nd_label_active_count(ndd); |
2470 | dev_dbg(ndd->dev, "%s: %d\n", __func__, count); | 2464 | dev_dbg(ndd->dev, "count: %d\n", count); |
2471 | if (!count) | 2465 | if (!count) |
2472 | continue; | 2466 | continue; |
2473 | for (j = 0; j < count; j++) { | 2467 | for (j = 0; j < count; j++) { |
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 184e070d50a2..32e0364b48b9 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h | |||
@@ -340,7 +340,6 @@ static inline struct device *nd_dax_create(struct nd_region *nd_region) | |||
340 | } | 340 | } |
341 | #endif | 341 | #endif |
342 | 342 | ||
343 | struct nd_region *to_nd_region(struct device *dev); | ||
344 | int nd_region_to_nstype(struct nd_region *nd_region); | 343 | int nd_region_to_nstype(struct nd_region *nd_region); |
345 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err); | 344 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err); |
346 | u64 nd_region_interleave_set_cookie(struct nd_region *nd_region, | 345 | u64 nd_region_interleave_set_cookie(struct nd_region *nd_region, |
diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c new file mode 100644 index 000000000000..85013bad35de --- /dev/null +++ b/drivers/nvdimm/of_pmem.c | |||
@@ -0,0 +1,119 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | |||
3 | #define pr_fmt(fmt) "of_pmem: " fmt | ||
4 | |||
5 | #include <linux/of_platform.h> | ||
6 | #include <linux/of_address.h> | ||
7 | #include <linux/libnvdimm.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/ioport.h> | ||
10 | #include <linux/slab.h> | ||
11 | |||
12 | static const struct attribute_group *region_attr_groups[] = { | ||
13 | &nd_region_attribute_group, | ||
14 | &nd_device_attribute_group, | ||
15 | NULL, | ||
16 | }; | ||
17 | |||
18 | static const struct attribute_group *bus_attr_groups[] = { | ||
19 | &nvdimm_bus_attribute_group, | ||
20 | NULL, | ||
21 | }; | ||
22 | |||
23 | struct of_pmem_private { | ||
24 | struct nvdimm_bus_descriptor bus_desc; | ||
25 | struct nvdimm_bus *bus; | ||
26 | }; | ||
27 | |||
28 | static int of_pmem_region_probe(struct platform_device *pdev) | ||
29 | { | ||
30 | struct of_pmem_private *priv; | ||
31 | struct device_node *np; | ||
32 | struct nvdimm_bus *bus; | ||
33 | bool is_volatile; | ||
34 | int i; | ||
35 | |||
36 | np = dev_of_node(&pdev->dev); | ||
37 | if (!np) | ||
38 | return -ENXIO; | ||
39 | |||
40 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
41 | if (!priv) | ||
42 | return -ENOMEM; | ||
43 | |||
44 | priv->bus_desc.attr_groups = bus_attr_groups; | ||
45 | priv->bus_desc.provider_name = "of_pmem"; | ||
46 | priv->bus_desc.module = THIS_MODULE; | ||
47 | priv->bus_desc.of_node = np; | ||
48 | |||
49 | priv->bus = bus = nvdimm_bus_register(&pdev->dev, &priv->bus_desc); | ||
50 | if (!bus) { | ||
51 | kfree(priv); | ||
52 | return -ENODEV; | ||
53 | } | ||
54 | platform_set_drvdata(pdev, priv); | ||
55 | |||
56 | is_volatile = !!of_find_property(np, "volatile", NULL); | ||
57 | dev_dbg(&pdev->dev, "Registering %s regions from %pOF\n", | ||
58 | is_volatile ? "volatile" : "non-volatile", np); | ||
59 | |||
60 | for (i = 0; i < pdev->num_resources; i++) { | ||
61 | struct nd_region_desc ndr_desc; | ||
62 | struct nd_region *region; | ||
63 | |||
64 | /* | ||
65 | * NB: libnvdimm copies the data from ndr_desc into it's own | ||
66 | * structures so passing a stack pointer is fine. | ||
67 | */ | ||
68 | memset(&ndr_desc, 0, sizeof(ndr_desc)); | ||
69 | ndr_desc.attr_groups = region_attr_groups; | ||
70 | ndr_desc.numa_node = of_node_to_nid(np); | ||
71 | ndr_desc.res = &pdev->resource[i]; | ||
72 | ndr_desc.of_node = np; | ||
73 | set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); | ||
74 | |||
75 | if (is_volatile) | ||
76 | region = nvdimm_volatile_region_create(bus, &ndr_desc); | ||
77 | else | ||
78 | region = nvdimm_pmem_region_create(bus, &ndr_desc); | ||
79 | |||
80 | if (!region) | ||
81 | dev_warn(&pdev->dev, "Unable to register region %pR from %pOF\n", | ||
82 | ndr_desc.res, np); | ||
83 | else | ||
84 | dev_dbg(&pdev->dev, "Registered region %pR from %pOF\n", | ||
85 | ndr_desc.res, np); | ||
86 | } | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int of_pmem_region_remove(struct platform_device *pdev) | ||
92 | { | ||
93 | struct of_pmem_private *priv = platform_get_drvdata(pdev); | ||
94 | |||
95 | nvdimm_bus_unregister(priv->bus); | ||
96 | kfree(priv); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static const struct of_device_id of_pmem_region_match[] = { | ||
102 | { .compatible = "pmem-region" }, | ||
103 | { }, | ||
104 | }; | ||
105 | |||
106 | static struct platform_driver of_pmem_region_driver = { | ||
107 | .probe = of_pmem_region_probe, | ||
108 | .remove = of_pmem_region_remove, | ||
109 | .driver = { | ||
110 | .name = "of_pmem", | ||
111 | .owner = THIS_MODULE, | ||
112 | .of_match_table = of_pmem_region_match, | ||
113 | }, | ||
114 | }; | ||
115 | |||
116 | module_platform_driver(of_pmem_region_driver); | ||
117 | MODULE_DEVICE_TABLE(of, of_pmem_region_match); | ||
118 | MODULE_LICENSE("GPL"); | ||
119 | MODULE_AUTHOR("IBM Corporation"); | ||
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 2f4d18752c97..30b08791597d 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c | |||
@@ -27,7 +27,7 @@ static void nd_pfn_release(struct device *dev) | |||
27 | struct nd_region *nd_region = to_nd_region(dev->parent); | 27 | struct nd_region *nd_region = to_nd_region(dev->parent); |
28 | struct nd_pfn *nd_pfn = to_nd_pfn(dev); | 28 | struct nd_pfn *nd_pfn = to_nd_pfn(dev); |
29 | 29 | ||
30 | dev_dbg(dev, "%s\n", __func__); | 30 | dev_dbg(dev, "trace\n"); |
31 | nd_detach_ndns(&nd_pfn->dev, &nd_pfn->ndns); | 31 | nd_detach_ndns(&nd_pfn->dev, &nd_pfn->ndns); |
32 | ida_simple_remove(&nd_region->pfn_ida, nd_pfn->id); | 32 | ida_simple_remove(&nd_region->pfn_ida, nd_pfn->id); |
33 | kfree(nd_pfn->uuid); | 33 | kfree(nd_pfn->uuid); |
@@ -94,8 +94,8 @@ static ssize_t mode_store(struct device *dev, | |||
94 | else | 94 | else |
95 | rc = -EINVAL; | 95 | rc = -EINVAL; |
96 | } | 96 | } |
97 | dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, | 97 | dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, |
98 | rc, buf, buf[len - 1] == '\n' ? "" : "\n"); | 98 | buf[len - 1] == '\n' ? "" : "\n"); |
99 | nvdimm_bus_unlock(dev); | 99 | nvdimm_bus_unlock(dev); |
100 | device_unlock(dev); | 100 | device_unlock(dev); |
101 | 101 | ||
@@ -144,8 +144,8 @@ static ssize_t align_store(struct device *dev, | |||
144 | nvdimm_bus_lock(dev); | 144 | nvdimm_bus_lock(dev); |
145 | rc = nd_size_select_store(dev, buf, &nd_pfn->align, | 145 | rc = nd_size_select_store(dev, buf, &nd_pfn->align, |
146 | nd_pfn_supported_alignments()); | 146 | nd_pfn_supported_alignments()); |
147 | dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, | 147 | dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, |
148 | rc, buf, buf[len - 1] == '\n' ? "" : "\n"); | 148 | buf[len - 1] == '\n' ? "" : "\n"); |
149 | nvdimm_bus_unlock(dev); | 149 | nvdimm_bus_unlock(dev); |
150 | device_unlock(dev); | 150 | device_unlock(dev); |
151 | 151 | ||
@@ -171,8 +171,8 @@ static ssize_t uuid_store(struct device *dev, | |||
171 | 171 | ||
172 | device_lock(dev); | 172 | device_lock(dev); |
173 | rc = nd_uuid_store(dev, &nd_pfn->uuid, buf, len); | 173 | rc = nd_uuid_store(dev, &nd_pfn->uuid, buf, len); |
174 | dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, | 174 | dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, |
175 | rc, buf, buf[len - 1] == '\n' ? "" : "\n"); | 175 | buf[len - 1] == '\n' ? "" : "\n"); |
176 | device_unlock(dev); | 176 | device_unlock(dev); |
177 | 177 | ||
178 | return rc ? rc : len; | 178 | return rc ? rc : len; |
@@ -201,8 +201,8 @@ static ssize_t namespace_store(struct device *dev, | |||
201 | device_lock(dev); | 201 | device_lock(dev); |
202 | nvdimm_bus_lock(dev); | 202 | nvdimm_bus_lock(dev); |
203 | rc = nd_namespace_store(dev, &nd_pfn->ndns, buf, len); | 203 | rc = nd_namespace_store(dev, &nd_pfn->ndns, buf, len); |
204 | dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, | 204 | dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, |
205 | rc, buf, buf[len - 1] == '\n' ? "" : "\n"); | 205 | buf[len - 1] == '\n' ? "" : "\n"); |
206 | nvdimm_bus_unlock(dev); | 206 | nvdimm_bus_unlock(dev); |
207 | device_unlock(dev); | 207 | device_unlock(dev); |
208 | 208 | ||
@@ -314,8 +314,8 @@ struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn, | |||
314 | dev = &nd_pfn->dev; | 314 | dev = &nd_pfn->dev; |
315 | device_initialize(&nd_pfn->dev); | 315 | device_initialize(&nd_pfn->dev); |
316 | if (ndns && !__nd_attach_ndns(&nd_pfn->dev, ndns, &nd_pfn->ndns)) { | 316 | if (ndns && !__nd_attach_ndns(&nd_pfn->dev, ndns, &nd_pfn->ndns)) { |
317 | dev_dbg(&ndns->dev, "%s failed, already claimed by %s\n", | 317 | dev_dbg(&ndns->dev, "failed, already claimed by %s\n", |
318 | __func__, dev_name(ndns->claim)); | 318 | dev_name(ndns->claim)); |
319 | put_device(dev); | 319 | put_device(dev); |
320 | return NULL; | 320 | return NULL; |
321 | } | 321 | } |
@@ -510,8 +510,7 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns) | |||
510 | nd_pfn = to_nd_pfn(pfn_dev); | 510 | nd_pfn = to_nd_pfn(pfn_dev); |
511 | nd_pfn->pfn_sb = pfn_sb; | 511 | nd_pfn->pfn_sb = pfn_sb; |
512 | rc = nd_pfn_validate(nd_pfn, PFN_SIG); | 512 | rc = nd_pfn_validate(nd_pfn, PFN_SIG); |
513 | dev_dbg(dev, "%s: pfn: %s\n", __func__, | 513 | dev_dbg(dev, "pfn: %s\n", rc == 0 ? dev_name(pfn_dev) : "<none>"); |
514 | rc == 0 ? dev_name(pfn_dev) : "<none>"); | ||
515 | if (rc < 0) { | 514 | if (rc < 0) { |
516 | nd_detach_ndns(pfn_dev, &nd_pfn->ndns); | 515 | nd_detach_ndns(pfn_dev, &nd_pfn->ndns); |
517 | put_device(pfn_dev); | 516 | put_device(pfn_dev); |
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 5a96d30c294a..9d714926ecf5 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c | |||
@@ -66,7 +66,7 @@ static blk_status_t pmem_clear_poison(struct pmem_device *pmem, | |||
66 | rc = BLK_STS_IOERR; | 66 | rc = BLK_STS_IOERR; |
67 | if (cleared > 0 && cleared / 512) { | 67 | if (cleared > 0 && cleared / 512) { |
68 | cleared /= 512; | 68 | cleared /= 512; |
69 | dev_dbg(dev, "%s: %#llx clear %ld sector%s\n", __func__, | 69 | dev_dbg(dev, "%#llx clear %ld sector%s\n", |
70 | (unsigned long long) sector, cleared, | 70 | (unsigned long long) sector, cleared, |
71 | cleared > 1 ? "s" : ""); | 71 | cleared > 1 ? "s" : ""); |
72 | badblocks_clear(&pmem->bb, sector, cleared); | 72 | badblocks_clear(&pmem->bb, sector, cleared); |
@@ -547,17 +547,7 @@ static struct nd_device_driver nd_pmem_driver = { | |||
547 | .type = ND_DRIVER_NAMESPACE_IO | ND_DRIVER_NAMESPACE_PMEM, | 547 | .type = ND_DRIVER_NAMESPACE_IO | ND_DRIVER_NAMESPACE_PMEM, |
548 | }; | 548 | }; |
549 | 549 | ||
550 | static int __init pmem_init(void) | 550 | module_nd_driver(nd_pmem_driver); |
551 | { | ||
552 | return nd_driver_register(&nd_pmem_driver); | ||
553 | } | ||
554 | module_init(pmem_init); | ||
555 | |||
556 | static void pmem_exit(void) | ||
557 | { | ||
558 | driver_unregister(&nd_pmem_driver.drv); | ||
559 | } | ||
560 | module_exit(pmem_exit); | ||
561 | 551 | ||
562 | MODULE_AUTHOR("Ross Zwisler <ross.zwisler@linux.intel.com>"); | 552 | MODULE_AUTHOR("Ross Zwisler <ross.zwisler@linux.intel.com>"); |
563 | MODULE_LICENSE("GPL v2"); | 553 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c index 034f0a07d627..b9ca0033cc99 100644 --- a/drivers/nvdimm/region.c +++ b/drivers/nvdimm/region.c | |||
@@ -27,10 +27,10 @@ static int nd_region_probe(struct device *dev) | |||
27 | if (nd_region->num_lanes > num_online_cpus() | 27 | if (nd_region->num_lanes > num_online_cpus() |
28 | && nd_region->num_lanes < num_possible_cpus() | 28 | && nd_region->num_lanes < num_possible_cpus() |
29 | && !test_and_set_bit(0, &once)) { | 29 | && !test_and_set_bit(0, &once)) { |
30 | dev_info(dev, "online cpus (%d) < concurrent i/o lanes (%d) < possible cpus (%d)\n", | 30 | dev_dbg(dev, "online cpus (%d) < concurrent i/o lanes (%d) < possible cpus (%d)\n", |
31 | num_online_cpus(), nd_region->num_lanes, | 31 | num_online_cpus(), nd_region->num_lanes, |
32 | num_possible_cpus()); | 32 | num_possible_cpus()); |
33 | dev_info(dev, "setting nr_cpus=%d may yield better libnvdimm device performance\n", | 33 | dev_dbg(dev, "setting nr_cpus=%d may yield better libnvdimm device performance\n", |
34 | nd_region->num_lanes); | 34 | nd_region->num_lanes); |
35 | } | 35 | } |
36 | 36 | ||
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 1593e1806b16..a612be6f019d 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c | |||
@@ -182,6 +182,14 @@ struct nd_region *to_nd_region(struct device *dev) | |||
182 | } | 182 | } |
183 | EXPORT_SYMBOL_GPL(to_nd_region); | 183 | EXPORT_SYMBOL_GPL(to_nd_region); |
184 | 184 | ||
185 | struct device *nd_region_dev(struct nd_region *nd_region) | ||
186 | { | ||
187 | if (!nd_region) | ||
188 | return NULL; | ||
189 | return &nd_region->dev; | ||
190 | } | ||
191 | EXPORT_SYMBOL_GPL(nd_region_dev); | ||
192 | |||
185 | struct nd_blk_region *to_nd_blk_region(struct device *dev) | 193 | struct nd_blk_region *to_nd_blk_region(struct device *dev) |
186 | { | 194 | { |
187 | struct nd_region *nd_region = to_nd_region(dev); | 195 | struct nd_region *nd_region = to_nd_region(dev); |
@@ -1014,6 +1022,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, | |||
1014 | dev->parent = &nvdimm_bus->dev; | 1022 | dev->parent = &nvdimm_bus->dev; |
1015 | dev->type = dev_type; | 1023 | dev->type = dev_type; |
1016 | dev->groups = ndr_desc->attr_groups; | 1024 | dev->groups = ndr_desc->attr_groups; |
1025 | dev->of_node = ndr_desc->of_node; | ||
1017 | nd_region->ndr_size = resource_size(ndr_desc->res); | 1026 | nd_region->ndr_size = resource_size(ndr_desc->res); |
1018 | nd_region->ndr_start = ndr_desc->res->start; | 1027 | nd_region->ndr_start = ndr_desc->res->start; |
1019 | nd_device_register(dev); | 1028 | nd_device_register(dev); |
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 1444333210c7..9ac7574e3cfb 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig | |||
@@ -15,8 +15,8 @@ config BLK_DEV_XPRAM | |||
15 | 15 | ||
16 | config DCSSBLK | 16 | config DCSSBLK |
17 | def_tristate m | 17 | def_tristate m |
18 | select DAX | ||
19 | select FS_DAX_LIMITED | 18 | select FS_DAX_LIMITED |
19 | select DAX_DRIVER | ||
20 | prompt "DCSSBLK support" | 20 | prompt "DCSSBLK support" |
21 | depends on S390 && BLOCK | 21 | depends on S390 && BLOCK |
22 | help | 22 | help |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 7a506c55a993..7ec920e27065 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -1948,11 +1948,6 @@ static int blkdev_releasepage(struct page *page, gfp_t wait) | |||
1948 | static int blkdev_writepages(struct address_space *mapping, | 1948 | static int blkdev_writepages(struct address_space *mapping, |
1949 | struct writeback_control *wbc) | 1949 | struct writeback_control *wbc) |
1950 | { | 1950 | { |
1951 | if (dax_mapping(mapping)) { | ||
1952 | struct block_device *bdev = I_BDEV(mapping->host); | ||
1953 | |||
1954 | return dax_writeback_mapping_range(mapping, bdev, wbc); | ||
1955 | } | ||
1956 | return generic_writepages(mapping, wbc); | 1951 | return generic_writepages(mapping, wbc); |
1957 | } | 1952 | } |
1958 | 1953 | ||
@@ -73,16 +73,15 @@ fs_initcall(init_dax_wait_table); | |||
73 | #define RADIX_DAX_ZERO_PAGE (1 << (RADIX_TREE_EXCEPTIONAL_SHIFT + 2)) | 73 | #define RADIX_DAX_ZERO_PAGE (1 << (RADIX_TREE_EXCEPTIONAL_SHIFT + 2)) |
74 | #define RADIX_DAX_EMPTY (1 << (RADIX_TREE_EXCEPTIONAL_SHIFT + 3)) | 74 | #define RADIX_DAX_EMPTY (1 << (RADIX_TREE_EXCEPTIONAL_SHIFT + 3)) |
75 | 75 | ||
76 | static unsigned long dax_radix_sector(void *entry) | 76 | static unsigned long dax_radix_pfn(void *entry) |
77 | { | 77 | { |
78 | return (unsigned long)entry >> RADIX_DAX_SHIFT; | 78 | return (unsigned long)entry >> RADIX_DAX_SHIFT; |
79 | } | 79 | } |
80 | 80 | ||
81 | static void *dax_radix_locked_entry(sector_t sector, unsigned long flags) | 81 | static void *dax_radix_locked_entry(unsigned long pfn, unsigned long flags) |
82 | { | 82 | { |
83 | return (void *)(RADIX_TREE_EXCEPTIONAL_ENTRY | flags | | 83 | return (void *)(RADIX_TREE_EXCEPTIONAL_ENTRY | flags | |
84 | ((unsigned long)sector << RADIX_DAX_SHIFT) | | 84 | (pfn << RADIX_DAX_SHIFT) | RADIX_DAX_ENTRY_LOCK); |
85 | RADIX_DAX_ENTRY_LOCK); | ||
86 | } | 85 | } |
87 | 86 | ||
88 | static unsigned int dax_radix_order(void *entry) | 87 | static unsigned int dax_radix_order(void *entry) |
@@ -299,6 +298,63 @@ static void put_unlocked_mapping_entry(struct address_space *mapping, | |||
299 | dax_wake_mapping_entry_waiter(mapping, index, entry, false); | 298 | dax_wake_mapping_entry_waiter(mapping, index, entry, false); |
300 | } | 299 | } |
301 | 300 | ||
301 | static unsigned long dax_entry_size(void *entry) | ||
302 | { | ||
303 | if (dax_is_zero_entry(entry)) | ||
304 | return 0; | ||
305 | else if (dax_is_empty_entry(entry)) | ||
306 | return 0; | ||
307 | else if (dax_is_pmd_entry(entry)) | ||
308 | return PMD_SIZE; | ||
309 | else | ||
310 | return PAGE_SIZE; | ||
311 | } | ||
312 | |||
313 | static unsigned long dax_radix_end_pfn(void *entry) | ||
314 | { | ||
315 | return dax_radix_pfn(entry) + dax_entry_size(entry) / PAGE_SIZE; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Iterate through all mapped pfns represented by an entry, i.e. skip | ||
320 | * 'empty' and 'zero' entries. | ||
321 | */ | ||
322 | #define for_each_mapped_pfn(entry, pfn) \ | ||
323 | for (pfn = dax_radix_pfn(entry); \ | ||
324 | pfn < dax_radix_end_pfn(entry); pfn++) | ||
325 | |||
326 | static void dax_associate_entry(void *entry, struct address_space *mapping) | ||
327 | { | ||
328 | unsigned long pfn; | ||
329 | |||
330 | if (IS_ENABLED(CONFIG_FS_DAX_LIMITED)) | ||
331 | return; | ||
332 | |||
333 | for_each_mapped_pfn(entry, pfn) { | ||
334 | struct page *page = pfn_to_page(pfn); | ||
335 | |||
336 | WARN_ON_ONCE(page->mapping); | ||
337 | page->mapping = mapping; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | static void dax_disassociate_entry(void *entry, struct address_space *mapping, | ||
342 | bool trunc) | ||
343 | { | ||
344 | unsigned long pfn; | ||
345 | |||
346 | if (IS_ENABLED(CONFIG_FS_DAX_LIMITED)) | ||
347 | return; | ||
348 | |||
349 | for_each_mapped_pfn(entry, pfn) { | ||
350 | struct page *page = pfn_to_page(pfn); | ||
351 | |||
352 | WARN_ON_ONCE(trunc && page_ref_count(page) > 1); | ||
353 | WARN_ON_ONCE(page->mapping && page->mapping != mapping); | ||
354 | page->mapping = NULL; | ||
355 | } | ||
356 | } | ||
357 | |||
302 | /* | 358 | /* |
303 | * Find radix tree entry at given index. If it points to an exceptional entry, | 359 | * Find radix tree entry at given index. If it points to an exceptional entry, |
304 | * return it with the radix tree entry locked. If the radix tree doesn't | 360 | * return it with the radix tree entry locked. If the radix tree doesn't |
@@ -405,6 +461,7 @@ restart: | |||
405 | } | 461 | } |
406 | 462 | ||
407 | if (pmd_downgrade) { | 463 | if (pmd_downgrade) { |
464 | dax_disassociate_entry(entry, mapping, false); | ||
408 | radix_tree_delete(&mapping->page_tree, index); | 465 | radix_tree_delete(&mapping->page_tree, index); |
409 | mapping->nrexceptional--; | 466 | mapping->nrexceptional--; |
410 | dax_wake_mapping_entry_waiter(mapping, index, entry, | 467 | dax_wake_mapping_entry_waiter(mapping, index, entry, |
@@ -454,6 +511,7 @@ static int __dax_invalidate_mapping_entry(struct address_space *mapping, | |||
454 | (radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) || | 511 | (radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) || |
455 | radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE))) | 512 | radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE))) |
456 | goto out; | 513 | goto out; |
514 | dax_disassociate_entry(entry, mapping, trunc); | ||
457 | radix_tree_delete(page_tree, index); | 515 | radix_tree_delete(page_tree, index); |
458 | mapping->nrexceptional--; | 516 | mapping->nrexceptional--; |
459 | ret = 1; | 517 | ret = 1; |
@@ -526,12 +584,13 @@ static int copy_user_dax(struct block_device *bdev, struct dax_device *dax_dev, | |||
526 | */ | 584 | */ |
527 | static void *dax_insert_mapping_entry(struct address_space *mapping, | 585 | static void *dax_insert_mapping_entry(struct address_space *mapping, |
528 | struct vm_fault *vmf, | 586 | struct vm_fault *vmf, |
529 | void *entry, sector_t sector, | 587 | void *entry, pfn_t pfn_t, |
530 | unsigned long flags, bool dirty) | 588 | unsigned long flags, bool dirty) |
531 | { | 589 | { |
532 | struct radix_tree_root *page_tree = &mapping->page_tree; | 590 | struct radix_tree_root *page_tree = &mapping->page_tree; |
533 | void *new_entry; | 591 | unsigned long pfn = pfn_t_to_pfn(pfn_t); |
534 | pgoff_t index = vmf->pgoff; | 592 | pgoff_t index = vmf->pgoff; |
593 | void *new_entry; | ||
535 | 594 | ||
536 | if (dirty) | 595 | if (dirty) |
537 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | 596 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); |
@@ -546,7 +605,11 @@ static void *dax_insert_mapping_entry(struct address_space *mapping, | |||
546 | } | 605 | } |
547 | 606 | ||
548 | spin_lock_irq(&mapping->tree_lock); | 607 | spin_lock_irq(&mapping->tree_lock); |
549 | new_entry = dax_radix_locked_entry(sector, flags); | 608 | new_entry = dax_radix_locked_entry(pfn, flags); |
609 | if (dax_entry_size(entry) != dax_entry_size(new_entry)) { | ||
610 | dax_disassociate_entry(entry, mapping, false); | ||
611 | dax_associate_entry(new_entry, mapping); | ||
612 | } | ||
550 | 613 | ||
551 | if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) { | 614 | if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) { |
552 | /* | 615 | /* |
@@ -657,17 +720,14 @@ unlock_pte: | |||
657 | i_mmap_unlock_read(mapping); | 720 | i_mmap_unlock_read(mapping); |
658 | } | 721 | } |
659 | 722 | ||
660 | static int dax_writeback_one(struct block_device *bdev, | 723 | static int dax_writeback_one(struct dax_device *dax_dev, |
661 | struct dax_device *dax_dev, struct address_space *mapping, | 724 | struct address_space *mapping, pgoff_t index, void *entry) |
662 | pgoff_t index, void *entry) | ||
663 | { | 725 | { |
664 | struct radix_tree_root *page_tree = &mapping->page_tree; | 726 | struct radix_tree_root *page_tree = &mapping->page_tree; |
665 | void *entry2, **slot, *kaddr; | 727 | void *entry2, **slot; |
666 | long ret = 0, id; | 728 | unsigned long pfn; |
667 | sector_t sector; | 729 | long ret = 0; |
668 | pgoff_t pgoff; | ||
669 | size_t size; | 730 | size_t size; |
670 | pfn_t pfn; | ||
671 | 731 | ||
672 | /* | 732 | /* |
673 | * A page got tagged dirty in DAX mapping? Something is seriously | 733 | * A page got tagged dirty in DAX mapping? Something is seriously |
@@ -683,10 +743,10 @@ static int dax_writeback_one(struct block_device *bdev, | |||
683 | goto put_unlocked; | 743 | goto put_unlocked; |
684 | /* | 744 | /* |
685 | * Entry got reallocated elsewhere? No need to writeback. We have to | 745 | * Entry got reallocated elsewhere? No need to writeback. We have to |
686 | * compare sectors as we must not bail out due to difference in lockbit | 746 | * compare pfns as we must not bail out due to difference in lockbit |
687 | * or entry type. | 747 | * or entry type. |
688 | */ | 748 | */ |
689 | if (dax_radix_sector(entry2) != dax_radix_sector(entry)) | 749 | if (dax_radix_pfn(entry2) != dax_radix_pfn(entry)) |
690 | goto put_unlocked; | 750 | goto put_unlocked; |
691 | if (WARN_ON_ONCE(dax_is_empty_entry(entry) || | 751 | if (WARN_ON_ONCE(dax_is_empty_entry(entry) || |
692 | dax_is_zero_entry(entry))) { | 752 | dax_is_zero_entry(entry))) { |
@@ -712,33 +772,15 @@ static int dax_writeback_one(struct block_device *bdev, | |||
712 | /* | 772 | /* |
713 | * Even if dax_writeback_mapping_range() was given a wbc->range_start | 773 | * Even if dax_writeback_mapping_range() was given a wbc->range_start |
714 | * in the middle of a PMD, the 'index' we are given will be aligned to | 774 | * in the middle of a PMD, the 'index' we are given will be aligned to |
715 | * the start index of the PMD, as will the sector we pull from | 775 | * the start index of the PMD, as will the pfn we pull from 'entry'. |
716 | * 'entry'. This allows us to flush for PMD_SIZE and not have to | 776 | * This allows us to flush for PMD_SIZE and not have to worry about |
717 | * worry about partial PMD writebacks. | 777 | * partial PMD writebacks. |
718 | */ | 778 | */ |
719 | sector = dax_radix_sector(entry); | 779 | pfn = dax_radix_pfn(entry); |
720 | size = PAGE_SIZE << dax_radix_order(entry); | 780 | size = PAGE_SIZE << dax_radix_order(entry); |
721 | 781 | ||
722 | id = dax_read_lock(); | 782 | dax_mapping_entry_mkclean(mapping, index, pfn); |
723 | ret = bdev_dax_pgoff(bdev, sector, size, &pgoff); | 783 | dax_flush(dax_dev, page_address(pfn_to_page(pfn)), size); |
724 | if (ret) | ||
725 | goto dax_unlock; | ||
726 | |||
727 | /* | ||
728 | * dax_direct_access() may sleep, so cannot hold tree_lock over | ||
729 | * its invocation. | ||
730 | */ | ||
731 | ret = dax_direct_access(dax_dev, pgoff, size / PAGE_SIZE, &kaddr, &pfn); | ||
732 | if (ret < 0) | ||
733 | goto dax_unlock; | ||
734 | |||
735 | if (WARN_ON_ONCE(ret < size / PAGE_SIZE)) { | ||
736 | ret = -EIO; | ||
737 | goto dax_unlock; | ||
738 | } | ||
739 | |||
740 | dax_mapping_entry_mkclean(mapping, index, pfn_t_to_pfn(pfn)); | ||
741 | dax_flush(dax_dev, kaddr, size); | ||
742 | /* | 784 | /* |
743 | * After we have flushed the cache, we can clear the dirty tag. There | 785 | * After we have flushed the cache, we can clear the dirty tag. There |
744 | * cannot be new dirty data in the pfn after the flush has completed as | 786 | * cannot be new dirty data in the pfn after the flush has completed as |
@@ -749,8 +791,6 @@ static int dax_writeback_one(struct block_device *bdev, | |||
749 | radix_tree_tag_clear(page_tree, index, PAGECACHE_TAG_DIRTY); | 791 | radix_tree_tag_clear(page_tree, index, PAGECACHE_TAG_DIRTY); |
750 | spin_unlock_irq(&mapping->tree_lock); | 792 | spin_unlock_irq(&mapping->tree_lock); |
751 | trace_dax_writeback_one(mapping->host, index, size >> PAGE_SHIFT); | 793 | trace_dax_writeback_one(mapping->host, index, size >> PAGE_SHIFT); |
752 | dax_unlock: | ||
753 | dax_read_unlock(id); | ||
754 | put_locked_mapping_entry(mapping, index); | 794 | put_locked_mapping_entry(mapping, index); |
755 | return ret; | 795 | return ret; |
756 | 796 | ||
@@ -808,8 +848,8 @@ int dax_writeback_mapping_range(struct address_space *mapping, | |||
808 | break; | 848 | break; |
809 | } | 849 | } |
810 | 850 | ||
811 | ret = dax_writeback_one(bdev, dax_dev, mapping, | 851 | ret = dax_writeback_one(dax_dev, mapping, indices[i], |
812 | indices[i], pvec.pages[i]); | 852 | pvec.pages[i]); |
813 | if (ret < 0) { | 853 | if (ret < 0) { |
814 | mapping_set_error(mapping, ret); | 854 | mapping_set_error(mapping, ret); |
815 | goto out; | 855 | goto out; |
@@ -877,6 +917,7 @@ static int dax_load_hole(struct address_space *mapping, void *entry, | |||
877 | int ret = VM_FAULT_NOPAGE; | 917 | int ret = VM_FAULT_NOPAGE; |
878 | struct page *zero_page; | 918 | struct page *zero_page; |
879 | void *entry2; | 919 | void *entry2; |
920 | pfn_t pfn; | ||
880 | 921 | ||
881 | zero_page = ZERO_PAGE(0); | 922 | zero_page = ZERO_PAGE(0); |
882 | if (unlikely(!zero_page)) { | 923 | if (unlikely(!zero_page)) { |
@@ -884,14 +925,15 @@ static int dax_load_hole(struct address_space *mapping, void *entry, | |||
884 | goto out; | 925 | goto out; |
885 | } | 926 | } |
886 | 927 | ||
887 | entry2 = dax_insert_mapping_entry(mapping, vmf, entry, 0, | 928 | pfn = page_to_pfn_t(zero_page); |
929 | entry2 = dax_insert_mapping_entry(mapping, vmf, entry, pfn, | ||
888 | RADIX_DAX_ZERO_PAGE, false); | 930 | RADIX_DAX_ZERO_PAGE, false); |
889 | if (IS_ERR(entry2)) { | 931 | if (IS_ERR(entry2)) { |
890 | ret = VM_FAULT_SIGBUS; | 932 | ret = VM_FAULT_SIGBUS; |
891 | goto out; | 933 | goto out; |
892 | } | 934 | } |
893 | 935 | ||
894 | vm_insert_mixed(vmf->vma, vaddr, page_to_pfn_t(zero_page)); | 936 | vm_insert_mixed(vmf->vma, vaddr, pfn); |
895 | out: | 937 | out: |
896 | trace_dax_load_hole(inode, vmf, ret); | 938 | trace_dax_load_hole(inode, vmf, ret); |
897 | return ret; | 939 | return ret; |
@@ -1200,8 +1242,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp, | |||
1200 | if (error < 0) | 1242 | if (error < 0) |
1201 | goto error_finish_iomap; | 1243 | goto error_finish_iomap; |
1202 | 1244 | ||
1203 | entry = dax_insert_mapping_entry(mapping, vmf, entry, | 1245 | entry = dax_insert_mapping_entry(mapping, vmf, entry, pfn, |
1204 | dax_iomap_sector(&iomap, pos), | ||
1205 | 0, write && !sync); | 1246 | 0, write && !sync); |
1206 | if (IS_ERR(entry)) { | 1247 | if (IS_ERR(entry)) { |
1207 | error = PTR_ERR(entry); | 1248 | error = PTR_ERR(entry); |
@@ -1280,13 +1321,15 @@ static int dax_pmd_load_hole(struct vm_fault *vmf, struct iomap *iomap, | |||
1280 | void *ret = NULL; | 1321 | void *ret = NULL; |
1281 | spinlock_t *ptl; | 1322 | spinlock_t *ptl; |
1282 | pmd_t pmd_entry; | 1323 | pmd_t pmd_entry; |
1324 | pfn_t pfn; | ||
1283 | 1325 | ||
1284 | zero_page = mm_get_huge_zero_page(vmf->vma->vm_mm); | 1326 | zero_page = mm_get_huge_zero_page(vmf->vma->vm_mm); |
1285 | 1327 | ||
1286 | if (unlikely(!zero_page)) | 1328 | if (unlikely(!zero_page)) |
1287 | goto fallback; | 1329 | goto fallback; |
1288 | 1330 | ||
1289 | ret = dax_insert_mapping_entry(mapping, vmf, entry, 0, | 1331 | pfn = page_to_pfn_t(zero_page); |
1332 | ret = dax_insert_mapping_entry(mapping, vmf, entry, pfn, | ||
1290 | RADIX_DAX_PMD | RADIX_DAX_ZERO_PAGE, false); | 1333 | RADIX_DAX_PMD | RADIX_DAX_ZERO_PAGE, false); |
1291 | if (IS_ERR(ret)) | 1334 | if (IS_ERR(ret)) |
1292 | goto fallback; | 1335 | goto fallback; |
@@ -1409,8 +1452,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp, | |||
1409 | if (error < 0) | 1452 | if (error < 0) |
1410 | goto finish_iomap; | 1453 | goto finish_iomap; |
1411 | 1454 | ||
1412 | entry = dax_insert_mapping_entry(mapping, vmf, entry, | 1455 | entry = dax_insert_mapping_entry(mapping, vmf, entry, pfn, |
1413 | dax_iomap_sector(&iomap, pos), | ||
1414 | RADIX_DAX_PMD, write && !sync); | 1456 | RADIX_DAX_PMD, write && !sync); |
1415 | if (IS_ERR(entry)) | 1457 | if (IS_ERR(entry)) |
1416 | goto finish_iomap; | 1458 | goto finish_iomap; |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 032295e1d386..cc40802ddfa8 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -814,6 +814,7 @@ extern const struct inode_operations ext2_file_inode_operations; | |||
814 | extern const struct file_operations ext2_file_operations; | 814 | extern const struct file_operations ext2_file_operations; |
815 | 815 | ||
816 | /* inode.c */ | 816 | /* inode.c */ |
817 | extern void ext2_set_file_ops(struct inode *inode); | ||
817 | extern const struct address_space_operations ext2_aops; | 818 | extern const struct address_space_operations ext2_aops; |
818 | extern const struct address_space_operations ext2_nobh_aops; | 819 | extern const struct address_space_operations ext2_nobh_aops; |
819 | extern const struct iomap_ops ext2_iomap_ops; | 820 | extern const struct iomap_ops ext2_iomap_ops; |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 9b2ac55ac34f..1e01fabef130 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -940,9 +940,6 @@ ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | |||
940 | loff_t offset = iocb->ki_pos; | 940 | loff_t offset = iocb->ki_pos; |
941 | ssize_t ret; | 941 | ssize_t ret; |
942 | 942 | ||
943 | if (WARN_ON_ONCE(IS_DAX(inode))) | ||
944 | return -EIO; | ||
945 | |||
946 | ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block); | 943 | ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block); |
947 | if (ret < 0 && iov_iter_rw(iter) == WRITE) | 944 | if (ret < 0 && iov_iter_rw(iter) == WRITE) |
948 | ext2_write_failed(mapping, offset + count); | 945 | ext2_write_failed(mapping, offset + count); |
@@ -952,17 +949,16 @@ ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | |||
952 | static int | 949 | static int |
953 | ext2_writepages(struct address_space *mapping, struct writeback_control *wbc) | 950 | ext2_writepages(struct address_space *mapping, struct writeback_control *wbc) |
954 | { | 951 | { |
955 | #ifdef CONFIG_FS_DAX | ||
956 | if (dax_mapping(mapping)) { | ||
957 | return dax_writeback_mapping_range(mapping, | ||
958 | mapping->host->i_sb->s_bdev, | ||
959 | wbc); | ||
960 | } | ||
961 | #endif | ||
962 | |||
963 | return mpage_writepages(mapping, wbc, ext2_get_block); | 952 | return mpage_writepages(mapping, wbc, ext2_get_block); |
964 | } | 953 | } |
965 | 954 | ||
955 | static int | ||
956 | ext2_dax_writepages(struct address_space *mapping, struct writeback_control *wbc) | ||
957 | { | ||
958 | return dax_writeback_mapping_range(mapping, | ||
959 | mapping->host->i_sb->s_bdev, wbc); | ||
960 | } | ||
961 | |||
966 | const struct address_space_operations ext2_aops = { | 962 | const struct address_space_operations ext2_aops = { |
967 | .readpage = ext2_readpage, | 963 | .readpage = ext2_readpage, |
968 | .readpages = ext2_readpages, | 964 | .readpages = ext2_readpages, |
@@ -990,6 +986,13 @@ const struct address_space_operations ext2_nobh_aops = { | |||
990 | .error_remove_page = generic_error_remove_page, | 986 | .error_remove_page = generic_error_remove_page, |
991 | }; | 987 | }; |
992 | 988 | ||
989 | static const struct address_space_operations ext2_dax_aops = { | ||
990 | .writepages = ext2_dax_writepages, | ||
991 | .direct_IO = noop_direct_IO, | ||
992 | .set_page_dirty = noop_set_page_dirty, | ||
993 | .invalidatepage = noop_invalidatepage, | ||
994 | }; | ||
995 | |||
993 | /* | 996 | /* |
994 | * Probably it should be a library function... search for first non-zero word | 997 | * Probably it should be a library function... search for first non-zero word |
995 | * or memcmp with zero_page, whatever is better for particular architecture. | 998 | * or memcmp with zero_page, whatever is better for particular architecture. |
@@ -1388,6 +1391,18 @@ void ext2_set_inode_flags(struct inode *inode) | |||
1388 | inode->i_flags |= S_DAX; | 1391 | inode->i_flags |= S_DAX; |
1389 | } | 1392 | } |
1390 | 1393 | ||
1394 | void ext2_set_file_ops(struct inode *inode) | ||
1395 | { | ||
1396 | inode->i_op = &ext2_file_inode_operations; | ||
1397 | inode->i_fop = &ext2_file_operations; | ||
1398 | if (IS_DAX(inode)) | ||
1399 | inode->i_mapping->a_ops = &ext2_dax_aops; | ||
1400 | else if (test_opt(inode->i_sb, NOBH)) | ||
1401 | inode->i_mapping->a_ops = &ext2_nobh_aops; | ||
1402 | else | ||
1403 | inode->i_mapping->a_ops = &ext2_aops; | ||
1404 | } | ||
1405 | |||
1391 | struct inode *ext2_iget (struct super_block *sb, unsigned long ino) | 1406 | struct inode *ext2_iget (struct super_block *sb, unsigned long ino) |
1392 | { | 1407 | { |
1393 | struct ext2_inode_info *ei; | 1408 | struct ext2_inode_info *ei; |
@@ -1480,14 +1495,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino) | |||
1480 | ei->i_data[n] = raw_inode->i_block[n]; | 1495 | ei->i_data[n] = raw_inode->i_block[n]; |
1481 | 1496 | ||
1482 | if (S_ISREG(inode->i_mode)) { | 1497 | if (S_ISREG(inode->i_mode)) { |
1483 | inode->i_op = &ext2_file_inode_operations; | 1498 | ext2_set_file_ops(inode); |
1484 | if (test_opt(inode->i_sb, NOBH)) { | ||
1485 | inode->i_mapping->a_ops = &ext2_nobh_aops; | ||
1486 | inode->i_fop = &ext2_file_operations; | ||
1487 | } else { | ||
1488 | inode->i_mapping->a_ops = &ext2_aops; | ||
1489 | inode->i_fop = &ext2_file_operations; | ||
1490 | } | ||
1491 | } else if (S_ISDIR(inode->i_mode)) { | 1499 | } else if (S_ISDIR(inode->i_mode)) { |
1492 | inode->i_op = &ext2_dir_inode_operations; | 1500 | inode->i_op = &ext2_dir_inode_operations; |
1493 | inode->i_fop = &ext2_dir_operations; | 1501 | inode->i_fop = &ext2_dir_operations; |
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index e078075dc66f..55f7caadb093 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c | |||
@@ -107,14 +107,7 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode | |||
107 | if (IS_ERR(inode)) | 107 | if (IS_ERR(inode)) |
108 | return PTR_ERR(inode); | 108 | return PTR_ERR(inode); |
109 | 109 | ||
110 | inode->i_op = &ext2_file_inode_operations; | 110 | ext2_set_file_ops(inode); |
111 | if (test_opt(inode->i_sb, NOBH)) { | ||
112 | inode->i_mapping->a_ops = &ext2_nobh_aops; | ||
113 | inode->i_fop = &ext2_file_operations; | ||
114 | } else { | ||
115 | inode->i_mapping->a_ops = &ext2_aops; | ||
116 | inode->i_fop = &ext2_file_operations; | ||
117 | } | ||
118 | mark_inode_dirty(inode); | 111 | mark_inode_dirty(inode); |
119 | return ext2_add_nondir(dentry, inode); | 112 | return ext2_add_nondir(dentry, inode); |
120 | } | 113 | } |
@@ -125,14 +118,7 @@ static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
125 | if (IS_ERR(inode)) | 118 | if (IS_ERR(inode)) |
126 | return PTR_ERR(inode); | 119 | return PTR_ERR(inode); |
127 | 120 | ||
128 | inode->i_op = &ext2_file_inode_operations; | 121 | ext2_set_file_ops(inode); |
129 | if (test_opt(inode->i_sb, NOBH)) { | ||
130 | inode->i_mapping->a_ops = &ext2_nobh_aops; | ||
131 | inode->i_fop = &ext2_file_operations; | ||
132 | } else { | ||
133 | inode->i_mapping->a_ops = &ext2_aops; | ||
134 | inode->i_fop = &ext2_file_operations; | ||
135 | } | ||
136 | mark_inode_dirty(inode); | 122 | mark_inode_dirty(inode); |
137 | d_tmpfile(dentry, inode); | 123 | d_tmpfile(dentry, inode); |
138 | unlock_new_inode(inode); | 124 | unlock_new_inode(inode); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 129205028300..1e50c5efae67 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -2716,12 +2716,6 @@ static int ext4_writepages(struct address_space *mapping, | |||
2716 | percpu_down_read(&sbi->s_journal_flag_rwsem); | 2716 | percpu_down_read(&sbi->s_journal_flag_rwsem); |
2717 | trace_ext4_writepages(inode, wbc); | 2717 | trace_ext4_writepages(inode, wbc); |
2718 | 2718 | ||
2719 | if (dax_mapping(mapping)) { | ||
2720 | ret = dax_writeback_mapping_range(mapping, inode->i_sb->s_bdev, | ||
2721 | wbc); | ||
2722 | goto out_writepages; | ||
2723 | } | ||
2724 | |||
2725 | /* | 2719 | /* |
2726 | * No pages to write? This is mainly a kludge to avoid starting | 2720 | * No pages to write? This is mainly a kludge to avoid starting |
2727 | * a transaction for special inodes like journal inode on last iput() | 2721 | * a transaction for special inodes like journal inode on last iput() |
@@ -2942,6 +2936,27 @@ out_writepages: | |||
2942 | return ret; | 2936 | return ret; |
2943 | } | 2937 | } |
2944 | 2938 | ||
2939 | static int ext4_dax_writepages(struct address_space *mapping, | ||
2940 | struct writeback_control *wbc) | ||
2941 | { | ||
2942 | int ret; | ||
2943 | long nr_to_write = wbc->nr_to_write; | ||
2944 | struct inode *inode = mapping->host; | ||
2945 | struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); | ||
2946 | |||
2947 | if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) | ||
2948 | return -EIO; | ||
2949 | |||
2950 | percpu_down_read(&sbi->s_journal_flag_rwsem); | ||
2951 | trace_ext4_writepages(inode, wbc); | ||
2952 | |||
2953 | ret = dax_writeback_mapping_range(mapping, inode->i_sb->s_bdev, wbc); | ||
2954 | trace_ext4_writepages_result(inode, wbc, ret, | ||
2955 | nr_to_write - wbc->nr_to_write); | ||
2956 | percpu_up_read(&sbi->s_journal_flag_rwsem); | ||
2957 | return ret; | ||
2958 | } | ||
2959 | |||
2945 | static int ext4_nonda_switch(struct super_block *sb) | 2960 | static int ext4_nonda_switch(struct super_block *sb) |
2946 | { | 2961 | { |
2947 | s64 free_clusters, dirty_clusters; | 2962 | s64 free_clusters, dirty_clusters; |
@@ -3845,10 +3860,6 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | |||
3845 | if (ext4_has_inline_data(inode)) | 3860 | if (ext4_has_inline_data(inode)) |
3846 | return 0; | 3861 | return 0; |
3847 | 3862 | ||
3848 | /* DAX uses iomap path now */ | ||
3849 | if (WARN_ON_ONCE(IS_DAX(inode))) | ||
3850 | return 0; | ||
3851 | |||
3852 | trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); | 3863 | trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); |
3853 | if (iov_iter_rw(iter) == READ) | 3864 | if (iov_iter_rw(iter) == READ) |
3854 | ret = ext4_direct_IO_read(iocb, iter); | 3865 | ret = ext4_direct_IO_read(iocb, iter); |
@@ -3934,6 +3945,13 @@ static const struct address_space_operations ext4_da_aops = { | |||
3934 | .error_remove_page = generic_error_remove_page, | 3945 | .error_remove_page = generic_error_remove_page, |
3935 | }; | 3946 | }; |
3936 | 3947 | ||
3948 | static const struct address_space_operations ext4_dax_aops = { | ||
3949 | .writepages = ext4_dax_writepages, | ||
3950 | .direct_IO = noop_direct_IO, | ||
3951 | .set_page_dirty = noop_set_page_dirty, | ||
3952 | .invalidatepage = noop_invalidatepage, | ||
3953 | }; | ||
3954 | |||
3937 | void ext4_set_aops(struct inode *inode) | 3955 | void ext4_set_aops(struct inode *inode) |
3938 | { | 3956 | { |
3939 | switch (ext4_inode_journal_mode(inode)) { | 3957 | switch (ext4_inode_journal_mode(inode)) { |
@@ -3946,7 +3964,9 @@ void ext4_set_aops(struct inode *inode) | |||
3946 | default: | 3964 | default: |
3947 | BUG(); | 3965 | BUG(); |
3948 | } | 3966 | } |
3949 | if (test_opt(inode->i_sb, DELALLOC)) | 3967 | if (IS_DAX(inode)) |
3968 | inode->i_mapping->a_ops = &ext4_dax_aops; | ||
3969 | else if (test_opt(inode->i_sb, DELALLOC)) | ||
3950 | inode->i_mapping->a_ops = &ext4_da_aops; | 3970 | inode->i_mapping->a_ops = &ext4_da_aops; |
3951 | else | 3971 | else |
3952 | inode->i_mapping->a_ops = &ext4_aops; | 3972 | inode->i_mapping->a_ops = &ext4_aops; |
diff --git a/fs/libfs.c b/fs/libfs.c index 7ff3cb904acd..0fb590d79f30 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -1060,6 +1060,45 @@ int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
1060 | } | 1060 | } |
1061 | EXPORT_SYMBOL(noop_fsync); | 1061 | EXPORT_SYMBOL(noop_fsync); |
1062 | 1062 | ||
1063 | int noop_set_page_dirty(struct page *page) | ||
1064 | { | ||
1065 | /* | ||
1066 | * Unlike __set_page_dirty_no_writeback that handles dirty page | ||
1067 | * tracking in the page object, dax does all dirty tracking in | ||
1068 | * the inode address_space in response to mkwrite faults. In the | ||
1069 | * dax case we only need to worry about potentially dirty CPU | ||
1070 | * caches, not dirty page cache pages to write back. | ||
1071 | * | ||
1072 | * This callback is defined to prevent fallback to | ||
1073 | * __set_page_dirty_buffers() in set_page_dirty(). | ||
1074 | */ | ||
1075 | return 0; | ||
1076 | } | ||
1077 | EXPORT_SYMBOL_GPL(noop_set_page_dirty); | ||
1078 | |||
1079 | void noop_invalidatepage(struct page *page, unsigned int offset, | ||
1080 | unsigned int length) | ||
1081 | { | ||
1082 | /* | ||
1083 | * There is no page cache to invalidate in the dax case, however | ||
1084 | * we need this callback defined to prevent falling back to | ||
1085 | * block_invalidatepage() in do_invalidatepage(). | ||
1086 | */ | ||
1087 | } | ||
1088 | EXPORT_SYMBOL_GPL(noop_invalidatepage); | ||
1089 | |||
1090 | ssize_t noop_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | ||
1091 | { | ||
1092 | /* | ||
1093 | * iomap based filesystems support direct I/O without need for | ||
1094 | * this callback. However, it still needs to be set in | ||
1095 | * inode->a_ops so that open/fcntl know that direct I/O is | ||
1096 | * generally supported. | ||
1097 | */ | ||
1098 | return -EINVAL; | ||
1099 | } | ||
1100 | EXPORT_SYMBOL_GPL(noop_direct_IO); | ||
1101 | |||
1063 | /* Because kfree isn't assignment-compatible with void(void*) ;-/ */ | 1102 | /* Because kfree isn't assignment-compatible with void(void*) ;-/ */ |
1064 | void kfree_link(void *p) | 1103 | void kfree_link(void *p) |
1065 | { | 1104 | { |
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 31f1f10eecd1..436a1de3fcdf 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c | |||
@@ -1195,16 +1195,22 @@ xfs_vm_writepages( | |||
1195 | int ret; | 1195 | int ret; |
1196 | 1196 | ||
1197 | xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); | 1197 | xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); |
1198 | if (dax_mapping(mapping)) | ||
1199 | return dax_writeback_mapping_range(mapping, | ||
1200 | xfs_find_bdev_for_inode(mapping->host), wbc); | ||
1201 | |||
1202 | ret = write_cache_pages(mapping, wbc, xfs_do_writepage, &wpc); | 1198 | ret = write_cache_pages(mapping, wbc, xfs_do_writepage, &wpc); |
1203 | if (wpc.ioend) | 1199 | if (wpc.ioend) |
1204 | ret = xfs_submit_ioend(wbc, wpc.ioend, ret); | 1200 | ret = xfs_submit_ioend(wbc, wpc.ioend, ret); |
1205 | return ret; | 1201 | return ret; |
1206 | } | 1202 | } |
1207 | 1203 | ||
1204 | STATIC int | ||
1205 | xfs_dax_writepages( | ||
1206 | struct address_space *mapping, | ||
1207 | struct writeback_control *wbc) | ||
1208 | { | ||
1209 | xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); | ||
1210 | return dax_writeback_mapping_range(mapping, | ||
1211 | xfs_find_bdev_for_inode(mapping->host), wbc); | ||
1212 | } | ||
1213 | |||
1208 | /* | 1214 | /* |
1209 | * Called to move a page into cleanable state - and from there | 1215 | * Called to move a page into cleanable state - and from there |
1210 | * to be released. The page should already be clean. We always | 1216 | * to be released. The page should already be clean. We always |
@@ -1367,17 +1373,6 @@ out_unlock: | |||
1367 | return error; | 1373 | return error; |
1368 | } | 1374 | } |
1369 | 1375 | ||
1370 | STATIC ssize_t | ||
1371 | xfs_vm_direct_IO( | ||
1372 | struct kiocb *iocb, | ||
1373 | struct iov_iter *iter) | ||
1374 | { | ||
1375 | /* | ||
1376 | * We just need the method present so that open/fcntl allow direct I/O. | ||
1377 | */ | ||
1378 | return -EINVAL; | ||
1379 | } | ||
1380 | |||
1381 | STATIC sector_t | 1376 | STATIC sector_t |
1382 | xfs_vm_bmap( | 1377 | xfs_vm_bmap( |
1383 | struct address_space *mapping, | 1378 | struct address_space *mapping, |
@@ -1500,8 +1495,15 @@ const struct address_space_operations xfs_address_space_operations = { | |||
1500 | .releasepage = xfs_vm_releasepage, | 1495 | .releasepage = xfs_vm_releasepage, |
1501 | .invalidatepage = xfs_vm_invalidatepage, | 1496 | .invalidatepage = xfs_vm_invalidatepage, |
1502 | .bmap = xfs_vm_bmap, | 1497 | .bmap = xfs_vm_bmap, |
1503 | .direct_IO = xfs_vm_direct_IO, | 1498 | .direct_IO = noop_direct_IO, |
1504 | .migratepage = buffer_migrate_page, | 1499 | .migratepage = buffer_migrate_page, |
1505 | .is_partially_uptodate = block_is_partially_uptodate, | 1500 | .is_partially_uptodate = block_is_partially_uptodate, |
1506 | .error_remove_page = generic_error_remove_page, | 1501 | .error_remove_page = generic_error_remove_page, |
1507 | }; | 1502 | }; |
1503 | |||
1504 | const struct address_space_operations xfs_dax_aops = { | ||
1505 | .writepages = xfs_dax_writepages, | ||
1506 | .direct_IO = noop_direct_IO, | ||
1507 | .set_page_dirty = noop_set_page_dirty, | ||
1508 | .invalidatepage = noop_invalidatepage, | ||
1509 | }; | ||
diff --git a/fs/xfs/xfs_aops.h b/fs/xfs/xfs_aops.h index 88c85ea63da0..69346d460dfa 100644 --- a/fs/xfs/xfs_aops.h +++ b/fs/xfs/xfs_aops.h | |||
@@ -54,6 +54,7 @@ struct xfs_ioend { | |||
54 | }; | 54 | }; |
55 | 55 | ||
56 | extern const struct address_space_operations xfs_address_space_operations; | 56 | extern const struct address_space_operations xfs_address_space_operations; |
57 | extern const struct address_space_operations xfs_dax_aops; | ||
57 | 58 | ||
58 | int xfs_setfilesize(struct xfs_inode *ip, xfs_off_t offset, size_t size); | 59 | int xfs_setfilesize(struct xfs_inode *ip, xfs_off_t offset, size_t size); |
59 | 60 | ||
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index e0307fbff911..154725b1b813 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -1285,7 +1285,10 @@ xfs_setup_iops( | |||
1285 | case S_IFREG: | 1285 | case S_IFREG: |
1286 | inode->i_op = &xfs_inode_operations; | 1286 | inode->i_op = &xfs_inode_operations; |
1287 | inode->i_fop = &xfs_file_operations; | 1287 | inode->i_fop = &xfs_file_operations; |
1288 | inode->i_mapping->a_ops = &xfs_address_space_operations; | 1288 | if (IS_DAX(inode)) |
1289 | inode->i_mapping->a_ops = &xfs_dax_aops; | ||
1290 | else | ||
1291 | inode->i_mapping->a_ops = &xfs_address_space_operations; | ||
1289 | break; | 1292 | break; |
1290 | case S_IFDIR: | 1293 | case S_IFDIR: |
1291 | if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) | 1294 | if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) |
diff --git a/include/linux/dax.h b/include/linux/dax.h index 0185ecdae135..f9eb22ad341e 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h | |||
@@ -26,18 +26,42 @@ extern struct attribute_group dax_attribute_group; | |||
26 | 26 | ||
27 | #if IS_ENABLED(CONFIG_DAX) | 27 | #if IS_ENABLED(CONFIG_DAX) |
28 | struct dax_device *dax_get_by_host(const char *host); | 28 | struct dax_device *dax_get_by_host(const char *host); |
29 | struct dax_device *alloc_dax(void *private, const char *host, | ||
30 | const struct dax_operations *ops); | ||
29 | void put_dax(struct dax_device *dax_dev); | 31 | void put_dax(struct dax_device *dax_dev); |
32 | void kill_dax(struct dax_device *dax_dev); | ||
33 | void dax_write_cache(struct dax_device *dax_dev, bool wc); | ||
34 | bool dax_write_cache_enabled(struct dax_device *dax_dev); | ||
30 | #else | 35 | #else |
31 | static inline struct dax_device *dax_get_by_host(const char *host) | 36 | static inline struct dax_device *dax_get_by_host(const char *host) |
32 | { | 37 | { |
33 | return NULL; | 38 | return NULL; |
34 | } | 39 | } |
35 | 40 | static inline struct dax_device *alloc_dax(void *private, const char *host, | |
41 | const struct dax_operations *ops) | ||
42 | { | ||
43 | /* | ||
44 | * Callers should check IS_ENABLED(CONFIG_DAX) to know if this | ||
45 | * NULL is an error or expected. | ||
46 | */ | ||
47 | return NULL; | ||
48 | } | ||
36 | static inline void put_dax(struct dax_device *dax_dev) | 49 | static inline void put_dax(struct dax_device *dax_dev) |
37 | { | 50 | { |
38 | } | 51 | } |
52 | static inline void kill_dax(struct dax_device *dax_dev) | ||
53 | { | ||
54 | } | ||
55 | static inline void dax_write_cache(struct dax_device *dax_dev, bool wc) | ||
56 | { | ||
57 | } | ||
58 | static inline bool dax_write_cache_enabled(struct dax_device *dax_dev) | ||
59 | { | ||
60 | return false; | ||
61 | } | ||
39 | #endif | 62 | #endif |
40 | 63 | ||
64 | struct writeback_control; | ||
41 | int bdev_dax_pgoff(struct block_device *, sector_t, size_t, pgoff_t *pgoff); | 65 | int bdev_dax_pgoff(struct block_device *, sector_t, size_t, pgoff_t *pgoff); |
42 | #if IS_ENABLED(CONFIG_FS_DAX) | 66 | #if IS_ENABLED(CONFIG_FS_DAX) |
43 | int __bdev_dax_supported(struct super_block *sb, int blocksize); | 67 | int __bdev_dax_supported(struct super_block *sb, int blocksize); |
@@ -57,6 +81,8 @@ static inline void fs_put_dax(struct dax_device *dax_dev) | |||
57 | } | 81 | } |
58 | 82 | ||
59 | struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev); | 83 | struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev); |
84 | int dax_writeback_mapping_range(struct address_space *mapping, | ||
85 | struct block_device *bdev, struct writeback_control *wbc); | ||
60 | #else | 86 | #else |
61 | static inline int bdev_dax_supported(struct super_block *sb, int blocksize) | 87 | static inline int bdev_dax_supported(struct super_block *sb, int blocksize) |
62 | { | 88 | { |
@@ -76,22 +102,23 @@ static inline struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev) | |||
76 | { | 102 | { |
77 | return NULL; | 103 | return NULL; |
78 | } | 104 | } |
105 | |||
106 | static inline int dax_writeback_mapping_range(struct address_space *mapping, | ||
107 | struct block_device *bdev, struct writeback_control *wbc) | ||
108 | { | ||
109 | return -EOPNOTSUPP; | ||
110 | } | ||
79 | #endif | 111 | #endif |
80 | 112 | ||
81 | int dax_read_lock(void); | 113 | int dax_read_lock(void); |
82 | void dax_read_unlock(int id); | 114 | void dax_read_unlock(int id); |
83 | struct dax_device *alloc_dax(void *private, const char *host, | ||
84 | const struct dax_operations *ops); | ||
85 | bool dax_alive(struct dax_device *dax_dev); | 115 | bool dax_alive(struct dax_device *dax_dev); |
86 | void kill_dax(struct dax_device *dax_dev); | ||
87 | void *dax_get_private(struct dax_device *dax_dev); | 116 | void *dax_get_private(struct dax_device *dax_dev); |
88 | long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages, | 117 | long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages, |
89 | void **kaddr, pfn_t *pfn); | 118 | void **kaddr, pfn_t *pfn); |
90 | size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr, | 119 | size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr, |
91 | size_t bytes, struct iov_iter *i); | 120 | size_t bytes, struct iov_iter *i); |
92 | void dax_flush(struct dax_device *dax_dev, void *addr, size_t size); | 121 | void dax_flush(struct dax_device *dax_dev, void *addr, size_t size); |
93 | void dax_write_cache(struct dax_device *dax_dev, bool wc); | ||
94 | bool dax_write_cache_enabled(struct dax_device *dax_dev); | ||
95 | 122 | ||
96 | ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, | 123 | ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, |
97 | const struct iomap_ops *ops); | 124 | const struct iomap_ops *ops); |
@@ -121,7 +148,4 @@ static inline bool dax_mapping(struct address_space *mapping) | |||
121 | return mapping->host && IS_DAX(mapping->host); | 148 | return mapping->host && IS_DAX(mapping->host); |
122 | } | 149 | } |
123 | 150 | ||
124 | struct writeback_control; | ||
125 | int dax_writeback_mapping_range(struct address_space *mapping, | ||
126 | struct block_device *bdev, struct writeback_control *wbc); | ||
127 | #endif | 151 | #endif |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 1ee7f592e239..2aa02cad94d4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -3127,6 +3127,10 @@ extern int simple_rmdir(struct inode *, struct dentry *); | |||
3127 | extern int simple_rename(struct inode *, struct dentry *, | 3127 | extern int simple_rename(struct inode *, struct dentry *, |
3128 | struct inode *, struct dentry *, unsigned int); | 3128 | struct inode *, struct dentry *, unsigned int); |
3129 | extern int noop_fsync(struct file *, loff_t, loff_t, int); | 3129 | extern int noop_fsync(struct file *, loff_t, loff_t, int); |
3130 | extern int noop_set_page_dirty(struct page *page); | ||
3131 | extern void noop_invalidatepage(struct page *page, unsigned int offset, | ||
3132 | unsigned int length); | ||
3133 | extern ssize_t noop_direct_IO(struct kiocb *iocb, struct iov_iter *iter); | ||
3130 | extern int simple_empty(struct dentry *); | 3134 | extern int simple_empty(struct dentry *); |
3131 | extern int simple_readpage(struct file *file, struct page *page); | 3135 | extern int simple_readpage(struct file *file, struct page *page); |
3132 | extern int simple_write_begin(struct file *file, struct address_space *mapping, | 3136 | extern int simple_write_begin(struct file *file, struct address_space *mapping, |
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index ff855ed965fb..097072c5a852 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h | |||
@@ -76,12 +76,14 @@ typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc, | |||
76 | struct nvdimm *nvdimm, unsigned int cmd, void *buf, | 76 | struct nvdimm *nvdimm, unsigned int cmd, void *buf, |
77 | unsigned int buf_len, int *cmd_rc); | 77 | unsigned int buf_len, int *cmd_rc); |
78 | 78 | ||
79 | struct device_node; | ||
79 | struct nvdimm_bus_descriptor { | 80 | struct nvdimm_bus_descriptor { |
80 | const struct attribute_group **attr_groups; | 81 | const struct attribute_group **attr_groups; |
81 | unsigned long bus_dsm_mask; | 82 | unsigned long bus_dsm_mask; |
82 | unsigned long cmd_mask; | 83 | unsigned long cmd_mask; |
83 | struct module *module; | 84 | struct module *module; |
84 | char *provider_name; | 85 | char *provider_name; |
86 | struct device_node *of_node; | ||
85 | ndctl_fn ndctl; | 87 | ndctl_fn ndctl; |
86 | int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc); | 88 | int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc); |
87 | int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc, | 89 | int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc, |
@@ -123,6 +125,7 @@ struct nd_region_desc { | |||
123 | int num_lanes; | 125 | int num_lanes; |
124 | int numa_node; | 126 | int numa_node; |
125 | unsigned long flags; | 127 | unsigned long flags; |
128 | struct device_node *of_node; | ||
126 | }; | 129 | }; |
127 | 130 | ||
128 | struct device; | 131 | struct device; |
@@ -164,6 +167,7 @@ void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus); | |||
164 | struct nvdimm_bus *to_nvdimm_bus(struct device *dev); | 167 | struct nvdimm_bus *to_nvdimm_bus(struct device *dev); |
165 | struct nvdimm *to_nvdimm(struct device *dev); | 168 | struct nvdimm *to_nvdimm(struct device *dev); |
166 | struct nd_region *to_nd_region(struct device *dev); | 169 | struct nd_region *to_nd_region(struct device *dev); |
170 | struct device *nd_region_dev(struct nd_region *nd_region); | ||
167 | struct nd_blk_region *to_nd_blk_region(struct device *dev); | 171 | struct nd_blk_region *to_nd_blk_region(struct device *dev); |
168 | struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus); | 172 | struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus); |
169 | struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus); | 173 | struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus); |
diff --git a/include/linux/nd.h b/include/linux/nd.h index 5dc6b695437d..43c181a6add5 100644 --- a/include/linux/nd.h +++ b/include/linux/nd.h | |||
@@ -180,6 +180,12 @@ struct nd_region; | |||
180 | void nvdimm_region_notify(struct nd_region *nd_region, enum nvdimm_event event); | 180 | void nvdimm_region_notify(struct nd_region *nd_region, enum nvdimm_event event); |
181 | int __must_check __nd_driver_register(struct nd_device_driver *nd_drv, | 181 | int __must_check __nd_driver_register(struct nd_device_driver *nd_drv, |
182 | struct module *module, const char *mod_name); | 182 | struct module *module, const char *mod_name); |
183 | static inline void nd_driver_unregister(struct nd_device_driver *drv) | ||
184 | { | ||
185 | driver_unregister(&drv->drv); | ||
186 | } | ||
183 | #define nd_driver_register(driver) \ | 187 | #define nd_driver_register(driver) \ |
184 | __nd_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) | 188 | __nd_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) |
189 | #define module_nd_driver(driver) \ | ||
190 | module_driver(driver, nd_driver_register, nd_driver_unregister) | ||
185 | #endif /* __LINUX_ND_H__ */ | 191 | #endif /* __LINUX_ND_H__ */ |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 620fa78b3b1b..cb166be4918d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -104,7 +104,8 @@ enum { | |||
104 | NUM_HINTS = 8, | 104 | NUM_HINTS = 8, |
105 | NUM_BDW = NUM_DCR, | 105 | NUM_BDW = NUM_DCR, |
106 | NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, | 106 | NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, |
107 | NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */, | 107 | NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ |
108 | + 4 /* spa1 iset */ + 1 /* spa11 iset */, | ||
108 | DIMM_SIZE = SZ_32M, | 109 | DIMM_SIZE = SZ_32M, |
109 | LABEL_SIZE = SZ_128K, | 110 | LABEL_SIZE = SZ_128K, |
110 | SPA_VCD_SIZE = SZ_4M, | 111 | SPA_VCD_SIZE = SZ_4M, |
@@ -153,6 +154,7 @@ struct nfit_test { | |||
153 | void *nfit_buf; | 154 | void *nfit_buf; |
154 | dma_addr_t nfit_dma; | 155 | dma_addr_t nfit_dma; |
155 | size_t nfit_size; | 156 | size_t nfit_size; |
157 | size_t nfit_filled; | ||
156 | int dcr_idx; | 158 | int dcr_idx; |
157 | int num_dcr; | 159 | int num_dcr; |
158 | int num_pm; | 160 | int num_pm; |
@@ -709,7 +711,9 @@ static void smart_notify(struct device *bus_dev, | |||
709 | >= thresh->media_temperature) | 711 | >= thresh->media_temperature) |
710 | || ((thresh->alarm_control & ND_INTEL_SMART_CTEMP_TRIP) | 712 | || ((thresh->alarm_control & ND_INTEL_SMART_CTEMP_TRIP) |
711 | && smart->ctrl_temperature | 713 | && smart->ctrl_temperature |
712 | >= thresh->ctrl_temperature)) { | 714 | >= thresh->ctrl_temperature) |
715 | || (smart->health != ND_INTEL_SMART_NON_CRITICAL_HEALTH) | ||
716 | || (smart->shutdown_state != 0)) { | ||
713 | device_lock(bus_dev); | 717 | device_lock(bus_dev); |
714 | __acpi_nvdimm_notify(dimm_dev, 0x81); | 718 | __acpi_nvdimm_notify(dimm_dev, 0x81); |
715 | device_unlock(bus_dev); | 719 | device_unlock(bus_dev); |
@@ -735,6 +739,32 @@ static int nfit_test_cmd_smart_set_threshold( | |||
735 | return 0; | 739 | return 0; |
736 | } | 740 | } |
737 | 741 | ||
742 | static int nfit_test_cmd_smart_inject( | ||
743 | struct nd_intel_smart_inject *inj, | ||
744 | unsigned int buf_len, | ||
745 | struct nd_intel_smart_threshold *thresh, | ||
746 | struct nd_intel_smart *smart, | ||
747 | struct device *bus_dev, struct device *dimm_dev) | ||
748 | { | ||
749 | if (buf_len != sizeof(*inj)) | ||
750 | return -EINVAL; | ||
751 | |||
752 | if (inj->mtemp_enable) | ||
753 | smart->media_temperature = inj->media_temperature; | ||
754 | if (inj->spare_enable) | ||
755 | smart->spares = inj->spares; | ||
756 | if (inj->fatal_enable) | ||
757 | smart->health = ND_INTEL_SMART_FATAL_HEALTH; | ||
758 | if (inj->unsafe_shutdown_enable) { | ||
759 | smart->shutdown_state = 1; | ||
760 | smart->shutdown_count++; | ||
761 | } | ||
762 | inj->status = 0; | ||
763 | smart_notify(bus_dev, dimm_dev, smart, thresh); | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
738 | static void uc_error_notify(struct work_struct *work) | 768 | static void uc_error_notify(struct work_struct *work) |
739 | { | 769 | { |
740 | struct nfit_test *t = container_of(work, typeof(*t), work); | 770 | struct nfit_test *t = container_of(work, typeof(*t), work); |
@@ -935,6 +965,13 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
935 | t->dcr_idx], | 965 | t->dcr_idx], |
936 | &t->smart[i - t->dcr_idx], | 966 | &t->smart[i - t->dcr_idx], |
937 | &t->pdev.dev, t->dimm_dev[i]); | 967 | &t->pdev.dev, t->dimm_dev[i]); |
968 | case ND_INTEL_SMART_INJECT: | ||
969 | return nfit_test_cmd_smart_inject(buf, | ||
970 | buf_len, | ||
971 | &t->smart_threshold[i - | ||
972 | t->dcr_idx], | ||
973 | &t->smart[i - t->dcr_idx], | ||
974 | &t->pdev.dev, t->dimm_dev[i]); | ||
938 | default: | 975 | default: |
939 | return -ENOTTY; | 976 | return -ENOTTY; |
940 | } | 977 | } |
@@ -1222,7 +1259,7 @@ static void smart_init(struct nfit_test *t) | |||
1222 | | ND_INTEL_SMART_MTEMP_VALID, | 1259 | | ND_INTEL_SMART_MTEMP_VALID, |
1223 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, | 1260 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, |
1224 | .media_temperature = 23 * 16, | 1261 | .media_temperature = 23 * 16, |
1225 | .ctrl_temperature = 30 * 16, | 1262 | .ctrl_temperature = 25 * 16, |
1226 | .pmic_temperature = 40 * 16, | 1263 | .pmic_temperature = 40 * 16, |
1227 | .spares = 75, | 1264 | .spares = 75, |
1228 | .alarm_flags = ND_INTEL_SMART_SPARE_TRIP | 1265 | .alarm_flags = ND_INTEL_SMART_SPARE_TRIP |
@@ -1366,7 +1403,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1366 | struct acpi_nfit_data_region *bdw; | 1403 | struct acpi_nfit_data_region *bdw; |
1367 | struct acpi_nfit_flush_address *flush; | 1404 | struct acpi_nfit_flush_address *flush; |
1368 | struct acpi_nfit_capabilities *pcap; | 1405 | struct acpi_nfit_capabilities *pcap; |
1369 | unsigned int offset, i; | 1406 | unsigned int offset = 0, i; |
1370 | 1407 | ||
1371 | /* | 1408 | /* |
1372 | * spa0 (interleave first half of dimm0 and dimm1, note storage | 1409 | * spa0 (interleave first half of dimm0 and dimm1, note storage |
@@ -1380,93 +1417,102 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1380 | spa->range_index = 0+1; | 1417 | spa->range_index = 0+1; |
1381 | spa->address = t->spa_set_dma[0]; | 1418 | spa->address = t->spa_set_dma[0]; |
1382 | spa->length = SPA0_SIZE; | 1419 | spa->length = SPA0_SIZE; |
1420 | offset += spa->header.length; | ||
1383 | 1421 | ||
1384 | /* | 1422 | /* |
1385 | * spa1 (interleave last half of the 4 DIMMS, note storage | 1423 | * spa1 (interleave last half of the 4 DIMMS, note storage |
1386 | * does not actually alias the related block-data-window | 1424 | * does not actually alias the related block-data-window |
1387 | * regions) | 1425 | * regions) |
1388 | */ | 1426 | */ |
1389 | spa = nfit_buf + sizeof(*spa); | 1427 | spa = nfit_buf + offset; |
1390 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1428 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1391 | spa->header.length = sizeof(*spa); | 1429 | spa->header.length = sizeof(*spa); |
1392 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); | 1430 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); |
1393 | spa->range_index = 1+1; | 1431 | spa->range_index = 1+1; |
1394 | spa->address = t->spa_set_dma[1]; | 1432 | spa->address = t->spa_set_dma[1]; |
1395 | spa->length = SPA1_SIZE; | 1433 | spa->length = SPA1_SIZE; |
1434 | offset += spa->header.length; | ||
1396 | 1435 | ||
1397 | /* spa2 (dcr0) dimm0 */ | 1436 | /* spa2 (dcr0) dimm0 */ |
1398 | spa = nfit_buf + sizeof(*spa) * 2; | 1437 | spa = nfit_buf + offset; |
1399 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1438 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1400 | spa->header.length = sizeof(*spa); | 1439 | spa->header.length = sizeof(*spa); |
1401 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | 1440 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); |
1402 | spa->range_index = 2+1; | 1441 | spa->range_index = 2+1; |
1403 | spa->address = t->dcr_dma[0]; | 1442 | spa->address = t->dcr_dma[0]; |
1404 | spa->length = DCR_SIZE; | 1443 | spa->length = DCR_SIZE; |
1444 | offset += spa->header.length; | ||
1405 | 1445 | ||
1406 | /* spa3 (dcr1) dimm1 */ | 1446 | /* spa3 (dcr1) dimm1 */ |
1407 | spa = nfit_buf + sizeof(*spa) * 3; | 1447 | spa = nfit_buf + offset; |
1408 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1448 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1409 | spa->header.length = sizeof(*spa); | 1449 | spa->header.length = sizeof(*spa); |
1410 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | 1450 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); |
1411 | spa->range_index = 3+1; | 1451 | spa->range_index = 3+1; |
1412 | spa->address = t->dcr_dma[1]; | 1452 | spa->address = t->dcr_dma[1]; |
1413 | spa->length = DCR_SIZE; | 1453 | spa->length = DCR_SIZE; |
1454 | offset += spa->header.length; | ||
1414 | 1455 | ||
1415 | /* spa4 (dcr2) dimm2 */ | 1456 | /* spa4 (dcr2) dimm2 */ |
1416 | spa = nfit_buf + sizeof(*spa) * 4; | 1457 | spa = nfit_buf + offset; |
1417 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1458 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1418 | spa->header.length = sizeof(*spa); | 1459 | spa->header.length = sizeof(*spa); |
1419 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | 1460 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); |
1420 | spa->range_index = 4+1; | 1461 | spa->range_index = 4+1; |
1421 | spa->address = t->dcr_dma[2]; | 1462 | spa->address = t->dcr_dma[2]; |
1422 | spa->length = DCR_SIZE; | 1463 | spa->length = DCR_SIZE; |
1464 | offset += spa->header.length; | ||
1423 | 1465 | ||
1424 | /* spa5 (dcr3) dimm3 */ | 1466 | /* spa5 (dcr3) dimm3 */ |
1425 | spa = nfit_buf + sizeof(*spa) * 5; | 1467 | spa = nfit_buf + offset; |
1426 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1468 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1427 | spa->header.length = sizeof(*spa); | 1469 | spa->header.length = sizeof(*spa); |
1428 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | 1470 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); |
1429 | spa->range_index = 5+1; | 1471 | spa->range_index = 5+1; |
1430 | spa->address = t->dcr_dma[3]; | 1472 | spa->address = t->dcr_dma[3]; |
1431 | spa->length = DCR_SIZE; | 1473 | spa->length = DCR_SIZE; |
1474 | offset += spa->header.length; | ||
1432 | 1475 | ||
1433 | /* spa6 (bdw for dcr0) dimm0 */ | 1476 | /* spa6 (bdw for dcr0) dimm0 */ |
1434 | spa = nfit_buf + sizeof(*spa) * 6; | 1477 | spa = nfit_buf + offset; |
1435 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1478 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1436 | spa->header.length = sizeof(*spa); | 1479 | spa->header.length = sizeof(*spa); |
1437 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 1480 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1438 | spa->range_index = 6+1; | 1481 | spa->range_index = 6+1; |
1439 | spa->address = t->dimm_dma[0]; | 1482 | spa->address = t->dimm_dma[0]; |
1440 | spa->length = DIMM_SIZE; | 1483 | spa->length = DIMM_SIZE; |
1484 | offset += spa->header.length; | ||
1441 | 1485 | ||
1442 | /* spa7 (bdw for dcr1) dimm1 */ | 1486 | /* spa7 (bdw for dcr1) dimm1 */ |
1443 | spa = nfit_buf + sizeof(*spa) * 7; | 1487 | spa = nfit_buf + offset; |
1444 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1488 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1445 | spa->header.length = sizeof(*spa); | 1489 | spa->header.length = sizeof(*spa); |
1446 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 1490 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1447 | spa->range_index = 7+1; | 1491 | spa->range_index = 7+1; |
1448 | spa->address = t->dimm_dma[1]; | 1492 | spa->address = t->dimm_dma[1]; |
1449 | spa->length = DIMM_SIZE; | 1493 | spa->length = DIMM_SIZE; |
1494 | offset += spa->header.length; | ||
1450 | 1495 | ||
1451 | /* spa8 (bdw for dcr2) dimm2 */ | 1496 | /* spa8 (bdw for dcr2) dimm2 */ |
1452 | spa = nfit_buf + sizeof(*spa) * 8; | 1497 | spa = nfit_buf + offset; |
1453 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1498 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1454 | spa->header.length = sizeof(*spa); | 1499 | spa->header.length = sizeof(*spa); |
1455 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 1500 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1456 | spa->range_index = 8+1; | 1501 | spa->range_index = 8+1; |
1457 | spa->address = t->dimm_dma[2]; | 1502 | spa->address = t->dimm_dma[2]; |
1458 | spa->length = DIMM_SIZE; | 1503 | spa->length = DIMM_SIZE; |
1504 | offset += spa->header.length; | ||
1459 | 1505 | ||
1460 | /* spa9 (bdw for dcr3) dimm3 */ | 1506 | /* spa9 (bdw for dcr3) dimm3 */ |
1461 | spa = nfit_buf + sizeof(*spa) * 9; | 1507 | spa = nfit_buf + offset; |
1462 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1508 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1463 | spa->header.length = sizeof(*spa); | 1509 | spa->header.length = sizeof(*spa); |
1464 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 1510 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1465 | spa->range_index = 9+1; | 1511 | spa->range_index = 9+1; |
1466 | spa->address = t->dimm_dma[3]; | 1512 | spa->address = t->dimm_dma[3]; |
1467 | spa->length = DIMM_SIZE; | 1513 | spa->length = DIMM_SIZE; |
1514 | offset += spa->header.length; | ||
1468 | 1515 | ||
1469 | offset = sizeof(*spa) * 10; | ||
1470 | /* mem-region0 (spa0, dimm0) */ | 1516 | /* mem-region0 (spa0, dimm0) */ |
1471 | memdev = nfit_buf + offset; | 1517 | memdev = nfit_buf + offset; |
1472 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1518 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
@@ -1481,9 +1527,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1481 | memdev->address = 0; | 1527 | memdev->address = 0; |
1482 | memdev->interleave_index = 0; | 1528 | memdev->interleave_index = 0; |
1483 | memdev->interleave_ways = 2; | 1529 | memdev->interleave_ways = 2; |
1530 | offset += memdev->header.length; | ||
1484 | 1531 | ||
1485 | /* mem-region1 (spa0, dimm1) */ | 1532 | /* mem-region1 (spa0, dimm1) */ |
1486 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map); | 1533 | memdev = nfit_buf + offset; |
1487 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1534 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1488 | memdev->header.length = sizeof(*memdev); | 1535 | memdev->header.length = sizeof(*memdev); |
1489 | memdev->device_handle = handle[1]; | 1536 | memdev->device_handle = handle[1]; |
@@ -1497,9 +1544,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1497 | memdev->interleave_index = 0; | 1544 | memdev->interleave_index = 0; |
1498 | memdev->interleave_ways = 2; | 1545 | memdev->interleave_ways = 2; |
1499 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 1546 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
1547 | offset += memdev->header.length; | ||
1500 | 1548 | ||
1501 | /* mem-region2 (spa1, dimm0) */ | 1549 | /* mem-region2 (spa1, dimm0) */ |
1502 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 2; | 1550 | memdev = nfit_buf + offset; |
1503 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1551 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1504 | memdev->header.length = sizeof(*memdev); | 1552 | memdev->header.length = sizeof(*memdev); |
1505 | memdev->device_handle = handle[0]; | 1553 | memdev->device_handle = handle[0]; |
@@ -1513,9 +1561,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1513 | memdev->interleave_index = 0; | 1561 | memdev->interleave_index = 0; |
1514 | memdev->interleave_ways = 4; | 1562 | memdev->interleave_ways = 4; |
1515 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 1563 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
1564 | offset += memdev->header.length; | ||
1516 | 1565 | ||
1517 | /* mem-region3 (spa1, dimm1) */ | 1566 | /* mem-region3 (spa1, dimm1) */ |
1518 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 3; | 1567 | memdev = nfit_buf + offset; |
1519 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1568 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1520 | memdev->header.length = sizeof(*memdev); | 1569 | memdev->header.length = sizeof(*memdev); |
1521 | memdev->device_handle = handle[1]; | 1570 | memdev->device_handle = handle[1]; |
@@ -1528,9 +1577,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1528 | memdev->address = SPA0_SIZE/2; | 1577 | memdev->address = SPA0_SIZE/2; |
1529 | memdev->interleave_index = 0; | 1578 | memdev->interleave_index = 0; |
1530 | memdev->interleave_ways = 4; | 1579 | memdev->interleave_ways = 4; |
1580 | offset += memdev->header.length; | ||
1531 | 1581 | ||
1532 | /* mem-region4 (spa1, dimm2) */ | 1582 | /* mem-region4 (spa1, dimm2) */ |
1533 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 4; | 1583 | memdev = nfit_buf + offset; |
1534 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1584 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1535 | memdev->header.length = sizeof(*memdev); | 1585 | memdev->header.length = sizeof(*memdev); |
1536 | memdev->device_handle = handle[2]; | 1586 | memdev->device_handle = handle[2]; |
@@ -1544,9 +1594,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1544 | memdev->interleave_index = 0; | 1594 | memdev->interleave_index = 0; |
1545 | memdev->interleave_ways = 4; | 1595 | memdev->interleave_ways = 4; |
1546 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 1596 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
1597 | offset += memdev->header.length; | ||
1547 | 1598 | ||
1548 | /* mem-region5 (spa1, dimm3) */ | 1599 | /* mem-region5 (spa1, dimm3) */ |
1549 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 5; | 1600 | memdev = nfit_buf + offset; |
1550 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1601 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1551 | memdev->header.length = sizeof(*memdev); | 1602 | memdev->header.length = sizeof(*memdev); |
1552 | memdev->device_handle = handle[3]; | 1603 | memdev->device_handle = handle[3]; |
@@ -1559,9 +1610,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1559 | memdev->address = SPA0_SIZE/2; | 1610 | memdev->address = SPA0_SIZE/2; |
1560 | memdev->interleave_index = 0; | 1611 | memdev->interleave_index = 0; |
1561 | memdev->interleave_ways = 4; | 1612 | memdev->interleave_ways = 4; |
1613 | offset += memdev->header.length; | ||
1562 | 1614 | ||
1563 | /* mem-region6 (spa/dcr0, dimm0) */ | 1615 | /* mem-region6 (spa/dcr0, dimm0) */ |
1564 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 6; | 1616 | memdev = nfit_buf + offset; |
1565 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1617 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1566 | memdev->header.length = sizeof(*memdev); | 1618 | memdev->header.length = sizeof(*memdev); |
1567 | memdev->device_handle = handle[0]; | 1619 | memdev->device_handle = handle[0]; |
@@ -1574,9 +1626,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1574 | memdev->address = 0; | 1626 | memdev->address = 0; |
1575 | memdev->interleave_index = 0; | 1627 | memdev->interleave_index = 0; |
1576 | memdev->interleave_ways = 1; | 1628 | memdev->interleave_ways = 1; |
1629 | offset += memdev->header.length; | ||
1577 | 1630 | ||
1578 | /* mem-region7 (spa/dcr1, dimm1) */ | 1631 | /* mem-region7 (spa/dcr1, dimm1) */ |
1579 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 7; | 1632 | memdev = nfit_buf + offset; |
1580 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1633 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1581 | memdev->header.length = sizeof(*memdev); | 1634 | memdev->header.length = sizeof(*memdev); |
1582 | memdev->device_handle = handle[1]; | 1635 | memdev->device_handle = handle[1]; |
@@ -1589,9 +1642,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1589 | memdev->address = 0; | 1642 | memdev->address = 0; |
1590 | memdev->interleave_index = 0; | 1643 | memdev->interleave_index = 0; |
1591 | memdev->interleave_ways = 1; | 1644 | memdev->interleave_ways = 1; |
1645 | offset += memdev->header.length; | ||
1592 | 1646 | ||
1593 | /* mem-region8 (spa/dcr2, dimm2) */ | 1647 | /* mem-region8 (spa/dcr2, dimm2) */ |
1594 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 8; | 1648 | memdev = nfit_buf + offset; |
1595 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1649 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1596 | memdev->header.length = sizeof(*memdev); | 1650 | memdev->header.length = sizeof(*memdev); |
1597 | memdev->device_handle = handle[2]; | 1651 | memdev->device_handle = handle[2]; |
@@ -1604,9 +1658,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1604 | memdev->address = 0; | 1658 | memdev->address = 0; |
1605 | memdev->interleave_index = 0; | 1659 | memdev->interleave_index = 0; |
1606 | memdev->interleave_ways = 1; | 1660 | memdev->interleave_ways = 1; |
1661 | offset += memdev->header.length; | ||
1607 | 1662 | ||
1608 | /* mem-region9 (spa/dcr3, dimm3) */ | 1663 | /* mem-region9 (spa/dcr3, dimm3) */ |
1609 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 9; | 1664 | memdev = nfit_buf + offset; |
1610 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1665 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1611 | memdev->header.length = sizeof(*memdev); | 1666 | memdev->header.length = sizeof(*memdev); |
1612 | memdev->device_handle = handle[3]; | 1667 | memdev->device_handle = handle[3]; |
@@ -1619,9 +1674,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1619 | memdev->address = 0; | 1674 | memdev->address = 0; |
1620 | memdev->interleave_index = 0; | 1675 | memdev->interleave_index = 0; |
1621 | memdev->interleave_ways = 1; | 1676 | memdev->interleave_ways = 1; |
1677 | offset += memdev->header.length; | ||
1622 | 1678 | ||
1623 | /* mem-region10 (spa/bdw0, dimm0) */ | 1679 | /* mem-region10 (spa/bdw0, dimm0) */ |
1624 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 10; | 1680 | memdev = nfit_buf + offset; |
1625 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1681 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1626 | memdev->header.length = sizeof(*memdev); | 1682 | memdev->header.length = sizeof(*memdev); |
1627 | memdev->device_handle = handle[0]; | 1683 | memdev->device_handle = handle[0]; |
@@ -1634,9 +1690,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1634 | memdev->address = 0; | 1690 | memdev->address = 0; |
1635 | memdev->interleave_index = 0; | 1691 | memdev->interleave_index = 0; |
1636 | memdev->interleave_ways = 1; | 1692 | memdev->interleave_ways = 1; |
1693 | offset += memdev->header.length; | ||
1637 | 1694 | ||
1638 | /* mem-region11 (spa/bdw1, dimm1) */ | 1695 | /* mem-region11 (spa/bdw1, dimm1) */ |
1639 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 11; | 1696 | memdev = nfit_buf + offset; |
1640 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1697 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1641 | memdev->header.length = sizeof(*memdev); | 1698 | memdev->header.length = sizeof(*memdev); |
1642 | memdev->device_handle = handle[1]; | 1699 | memdev->device_handle = handle[1]; |
@@ -1649,9 +1706,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1649 | memdev->address = 0; | 1706 | memdev->address = 0; |
1650 | memdev->interleave_index = 0; | 1707 | memdev->interleave_index = 0; |
1651 | memdev->interleave_ways = 1; | 1708 | memdev->interleave_ways = 1; |
1709 | offset += memdev->header.length; | ||
1652 | 1710 | ||
1653 | /* mem-region12 (spa/bdw2, dimm2) */ | 1711 | /* mem-region12 (spa/bdw2, dimm2) */ |
1654 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 12; | 1712 | memdev = nfit_buf + offset; |
1655 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1713 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1656 | memdev->header.length = sizeof(*memdev); | 1714 | memdev->header.length = sizeof(*memdev); |
1657 | memdev->device_handle = handle[2]; | 1715 | memdev->device_handle = handle[2]; |
@@ -1664,9 +1722,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1664 | memdev->address = 0; | 1722 | memdev->address = 0; |
1665 | memdev->interleave_index = 0; | 1723 | memdev->interleave_index = 0; |
1666 | memdev->interleave_ways = 1; | 1724 | memdev->interleave_ways = 1; |
1725 | offset += memdev->header.length; | ||
1667 | 1726 | ||
1668 | /* mem-region13 (spa/dcr3, dimm3) */ | 1727 | /* mem-region13 (spa/dcr3, dimm3) */ |
1669 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 13; | 1728 | memdev = nfit_buf + offset; |
1670 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1729 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1671 | memdev->header.length = sizeof(*memdev); | 1730 | memdev->header.length = sizeof(*memdev); |
1672 | memdev->device_handle = handle[3]; | 1731 | memdev->device_handle = handle[3]; |
@@ -1680,12 +1739,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1680 | memdev->interleave_index = 0; | 1739 | memdev->interleave_index = 0; |
1681 | memdev->interleave_ways = 1; | 1740 | memdev->interleave_ways = 1; |
1682 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 1741 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
1742 | offset += memdev->header.length; | ||
1683 | 1743 | ||
1684 | offset = offset + sizeof(struct acpi_nfit_memory_map) * 14; | ||
1685 | /* dcr-descriptor0: blk */ | 1744 | /* dcr-descriptor0: blk */ |
1686 | dcr = nfit_buf + offset; | 1745 | dcr = nfit_buf + offset; |
1687 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1746 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1688 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1747 | dcr->header.length = sizeof(*dcr); |
1689 | dcr->region_index = 0+1; | 1748 | dcr->region_index = 0+1; |
1690 | dcr_common_init(dcr); | 1749 | dcr_common_init(dcr); |
1691 | dcr->serial_number = ~handle[0]; | 1750 | dcr->serial_number = ~handle[0]; |
@@ -1696,11 +1755,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1696 | dcr->command_size = 8; | 1755 | dcr->command_size = 8; |
1697 | dcr->status_offset = 8; | 1756 | dcr->status_offset = 8; |
1698 | dcr->status_size = 4; | 1757 | dcr->status_size = 4; |
1758 | offset += dcr->header.length; | ||
1699 | 1759 | ||
1700 | /* dcr-descriptor1: blk */ | 1760 | /* dcr-descriptor1: blk */ |
1701 | dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region); | 1761 | dcr = nfit_buf + offset; |
1702 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1762 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1703 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1763 | dcr->header.length = sizeof(*dcr); |
1704 | dcr->region_index = 1+1; | 1764 | dcr->region_index = 1+1; |
1705 | dcr_common_init(dcr); | 1765 | dcr_common_init(dcr); |
1706 | dcr->serial_number = ~handle[1]; | 1766 | dcr->serial_number = ~handle[1]; |
@@ -1711,11 +1771,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1711 | dcr->command_size = 8; | 1771 | dcr->command_size = 8; |
1712 | dcr->status_offset = 8; | 1772 | dcr->status_offset = 8; |
1713 | dcr->status_size = 4; | 1773 | dcr->status_size = 4; |
1774 | offset += dcr->header.length; | ||
1714 | 1775 | ||
1715 | /* dcr-descriptor2: blk */ | 1776 | /* dcr-descriptor2: blk */ |
1716 | dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region) * 2; | 1777 | dcr = nfit_buf + offset; |
1717 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1778 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1718 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1779 | dcr->header.length = sizeof(*dcr); |
1719 | dcr->region_index = 2+1; | 1780 | dcr->region_index = 2+1; |
1720 | dcr_common_init(dcr); | 1781 | dcr_common_init(dcr); |
1721 | dcr->serial_number = ~handle[2]; | 1782 | dcr->serial_number = ~handle[2]; |
@@ -1726,11 +1787,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1726 | dcr->command_size = 8; | 1787 | dcr->command_size = 8; |
1727 | dcr->status_offset = 8; | 1788 | dcr->status_offset = 8; |
1728 | dcr->status_size = 4; | 1789 | dcr->status_size = 4; |
1790 | offset += dcr->header.length; | ||
1729 | 1791 | ||
1730 | /* dcr-descriptor3: blk */ | 1792 | /* dcr-descriptor3: blk */ |
1731 | dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region) * 3; | 1793 | dcr = nfit_buf + offset; |
1732 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1794 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1733 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1795 | dcr->header.length = sizeof(*dcr); |
1734 | dcr->region_index = 3+1; | 1796 | dcr->region_index = 3+1; |
1735 | dcr_common_init(dcr); | 1797 | dcr_common_init(dcr); |
1736 | dcr->serial_number = ~handle[3]; | 1798 | dcr->serial_number = ~handle[3]; |
@@ -1741,8 +1803,8 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1741 | dcr->command_size = 8; | 1803 | dcr->command_size = 8; |
1742 | dcr->status_offset = 8; | 1804 | dcr->status_offset = 8; |
1743 | dcr->status_size = 4; | 1805 | dcr->status_size = 4; |
1806 | offset += dcr->header.length; | ||
1744 | 1807 | ||
1745 | offset = offset + sizeof(struct acpi_nfit_control_region) * 4; | ||
1746 | /* dcr-descriptor0: pmem */ | 1808 | /* dcr-descriptor0: pmem */ |
1747 | dcr = nfit_buf + offset; | 1809 | dcr = nfit_buf + offset; |
1748 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1810 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
@@ -1753,10 +1815,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1753 | dcr->serial_number = ~handle[0]; | 1815 | dcr->serial_number = ~handle[0]; |
1754 | dcr->code = NFIT_FIC_BYTEN; | 1816 | dcr->code = NFIT_FIC_BYTEN; |
1755 | dcr->windows = 0; | 1817 | dcr->windows = 0; |
1818 | offset += dcr->header.length; | ||
1756 | 1819 | ||
1757 | /* dcr-descriptor1: pmem */ | 1820 | /* dcr-descriptor1: pmem */ |
1758 | dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, | 1821 | dcr = nfit_buf + offset; |
1759 | window_size); | ||
1760 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1822 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1761 | dcr->header.length = offsetof(struct acpi_nfit_control_region, | 1823 | dcr->header.length = offsetof(struct acpi_nfit_control_region, |
1762 | window_size); | 1824 | window_size); |
@@ -1765,10 +1827,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1765 | dcr->serial_number = ~handle[1]; | 1827 | dcr->serial_number = ~handle[1]; |
1766 | dcr->code = NFIT_FIC_BYTEN; | 1828 | dcr->code = NFIT_FIC_BYTEN; |
1767 | dcr->windows = 0; | 1829 | dcr->windows = 0; |
1830 | offset += dcr->header.length; | ||
1768 | 1831 | ||
1769 | /* dcr-descriptor2: pmem */ | 1832 | /* dcr-descriptor2: pmem */ |
1770 | dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, | 1833 | dcr = nfit_buf + offset; |
1771 | window_size) * 2; | ||
1772 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1834 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1773 | dcr->header.length = offsetof(struct acpi_nfit_control_region, | 1835 | dcr->header.length = offsetof(struct acpi_nfit_control_region, |
1774 | window_size); | 1836 | window_size); |
@@ -1777,10 +1839,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1777 | dcr->serial_number = ~handle[2]; | 1839 | dcr->serial_number = ~handle[2]; |
1778 | dcr->code = NFIT_FIC_BYTEN; | 1840 | dcr->code = NFIT_FIC_BYTEN; |
1779 | dcr->windows = 0; | 1841 | dcr->windows = 0; |
1842 | offset += dcr->header.length; | ||
1780 | 1843 | ||
1781 | /* dcr-descriptor3: pmem */ | 1844 | /* dcr-descriptor3: pmem */ |
1782 | dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, | 1845 | dcr = nfit_buf + offset; |
1783 | window_size) * 3; | ||
1784 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1846 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1785 | dcr->header.length = offsetof(struct acpi_nfit_control_region, | 1847 | dcr->header.length = offsetof(struct acpi_nfit_control_region, |
1786 | window_size); | 1848 | window_size); |
@@ -1789,54 +1851,56 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1789 | dcr->serial_number = ~handle[3]; | 1851 | dcr->serial_number = ~handle[3]; |
1790 | dcr->code = NFIT_FIC_BYTEN; | 1852 | dcr->code = NFIT_FIC_BYTEN; |
1791 | dcr->windows = 0; | 1853 | dcr->windows = 0; |
1854 | offset += dcr->header.length; | ||
1792 | 1855 | ||
1793 | offset = offset + offsetof(struct acpi_nfit_control_region, | ||
1794 | window_size) * 4; | ||
1795 | /* bdw0 (spa/dcr0, dimm0) */ | 1856 | /* bdw0 (spa/dcr0, dimm0) */ |
1796 | bdw = nfit_buf + offset; | 1857 | bdw = nfit_buf + offset; |
1797 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1858 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1798 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1859 | bdw->header.length = sizeof(*bdw); |
1799 | bdw->region_index = 0+1; | 1860 | bdw->region_index = 0+1; |
1800 | bdw->windows = 1; | 1861 | bdw->windows = 1; |
1801 | bdw->offset = 0; | 1862 | bdw->offset = 0; |
1802 | bdw->size = BDW_SIZE; | 1863 | bdw->size = BDW_SIZE; |
1803 | bdw->capacity = DIMM_SIZE; | 1864 | bdw->capacity = DIMM_SIZE; |
1804 | bdw->start_address = 0; | 1865 | bdw->start_address = 0; |
1866 | offset += bdw->header.length; | ||
1805 | 1867 | ||
1806 | /* bdw1 (spa/dcr1, dimm1) */ | 1868 | /* bdw1 (spa/dcr1, dimm1) */ |
1807 | bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region); | 1869 | bdw = nfit_buf + offset; |
1808 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1870 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1809 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1871 | bdw->header.length = sizeof(*bdw); |
1810 | bdw->region_index = 1+1; | 1872 | bdw->region_index = 1+1; |
1811 | bdw->windows = 1; | 1873 | bdw->windows = 1; |
1812 | bdw->offset = 0; | 1874 | bdw->offset = 0; |
1813 | bdw->size = BDW_SIZE; | 1875 | bdw->size = BDW_SIZE; |
1814 | bdw->capacity = DIMM_SIZE; | 1876 | bdw->capacity = DIMM_SIZE; |
1815 | bdw->start_address = 0; | 1877 | bdw->start_address = 0; |
1878 | offset += bdw->header.length; | ||
1816 | 1879 | ||
1817 | /* bdw2 (spa/dcr2, dimm2) */ | 1880 | /* bdw2 (spa/dcr2, dimm2) */ |
1818 | bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region) * 2; | 1881 | bdw = nfit_buf + offset; |
1819 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1882 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1820 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1883 | bdw->header.length = sizeof(*bdw); |
1821 | bdw->region_index = 2+1; | 1884 | bdw->region_index = 2+1; |
1822 | bdw->windows = 1; | 1885 | bdw->windows = 1; |
1823 | bdw->offset = 0; | 1886 | bdw->offset = 0; |
1824 | bdw->size = BDW_SIZE; | 1887 | bdw->size = BDW_SIZE; |
1825 | bdw->capacity = DIMM_SIZE; | 1888 | bdw->capacity = DIMM_SIZE; |
1826 | bdw->start_address = 0; | 1889 | bdw->start_address = 0; |
1890 | offset += bdw->header.length; | ||
1827 | 1891 | ||
1828 | /* bdw3 (spa/dcr3, dimm3) */ | 1892 | /* bdw3 (spa/dcr3, dimm3) */ |
1829 | bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region) * 3; | 1893 | bdw = nfit_buf + offset; |
1830 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1894 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1831 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1895 | bdw->header.length = sizeof(*bdw); |
1832 | bdw->region_index = 3+1; | 1896 | bdw->region_index = 3+1; |
1833 | bdw->windows = 1; | 1897 | bdw->windows = 1; |
1834 | bdw->offset = 0; | 1898 | bdw->offset = 0; |
1835 | bdw->size = BDW_SIZE; | 1899 | bdw->size = BDW_SIZE; |
1836 | bdw->capacity = DIMM_SIZE; | 1900 | bdw->capacity = DIMM_SIZE; |
1837 | bdw->start_address = 0; | 1901 | bdw->start_address = 0; |
1902 | offset += bdw->header.length; | ||
1838 | 1903 | ||
1839 | offset = offset + sizeof(struct acpi_nfit_data_region) * 4; | ||
1840 | /* flush0 (dimm0) */ | 1904 | /* flush0 (dimm0) */ |
1841 | flush = nfit_buf + offset; | 1905 | flush = nfit_buf + offset; |
1842 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 1906 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
@@ -1845,48 +1909,52 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1845 | flush->hint_count = NUM_HINTS; | 1909 | flush->hint_count = NUM_HINTS; |
1846 | for (i = 0; i < NUM_HINTS; i++) | 1910 | for (i = 0; i < NUM_HINTS; i++) |
1847 | flush->hint_address[i] = t->flush_dma[0] + i * sizeof(u64); | 1911 | flush->hint_address[i] = t->flush_dma[0] + i * sizeof(u64); |
1912 | offset += flush->header.length; | ||
1848 | 1913 | ||
1849 | /* flush1 (dimm1) */ | 1914 | /* flush1 (dimm1) */ |
1850 | flush = nfit_buf + offset + flush_hint_size * 1; | 1915 | flush = nfit_buf + offset; |
1851 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 1916 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
1852 | flush->header.length = flush_hint_size; | 1917 | flush->header.length = flush_hint_size; |
1853 | flush->device_handle = handle[1]; | 1918 | flush->device_handle = handle[1]; |
1854 | flush->hint_count = NUM_HINTS; | 1919 | flush->hint_count = NUM_HINTS; |
1855 | for (i = 0; i < NUM_HINTS; i++) | 1920 | for (i = 0; i < NUM_HINTS; i++) |
1856 | flush->hint_address[i] = t->flush_dma[1] + i * sizeof(u64); | 1921 | flush->hint_address[i] = t->flush_dma[1] + i * sizeof(u64); |
1922 | offset += flush->header.length; | ||
1857 | 1923 | ||
1858 | /* flush2 (dimm2) */ | 1924 | /* flush2 (dimm2) */ |
1859 | flush = nfit_buf + offset + flush_hint_size * 2; | 1925 | flush = nfit_buf + offset; |
1860 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 1926 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
1861 | flush->header.length = flush_hint_size; | 1927 | flush->header.length = flush_hint_size; |
1862 | flush->device_handle = handle[2]; | 1928 | flush->device_handle = handle[2]; |
1863 | flush->hint_count = NUM_HINTS; | 1929 | flush->hint_count = NUM_HINTS; |
1864 | for (i = 0; i < NUM_HINTS; i++) | 1930 | for (i = 0; i < NUM_HINTS; i++) |
1865 | flush->hint_address[i] = t->flush_dma[2] + i * sizeof(u64); | 1931 | flush->hint_address[i] = t->flush_dma[2] + i * sizeof(u64); |
1932 | offset += flush->header.length; | ||
1866 | 1933 | ||
1867 | /* flush3 (dimm3) */ | 1934 | /* flush3 (dimm3) */ |
1868 | flush = nfit_buf + offset + flush_hint_size * 3; | 1935 | flush = nfit_buf + offset; |
1869 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 1936 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
1870 | flush->header.length = flush_hint_size; | 1937 | flush->header.length = flush_hint_size; |
1871 | flush->device_handle = handle[3]; | 1938 | flush->device_handle = handle[3]; |
1872 | flush->hint_count = NUM_HINTS; | 1939 | flush->hint_count = NUM_HINTS; |
1873 | for (i = 0; i < NUM_HINTS; i++) | 1940 | for (i = 0; i < NUM_HINTS; i++) |
1874 | flush->hint_address[i] = t->flush_dma[3] + i * sizeof(u64); | 1941 | flush->hint_address[i] = t->flush_dma[3] + i * sizeof(u64); |
1942 | offset += flush->header.length; | ||
1875 | 1943 | ||
1876 | /* platform capabilities */ | 1944 | /* platform capabilities */ |
1877 | pcap = nfit_buf + offset + flush_hint_size * 4; | 1945 | pcap = nfit_buf + offset; |
1878 | pcap->header.type = ACPI_NFIT_TYPE_CAPABILITIES; | 1946 | pcap->header.type = ACPI_NFIT_TYPE_CAPABILITIES; |
1879 | pcap->header.length = sizeof(*pcap); | 1947 | pcap->header.length = sizeof(*pcap); |
1880 | pcap->highest_capability = 1; | 1948 | pcap->highest_capability = 1; |
1881 | pcap->capabilities = ACPI_NFIT_CAPABILITY_CACHE_FLUSH | | 1949 | pcap->capabilities = ACPI_NFIT_CAPABILITY_CACHE_FLUSH | |
1882 | ACPI_NFIT_CAPABILITY_MEM_FLUSH; | 1950 | ACPI_NFIT_CAPABILITY_MEM_FLUSH; |
1951 | offset += pcap->header.length; | ||
1883 | 1952 | ||
1884 | if (t->setup_hotplug) { | 1953 | if (t->setup_hotplug) { |
1885 | offset = offset + flush_hint_size * 4 + sizeof(*pcap); | ||
1886 | /* dcr-descriptor4: blk */ | 1954 | /* dcr-descriptor4: blk */ |
1887 | dcr = nfit_buf + offset; | 1955 | dcr = nfit_buf + offset; |
1888 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1956 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1889 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1957 | dcr->header.length = sizeof(*dcr); |
1890 | dcr->region_index = 8+1; | 1958 | dcr->region_index = 8+1; |
1891 | dcr_common_init(dcr); | 1959 | dcr_common_init(dcr); |
1892 | dcr->serial_number = ~handle[4]; | 1960 | dcr->serial_number = ~handle[4]; |
@@ -1897,8 +1965,8 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1897 | dcr->command_size = 8; | 1965 | dcr->command_size = 8; |
1898 | dcr->status_offset = 8; | 1966 | dcr->status_offset = 8; |
1899 | dcr->status_size = 4; | 1967 | dcr->status_size = 4; |
1968 | offset += dcr->header.length; | ||
1900 | 1969 | ||
1901 | offset = offset + sizeof(struct acpi_nfit_control_region); | ||
1902 | /* dcr-descriptor4: pmem */ | 1970 | /* dcr-descriptor4: pmem */ |
1903 | dcr = nfit_buf + offset; | 1971 | dcr = nfit_buf + offset; |
1904 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1972 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
@@ -1909,21 +1977,20 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1909 | dcr->serial_number = ~handle[4]; | 1977 | dcr->serial_number = ~handle[4]; |
1910 | dcr->code = NFIT_FIC_BYTEN; | 1978 | dcr->code = NFIT_FIC_BYTEN; |
1911 | dcr->windows = 0; | 1979 | dcr->windows = 0; |
1980 | offset += dcr->header.length; | ||
1912 | 1981 | ||
1913 | offset = offset + offsetof(struct acpi_nfit_control_region, | ||
1914 | window_size); | ||
1915 | /* bdw4 (spa/dcr4, dimm4) */ | 1982 | /* bdw4 (spa/dcr4, dimm4) */ |
1916 | bdw = nfit_buf + offset; | 1983 | bdw = nfit_buf + offset; |
1917 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1984 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1918 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1985 | bdw->header.length = sizeof(*bdw); |
1919 | bdw->region_index = 8+1; | 1986 | bdw->region_index = 8+1; |
1920 | bdw->windows = 1; | 1987 | bdw->windows = 1; |
1921 | bdw->offset = 0; | 1988 | bdw->offset = 0; |
1922 | bdw->size = BDW_SIZE; | 1989 | bdw->size = BDW_SIZE; |
1923 | bdw->capacity = DIMM_SIZE; | 1990 | bdw->capacity = DIMM_SIZE; |
1924 | bdw->start_address = 0; | 1991 | bdw->start_address = 0; |
1992 | offset += bdw->header.length; | ||
1925 | 1993 | ||
1926 | offset = offset + sizeof(struct acpi_nfit_data_region); | ||
1927 | /* spa10 (dcr4) dimm4 */ | 1994 | /* spa10 (dcr4) dimm4 */ |
1928 | spa = nfit_buf + offset; | 1995 | spa = nfit_buf + offset; |
1929 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1996 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
@@ -1932,30 +1999,32 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1932 | spa->range_index = 10+1; | 1999 | spa->range_index = 10+1; |
1933 | spa->address = t->dcr_dma[4]; | 2000 | spa->address = t->dcr_dma[4]; |
1934 | spa->length = DCR_SIZE; | 2001 | spa->length = DCR_SIZE; |
2002 | offset += spa->header.length; | ||
1935 | 2003 | ||
1936 | /* | 2004 | /* |
1937 | * spa11 (single-dimm interleave for hotplug, note storage | 2005 | * spa11 (single-dimm interleave for hotplug, note storage |
1938 | * does not actually alias the related block-data-window | 2006 | * does not actually alias the related block-data-window |
1939 | * regions) | 2007 | * regions) |
1940 | */ | 2008 | */ |
1941 | spa = nfit_buf + offset + sizeof(*spa); | 2009 | spa = nfit_buf + offset; |
1942 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 2010 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1943 | spa->header.length = sizeof(*spa); | 2011 | spa->header.length = sizeof(*spa); |
1944 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); | 2012 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); |
1945 | spa->range_index = 11+1; | 2013 | spa->range_index = 11+1; |
1946 | spa->address = t->spa_set_dma[2]; | 2014 | spa->address = t->spa_set_dma[2]; |
1947 | spa->length = SPA0_SIZE; | 2015 | spa->length = SPA0_SIZE; |
2016 | offset += spa->header.length; | ||
1948 | 2017 | ||
1949 | /* spa12 (bdw for dcr4) dimm4 */ | 2018 | /* spa12 (bdw for dcr4) dimm4 */ |
1950 | spa = nfit_buf + offset + sizeof(*spa) * 2; | 2019 | spa = nfit_buf + offset; |
1951 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 2020 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1952 | spa->header.length = sizeof(*spa); | 2021 | spa->header.length = sizeof(*spa); |
1953 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 2022 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1954 | spa->range_index = 12+1; | 2023 | spa->range_index = 12+1; |
1955 | spa->address = t->dimm_dma[4]; | 2024 | spa->address = t->dimm_dma[4]; |
1956 | spa->length = DIMM_SIZE; | 2025 | spa->length = DIMM_SIZE; |
2026 | offset += spa->header.length; | ||
1957 | 2027 | ||
1958 | offset = offset + sizeof(*spa) * 3; | ||
1959 | /* mem-region14 (spa/dcr4, dimm4) */ | 2028 | /* mem-region14 (spa/dcr4, dimm4) */ |
1960 | memdev = nfit_buf + offset; | 2029 | memdev = nfit_buf + offset; |
1961 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2030 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
@@ -1970,10 +2039,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1970 | memdev->address = 0; | 2039 | memdev->address = 0; |
1971 | memdev->interleave_index = 0; | 2040 | memdev->interleave_index = 0; |
1972 | memdev->interleave_ways = 1; | 2041 | memdev->interleave_ways = 1; |
2042 | offset += memdev->header.length; | ||
1973 | 2043 | ||
1974 | /* mem-region15 (spa0, dimm4) */ | 2044 | /* mem-region15 (spa11, dimm4) */ |
1975 | memdev = nfit_buf + offset + | 2045 | memdev = nfit_buf + offset; |
1976 | sizeof(struct acpi_nfit_memory_map); | ||
1977 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2046 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1978 | memdev->header.length = sizeof(*memdev); | 2047 | memdev->header.length = sizeof(*memdev); |
1979 | memdev->device_handle = handle[4]; | 2048 | memdev->device_handle = handle[4]; |
@@ -1987,10 +2056,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1987 | memdev->interleave_index = 0; | 2056 | memdev->interleave_index = 0; |
1988 | memdev->interleave_ways = 1; | 2057 | memdev->interleave_ways = 1; |
1989 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 2058 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
2059 | offset += memdev->header.length; | ||
1990 | 2060 | ||
1991 | /* mem-region16 (spa/bdw4, dimm4) */ | 2061 | /* mem-region16 (spa/bdw4, dimm4) */ |
1992 | memdev = nfit_buf + offset + | 2062 | memdev = nfit_buf + offset; |
1993 | sizeof(struct acpi_nfit_memory_map) * 2; | ||
1994 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2063 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1995 | memdev->header.length = sizeof(*memdev); | 2064 | memdev->header.length = sizeof(*memdev); |
1996 | memdev->device_handle = handle[4]; | 2065 | memdev->device_handle = handle[4]; |
@@ -2003,8 +2072,8 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
2003 | memdev->address = 0; | 2072 | memdev->address = 0; |
2004 | memdev->interleave_index = 0; | 2073 | memdev->interleave_index = 0; |
2005 | memdev->interleave_ways = 1; | 2074 | memdev->interleave_ways = 1; |
2075 | offset += memdev->header.length; | ||
2006 | 2076 | ||
2007 | offset = offset + sizeof(struct acpi_nfit_memory_map) * 3; | ||
2008 | /* flush3 (dimm4) */ | 2077 | /* flush3 (dimm4) */ |
2009 | flush = nfit_buf + offset; | 2078 | flush = nfit_buf + offset; |
2010 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 2079 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
@@ -2014,8 +2083,14 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
2014 | for (i = 0; i < NUM_HINTS; i++) | 2083 | for (i = 0; i < NUM_HINTS; i++) |
2015 | flush->hint_address[i] = t->flush_dma[4] | 2084 | flush->hint_address[i] = t->flush_dma[4] |
2016 | + i * sizeof(u64); | 2085 | + i * sizeof(u64); |
2086 | offset += flush->header.length; | ||
2087 | |||
2088 | /* sanity check to make sure we've filled the buffer */ | ||
2089 | WARN_ON(offset != t->nfit_size); | ||
2017 | } | 2090 | } |
2018 | 2091 | ||
2092 | t->nfit_filled = offset; | ||
2093 | |||
2019 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], | 2094 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], |
2020 | SPA0_SIZE); | 2095 | SPA0_SIZE); |
2021 | 2096 | ||
@@ -2026,6 +2101,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
2026 | set_bit(ND_INTEL_SMART, &acpi_desc->dimm_cmd_force_en); | 2101 | set_bit(ND_INTEL_SMART, &acpi_desc->dimm_cmd_force_en); |
2027 | set_bit(ND_INTEL_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | 2102 | set_bit(ND_INTEL_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); |
2028 | set_bit(ND_INTEL_SMART_SET_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | 2103 | set_bit(ND_INTEL_SMART_SET_THRESHOLD, &acpi_desc->dimm_cmd_force_en); |
2104 | set_bit(ND_INTEL_SMART_INJECT, &acpi_desc->dimm_cmd_force_en); | ||
2029 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); | 2105 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); |
2030 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); | 2106 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
2031 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); | 2107 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
@@ -2061,17 +2137,18 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2061 | spa->range_index = 0+1; | 2137 | spa->range_index = 0+1; |
2062 | spa->address = t->spa_set_dma[0]; | 2138 | spa->address = t->spa_set_dma[0]; |
2063 | spa->length = SPA2_SIZE; | 2139 | spa->length = SPA2_SIZE; |
2140 | offset += spa->header.length; | ||
2064 | 2141 | ||
2065 | /* virtual cd region */ | 2142 | /* virtual cd region */ |
2066 | spa = nfit_buf + sizeof(*spa); | 2143 | spa = nfit_buf + offset; |
2067 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 2144 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
2068 | spa->header.length = sizeof(*spa); | 2145 | spa->header.length = sizeof(*spa); |
2069 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_VCD), 16); | 2146 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_VCD), 16); |
2070 | spa->range_index = 0; | 2147 | spa->range_index = 0; |
2071 | spa->address = t->spa_set_dma[1]; | 2148 | spa->address = t->spa_set_dma[1]; |
2072 | spa->length = SPA_VCD_SIZE; | 2149 | spa->length = SPA_VCD_SIZE; |
2150 | offset += spa->header.length; | ||
2073 | 2151 | ||
2074 | offset += sizeof(*spa) * 2; | ||
2075 | /* mem-region0 (spa0, dimm0) */ | 2152 | /* mem-region0 (spa0, dimm0) */ |
2076 | memdev = nfit_buf + offset; | 2153 | memdev = nfit_buf + offset; |
2077 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2154 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
@@ -2089,8 +2166,8 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2089 | memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED | 2166 | memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED |
2090 | | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED | 2167 | | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED |
2091 | | ACPI_NFIT_MEM_NOT_ARMED; | 2168 | | ACPI_NFIT_MEM_NOT_ARMED; |
2169 | offset += memdev->header.length; | ||
2092 | 2170 | ||
2093 | offset += sizeof(*memdev); | ||
2094 | /* dcr-descriptor0 */ | 2171 | /* dcr-descriptor0 */ |
2095 | dcr = nfit_buf + offset; | 2172 | dcr = nfit_buf + offset; |
2096 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 2173 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
@@ -2101,8 +2178,8 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2101 | dcr->serial_number = ~handle[5]; | 2178 | dcr->serial_number = ~handle[5]; |
2102 | dcr->code = NFIT_FIC_BYTE; | 2179 | dcr->code = NFIT_FIC_BYTE; |
2103 | dcr->windows = 0; | 2180 | dcr->windows = 0; |
2104 | |||
2105 | offset += dcr->header.length; | 2181 | offset += dcr->header.length; |
2182 | |||
2106 | memdev = nfit_buf + offset; | 2183 | memdev = nfit_buf + offset; |
2107 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2184 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
2108 | memdev->header.length = sizeof(*memdev); | 2185 | memdev->header.length = sizeof(*memdev); |
@@ -2117,9 +2194,9 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2117 | memdev->interleave_index = 0; | 2194 | memdev->interleave_index = 0; |
2118 | memdev->interleave_ways = 1; | 2195 | memdev->interleave_ways = 1; |
2119 | memdev->flags = ACPI_NFIT_MEM_MAP_FAILED; | 2196 | memdev->flags = ACPI_NFIT_MEM_MAP_FAILED; |
2197 | offset += memdev->header.length; | ||
2120 | 2198 | ||
2121 | /* dcr-descriptor1 */ | 2199 | /* dcr-descriptor1 */ |
2122 | offset += sizeof(*memdev); | ||
2123 | dcr = nfit_buf + offset; | 2200 | dcr = nfit_buf + offset; |
2124 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 2201 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
2125 | dcr->header.length = offsetof(struct acpi_nfit_control_region, | 2202 | dcr->header.length = offsetof(struct acpi_nfit_control_region, |
@@ -2129,6 +2206,12 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2129 | dcr->serial_number = ~handle[6]; | 2206 | dcr->serial_number = ~handle[6]; |
2130 | dcr->code = NFIT_FIC_BYTE; | 2207 | dcr->code = NFIT_FIC_BYTE; |
2131 | dcr->windows = 0; | 2208 | dcr->windows = 0; |
2209 | offset += dcr->header.length; | ||
2210 | |||
2211 | /* sanity check to make sure we've filled the buffer */ | ||
2212 | WARN_ON(offset != t->nfit_size); | ||
2213 | |||
2214 | t->nfit_filled = offset; | ||
2132 | 2215 | ||
2133 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], | 2216 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], |
2134 | SPA2_SIZE); | 2217 | SPA2_SIZE); |
@@ -2487,7 +2570,7 @@ static int nfit_test_probe(struct platform_device *pdev) | |||
2487 | nd_desc->ndctl = nfit_test_ctl; | 2570 | nd_desc->ndctl = nfit_test_ctl; |
2488 | 2571 | ||
2489 | rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf, | 2572 | rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf, |
2490 | nfit_test->nfit_size); | 2573 | nfit_test->nfit_filled); |
2491 | if (rc) | 2574 | if (rc) |
2492 | return rc; | 2575 | return rc; |
2493 | 2576 | ||
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index 428344519cdf..33752e06ff8d 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h | |||
@@ -93,6 +93,7 @@ struct nd_cmd_ars_err_inj_stat { | |||
93 | #define ND_INTEL_FW_FINISH_UPDATE 15 | 93 | #define ND_INTEL_FW_FINISH_UPDATE 15 |
94 | #define ND_INTEL_FW_FINISH_QUERY 16 | 94 | #define ND_INTEL_FW_FINISH_QUERY 16 |
95 | #define ND_INTEL_SMART_SET_THRESHOLD 17 | 95 | #define ND_INTEL_SMART_SET_THRESHOLD 17 |
96 | #define ND_INTEL_SMART_INJECT 18 | ||
96 | 97 | ||
97 | #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) | 98 | #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) |
98 | #define ND_INTEL_SMART_SPARES_VALID (1 << 1) | 99 | #define ND_INTEL_SMART_SPARES_VALID (1 << 1) |
@@ -111,6 +112,10 @@ struct nd_cmd_ars_err_inj_stat { | |||
111 | #define ND_INTEL_SMART_NON_CRITICAL_HEALTH (1 << 0) | 112 | #define ND_INTEL_SMART_NON_CRITICAL_HEALTH (1 << 0) |
112 | #define ND_INTEL_SMART_CRITICAL_HEALTH (1 << 1) | 113 | #define ND_INTEL_SMART_CRITICAL_HEALTH (1 << 1) |
113 | #define ND_INTEL_SMART_FATAL_HEALTH (1 << 2) | 114 | #define ND_INTEL_SMART_FATAL_HEALTH (1 << 2) |
115 | #define ND_INTEL_SMART_INJECT_MTEMP (1 << 0) | ||
116 | #define ND_INTEL_SMART_INJECT_SPARE (1 << 1) | ||
117 | #define ND_INTEL_SMART_INJECT_FATAL (1 << 2) | ||
118 | #define ND_INTEL_SMART_INJECT_SHUTDOWN (1 << 3) | ||
114 | 119 | ||
115 | struct nd_intel_smart { | 120 | struct nd_intel_smart { |
116 | __u32 status; | 121 | __u32 status; |
@@ -158,6 +163,17 @@ struct nd_intel_smart_set_threshold { | |||
158 | __u32 status; | 163 | __u32 status; |
159 | } __packed; | 164 | } __packed; |
160 | 165 | ||
166 | struct nd_intel_smart_inject { | ||
167 | __u64 flags; | ||
168 | __u8 mtemp_enable; | ||
169 | __u16 media_temperature; | ||
170 | __u8 spare_enable; | ||
171 | __u8 spares; | ||
172 | __u8 fatal_enable; | ||
173 | __u8 unsafe_shutdown_enable; | ||
174 | __u32 status; | ||
175 | } __packed; | ||
176 | |||
161 | #define INTEL_FW_STORAGE_SIZE 0x100000 | 177 | #define INTEL_FW_STORAGE_SIZE 0x100000 |
162 | #define INTEL_FW_MAX_SEND_LEN 0xFFEC | 178 | #define INTEL_FW_MAX_SEND_LEN 0xFFEC |
163 | #define INTEL_FW_QUERY_INTERVAL 250000 | 179 | #define INTEL_FW_QUERY_INTERVAL 250000 |