diff options
| -rw-r--r-- | .mailmap | 1 | ||||
| -rw-r--r-- | MAINTAINERS | 13 | ||||
| -rw-r--r-- | drivers/acpi/nfit/core.c | 24 | ||||
| -rw-r--r-- | drivers/acpi/nfit/nfit.h | 1 | ||||
| -rw-r--r-- | drivers/dax/pmem.c | 12 | ||||
| -rw-r--r-- | drivers/dax/super.c | 3 | ||||
| -rw-r--r-- | drivers/md/dm-writecache.c | 3 | ||||
| -rw-r--r-- | drivers/nvdimm/bus.c | 4 | ||||
| -rw-r--r-- | drivers/nvdimm/dimm.c | 24 | ||||
| -rw-r--r-- | drivers/nvdimm/dimm_devs.c | 31 | ||||
| -rw-r--r-- | drivers/nvdimm/namespace_devs.c | 29 | ||||
| -rw-r--r-- | drivers/nvdimm/nd-core.h | 8 | ||||
| -rw-r--r-- | drivers/nvdimm/nd.h | 1 | ||||
| -rw-r--r-- | drivers/nvdimm/pmem.c | 7 | ||||
| -rw-r--r-- | drivers/nvdimm/region_devs.c | 40 | ||||
| -rw-r--r-- | drivers/s390/block/dcssblk.c | 8 | ||||
| -rw-r--r-- | fs/dax.c | 13 | ||||
| -rw-r--r-- | tools/testing/nvdimm/pmem-dax.c | 12 | ||||
| -rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 126 |
19 files changed, 270 insertions, 90 deletions
| @@ -159,6 +159,7 @@ Ralf Wildenhues <Ralf.Wildenhues@gmx.de> | |||
| 159 | Randy Dunlap <rdunlap@infradead.org> <rdunlap@xenotime.net> | 159 | Randy Dunlap <rdunlap@infradead.org> <rdunlap@xenotime.net> |
| 160 | Rémi Denis-Courmont <rdenis@simphalempin.com> | 160 | Rémi Denis-Courmont <rdenis@simphalempin.com> |
| 161 | Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> | 161 | Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> |
| 162 | Ross Zwisler <zwisler@kernel.org> <ross.zwisler@linux.intel.com> | ||
| 162 | Rudolf Marek <R.Marek@sh.cvut.cz> | 163 | Rudolf Marek <R.Marek@sh.cvut.cz> |
| 163 | Rui Saraiva <rmps@joel.ist.utl.pt> | 164 | Rui Saraiva <rmps@joel.ist.utl.pt> |
| 164 | Sachin P Sant <ssant@in.ibm.com> | 165 | Sachin P Sant <ssant@in.ibm.com> |
diff --git a/MAINTAINERS b/MAINTAINERS index e20e7c42347b..a5b256b25905 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -4364,7 +4364,8 @@ F: drivers/i2c/busses/i2c-diolan-u2c.c | |||
| 4364 | 4364 | ||
| 4365 | FILESYSTEM DIRECT ACCESS (DAX) | 4365 | FILESYSTEM DIRECT ACCESS (DAX) |
| 4366 | M: Matthew Wilcox <mawilcox@microsoft.com> | 4366 | M: Matthew Wilcox <mawilcox@microsoft.com> |
| 4367 | M: Ross Zwisler <ross.zwisler@linux.intel.com> | 4367 | M: Ross Zwisler <zwisler@kernel.org> |
| 4368 | M: Jan Kara <jack@suse.cz> | ||
| 4368 | L: linux-fsdevel@vger.kernel.org | 4369 | L: linux-fsdevel@vger.kernel.org |
| 4369 | S: Supported | 4370 | S: Supported |
| 4370 | F: fs/dax.c | 4371 | F: fs/dax.c |
| @@ -4374,7 +4375,7 @@ F: include/trace/events/fs_dax.h | |||
| 4374 | DEVICE DIRECT ACCESS (DAX) | 4375 | DEVICE DIRECT ACCESS (DAX) |
| 4375 | M: Dan Williams <dan.j.williams@intel.com> | 4376 | M: Dan Williams <dan.j.williams@intel.com> |
| 4376 | M: Dave Jiang <dave.jiang@intel.com> | 4377 | M: Dave Jiang <dave.jiang@intel.com> |
| 4377 | M: Ross Zwisler <ross.zwisler@linux.intel.com> | 4378 | M: Ross Zwisler <zwisler@kernel.org> |
| 4378 | M: Vishal Verma <vishal.l.verma@intel.com> | 4379 | M: Vishal Verma <vishal.l.verma@intel.com> |
| 4379 | L: linux-nvdimm@lists.01.org | 4380 | L: linux-nvdimm@lists.01.org |
| 4380 | S: Supported | 4381 | S: Supported |
| @@ -8303,7 +8304,7 @@ S: Maintained | |||
| 8303 | F: tools/lib/lockdep/ | 8304 | F: tools/lib/lockdep/ |
| 8304 | 8305 | ||
| 8305 | LIBNVDIMM BLK: MMIO-APERTURE DRIVER | 8306 | LIBNVDIMM BLK: MMIO-APERTURE DRIVER |
| 8306 | M: Ross Zwisler <ross.zwisler@linux.intel.com> | 8307 | M: Ross Zwisler <zwisler@kernel.org> |
| 8307 | M: Dan Williams <dan.j.williams@intel.com> | 8308 | M: Dan Williams <dan.j.williams@intel.com> |
| 8308 | M: Vishal Verma <vishal.l.verma@intel.com> | 8309 | M: Vishal Verma <vishal.l.verma@intel.com> |
| 8309 | M: Dave Jiang <dave.jiang@intel.com> | 8310 | M: Dave Jiang <dave.jiang@intel.com> |
| @@ -8316,7 +8317,7 @@ F: drivers/nvdimm/region_devs.c | |||
| 8316 | LIBNVDIMM BTT: BLOCK TRANSLATION TABLE | 8317 | LIBNVDIMM BTT: BLOCK TRANSLATION TABLE |
| 8317 | M: Vishal Verma <vishal.l.verma@intel.com> | 8318 | M: Vishal Verma <vishal.l.verma@intel.com> |
| 8318 | M: Dan Williams <dan.j.williams@intel.com> | 8319 | M: Dan Williams <dan.j.williams@intel.com> |
| 8319 | M: Ross Zwisler <ross.zwisler@linux.intel.com> | 8320 | M: Ross Zwisler <zwisler@kernel.org> |
| 8320 | M: Dave Jiang <dave.jiang@intel.com> | 8321 | M: Dave Jiang <dave.jiang@intel.com> |
| 8321 | L: linux-nvdimm@lists.01.org | 8322 | L: linux-nvdimm@lists.01.org |
| 8322 | Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ | 8323 | Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ |
| @@ -8324,7 +8325,7 @@ S: Supported | |||
| 8324 | F: drivers/nvdimm/btt* | 8325 | F: drivers/nvdimm/btt* |
| 8325 | 8326 | ||
| 8326 | LIBNVDIMM PMEM: PERSISTENT MEMORY DRIVER | 8327 | LIBNVDIMM PMEM: PERSISTENT MEMORY DRIVER |
| 8327 | M: Ross Zwisler <ross.zwisler@linux.intel.com> | 8328 | M: Ross Zwisler <zwisler@kernel.org> |
| 8328 | M: Dan Williams <dan.j.williams@intel.com> | 8329 | M: Dan Williams <dan.j.williams@intel.com> |
| 8329 | M: Vishal Verma <vishal.l.verma@intel.com> | 8330 | M: Vishal Verma <vishal.l.verma@intel.com> |
| 8330 | M: Dave Jiang <dave.jiang@intel.com> | 8331 | M: Dave Jiang <dave.jiang@intel.com> |
| @@ -8343,7 +8344,7 @@ F: Documentation/devicetree/bindings/pmem/pmem-region.txt | |||
| 8343 | 8344 | ||
| 8344 | LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM | 8345 | LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM |
| 8345 | M: Dan Williams <dan.j.williams@intel.com> | 8346 | M: Dan Williams <dan.j.williams@intel.com> |
| 8346 | M: Ross Zwisler <ross.zwisler@linux.intel.com> | 8347 | M: Ross Zwisler <zwisler@kernel.org> |
| 8347 | M: Vishal Verma <vishal.l.verma@intel.com> | 8348 | M: Vishal Verma <vishal.l.verma@intel.com> |
| 8348 | M: Dave Jiang <dave.jiang@intel.com> | 8349 | M: Dave Jiang <dave.jiang@intel.com> |
| 8349 | L: linux-nvdimm@lists.01.org | 8350 | L: linux-nvdimm@lists.01.org |
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 7c479002e798..b072cfc5f20e 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
| @@ -1699,7 +1699,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
| 1699 | { | 1699 | { |
| 1700 | struct acpi_device *adev, *adev_dimm; | 1700 | struct acpi_device *adev, *adev_dimm; |
| 1701 | struct device *dev = acpi_desc->dev; | 1701 | struct device *dev = acpi_desc->dev; |
| 1702 | unsigned long dsm_mask; | 1702 | unsigned long dsm_mask, label_mask; |
| 1703 | const guid_t *guid; | 1703 | const guid_t *guid; |
| 1704 | int i; | 1704 | int i; |
| 1705 | int family = -1; | 1705 | int family = -1; |
| @@ -1771,6 +1771,16 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
| 1771 | 1ULL << i)) | 1771 | 1ULL << i)) |
| 1772 | set_bit(i, &nfit_mem->dsm_mask); | 1772 | set_bit(i, &nfit_mem->dsm_mask); |
| 1773 | 1773 | ||
| 1774 | /* | ||
| 1775 | * Prefer the NVDIMM_FAMILY_INTEL label read commands if present | ||
| 1776 | * due to their better semantics handling locked capacity. | ||
| 1777 | */ | ||
| 1778 | label_mask = 1 << ND_CMD_GET_CONFIG_SIZE | 1 << ND_CMD_GET_CONFIG_DATA | ||
| 1779 | | 1 << ND_CMD_SET_CONFIG_DATA; | ||
| 1780 | if (family == NVDIMM_FAMILY_INTEL | ||
| 1781 | && (dsm_mask & label_mask) == label_mask) | ||
| 1782 | return 0; | ||
| 1783 | |||
| 1774 | if (acpi_nvdimm_has_method(adev_dimm, "_LSI") | 1784 | if (acpi_nvdimm_has_method(adev_dimm, "_LSI") |
| 1775 | && acpi_nvdimm_has_method(adev_dimm, "_LSR")) { | 1785 | && acpi_nvdimm_has_method(adev_dimm, "_LSR")) { |
| 1776 | dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev)); | 1786 | dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev)); |
| @@ -2559,7 +2569,12 @@ static void ars_complete(struct acpi_nfit_desc *acpi_desc, | |||
| 2559 | test_bit(ARS_SHORT, &nfit_spa->ars_state) | 2569 | test_bit(ARS_SHORT, &nfit_spa->ars_state) |
| 2560 | ? "short" : "long"); | 2570 | ? "short" : "long"); |
| 2561 | clear_bit(ARS_SHORT, &nfit_spa->ars_state); | 2571 | clear_bit(ARS_SHORT, &nfit_spa->ars_state); |
| 2562 | set_bit(ARS_DONE, &nfit_spa->ars_state); | 2572 | if (test_and_clear_bit(ARS_REQ_REDO, &nfit_spa->ars_state)) { |
| 2573 | set_bit(ARS_SHORT, &nfit_spa->ars_state); | ||
| 2574 | set_bit(ARS_REQ, &nfit_spa->ars_state); | ||
| 2575 | dev_dbg(dev, "ARS: processing scrub request received while in progress\n"); | ||
| 2576 | } else | ||
| 2577 | set_bit(ARS_DONE, &nfit_spa->ars_state); | ||
| 2563 | } | 2578 | } |
| 2564 | 2579 | ||
| 2565 | static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc) | 2580 | static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc) |
| @@ -3256,9 +3271,10 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags) | |||
| 3256 | if (test_bit(ARS_FAILED, &nfit_spa->ars_state)) | 3271 | if (test_bit(ARS_FAILED, &nfit_spa->ars_state)) |
| 3257 | continue; | 3272 | continue; |
| 3258 | 3273 | ||
| 3259 | if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state)) | 3274 | if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state)) { |
| 3260 | busy++; | 3275 | busy++; |
| 3261 | else { | 3276 | set_bit(ARS_REQ_REDO, &nfit_spa->ars_state); |
| 3277 | } else { | ||
| 3262 | if (test_bit(ARS_SHORT, &flags)) | 3278 | if (test_bit(ARS_SHORT, &flags)) |
| 3263 | set_bit(ARS_SHORT, &nfit_spa->ars_state); | 3279 | set_bit(ARS_SHORT, &nfit_spa->ars_state); |
| 3264 | scheduled++; | 3280 | scheduled++; |
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index a97ff42fe311..d1274ea2d251 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h | |||
| @@ -119,6 +119,7 @@ enum nfit_dimm_notifiers { | |||
| 119 | 119 | ||
| 120 | enum nfit_ars_state { | 120 | enum nfit_ars_state { |
| 121 | ARS_REQ, | 121 | ARS_REQ, |
| 122 | ARS_REQ_REDO, | ||
| 122 | ARS_DONE, | 123 | ARS_DONE, |
| 123 | ARS_SHORT, | 124 | ARS_SHORT, |
| 124 | ARS_FAILED, | 125 | ARS_FAILED, |
diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index fd49b24fd6af..99e2aace8078 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c | |||
| @@ -105,15 +105,19 @@ static int dax_pmem_probe(struct device *dev) | |||
| 105 | if (rc) | 105 | if (rc) |
| 106 | return rc; | 106 | return rc; |
| 107 | 107 | ||
| 108 | rc = devm_add_action_or_reset(dev, dax_pmem_percpu_exit, | 108 | rc = devm_add_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref); |
| 109 | &dax_pmem->ref); | 109 | if (rc) { |
| 110 | if (rc) | 110 | percpu_ref_exit(&dax_pmem->ref); |
| 111 | return rc; | 111 | return rc; |
| 112 | } | ||
| 112 | 113 | ||
| 113 | dax_pmem->pgmap.ref = &dax_pmem->ref; | 114 | dax_pmem->pgmap.ref = &dax_pmem->ref; |
| 114 | addr = devm_memremap_pages(dev, &dax_pmem->pgmap); | 115 | addr = devm_memremap_pages(dev, &dax_pmem->pgmap); |
| 115 | if (IS_ERR(addr)) | 116 | if (IS_ERR(addr)) { |
| 117 | devm_remove_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref); | ||
| 118 | percpu_ref_exit(&dax_pmem->ref); | ||
| 116 | return PTR_ERR(addr); | 119 | return PTR_ERR(addr); |
| 120 | } | ||
| 117 | 121 | ||
| 118 | rc = devm_add_action_or_reset(dev, dax_pmem_percpu_kill, | 122 | rc = devm_add_action_or_reset(dev, dax_pmem_percpu_kill, |
| 119 | &dax_pmem->ref); | 123 | &dax_pmem->ref); |
diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 45276abf03aa..6e928f37d084 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c | |||
| @@ -89,7 +89,6 @@ bool __bdev_dax_supported(struct block_device *bdev, int blocksize) | |||
| 89 | struct request_queue *q; | 89 | struct request_queue *q; |
| 90 | pgoff_t pgoff; | 90 | pgoff_t pgoff; |
| 91 | int err, id; | 91 | int err, id; |
| 92 | void *kaddr; | ||
| 93 | pfn_t pfn; | 92 | pfn_t pfn; |
| 94 | long len; | 93 | long len; |
| 95 | char buf[BDEVNAME_SIZE]; | 94 | char buf[BDEVNAME_SIZE]; |
| @@ -122,7 +121,7 @@ bool __bdev_dax_supported(struct block_device *bdev, int blocksize) | |||
| 122 | } | 121 | } |
| 123 | 122 | ||
| 124 | id = dax_read_lock(); | 123 | id = dax_read_lock(); |
| 125 | len = dax_direct_access(dax_dev, pgoff, 1, &kaddr, &pfn); | 124 | len = dax_direct_access(dax_dev, pgoff, 1, NULL, &pfn); |
| 126 | dax_read_unlock(id); | 125 | dax_read_unlock(id); |
| 127 | 126 | ||
| 128 | put_dax(dax_dev); | 127 | put_dax(dax_dev); |
diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c index 3a28a68f184c..5f1f80d424dd 100644 --- a/drivers/md/dm-writecache.c +++ b/drivers/md/dm-writecache.c | |||
| @@ -268,9 +268,8 @@ static int persistent_memory_claim(struct dm_writecache *wc) | |||
| 268 | i = 0; | 268 | i = 0; |
| 269 | do { | 269 | do { |
| 270 | long daa; | 270 | long daa; |
| 271 | void *dummy_addr; | ||
| 272 | daa = dax_direct_access(wc->ssd_dev->dax_dev, i, p - i, | 271 | daa = dax_direct_access(wc->ssd_dev->dax_dev, i, p - i, |
| 273 | &dummy_addr, &pfn); | 272 | NULL, &pfn); |
| 274 | if (daa <= 0) { | 273 | if (daa <= 0) { |
| 275 | r = daa ? daa : -EINVAL; | 274 | r = daa ? daa : -EINVAL; |
| 276 | goto err3; | 275 | goto err3; |
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 27902a8799b1..8aae6dcc839f 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c | |||
| @@ -812,9 +812,9 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd, | |||
| 812 | * overshoots the remainder by 4 bytes, assume it was | 812 | * overshoots the remainder by 4 bytes, assume it was |
| 813 | * including 'status'. | 813 | * including 'status'. |
| 814 | */ | 814 | */ |
| 815 | if (out_field[1] - 8 == remainder) | 815 | if (out_field[1] - 4 == remainder) |
| 816 | return remainder; | 816 | return remainder; |
| 817 | return out_field[1] - 4; | 817 | return out_field[1] - 8; |
| 818 | } else if (cmd == ND_CMD_CALL) { | 818 | } else if (cmd == ND_CMD_CALL) { |
| 819 | struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field; | 819 | struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field; |
| 820 | 820 | ||
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 233907889f96..6c8fb7590838 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c | |||
| @@ -34,6 +34,9 @@ static int nvdimm_probe(struct device *dev) | |||
| 34 | return rc; | 34 | return rc; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | /* reset locked, to be validated below... */ | ||
| 38 | nvdimm_clear_locked(dev); | ||
| 39 | |||
| 37 | ndd = kzalloc(sizeof(*ndd), GFP_KERNEL); | 40 | ndd = kzalloc(sizeof(*ndd), GFP_KERNEL); |
| 38 | if (!ndd) | 41 | if (!ndd) |
| 39 | return -ENOMEM; | 42 | return -ENOMEM; |
| @@ -48,12 +51,30 @@ static int nvdimm_probe(struct device *dev) | |||
| 48 | get_device(dev); | 51 | get_device(dev); |
| 49 | kref_init(&ndd->kref); | 52 | kref_init(&ndd->kref); |
| 50 | 53 | ||
| 54 | /* | ||
| 55 | * EACCES failures reading the namespace label-area-properties | ||
| 56 | * are interpreted as the DIMM capacity being locked but the | ||
| 57 | * namespace labels themselves being accessible. | ||
| 58 | */ | ||
| 51 | rc = nvdimm_init_nsarea(ndd); | 59 | rc = nvdimm_init_nsarea(ndd); |
| 52 | if (rc == -EACCES) | 60 | if (rc == -EACCES) { |
| 61 | /* | ||
| 62 | * See nvdimm_namespace_common_probe() where we fail to | ||
| 63 | * allow namespaces to probe while the DIMM is locked, | ||
| 64 | * but we do allow for namespace enumeration. | ||
| 65 | */ | ||
| 53 | nvdimm_set_locked(dev); | 66 | nvdimm_set_locked(dev); |
| 67 | rc = 0; | ||
| 68 | } | ||
| 54 | if (rc) | 69 | if (rc) |
| 55 | goto err; | 70 | goto err; |
| 56 | 71 | ||
| 72 | /* | ||
| 73 | * EACCES failures reading the namespace label-data are | ||
| 74 | * interpreted as the label area being locked in addition to the | ||
| 75 | * DIMM capacity. We fail the dimm probe to prevent regions from | ||
| 76 | * attempting to parse the label area. | ||
| 77 | */ | ||
| 57 | rc = nvdimm_init_config_data(ndd); | 78 | rc = nvdimm_init_config_data(ndd); |
| 58 | if (rc == -EACCES) | 79 | if (rc == -EACCES) |
| 59 | nvdimm_set_locked(dev); | 80 | nvdimm_set_locked(dev); |
| @@ -72,7 +93,6 @@ static int nvdimm_probe(struct device *dev) | |||
| 72 | if (rc == 0) | 93 | if (rc == 0) |
| 73 | nvdimm_set_aliasing(dev); | 94 | nvdimm_set_aliasing(dev); |
| 74 | } | 95 | } |
| 75 | nvdimm_clear_locked(dev); | ||
| 76 | nvdimm_bus_unlock(dev); | 96 | nvdimm_bus_unlock(dev); |
| 77 | 97 | ||
| 78 | if (rc) | 98 | if (rc) |
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 8d348b22ba45..863cabc35215 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c | |||
| @@ -537,6 +537,37 @@ resource_size_t nd_blk_available_dpa(struct nd_region *nd_region) | |||
| 537 | } | 537 | } |
| 538 | 538 | ||
| 539 | /** | 539 | /** |
| 540 | * nd_pmem_max_contiguous_dpa - For the given dimm+region, return the max | ||
| 541 | * contiguous unallocated dpa range. | ||
| 542 | * @nd_region: constrain available space check to this reference region | ||
| 543 | * @nd_mapping: container of dpa-resource-root + labels | ||
| 544 | */ | ||
| 545 | resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region, | ||
| 546 | struct nd_mapping *nd_mapping) | ||
| 547 | { | ||
| 548 | struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); | ||
| 549 | struct nvdimm_bus *nvdimm_bus; | ||
| 550 | resource_size_t max = 0; | ||
| 551 | struct resource *res; | ||
| 552 | |||
| 553 | /* if a dimm is disabled the available capacity is zero */ | ||
| 554 | if (!ndd) | ||
| 555 | return 0; | ||
| 556 | |||
| 557 | nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); | ||
| 558 | if (__reserve_free_pmem(&nd_region->dev, nd_mapping->nvdimm)) | ||
| 559 | return 0; | ||
| 560 | for_each_dpa_resource(ndd, res) { | ||
| 561 | if (strcmp(res->name, "pmem-reserve") != 0) | ||
| 562 | continue; | ||
| 563 | if (resource_size(res) > max) | ||
| 564 | max = resource_size(res); | ||
| 565 | } | ||
| 566 | release_free_pmem(nvdimm_bus, nd_mapping); | ||
| 567 | return max; | ||
| 568 | } | ||
| 569 | |||
| 570 | /** | ||
| 540 | * nd_pmem_available_dpa - for the given dimm+region account unallocated dpa | 571 | * nd_pmem_available_dpa - for the given dimm+region account unallocated dpa |
| 541 | * @nd_mapping: container of dpa-resource-root + labels | 572 | * @nd_mapping: container of dpa-resource-root + labels |
| 542 | * @nd_region: constrain available space check to this reference region | 573 | * @nd_region: constrain available space check to this reference region |
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 28afdd668905..4a4266250c28 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c | |||
| @@ -799,7 +799,7 @@ static int merge_dpa(struct nd_region *nd_region, | |||
| 799 | return 0; | 799 | return 0; |
| 800 | } | 800 | } |
| 801 | 801 | ||
| 802 | static int __reserve_free_pmem(struct device *dev, void *data) | 802 | int __reserve_free_pmem(struct device *dev, void *data) |
| 803 | { | 803 | { |
| 804 | struct nvdimm *nvdimm = data; | 804 | struct nvdimm *nvdimm = data; |
| 805 | struct nd_region *nd_region; | 805 | struct nd_region *nd_region; |
| @@ -836,7 +836,7 @@ static int __reserve_free_pmem(struct device *dev, void *data) | |||
| 836 | return 0; | 836 | return 0; |
| 837 | } | 837 | } |
| 838 | 838 | ||
| 839 | static void release_free_pmem(struct nvdimm_bus *nvdimm_bus, | 839 | void release_free_pmem(struct nvdimm_bus *nvdimm_bus, |
| 840 | struct nd_mapping *nd_mapping) | 840 | struct nd_mapping *nd_mapping) |
| 841 | { | 841 | { |
| 842 | struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); | 842 | struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); |
| @@ -1032,7 +1032,7 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) | |||
| 1032 | 1032 | ||
| 1033 | allocated += nvdimm_allocated_dpa(ndd, &label_id); | 1033 | allocated += nvdimm_allocated_dpa(ndd, &label_id); |
| 1034 | } | 1034 | } |
| 1035 | available = nd_region_available_dpa(nd_region); | 1035 | available = nd_region_allocatable_dpa(nd_region); |
| 1036 | 1036 | ||
| 1037 | if (val > available + allocated) | 1037 | if (val > available + allocated) |
| 1038 | return -ENOSPC; | 1038 | return -ENOSPC; |
| @@ -1144,6 +1144,26 @@ resource_size_t nvdimm_namespace_capacity(struct nd_namespace_common *ndns) | |||
| 1144 | } | 1144 | } |
| 1145 | EXPORT_SYMBOL(nvdimm_namespace_capacity); | 1145 | EXPORT_SYMBOL(nvdimm_namespace_capacity); |
| 1146 | 1146 | ||
| 1147 | bool nvdimm_namespace_locked(struct nd_namespace_common *ndns) | ||
| 1148 | { | ||
| 1149 | int i; | ||
| 1150 | bool locked = false; | ||
| 1151 | struct device *dev = &ndns->dev; | ||
| 1152 | struct nd_region *nd_region = to_nd_region(dev->parent); | ||
| 1153 | |||
| 1154 | for (i = 0; i < nd_region->ndr_mappings; i++) { | ||
| 1155 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; | ||
| 1156 | struct nvdimm *nvdimm = nd_mapping->nvdimm; | ||
| 1157 | |||
| 1158 | if (test_bit(NDD_LOCKED, &nvdimm->flags)) { | ||
| 1159 | dev_dbg(dev, "%s locked\n", nvdimm_name(nvdimm)); | ||
| 1160 | locked = true; | ||
| 1161 | } | ||
| 1162 | } | ||
| 1163 | return locked; | ||
| 1164 | } | ||
| 1165 | EXPORT_SYMBOL(nvdimm_namespace_locked); | ||
| 1166 | |||
| 1147 | static ssize_t size_show(struct device *dev, | 1167 | static ssize_t size_show(struct device *dev, |
| 1148 | struct device_attribute *attr, char *buf) | 1168 | struct device_attribute *attr, char *buf) |
| 1149 | { | 1169 | { |
| @@ -1695,6 +1715,9 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev) | |||
| 1695 | } | 1715 | } |
| 1696 | } | 1716 | } |
| 1697 | 1717 | ||
| 1718 | if (nvdimm_namespace_locked(ndns)) | ||
| 1719 | return ERR_PTR(-EACCES); | ||
| 1720 | |||
| 1698 | size = nvdimm_namespace_capacity(ndns); | 1721 | size = nvdimm_namespace_capacity(ndns); |
| 1699 | if (size < ND_MIN_NAMESPACE_SIZE) { | 1722 | if (size < ND_MIN_NAMESPACE_SIZE) { |
| 1700 | dev_dbg(&ndns->dev, "%pa, too small must be at least %#x\n", | 1723 | dev_dbg(&ndns->dev, "%pa, too small must be at least %#x\n", |
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 79274ead54fb..ac68072fb8cd 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h | |||
| @@ -100,6 +100,14 @@ struct nd_region; | |||
| 100 | struct nvdimm_drvdata; | 100 | struct nvdimm_drvdata; |
| 101 | struct nd_mapping; | 101 | struct nd_mapping; |
| 102 | void nd_mapping_free_labels(struct nd_mapping *nd_mapping); | 102 | void nd_mapping_free_labels(struct nd_mapping *nd_mapping); |
| 103 | |||
| 104 | int __reserve_free_pmem(struct device *dev, void *data); | ||
| 105 | void release_free_pmem(struct nvdimm_bus *nvdimm_bus, | ||
| 106 | struct nd_mapping *nd_mapping); | ||
| 107 | |||
| 108 | resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region, | ||
| 109 | struct nd_mapping *nd_mapping); | ||
| 110 | resource_size_t nd_region_allocatable_dpa(struct nd_region *nd_region); | ||
| 103 | resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region, | 111 | resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region, |
| 104 | struct nd_mapping *nd_mapping, resource_size_t *overlap); | 112 | struct nd_mapping *nd_mapping, resource_size_t *overlap); |
| 105 | resource_size_t nd_blk_available_dpa(struct nd_region *nd_region); | 113 | resource_size_t nd_blk_available_dpa(struct nd_region *nd_region); |
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 6ee7fd7e4bbd..98317e7ce5b5 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h | |||
| @@ -357,6 +357,7 @@ struct resource *nvdimm_allocate_dpa(struct nvdimm_drvdata *ndd, | |||
| 357 | struct nd_label_id *label_id, resource_size_t start, | 357 | struct nd_label_id *label_id, resource_size_t start, |
| 358 | resource_size_t n); | 358 | resource_size_t n); |
| 359 | resource_size_t nvdimm_namespace_capacity(struct nd_namespace_common *ndns); | 359 | resource_size_t nvdimm_namespace_capacity(struct nd_namespace_common *ndns); |
| 360 | bool nvdimm_namespace_locked(struct nd_namespace_common *ndns); | ||
| 360 | struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev); | 361 | struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev); |
| 361 | int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns); | 362 | int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns); |
| 362 | int nvdimm_namespace_detach_btt(struct nd_btt *nd_btt); | 363 | int nvdimm_namespace_detach_btt(struct nd_btt *nd_btt); |
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index dd17acd8fe68..c23649867696 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c | |||
| @@ -226,8 +226,11 @@ __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, | |||
| 226 | if (unlikely(is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) / 512, | 226 | if (unlikely(is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) / 512, |
| 227 | PFN_PHYS(nr_pages)))) | 227 | PFN_PHYS(nr_pages)))) |
| 228 | return -EIO; | 228 | return -EIO; |
| 229 | *kaddr = pmem->virt_addr + offset; | 229 | |
| 230 | *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); | 230 | if (kaddr) |
| 231 | *kaddr = pmem->virt_addr + offset; | ||
| 232 | if (pfn) | ||
| 233 | *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); | ||
| 231 | 234 | ||
| 232 | /* | 235 | /* |
| 233 | * If badblocks are present, limit known good range to the | 236 | * If badblocks are present, limit known good range to the |
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index ec3543b83330..fa37afcd43ff 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c | |||
| @@ -389,6 +389,30 @@ resource_size_t nd_region_available_dpa(struct nd_region *nd_region) | |||
| 389 | return available; | 389 | return available; |
| 390 | } | 390 | } |
| 391 | 391 | ||
| 392 | resource_size_t nd_region_allocatable_dpa(struct nd_region *nd_region) | ||
| 393 | { | ||
| 394 | resource_size_t available = 0; | ||
| 395 | int i; | ||
| 396 | |||
| 397 | if (is_memory(&nd_region->dev)) | ||
| 398 | available = PHYS_ADDR_MAX; | ||
| 399 | |||
| 400 | WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev)); | ||
| 401 | for (i = 0; i < nd_region->ndr_mappings; i++) { | ||
| 402 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; | ||
| 403 | |||
| 404 | if (is_memory(&nd_region->dev)) | ||
| 405 | available = min(available, | ||
| 406 | nd_pmem_max_contiguous_dpa(nd_region, | ||
| 407 | nd_mapping)); | ||
| 408 | else if (is_nd_blk(&nd_region->dev)) | ||
| 409 | available += nd_blk_available_dpa(nd_region); | ||
| 410 | } | ||
| 411 | if (is_memory(&nd_region->dev)) | ||
| 412 | return available * nd_region->ndr_mappings; | ||
| 413 | return available; | ||
| 414 | } | ||
| 415 | |||
| 392 | static ssize_t available_size_show(struct device *dev, | 416 | static ssize_t available_size_show(struct device *dev, |
| 393 | struct device_attribute *attr, char *buf) | 417 | struct device_attribute *attr, char *buf) |
| 394 | { | 418 | { |
| @@ -410,6 +434,21 @@ static ssize_t available_size_show(struct device *dev, | |||
| 410 | } | 434 | } |
| 411 | static DEVICE_ATTR_RO(available_size); | 435 | static DEVICE_ATTR_RO(available_size); |
| 412 | 436 | ||
| 437 | static ssize_t max_available_extent_show(struct device *dev, | ||
| 438 | struct device_attribute *attr, char *buf) | ||
| 439 | { | ||
| 440 | struct nd_region *nd_region = to_nd_region(dev); | ||
| 441 | unsigned long long available = 0; | ||
| 442 | |||
| 443 | nvdimm_bus_lock(dev); | ||
| 444 | wait_nvdimm_bus_probe_idle(dev); | ||
| 445 | available = nd_region_allocatable_dpa(nd_region); | ||
| 446 | nvdimm_bus_unlock(dev); | ||
| 447 | |||
| 448 | return sprintf(buf, "%llu\n", available); | ||
| 449 | } | ||
| 450 | static DEVICE_ATTR_RO(max_available_extent); | ||
| 451 | |||
| 413 | static ssize_t init_namespaces_show(struct device *dev, | 452 | static ssize_t init_namespaces_show(struct device *dev, |
| 414 | struct device_attribute *attr, char *buf) | 453 | struct device_attribute *attr, char *buf) |
| 415 | { | 454 | { |
| @@ -561,6 +600,7 @@ static struct attribute *nd_region_attributes[] = { | |||
| 561 | &dev_attr_read_only.attr, | 600 | &dev_attr_read_only.attr, |
| 562 | &dev_attr_set_cookie.attr, | 601 | &dev_attr_set_cookie.attr, |
| 563 | &dev_attr_available_size.attr, | 602 | &dev_attr_available_size.attr, |
| 603 | &dev_attr_max_available_extent.attr, | ||
| 564 | &dev_attr_namespace_seed.attr, | 604 | &dev_attr_namespace_seed.attr, |
| 565 | &dev_attr_init_namespaces.attr, | 605 | &dev_attr_init_namespaces.attr, |
| 566 | &dev_attr_badblocks.attr, | 606 | &dev_attr_badblocks.attr, |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index ed607288e696..23e526cda5c1 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
| @@ -922,9 +922,11 @@ __dcssblk_direct_access(struct dcssblk_dev_info *dev_info, pgoff_t pgoff, | |||
| 922 | unsigned long dev_sz; | 922 | unsigned long dev_sz; |
| 923 | 923 | ||
| 924 | dev_sz = dev_info->end - dev_info->start + 1; | 924 | dev_sz = dev_info->end - dev_info->start + 1; |
| 925 | *kaddr = (void *) dev_info->start + offset; | 925 | if (kaddr) |
| 926 | *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), | 926 | *kaddr = (void *) dev_info->start + offset; |
| 927 | PFN_DEV|PFN_SPECIAL); | 927 | if (pfn) |
| 928 | *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), | ||
| 929 | PFN_DEV|PFN_SPECIAL); | ||
| 928 | 930 | ||
| 929 | return (dev_sz - offset) / PAGE_SIZE; | 931 | return (dev_sz - offset) / PAGE_SIZE; |
| 930 | } | 932 | } |
| @@ -655,7 +655,6 @@ static int copy_user_dax(struct block_device *bdev, struct dax_device *dax_dev, | |||
| 655 | { | 655 | { |
| 656 | void *vto, *kaddr; | 656 | void *vto, *kaddr; |
| 657 | pgoff_t pgoff; | 657 | pgoff_t pgoff; |
| 658 | pfn_t pfn; | ||
| 659 | long rc; | 658 | long rc; |
| 660 | int id; | 659 | int id; |
| 661 | 660 | ||
| @@ -664,7 +663,7 @@ static int copy_user_dax(struct block_device *bdev, struct dax_device *dax_dev, | |||
| 664 | return rc; | 663 | return rc; |
| 665 | 664 | ||
| 666 | id = dax_read_lock(); | 665 | id = dax_read_lock(); |
| 667 | rc = dax_direct_access(dax_dev, pgoff, PHYS_PFN(size), &kaddr, &pfn); | 666 | rc = dax_direct_access(dax_dev, pgoff, PHYS_PFN(size), &kaddr, NULL); |
| 668 | if (rc < 0) { | 667 | if (rc < 0) { |
| 669 | dax_read_unlock(id); | 668 | dax_read_unlock(id); |
| 670 | return rc; | 669 | return rc; |
| @@ -975,7 +974,6 @@ static int dax_iomap_pfn(struct iomap *iomap, loff_t pos, size_t size, | |||
| 975 | { | 974 | { |
| 976 | const sector_t sector = dax_iomap_sector(iomap, pos); | 975 | const sector_t sector = dax_iomap_sector(iomap, pos); |
| 977 | pgoff_t pgoff; | 976 | pgoff_t pgoff; |
| 978 | void *kaddr; | ||
| 979 | int id, rc; | 977 | int id, rc; |
| 980 | long length; | 978 | long length; |
| 981 | 979 | ||
| @@ -984,7 +982,7 @@ static int dax_iomap_pfn(struct iomap *iomap, loff_t pos, size_t size, | |||
| 984 | return rc; | 982 | return rc; |
| 985 | id = dax_read_lock(); | 983 | id = dax_read_lock(); |
| 986 | length = dax_direct_access(iomap->dax_dev, pgoff, PHYS_PFN(size), | 984 | length = dax_direct_access(iomap->dax_dev, pgoff, PHYS_PFN(size), |
| 987 | &kaddr, pfnp); | 985 | NULL, pfnp); |
| 988 | if (length < 0) { | 986 | if (length < 0) { |
| 989 | rc = length; | 987 | rc = length; |
| 990 | goto out; | 988 | goto out; |
| @@ -1060,15 +1058,13 @@ int __dax_zero_page_range(struct block_device *bdev, | |||
| 1060 | pgoff_t pgoff; | 1058 | pgoff_t pgoff; |
| 1061 | long rc, id; | 1059 | long rc, id; |
| 1062 | void *kaddr; | 1060 | void *kaddr; |
| 1063 | pfn_t pfn; | ||
| 1064 | 1061 | ||
| 1065 | rc = bdev_dax_pgoff(bdev, sector, PAGE_SIZE, &pgoff); | 1062 | rc = bdev_dax_pgoff(bdev, sector, PAGE_SIZE, &pgoff); |
| 1066 | if (rc) | 1063 | if (rc) |
| 1067 | return rc; | 1064 | return rc; |
| 1068 | 1065 | ||
| 1069 | id = dax_read_lock(); | 1066 | id = dax_read_lock(); |
| 1070 | rc = dax_direct_access(dax_dev, pgoff, 1, &kaddr, | 1067 | rc = dax_direct_access(dax_dev, pgoff, 1, &kaddr, NULL); |
| 1071 | &pfn); | ||
| 1072 | if (rc < 0) { | 1068 | if (rc < 0) { |
| 1073 | dax_read_unlock(id); | 1069 | dax_read_unlock(id); |
| 1074 | return rc; | 1070 | return rc; |
| @@ -1124,7 +1120,6 @@ dax_iomap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, | |||
| 1124 | ssize_t map_len; | 1120 | ssize_t map_len; |
| 1125 | pgoff_t pgoff; | 1121 | pgoff_t pgoff; |
| 1126 | void *kaddr; | 1122 | void *kaddr; |
| 1127 | pfn_t pfn; | ||
| 1128 | 1123 | ||
| 1129 | if (fatal_signal_pending(current)) { | 1124 | if (fatal_signal_pending(current)) { |
| 1130 | ret = -EINTR; | 1125 | ret = -EINTR; |
| @@ -1136,7 +1131,7 @@ dax_iomap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, | |||
| 1136 | break; | 1131 | break; |
| 1137 | 1132 | ||
| 1138 | map_len = dax_direct_access(dax_dev, pgoff, PHYS_PFN(size), | 1133 | map_len = dax_direct_access(dax_dev, pgoff, PHYS_PFN(size), |
| 1139 | &kaddr, &pfn); | 1134 | &kaddr, NULL); |
| 1140 | if (map_len < 0) { | 1135 | if (map_len < 0) { |
| 1141 | ret = map_len; | 1136 | ret = map_len; |
| 1142 | break; | 1137 | break; |
diff --git a/tools/testing/nvdimm/pmem-dax.c b/tools/testing/nvdimm/pmem-dax.c index b53596ad601b..2e7fd8227969 100644 --- a/tools/testing/nvdimm/pmem-dax.c +++ b/tools/testing/nvdimm/pmem-dax.c | |||
| @@ -31,17 +31,21 @@ long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, | |||
| 31 | if (get_nfit_res(pmem->phys_addr + offset)) { | 31 | if (get_nfit_res(pmem->phys_addr + offset)) { |
| 32 | struct page *page; | 32 | struct page *page; |
| 33 | 33 | ||
| 34 | *kaddr = pmem->virt_addr + offset; | 34 | if (kaddr) |
| 35 | *kaddr = pmem->virt_addr + offset; | ||
| 35 | page = vmalloc_to_page(pmem->virt_addr + offset); | 36 | page = vmalloc_to_page(pmem->virt_addr + offset); |
| 36 | *pfn = page_to_pfn_t(page); | 37 | if (pfn) |
| 38 | *pfn = page_to_pfn_t(page); | ||
| 37 | pr_debug_ratelimited("%s: pmem: %p pgoff: %#lx pfn: %#lx\n", | 39 | pr_debug_ratelimited("%s: pmem: %p pgoff: %#lx pfn: %#lx\n", |
| 38 | __func__, pmem, pgoff, page_to_pfn(page)); | 40 | __func__, pmem, pgoff, page_to_pfn(page)); |
| 39 | 41 | ||
| 40 | return 1; | 42 | return 1; |
| 41 | } | 43 | } |
| 42 | 44 | ||
| 43 | *kaddr = pmem->virt_addr + offset; | 45 | if (kaddr) |
| 44 | *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); | 46 | *kaddr = pmem->virt_addr + offset; |
| 47 | if (pfn) | ||
| 48 | *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); | ||
| 45 | 49 | ||
| 46 | /* | 50 | /* |
| 47 | * If badblocks are present, limit known good range to the | 51 | * If badblocks are present, limit known good range to the |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index e2926f72a821..cffc2c5a778d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
| @@ -142,6 +142,28 @@ static u32 handle[] = { | |||
| 142 | static unsigned long dimm_fail_cmd_flags[NUM_DCR]; | 142 | static unsigned long dimm_fail_cmd_flags[NUM_DCR]; |
| 143 | static int dimm_fail_cmd_code[NUM_DCR]; | 143 | static int dimm_fail_cmd_code[NUM_DCR]; |
| 144 | 144 | ||
| 145 | static const struct nd_intel_smart smart_def = { | ||
| 146 | .flags = ND_INTEL_SMART_HEALTH_VALID | ||
| 147 | | ND_INTEL_SMART_SPARES_VALID | ||
| 148 | | ND_INTEL_SMART_ALARM_VALID | ||
| 149 | | ND_INTEL_SMART_USED_VALID | ||
| 150 | | ND_INTEL_SMART_SHUTDOWN_VALID | ||
| 151 | | ND_INTEL_SMART_MTEMP_VALID | ||
| 152 | | ND_INTEL_SMART_CTEMP_VALID, | ||
| 153 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, | ||
| 154 | .media_temperature = 23 * 16, | ||
| 155 | .ctrl_temperature = 25 * 16, | ||
| 156 | .pmic_temperature = 40 * 16, | ||
| 157 | .spares = 75, | ||
| 158 | .alarm_flags = ND_INTEL_SMART_SPARE_TRIP | ||
| 159 | | ND_INTEL_SMART_TEMP_TRIP, | ||
| 160 | .ait_status = 1, | ||
| 161 | .life_used = 5, | ||
| 162 | .shutdown_state = 0, | ||
| 163 | .vendor_size = 0, | ||
| 164 | .shutdown_count = 100, | ||
| 165 | }; | ||
| 166 | |||
| 145 | struct nfit_test_fw { | 167 | struct nfit_test_fw { |
| 146 | enum intel_fw_update_state state; | 168 | enum intel_fw_update_state state; |
| 147 | u32 context; | 169 | u32 context; |
| @@ -752,15 +774,30 @@ static int nfit_test_cmd_smart_inject( | |||
| 752 | if (buf_len != sizeof(*inj)) | 774 | if (buf_len != sizeof(*inj)) |
| 753 | return -EINVAL; | 775 | return -EINVAL; |
| 754 | 776 | ||
| 755 | if (inj->mtemp_enable) | 777 | if (inj->flags & ND_INTEL_SMART_INJECT_MTEMP) { |
| 756 | smart->media_temperature = inj->media_temperature; | 778 | if (inj->mtemp_enable) |
| 757 | if (inj->spare_enable) | 779 | smart->media_temperature = inj->media_temperature; |
| 758 | smart->spares = inj->spares; | 780 | else |
| 759 | if (inj->fatal_enable) | 781 | smart->media_temperature = smart_def.media_temperature; |
| 760 | smart->health = ND_INTEL_SMART_FATAL_HEALTH; | 782 | } |
| 761 | if (inj->unsafe_shutdown_enable) { | 783 | if (inj->flags & ND_INTEL_SMART_INJECT_SPARE) { |
| 762 | smart->shutdown_state = 1; | 784 | if (inj->spare_enable) |
| 763 | smart->shutdown_count++; | 785 | smart->spares = inj->spares; |
| 786 | else | ||
| 787 | smart->spares = smart_def.spares; | ||
| 788 | } | ||
| 789 | if (inj->flags & ND_INTEL_SMART_INJECT_FATAL) { | ||
| 790 | if (inj->fatal_enable) | ||
| 791 | smart->health = ND_INTEL_SMART_FATAL_HEALTH; | ||
| 792 | else | ||
| 793 | smart->health = ND_INTEL_SMART_NON_CRITICAL_HEALTH; | ||
| 794 | } | ||
| 795 | if (inj->flags & ND_INTEL_SMART_INJECT_SHUTDOWN) { | ||
| 796 | if (inj->unsafe_shutdown_enable) { | ||
| 797 | smart->shutdown_state = 1; | ||
| 798 | smart->shutdown_count++; | ||
| 799 | } else | ||
| 800 | smart->shutdown_state = 0; | ||
| 764 | } | 801 | } |
| 765 | inj->status = 0; | 802 | inj->status = 0; |
| 766 | smart_notify(bus_dev, dimm_dev, smart, thresh); | 803 | smart_notify(bus_dev, dimm_dev, smart, thresh); |
| @@ -884,6 +921,16 @@ static int nd_intel_test_cmd_set_lss_status(struct nfit_test *t, | |||
| 884 | return 0; | 921 | return 0; |
| 885 | } | 922 | } |
| 886 | 923 | ||
| 924 | static int override_return_code(int dimm, unsigned int func, int rc) | ||
| 925 | { | ||
| 926 | if ((1 << func) & dimm_fail_cmd_flags[dimm]) { | ||
| 927 | if (dimm_fail_cmd_code[dimm]) | ||
| 928 | return dimm_fail_cmd_code[dimm]; | ||
| 929 | return -EIO; | ||
| 930 | } | ||
| 931 | return rc; | ||
| 932 | } | ||
| 933 | |||
| 887 | static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) | 934 | static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) |
| 888 | { | 935 | { |
| 889 | int i; | 936 | int i; |
| @@ -894,13 +941,6 @@ static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) | |||
| 894 | break; | 941 | break; |
| 895 | if (i >= ARRAY_SIZE(handle)) | 942 | if (i >= ARRAY_SIZE(handle)) |
| 896 | return -ENXIO; | 943 | return -ENXIO; |
| 897 | |||
| 898 | if ((1 << func) & dimm_fail_cmd_flags[i]) { | ||
| 899 | if (dimm_fail_cmd_code[i]) | ||
| 900 | return dimm_fail_cmd_code[i]; | ||
| 901 | return -EIO; | ||
| 902 | } | ||
| 903 | |||
| 904 | return i; | 944 | return i; |
| 905 | } | 945 | } |
| 906 | 946 | ||
| @@ -939,48 +979,59 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 939 | 979 | ||
| 940 | switch (func) { | 980 | switch (func) { |
| 941 | case ND_INTEL_ENABLE_LSS_STATUS: | 981 | case ND_INTEL_ENABLE_LSS_STATUS: |
| 942 | return nd_intel_test_cmd_set_lss_status(t, | 982 | rc = nd_intel_test_cmd_set_lss_status(t, |
| 943 | buf, buf_len); | 983 | buf, buf_len); |
| 984 | break; | ||
| 944 | case ND_INTEL_FW_GET_INFO: | 985 | case ND_INTEL_FW_GET_INFO: |
| 945 | return nd_intel_test_get_fw_info(t, buf, | 986 | rc = nd_intel_test_get_fw_info(t, buf, |
| 946 | buf_len, i - t->dcr_idx); | 987 | buf_len, i - t->dcr_idx); |
| 988 | break; | ||
| 947 | case ND_INTEL_FW_START_UPDATE: | 989 | case ND_INTEL_FW_START_UPDATE: |
| 948 | return nd_intel_test_start_update(t, buf, | 990 | rc = nd_intel_test_start_update(t, buf, |
| 949 | buf_len, i - t->dcr_idx); | 991 | buf_len, i - t->dcr_idx); |
| 992 | break; | ||
| 950 | case ND_INTEL_FW_SEND_DATA: | 993 | case ND_INTEL_FW_SEND_DATA: |
| 951 | return nd_intel_test_send_data(t, buf, | 994 | rc = nd_intel_test_send_data(t, buf, |
| 952 | buf_len, i - t->dcr_idx); | 995 | buf_len, i - t->dcr_idx); |
| 996 | break; | ||
| 953 | case ND_INTEL_FW_FINISH_UPDATE: | 997 | case ND_INTEL_FW_FINISH_UPDATE: |
| 954 | return nd_intel_test_finish_fw(t, buf, | 998 | rc = nd_intel_test_finish_fw(t, buf, |
| 955 | buf_len, i - t->dcr_idx); | 999 | buf_len, i - t->dcr_idx); |
| 1000 | break; | ||
| 956 | case ND_INTEL_FW_FINISH_QUERY: | 1001 | case ND_INTEL_FW_FINISH_QUERY: |
| 957 | return nd_intel_test_finish_query(t, buf, | 1002 | rc = nd_intel_test_finish_query(t, buf, |
| 958 | buf_len, i - t->dcr_idx); | 1003 | buf_len, i - t->dcr_idx); |
| 1004 | break; | ||
| 959 | case ND_INTEL_SMART: | 1005 | case ND_INTEL_SMART: |
| 960 | return nfit_test_cmd_smart(buf, buf_len, | 1006 | rc = nfit_test_cmd_smart(buf, buf_len, |
| 961 | &t->smart[i - t->dcr_idx]); | 1007 | &t->smart[i - t->dcr_idx]); |
| 1008 | break; | ||
| 962 | case ND_INTEL_SMART_THRESHOLD: | 1009 | case ND_INTEL_SMART_THRESHOLD: |
| 963 | return nfit_test_cmd_smart_threshold(buf, | 1010 | rc = nfit_test_cmd_smart_threshold(buf, |
| 964 | buf_len, | 1011 | buf_len, |
| 965 | &t->smart_threshold[i - | 1012 | &t->smart_threshold[i - |
| 966 | t->dcr_idx]); | 1013 | t->dcr_idx]); |
| 1014 | break; | ||
| 967 | case ND_INTEL_SMART_SET_THRESHOLD: | 1015 | case ND_INTEL_SMART_SET_THRESHOLD: |
| 968 | return nfit_test_cmd_smart_set_threshold(buf, | 1016 | rc = nfit_test_cmd_smart_set_threshold(buf, |
| 969 | buf_len, | 1017 | buf_len, |
| 970 | &t->smart_threshold[i - | 1018 | &t->smart_threshold[i - |
| 971 | t->dcr_idx], | 1019 | t->dcr_idx], |
| 972 | &t->smart[i - t->dcr_idx], | 1020 | &t->smart[i - t->dcr_idx], |
| 973 | &t->pdev.dev, t->dimm_dev[i]); | 1021 | &t->pdev.dev, t->dimm_dev[i]); |
| 1022 | break; | ||
| 974 | case ND_INTEL_SMART_INJECT: | 1023 | case ND_INTEL_SMART_INJECT: |
| 975 | return nfit_test_cmd_smart_inject(buf, | 1024 | rc = nfit_test_cmd_smart_inject(buf, |
| 976 | buf_len, | 1025 | buf_len, |
| 977 | &t->smart_threshold[i - | 1026 | &t->smart_threshold[i - |
| 978 | t->dcr_idx], | 1027 | t->dcr_idx], |
| 979 | &t->smart[i - t->dcr_idx], | 1028 | &t->smart[i - t->dcr_idx], |
| 980 | &t->pdev.dev, t->dimm_dev[i]); | 1029 | &t->pdev.dev, t->dimm_dev[i]); |
| 1030 | break; | ||
| 981 | default: | 1031 | default: |
| 982 | return -ENOTTY; | 1032 | return -ENOTTY; |
| 983 | } | 1033 | } |
| 1034 | return override_return_code(i, func, rc); | ||
| 984 | } | 1035 | } |
| 985 | 1036 | ||
| 986 | if (!test_bit(cmd, &cmd_mask) | 1037 | if (!test_bit(cmd, &cmd_mask) |
| @@ -1006,6 +1057,7 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 1006 | default: | 1057 | default: |
| 1007 | return -ENOTTY; | 1058 | return -ENOTTY; |
| 1008 | } | 1059 | } |
| 1060 | return override_return_code(i, func, rc); | ||
| 1009 | } else { | 1061 | } else { |
| 1010 | struct ars_state *ars_state = &t->ars_state; | 1062 | struct ars_state *ars_state = &t->ars_state; |
| 1011 | struct nd_cmd_pkg *call_pkg = buf; | 1063 | struct nd_cmd_pkg *call_pkg = buf; |
| @@ -1302,29 +1354,9 @@ static void smart_init(struct nfit_test *t) | |||
| 1302 | .ctrl_temperature = 30 * 16, | 1354 | .ctrl_temperature = 30 * 16, |
| 1303 | .spares = 5, | 1355 | .spares = 5, |
| 1304 | }; | 1356 | }; |
| 1305 | const struct nd_intel_smart smart_data = { | ||
| 1306 | .flags = ND_INTEL_SMART_HEALTH_VALID | ||
| 1307 | | ND_INTEL_SMART_SPARES_VALID | ||
| 1308 | | ND_INTEL_SMART_ALARM_VALID | ||
| 1309 | | ND_INTEL_SMART_USED_VALID | ||
| 1310 | | ND_INTEL_SMART_SHUTDOWN_VALID | ||
| 1311 | | ND_INTEL_SMART_MTEMP_VALID, | ||
| 1312 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, | ||
| 1313 | .media_temperature = 23 * 16, | ||
| 1314 | .ctrl_temperature = 25 * 16, | ||
| 1315 | .pmic_temperature = 40 * 16, | ||
| 1316 | .spares = 75, | ||
| 1317 | .alarm_flags = ND_INTEL_SMART_SPARE_TRIP | ||
| 1318 | | ND_INTEL_SMART_TEMP_TRIP, | ||
| 1319 | .ait_status = 1, | ||
| 1320 | .life_used = 5, | ||
| 1321 | .shutdown_state = 0, | ||
| 1322 | .vendor_size = 0, | ||
| 1323 | .shutdown_count = 100, | ||
| 1324 | }; | ||
| 1325 | 1357 | ||
| 1326 | for (i = 0; i < t->num_dcr; i++) { | 1358 | for (i = 0; i < t->num_dcr; i++) { |
| 1327 | memcpy(&t->smart[i], &smart_data, sizeof(smart_data)); | 1359 | memcpy(&t->smart[i], &smart_def, sizeof(smart_def)); |
| 1328 | memcpy(&t->smart_threshold[i], &smart_t_data, | 1360 | memcpy(&t->smart_threshold[i], &smart_t_data, |
| 1329 | sizeof(smart_t_data)); | 1361 | sizeof(smart_t_data)); |
| 1330 | } | 1362 | } |
