diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2018-10-29 18:52:42 -0400 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2019-01-07 00:26:21 -0500 |
| commit | 89ec9f2cfa36cc5fca2fb445ed221bb9add7b536 (patch) | |
| tree | 1306755d2ecae784ddee3df710c16c4cfeaff771 | |
| parent | 9567da0b408a2553d32ca83cba4f1fc5a8aad459 (diff) | |
device-dax: Move resource pinning+mapping into the common driver
Move the responsibility of calling devm_request_resource() and
devm_memremap_pages() into the common device-dax driver. This is another
preparatory step to allowing an alternate personality driver for a
device-dax range.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
| -rw-r--r-- | drivers/dax/bus.c | 6 | ||||
| -rw-r--r-- | drivers/dax/bus.h | 3 | ||||
| -rw-r--r-- | drivers/dax/dax-private.h | 9 | ||||
| -rw-r--r-- | drivers/dax/device.c | 61 | ||||
| -rw-r--r-- | drivers/dax/pmem.c | 90 |
5 files changed, 90 insertions, 79 deletions
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 0cff32102c4c..69aae2cbd45f 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */ | 2 | /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */ |
| 3 | #include <linux/memremap.h> | ||
| 3 | #include <linux/device.h> | 4 | #include <linux/device.h> |
| 4 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
| 5 | #include <linux/dax.h> | 6 | #include <linux/dax.h> |
| @@ -206,7 +207,8 @@ static void unregister_dev_dax(void *dev) | |||
| 206 | put_device(dev); | 207 | put_device(dev); |
| 207 | } | 208 | } |
| 208 | 209 | ||
| 209 | struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id) | 210 | struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, |
| 211 | struct dev_pagemap *pgmap) | ||
| 210 | { | 212 | { |
| 211 | struct device *parent = dax_region->dev; | 213 | struct device *parent = dax_region->dev; |
| 212 | struct dax_device *dax_dev; | 214 | struct dax_device *dax_dev; |
| @@ -222,6 +224,8 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id) | |||
| 222 | if (!dev_dax) | 224 | if (!dev_dax) |
| 223 | return ERR_PTR(-ENOMEM); | 225 | return ERR_PTR(-ENOMEM); |
| 224 | 226 | ||
| 227 | memcpy(&dev_dax->pgmap, pgmap, sizeof(*pgmap)); | ||
| 228 | |||
| 225 | /* | 229 | /* |
| 226 | * No 'host' or dax_operations since there is no access to this | 230 | * No 'host' or dax_operations since there is no access to this |
| 227 | * device outside of mmap of the resulting character device. | 231 | * device outside of mmap of the resulting character device. |
diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index ea509504df3a..e08e0c394983 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h | |||
| @@ -10,7 +10,8 @@ struct dax_region; | |||
| 10 | void dax_region_put(struct dax_region *dax_region); | 10 | void dax_region_put(struct dax_region *dax_region); |
| 11 | struct dax_region *alloc_dax_region(struct device *parent, int region_id, | 11 | struct dax_region *alloc_dax_region(struct device *parent, int region_id, |
| 12 | struct resource *res, unsigned int align, unsigned long flags); | 12 | struct resource *res, unsigned int align, unsigned long flags); |
| 13 | struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id); | 13 | struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, |
| 14 | struct dev_pagemap *pgmap); | ||
| 14 | int __dax_driver_register(struct device_driver *drv, | 15 | int __dax_driver_register(struct device_driver *drv, |
| 15 | struct module *module, const char *mod_name); | 16 | struct module *module, const char *mod_name); |
| 16 | #define dax_driver_register(driver) \ | 17 | #define dax_driver_register(driver) \ |
diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index c3a121700837..a82ce48f5884 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h | |||
| @@ -42,15 +42,22 @@ struct dax_region { | |||
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | /** | 44 | /** |
| 45 | * struct dev_dax - instance data for a subdivision of a dax region | 45 | * struct dev_dax - instance data for a subdivision of a dax region, and |
| 46 | * data while the device is activated in the driver. | ||
| 46 | * @region - parent region | 47 | * @region - parent region |
| 47 | * @dax_dev - core dax functionality | 48 | * @dax_dev - core dax functionality |
| 48 | * @dev - device core | 49 | * @dev - device core |
| 50 | * @pgmap - pgmap for memmap setup / lifetime (driver owned) | ||
| 51 | * @ref: pgmap reference count (driver owned) | ||
| 52 | * @cmp: @ref final put completion (driver owned) | ||
| 49 | */ | 53 | */ |
| 50 | struct dev_dax { | 54 | struct dev_dax { |
| 51 | struct dax_region *region; | 55 | struct dax_region *region; |
| 52 | struct dax_device *dax_dev; | 56 | struct dax_device *dax_dev; |
| 53 | struct device dev; | 57 | struct device dev; |
| 58 | struct dev_pagemap pgmap; | ||
| 59 | struct percpu_ref ref; | ||
| 60 | struct completion cmp; | ||
| 54 | }; | 61 | }; |
| 55 | 62 | ||
| 56 | static inline struct dev_dax *to_dev_dax(struct device *dev) | 63 | static inline struct dev_dax *to_dev_dax(struct device *dev) |
diff --git a/drivers/dax/device.c b/drivers/dax/device.c index f55829404a24..6ad964d7b077 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* Copyright(c) 2016-2018 Intel Corporation. All rights reserved. */ | 2 | /* Copyright(c) 2016-2018 Intel Corporation. All rights reserved. */ |
| 3 | #include <linux/memremap.h> | ||
| 3 | #include <linux/pagemap.h> | 4 | #include <linux/pagemap.h> |
| 4 | #include <linux/module.h> | 5 | #include <linux/module.h> |
| 5 | #include <linux/device.h> | 6 | #include <linux/device.h> |
| @@ -13,6 +14,38 @@ | |||
| 13 | #include "dax-private.h" | 14 | #include "dax-private.h" |
| 14 | #include "bus.h" | 15 | #include "bus.h" |
| 15 | 16 | ||
| 17 | static struct dev_dax *ref_to_dev_dax(struct percpu_ref *ref) | ||
| 18 | { | ||
| 19 | return container_of(ref, struct dev_dax, ref); | ||
| 20 | } | ||
| 21 | |||
| 22 | static void dev_dax_percpu_release(struct percpu_ref *ref) | ||
| 23 | { | ||
| 24 | struct dev_dax *dev_dax = ref_to_dev_dax(ref); | ||
| 25 | |||
| 26 | dev_dbg(&dev_dax->dev, "%s\n", __func__); | ||
| 27 | complete(&dev_dax->cmp); | ||
| 28 | } | ||
| 29 | |||
| 30 | static void dev_dax_percpu_exit(void *data) | ||
| 31 | { | ||
| 32 | struct percpu_ref *ref = data; | ||
| 33 | struct dev_dax *dev_dax = ref_to_dev_dax(ref); | ||
| 34 | |||
| 35 | dev_dbg(&dev_dax->dev, "%s\n", __func__); | ||
| 36 | wait_for_completion(&dev_dax->cmp); | ||
| 37 | percpu_ref_exit(ref); | ||
| 38 | } | ||
| 39 | |||
| 40 | static void dev_dax_percpu_kill(struct percpu_ref *data) | ||
| 41 | { | ||
| 42 | struct percpu_ref *ref = data; | ||
| 43 | struct dev_dax *dev_dax = ref_to_dev_dax(ref); | ||
| 44 | |||
| 45 | dev_dbg(&dev_dax->dev, "%s\n", __func__); | ||
| 46 | percpu_ref_kill(ref); | ||
| 47 | } | ||
| 48 | |||
| 16 | static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, | 49 | static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, |
| 17 | const char *func) | 50 | const char *func) |
| 18 | { | 51 | { |
| @@ -416,10 +449,38 @@ static int dev_dax_probe(struct device *dev) | |||
| 416 | { | 449 | { |
| 417 | struct dev_dax *dev_dax = to_dev_dax(dev); | 450 | struct dev_dax *dev_dax = to_dev_dax(dev); |
| 418 | struct dax_device *dax_dev = dev_dax->dax_dev; | 451 | struct dax_device *dax_dev = dev_dax->dax_dev; |
| 452 | struct resource *res = &dev_dax->region->res; | ||
| 419 | struct inode *inode; | 453 | struct inode *inode; |
| 420 | struct cdev *cdev; | 454 | struct cdev *cdev; |
| 455 | void *addr; | ||
| 421 | int rc; | 456 | int rc; |
| 422 | 457 | ||
| 458 | /* 1:1 map region resource range to device-dax instance range */ | ||
| 459 | if (!devm_request_mem_region(dev, res->start, resource_size(res), | ||
| 460 | dev_name(dev))) { | ||
| 461 | dev_warn(dev, "could not reserve region %pR\n", res); | ||
| 462 | return -EBUSY; | ||
| 463 | } | ||
| 464 | |||
| 465 | init_completion(&dev_dax->cmp); | ||
| 466 | rc = percpu_ref_init(&dev_dax->ref, dev_dax_percpu_release, 0, | ||
| 467 | GFP_KERNEL); | ||
| 468 | if (rc) | ||
| 469 | return rc; | ||
| 470 | |||
| 471 | rc = devm_add_action_or_reset(dev, dev_dax_percpu_exit, &dev_dax->ref); | ||
| 472 | if (rc) | ||
| 473 | return rc; | ||
| 474 | |||
| 475 | dev_dax->pgmap.ref = &dev_dax->ref; | ||
| 476 | dev_dax->pgmap.kill = dev_dax_percpu_kill; | ||
| 477 | addr = devm_memremap_pages(dev, &dev_dax->pgmap); | ||
| 478 | if (IS_ERR(addr)) { | ||
| 479 | devm_remove_action(dev, dev_dax_percpu_exit, &dev_dax->ref); | ||
| 480 | percpu_ref_exit(&dev_dax->ref); | ||
| 481 | return PTR_ERR(addr); | ||
| 482 | } | ||
| 483 | |||
| 423 | inode = dax_inode(dax_dev); | 484 | inode = dax_inode(dax_dev); |
| 424 | cdev = inode->i_cdev; | 485 | cdev = inode->i_cdev; |
| 425 | cdev_init(cdev, &dax_fops); | 486 | cdev_init(cdev, &dax_fops); |
diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index e1b50d8fd1f8..d3cefa7868ac 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c | |||
| @@ -18,54 +18,16 @@ | |||
| 18 | #include "../nvdimm/nd.h" | 18 | #include "../nvdimm/nd.h" |
| 19 | #include "bus.h" | 19 | #include "bus.h" |
| 20 | 20 | ||
| 21 | struct dax_pmem { | ||
| 22 | struct device *dev; | ||
| 23 | struct percpu_ref ref; | ||
| 24 | struct dev_pagemap pgmap; | ||
| 25 | struct completion cmp; | ||
| 26 | }; | ||
| 27 | |||
| 28 | static struct dax_pmem *to_dax_pmem(struct percpu_ref *ref) | ||
| 29 | { | ||
| 30 | return container_of(ref, struct dax_pmem, ref); | ||
| 31 | } | ||
| 32 | |||
| 33 | static void dax_pmem_percpu_release(struct percpu_ref *ref) | ||
| 34 | { | ||
| 35 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); | ||
| 36 | |||
| 37 | dev_dbg(dax_pmem->dev, "trace\n"); | ||
| 38 | complete(&dax_pmem->cmp); | ||
| 39 | } | ||
| 40 | |||
| 41 | static void dax_pmem_percpu_exit(void *data) | ||
| 42 | { | ||
| 43 | struct percpu_ref *ref = data; | ||
| 44 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); | ||
| 45 | |||
| 46 | dev_dbg(dax_pmem->dev, "trace\n"); | ||
| 47 | wait_for_completion(&dax_pmem->cmp); | ||
| 48 | percpu_ref_exit(ref); | ||
| 49 | } | ||
| 50 | |||
| 51 | static void dax_pmem_percpu_kill(struct percpu_ref *ref) | ||
| 52 | { | ||
| 53 | struct dax_pmem *dax_pmem = to_dax_pmem(ref); | ||
| 54 | |||
| 55 | dev_dbg(dax_pmem->dev, "trace\n"); | ||
| 56 | percpu_ref_kill(ref); | ||
| 57 | } | ||
| 58 | |||
| 59 | static int dax_pmem_probe(struct device *dev) | 21 | static int dax_pmem_probe(struct device *dev) |
| 60 | { | 22 | { |
| 61 | void *addr; | ||
| 62 | struct resource res; | 23 | struct resource res; |
| 63 | int rc, id, region_id; | 24 | int rc, id, region_id; |
| 25 | resource_size_t offset; | ||
| 64 | struct nd_pfn_sb *pfn_sb; | 26 | struct nd_pfn_sb *pfn_sb; |
| 65 | struct dev_dax *dev_dax; | 27 | struct dev_dax *dev_dax; |
| 66 | struct dax_pmem *dax_pmem; | ||
| 67 | struct nd_namespace_io *nsio; | 28 | struct nd_namespace_io *nsio; |
| 68 | struct dax_region *dax_region; | 29 | struct dax_region *dax_region; |
| 30 | struct dev_pagemap pgmap = { 0 }; | ||
| 69 | struct nd_namespace_common *ndns; | 31 | struct nd_namespace_common *ndns; |
| 70 | struct nd_dax *nd_dax = to_nd_dax(dev); | 32 | struct nd_dax *nd_dax = to_nd_dax(dev); |
| 71 | struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; | 33 | struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; |
| @@ -75,61 +37,37 @@ static int dax_pmem_probe(struct device *dev) | |||
| 75 | return PTR_ERR(ndns); | 37 | return PTR_ERR(ndns); |
| 76 | nsio = to_nd_namespace_io(&ndns->dev); | 38 | nsio = to_nd_namespace_io(&ndns->dev); |
| 77 | 39 | ||
| 78 | dax_pmem = devm_kzalloc(dev, sizeof(*dax_pmem), GFP_KERNEL); | ||
| 79 | if (!dax_pmem) | ||
| 80 | return -ENOMEM; | ||
| 81 | |||
| 82 | /* parse the 'pfn' info block via ->rw_bytes */ | 40 | /* parse the 'pfn' info block via ->rw_bytes */ |
| 83 | rc = devm_nsio_enable(dev, nsio); | 41 | rc = devm_nsio_enable(dev, nsio); |
| 84 | if (rc) | 42 | if (rc) |
| 85 | return rc; | 43 | return rc; |
| 86 | rc = nvdimm_setup_pfn(nd_pfn, &dax_pmem->pgmap); | 44 | rc = nvdimm_setup_pfn(nd_pfn, &pgmap); |
| 87 | if (rc) | 45 | if (rc) |
| 88 | return rc; | 46 | return rc; |
| 89 | devm_nsio_disable(dev, nsio); | 47 | devm_nsio_disable(dev, nsio); |
| 90 | 48 | ||
| 91 | pfn_sb = nd_pfn->pfn_sb; | 49 | /* reserve the metadata area, device-dax will reserve the data */ |
| 92 | 50 | pfn_sb = nd_pfn->pfn_sb; | |
| 93 | if (!devm_request_mem_region(dev, nsio->res.start, | 51 | offset = le64_to_cpu(pfn_sb->dataoff); |
| 94 | resource_size(&nsio->res), | 52 | if (!devm_request_mem_region(dev, nsio->res.start, offset, |
| 95 | dev_name(&ndns->dev))) { | 53 | dev_name(&ndns->dev))) { |
| 96 | dev_warn(dev, "could not reserve region %pR\n", &nsio->res); | 54 | dev_warn(dev, "could not reserve metadata\n"); |
| 97 | return -EBUSY; | 55 | return -EBUSY; |
| 98 | } | 56 | } |
| 99 | |||
| 100 | dax_pmem->dev = dev; | ||
| 101 | init_completion(&dax_pmem->cmp); | ||
| 102 | rc = percpu_ref_init(&dax_pmem->ref, dax_pmem_percpu_release, 0, | ||
| 103 | GFP_KERNEL); | ||
| 104 | if (rc) | ||
| 105 | return rc; | ||
| 106 | |||
| 107 | rc = devm_add_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref); | ||
| 108 | if (rc) { | ||
| 109 | percpu_ref_exit(&dax_pmem->ref); | ||
| 110 | return rc; | ||
| 111 | } | ||
| 112 | |||
| 113 | dax_pmem->pgmap.ref = &dax_pmem->ref; | ||
| 114 | dax_pmem->pgmap.kill = dax_pmem_percpu_kill; | ||
| 115 | addr = devm_memremap_pages(dev, &dax_pmem->pgmap); | ||
| 116 | if (IS_ERR(addr)) | ||
| 117 | return PTR_ERR(addr); | ||
| 118 | |||
| 119 | /* adjust the dax_region resource to the start of data */ | ||
| 120 | memcpy(&res, &dax_pmem->pgmap.res, sizeof(res)); | ||
| 121 | res.start += le64_to_cpu(pfn_sb->dataoff); | ||
| 122 | 57 | ||
| 123 | rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); | 58 | rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); |
| 124 | if (rc != 2) | 59 | if (rc != 2) |
| 125 | return -EINVAL; | 60 | return -EINVAL; |
| 126 | 61 | ||
| 62 | /* adjust the dax_region resource to the start of data */ | ||
| 63 | memcpy(&res, &pgmap.res, sizeof(res)); | ||
| 64 | res.start += offset; | ||
| 127 | dax_region = alloc_dax_region(dev, region_id, &res, | 65 | dax_region = alloc_dax_region(dev, region_id, &res, |
| 128 | le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP); | 66 | le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP); |
| 129 | if (!dax_region) | 67 | if (!dax_region) |
| 130 | return -ENOMEM; | 68 | return -ENOMEM; |
| 131 | 69 | ||
| 132 | dev_dax = devm_create_dev_dax(dax_region, id); | 70 | dev_dax = devm_create_dev_dax(dax_region, id, &pgmap); |
| 133 | 71 | ||
| 134 | /* child dev_dax instances now own the lifetime of the dax_region */ | 72 | /* child dev_dax instances now own the lifetime of the dax_region */ |
| 135 | dax_region_put(dax_region); | 73 | dax_region_put(dax_region); |
