aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dax/device.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2018-10-29 15:52:42 -0700
committerDan Williams <dan.j.williams@intel.com>2019-01-06 21:26:21 -0800
commit89ec9f2cfa36cc5fca2fb445ed221bb9add7b536 (patch)
tree1306755d2ecae784ddee3df710c16c4cfeaff771 /drivers/dax/device.c
parentdevice-dax: Introduce bus + driver model (diff)
downloadlinux-dev-89ec9f2cfa36cc5fca2fb445ed221bb9add7b536.tar.xz
linux-dev-89ec9f2cfa36cc5fca2fb445ed221bb9add7b536.zip
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>
Diffstat (limited to 'drivers/dax/device.c')
-rw-r--r--drivers/dax/device.c61
1 files changed, 61 insertions, 0 deletions
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 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2016-2018 Intel Corporation. All rights reserved. */
+#include <linux/memremap.h>
#include <linux/pagemap.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -13,6 +14,38 @@
#include "dax-private.h"
#include "bus.h"
+static struct dev_dax *ref_to_dev_dax(struct percpu_ref *ref)
+{
+ return container_of(ref, struct dev_dax, ref);
+}
+
+static void dev_dax_percpu_release(struct percpu_ref *ref)
+{
+ struct dev_dax *dev_dax = ref_to_dev_dax(ref);
+
+ dev_dbg(&dev_dax->dev, "%s\n", __func__);
+ complete(&dev_dax->cmp);
+}
+
+static void dev_dax_percpu_exit(void *data)
+{
+ struct percpu_ref *ref = data;
+ struct dev_dax *dev_dax = ref_to_dev_dax(ref);
+
+ dev_dbg(&dev_dax->dev, "%s\n", __func__);
+ wait_for_completion(&dev_dax->cmp);
+ percpu_ref_exit(ref);
+}
+
+static void dev_dax_percpu_kill(struct percpu_ref *data)
+{
+ struct percpu_ref *ref = data;
+ struct dev_dax *dev_dax = ref_to_dev_dax(ref);
+
+ dev_dbg(&dev_dax->dev, "%s\n", __func__);
+ percpu_ref_kill(ref);
+}
+
static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
const char *func)
{
@@ -416,10 +449,38 @@ static int dev_dax_probe(struct device *dev)
{
struct dev_dax *dev_dax = to_dev_dax(dev);
struct dax_device *dax_dev = dev_dax->dax_dev;
+ struct resource *res = &dev_dax->region->res;
struct inode *inode;
struct cdev *cdev;
+ void *addr;
int rc;
+ /* 1:1 map region resource range to device-dax instance range */
+ if (!devm_request_mem_region(dev, res->start, resource_size(res),
+ dev_name(dev))) {
+ dev_warn(dev, "could not reserve region %pR\n", res);
+ return -EBUSY;
+ }
+
+ init_completion(&dev_dax->cmp);
+ rc = percpu_ref_init(&dev_dax->ref, dev_dax_percpu_release, 0,
+ GFP_KERNEL);
+ if (rc)
+ return rc;
+
+ rc = devm_add_action_or_reset(dev, dev_dax_percpu_exit, &dev_dax->ref);
+ if (rc)
+ return rc;
+
+ dev_dax->pgmap.ref = &dev_dax->ref;
+ dev_dax->pgmap.kill = dev_dax_percpu_kill;
+ addr = devm_memremap_pages(dev, &dev_dax->pgmap);
+ if (IS_ERR(addr)) {
+ devm_remove_action(dev, dev_dax_percpu_exit, &dev_dax->ref);
+ percpu_ref_exit(&dev_dax->ref);
+ return PTR_ERR(addr);
+ }
+
inode = dax_inode(dax_dev);
cdev = inode->i_cdev;
cdev_init(cdev, &dax_fops);