summaryrefslogtreecommitdiffstats
path: root/drivers/nvdimm
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2016-03-11 13:15:36 -0500
committerDan Williams <dan.j.williams@intel.com>2016-05-09 18:35:42 -0400
commitcd03412a51ac4cb3001a8cdfae4560c9602f3387 (patch)
treec2d501759d7d96fab9a0f70eefba139876bb12de /drivers/nvdimm
parent0bfb8dd3edd6e423b5053c86e10c97e92cf205ea (diff)
libnvdimm, dax: introduce device-dax infrastructure
Device DAX is the device-centric analogue of Filesystem DAX (CONFIG_FS_DAX). It allows persistent memory ranges to be allocated and mapped without need of an intervening file system. This initial infrastructure arranges for a libnvdimm pfn-device to be represented as a different device-type so that it can be attached to a driver other than the pmem driver. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/nvdimm')
-rw-r--r--drivers/nvdimm/Kconfig13
-rw-r--r--drivers/nvdimm/Makefile1
-rw-r--r--drivers/nvdimm/bus.c4
-rw-r--r--drivers/nvdimm/claim.c2
-rw-r--r--drivers/nvdimm/dax_devs.c99
-rw-r--r--drivers/nvdimm/namespace_devs.c19
-rw-r--r--drivers/nvdimm/nd-core.h1
-rw-r--r--drivers/nvdimm/nd.h25
-rw-r--r--drivers/nvdimm/pfn_devs.c100
-rw-r--r--drivers/nvdimm/region.c2
-rw-r--r--drivers/nvdimm/region_devs.c29
11 files changed, 261 insertions, 34 deletions
diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig
index 53c11621d5b1..7c8a3bf07884 100644
--- a/drivers/nvdimm/Kconfig
+++ b/drivers/nvdimm/Kconfig
@@ -88,4 +88,17 @@ config NVDIMM_PFN
88 88
89 Select Y if unsure 89 Select Y if unsure
90 90
91config NVDIMM_DAX
92 bool "NVDIMM DAX: Raw access to persistent memory"
93 default LIBNVDIMM
94 depends on NVDIMM_PFN
95 help
96 Support raw device dax access to a persistent memory
97 namespace. For environments that want to hard partition
98 peristent memory, this capability provides a mechanism to
99 sub-divide a namespace into character devices that can only be
100 accessed via DAX (mmap(2)).
101
102 Select Y if unsure
103
91endif 104endif
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile
index ea84d3c4e8e5..909554c3f955 100644
--- a/drivers/nvdimm/Makefile
+++ b/drivers/nvdimm/Makefile
@@ -23,3 +23,4 @@ libnvdimm-y += label.o
23libnvdimm-$(CONFIG_ND_CLAIM) += claim.o 23libnvdimm-$(CONFIG_ND_CLAIM) += claim.o
24libnvdimm-$(CONFIG_BTT) += btt_devs.o 24libnvdimm-$(CONFIG_BTT) += btt_devs.o
25libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o 25libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o
26libnvdimm-$(CONFIG_NVDIMM_DAX) += dax_devs.o
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 19f822d7f652..97589e3cb852 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -40,6 +40,8 @@ static int to_nd_device_type(struct device *dev)
40 return ND_DEVICE_REGION_PMEM; 40 return ND_DEVICE_REGION_PMEM;
41 else if (is_nd_blk(dev)) 41 else if (is_nd_blk(dev))
42 return ND_DEVICE_REGION_BLK; 42 return ND_DEVICE_REGION_BLK;
43 else if (is_nd_dax(dev))
44 return ND_DEVICE_DAX_PMEM;
43 else if (is_nd_pmem(dev->parent) || is_nd_blk(dev->parent)) 45 else if (is_nd_pmem(dev->parent) || is_nd_blk(dev->parent))
44 return nd_region_to_nstype(to_nd_region(dev->parent)); 46 return nd_region_to_nstype(to_nd_region(dev->parent));
45 47
@@ -246,6 +248,8 @@ static void nd_async_device_unregister(void *d, async_cookie_t cookie)
246 248
247void __nd_device_register(struct device *dev) 249void __nd_device_register(struct device *dev)
248{ 250{
251 if (!dev)
252 return;
249 dev->bus = &nvdimm_bus_type; 253 dev->bus = &nvdimm_bus_type;
250 get_device(dev); 254 get_device(dev);
251 async_schedule_domain(nd_async_device_register, dev, 255 async_schedule_domain(nd_async_device_register, dev,
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index 6bbd0a36994a..5f53db59a058 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -85,6 +85,8 @@ static bool is_idle(struct device *dev, struct nd_namespace_common *ndns)
85 seed = nd_region->btt_seed; 85 seed = nd_region->btt_seed;
86 else if (is_nd_pfn(dev)) 86 else if (is_nd_pfn(dev))
87 seed = nd_region->pfn_seed; 87 seed = nd_region->pfn_seed;
88 else if (is_nd_dax(dev))
89 seed = nd_region->dax_seed;
88 90
89 if (seed == dev || ndns || dev->driver) 91 if (seed == dev || ndns || dev->driver)
90 return false; 92 return false;
diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c
new file mode 100644
index 000000000000..f90f7549e7f4
--- /dev/null
+++ b/drivers/nvdimm/dax_devs.c
@@ -0,0 +1,99 @@
1/*
2 * Copyright(c) 2013-2016 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 */
13#include <linux/device.h>
14#include <linux/sizes.h>
15#include <linux/slab.h>
16#include <linux/mm.h>
17#include "nd-core.h"
18#include "nd.h"
19
20static void nd_dax_release(struct device *dev)
21{
22 struct nd_region *nd_region = to_nd_region(dev->parent);
23 struct nd_dax *nd_dax = to_nd_dax(dev);
24 struct nd_pfn *nd_pfn = &nd_dax->nd_pfn;
25
26 dev_dbg(dev, "%s\n", __func__);
27 nd_detach_ndns(dev, &nd_pfn->ndns);
28 ida_simple_remove(&nd_region->dax_ida, nd_pfn->id);
29 kfree(nd_pfn->uuid);
30 kfree(nd_dax);
31}
32
33static struct device_type nd_dax_device_type = {
34 .name = "nd_dax",
35 .release = nd_dax_release,
36};
37
38bool is_nd_dax(struct device *dev)
39{
40 return dev ? dev->type == &nd_dax_device_type : false;
41}
42EXPORT_SYMBOL(is_nd_dax);
43
44struct nd_dax *to_nd_dax(struct device *dev)
45{
46 struct nd_dax *nd_dax = container_of(dev, struct nd_dax, nd_pfn.dev);
47
48 WARN_ON(!is_nd_dax(dev));
49 return nd_dax;
50}
51EXPORT_SYMBOL(to_nd_dax);
52
53static const struct attribute_group *nd_dax_attribute_groups[] = {
54 &nd_pfn_attribute_group,
55 &nd_device_attribute_group,
56 &nd_numa_attribute_group,
57 NULL,
58};
59
60static struct nd_dax *nd_dax_alloc(struct nd_region *nd_region)
61{
62 struct nd_pfn *nd_pfn;
63 struct nd_dax *nd_dax;
64 struct device *dev;
65
66 nd_dax = kzalloc(sizeof(*nd_dax), GFP_KERNEL);
67 if (!nd_dax)
68 return NULL;
69
70 nd_pfn = &nd_dax->nd_pfn;
71 nd_pfn->id = ida_simple_get(&nd_region->dax_ida, 0, 0, GFP_KERNEL);
72 if (nd_pfn->id < 0) {
73 kfree(nd_dax);
74 return NULL;
75 }
76
77 dev = &nd_pfn->dev;
78 dev_set_name(dev, "dax%d.%d", nd_region->id, nd_pfn->id);
79 dev->groups = nd_dax_attribute_groups;
80 dev->type = &nd_dax_device_type;
81 dev->parent = &nd_region->dev;
82
83 return nd_dax;
84}
85
86struct device *nd_dax_create(struct nd_region *nd_region)
87{
88 struct device *dev = NULL;
89 struct nd_dax *nd_dax;
90
91 if (!is_nd_pmem(&nd_region->dev))
92 return NULL;
93
94 nd_dax = nd_dax_alloc(nd_region);
95 if (nd_dax)
96 dev = nd_pfn_devinit(&nd_dax->nd_pfn, NULL);
97 __nd_device_register(dev);
98 return dev;
99}
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index e5ad5162bf34..c5e3196c45b0 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1288,6 +1288,8 @@ static ssize_t mode_show(struct device *dev,
1288 mode = "safe"; 1288 mode = "safe";
1289 else if (claim && is_nd_pfn(claim)) 1289 else if (claim && is_nd_pfn(claim))
1290 mode = "memory"; 1290 mode = "memory";
1291 else if (claim && is_nd_dax(claim))
1292 mode = "dax";
1291 else if (!claim && pmem_should_map_pages(dev)) 1293 else if (!claim && pmem_should_map_pages(dev))
1292 mode = "memory"; 1294 mode = "memory";
1293 else 1295 else
@@ -1379,14 +1381,17 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev)
1379{ 1381{
1380 struct nd_btt *nd_btt = is_nd_btt(dev) ? to_nd_btt(dev) : NULL; 1382 struct nd_btt *nd_btt = is_nd_btt(dev) ? to_nd_btt(dev) : NULL;
1381 struct nd_pfn *nd_pfn = is_nd_pfn(dev) ? to_nd_pfn(dev) : NULL; 1383 struct nd_pfn *nd_pfn = is_nd_pfn(dev) ? to_nd_pfn(dev) : NULL;
1384 struct nd_dax *nd_dax = is_nd_dax(dev) ? to_nd_dax(dev) : NULL;
1382 struct nd_namespace_common *ndns = NULL; 1385 struct nd_namespace_common *ndns = NULL;
1383 resource_size_t size; 1386 resource_size_t size;
1384 1387
1385 if (nd_btt || nd_pfn) { 1388 if (nd_btt || nd_pfn || nd_dax) {
1386 if (nd_btt) 1389 if (nd_btt)
1387 ndns = nd_btt->ndns; 1390 ndns = nd_btt->ndns;
1388 else if (nd_pfn) 1391 else if (nd_pfn)
1389 ndns = nd_pfn->ndns; 1392 ndns = nd_pfn->ndns;
1393 else if (nd_dax)
1394 ndns = nd_dax->nd_pfn.ndns;
1390 1395
1391 if (!ndns) 1396 if (!ndns)
1392 return ERR_PTR(-ENODEV); 1397 return ERR_PTR(-ENODEV);
@@ -1779,6 +1784,18 @@ void nd_region_create_blk_seed(struct nd_region *nd_region)
1779 nd_device_register(nd_region->ns_seed); 1784 nd_device_register(nd_region->ns_seed);
1780} 1785}
1781 1786
1787void nd_region_create_dax_seed(struct nd_region *nd_region)
1788{
1789 WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
1790 nd_region->dax_seed = nd_dax_create(nd_region);
1791 /*
1792 * Seed creation failures are not fatal, provisioning is simply
1793 * disabled until memory becomes available
1794 */
1795 if (!nd_region->dax_seed)
1796 dev_err(&nd_region->dev, "failed to create dax namespace\n");
1797}
1798
1782void nd_region_create_pfn_seed(struct nd_region *nd_region) 1799void nd_region_create_pfn_seed(struct nd_region *nd_region)
1783{ 1800{
1784 WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev)); 1801 WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index 1d1500f3d8b5..cb65308c0329 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -54,6 +54,7 @@ struct nd_region;
54void nd_region_create_blk_seed(struct nd_region *nd_region); 54void nd_region_create_blk_seed(struct nd_region *nd_region);
55void nd_region_create_btt_seed(struct nd_region *nd_region); 55void nd_region_create_btt_seed(struct nd_region *nd_region);
56void nd_region_create_pfn_seed(struct nd_region *nd_region); 56void nd_region_create_pfn_seed(struct nd_region *nd_region);
57void nd_region_create_dax_seed(struct nd_region *nd_region);
57void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev); 58void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev);
58int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus); 59int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
59void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); 60void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 6c36509662e4..46910b8f32b1 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -101,10 +101,12 @@ struct nd_region {
101 struct ida ns_ida; 101 struct ida ns_ida;
102 struct ida btt_ida; 102 struct ida btt_ida;
103 struct ida pfn_ida; 103 struct ida pfn_ida;
104 struct ida dax_ida;
104 unsigned long flags; 105 unsigned long flags;
105 struct device *ns_seed; 106 struct device *ns_seed;
106 struct device *btt_seed; 107 struct device *btt_seed;
107 struct device *pfn_seed; 108 struct device *pfn_seed;
109 struct device *dax_seed;
108 u16 ndr_mappings; 110 u16 ndr_mappings;
109 u64 ndr_size; 111 u64 ndr_size;
110 u64 ndr_start; 112 u64 ndr_start;
@@ -161,6 +163,10 @@ struct nd_pfn {
161 struct nd_namespace_common *ndns; 163 struct nd_namespace_common *ndns;
162}; 164};
163 165
166struct nd_dax {
167 struct nd_pfn nd_pfn;
168};
169
164enum nd_async_mode { 170enum nd_async_mode {
165 ND_SYNC, 171 ND_SYNC,
166 ND_ASYNC, 172 ND_ASYNC,
@@ -224,7 +230,10 @@ struct nd_pfn *to_nd_pfn(struct device *dev);
224int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns); 230int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns);
225bool is_nd_pfn(struct device *dev); 231bool is_nd_pfn(struct device *dev);
226struct device *nd_pfn_create(struct nd_region *nd_region); 232struct device *nd_pfn_create(struct nd_region *nd_region);
233struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn,
234 struct nd_namespace_common *ndns);
227int nd_pfn_validate(struct nd_pfn *nd_pfn); 235int nd_pfn_validate(struct nd_pfn *nd_pfn);
236extern struct attribute_group nd_pfn_attribute_group;
228#else 237#else
229static inline int nd_pfn_probe(struct device *dev, 238static inline int nd_pfn_probe(struct device *dev,
230 struct nd_namespace_common *ndns) 239 struct nd_namespace_common *ndns)
@@ -248,6 +257,22 @@ static inline int nd_pfn_validate(struct nd_pfn *nd_pfn)
248} 257}
249#endif 258#endif
250 259
260struct nd_dax *to_nd_dax(struct device *dev);
261#if IS_ENABLED(CONFIG_NVDIMM_DAX)
262bool is_nd_dax(struct device *dev);
263struct device *nd_dax_create(struct nd_region *nd_region);
264#else
265static inline bool is_nd_dax(struct device *dev)
266{
267 return false;
268}
269
270static inline struct device *nd_dax_create(struct nd_region *nd_region)
271{
272 return NULL;
273}
274#endif
275
251struct nd_region *to_nd_region(struct device *dev); 276struct nd_region *to_nd_region(struct device *dev);
252int nd_region_to_nstype(struct nd_region *nd_region); 277int nd_region_to_nstype(struct nd_region *nd_region);
253int nd_region_register_namespaces(struct nd_region *nd_region, int *err); 278int nd_region_register_namespaces(struct nd_region *nd_region, int *err);
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index e8693fe65e49..6ade2eb7615d 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. 2 * Copyright(c) 2013-2016 Intel Corporation. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of version 2 of the GNU General Public License as 5 * it under the terms of version 2 of the GNU General Public License as
@@ -54,10 +54,29 @@ struct nd_pfn *to_nd_pfn(struct device *dev)
54} 54}
55EXPORT_SYMBOL(to_nd_pfn); 55EXPORT_SYMBOL(to_nd_pfn);
56 56
57static struct nd_pfn *to_nd_pfn_safe(struct device *dev)
58{
59 /*
60 * pfn device attributes are re-used by dax device instances, so we
61 * need to be careful to correct device-to-nd_pfn conversion.
62 */
63 if (is_nd_pfn(dev))
64 return to_nd_pfn(dev);
65
66 if (is_nd_dax(dev)) {
67 struct nd_dax *nd_dax = to_nd_dax(dev);
68
69 return &nd_dax->nd_pfn;
70 }
71
72 WARN_ON(1);
73 return NULL;
74}
75
57static ssize_t mode_show(struct device *dev, 76static ssize_t mode_show(struct device *dev,
58 struct device_attribute *attr, char *buf) 77 struct device_attribute *attr, char *buf)
59{ 78{
60 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 79 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
61 80
62 switch (nd_pfn->mode) { 81 switch (nd_pfn->mode) {
63 case PFN_MODE_RAM: 82 case PFN_MODE_RAM:
@@ -72,7 +91,7 @@ static ssize_t mode_show(struct device *dev,
72static ssize_t mode_store(struct device *dev, 91static ssize_t mode_store(struct device *dev,
73 struct device_attribute *attr, const char *buf, size_t len) 92 struct device_attribute *attr, const char *buf, size_t len)
74{ 93{
75 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 94 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
76 ssize_t rc = 0; 95 ssize_t rc = 0;
77 96
78 device_lock(dev); 97 device_lock(dev);
@@ -106,7 +125,7 @@ static DEVICE_ATTR_RW(mode);
106static ssize_t align_show(struct device *dev, 125static ssize_t align_show(struct device *dev,
107 struct device_attribute *attr, char *buf) 126 struct device_attribute *attr, char *buf)
108{ 127{
109 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 128 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
110 129
111 return sprintf(buf, "%lx\n", nd_pfn->align); 130 return sprintf(buf, "%lx\n", nd_pfn->align);
112} 131}
@@ -134,7 +153,7 @@ static ssize_t __align_store(struct nd_pfn *nd_pfn, const char *buf)
134static ssize_t align_store(struct device *dev, 153static ssize_t align_store(struct device *dev,
135 struct device_attribute *attr, const char *buf, size_t len) 154 struct device_attribute *attr, const char *buf, size_t len)
136{ 155{
137 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 156 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
138 ssize_t rc; 157 ssize_t rc;
139 158
140 device_lock(dev); 159 device_lock(dev);
@@ -152,7 +171,7 @@ static DEVICE_ATTR_RW(align);
152static ssize_t uuid_show(struct device *dev, 171static ssize_t uuid_show(struct device *dev,
153 struct device_attribute *attr, char *buf) 172 struct device_attribute *attr, char *buf)
154{ 173{
155 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 174 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
156 175
157 if (nd_pfn->uuid) 176 if (nd_pfn->uuid)
158 return sprintf(buf, "%pUb\n", nd_pfn->uuid); 177 return sprintf(buf, "%pUb\n", nd_pfn->uuid);
@@ -162,7 +181,7 @@ static ssize_t uuid_show(struct device *dev,
162static ssize_t uuid_store(struct device *dev, 181static ssize_t uuid_store(struct device *dev,
163 struct device_attribute *attr, const char *buf, size_t len) 182 struct device_attribute *attr, const char *buf, size_t len)
164{ 183{
165 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 184 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
166 ssize_t rc; 185 ssize_t rc;
167 186
168 device_lock(dev); 187 device_lock(dev);
@@ -178,7 +197,7 @@ static DEVICE_ATTR_RW(uuid);
178static ssize_t namespace_show(struct device *dev, 197static ssize_t namespace_show(struct device *dev,
179 struct device_attribute *attr, char *buf) 198 struct device_attribute *attr, char *buf)
180{ 199{
181 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 200 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
182 ssize_t rc; 201 ssize_t rc;
183 202
184 nvdimm_bus_lock(dev); 203 nvdimm_bus_lock(dev);
@@ -191,7 +210,7 @@ static ssize_t namespace_show(struct device *dev,
191static ssize_t namespace_store(struct device *dev, 210static ssize_t namespace_store(struct device *dev,
192 struct device_attribute *attr, const char *buf, size_t len) 211 struct device_attribute *attr, const char *buf, size_t len)
193{ 212{
194 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 213 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
195 ssize_t rc; 214 ssize_t rc;
196 215
197 device_lock(dev); 216 device_lock(dev);
@@ -209,7 +228,7 @@ static DEVICE_ATTR_RW(namespace);
209static ssize_t resource_show(struct device *dev, 228static ssize_t resource_show(struct device *dev,
210 struct device_attribute *attr, char *buf) 229 struct device_attribute *attr, char *buf)
211{ 230{
212 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 231 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
213 ssize_t rc; 232 ssize_t rc;
214 233
215 device_lock(dev); 234 device_lock(dev);
@@ -235,7 +254,7 @@ static DEVICE_ATTR_RO(resource);
235static ssize_t size_show(struct device *dev, 254static ssize_t size_show(struct device *dev,
236 struct device_attribute *attr, char *buf) 255 struct device_attribute *attr, char *buf)
237{ 256{
238 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 257 struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
239 ssize_t rc; 258 ssize_t rc;
240 259
241 device_lock(dev); 260 device_lock(dev);
@@ -270,7 +289,7 @@ static struct attribute *nd_pfn_attributes[] = {
270 NULL, 289 NULL,
271}; 290};
272 291
273static struct attribute_group nd_pfn_attribute_group = { 292struct attribute_group nd_pfn_attribute_group = {
274 .attrs = nd_pfn_attributes, 293 .attrs = nd_pfn_attributes,
275}; 294};
276 295
@@ -281,15 +300,31 @@ static const struct attribute_group *nd_pfn_attribute_groups[] = {
281 NULL, 300 NULL,
282}; 301};
283 302
284static struct device *__nd_pfn_create(struct nd_region *nd_region, 303struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn,
285 struct nd_namespace_common *ndns) 304 struct nd_namespace_common *ndns)
286{ 305{
287 struct nd_pfn *nd_pfn; 306 struct device *dev = &nd_pfn->dev;
288 struct device *dev;
289 307
290 /* we can only create pages for contiguous ranged of pmem */ 308 if (!nd_pfn)
291 if (!is_nd_pmem(&nd_region->dev)) 309 return NULL;
310
311 nd_pfn->mode = PFN_MODE_NONE;
312 nd_pfn->align = HPAGE_SIZE;
313 dev = &nd_pfn->dev;
314 device_initialize(&nd_pfn->dev);
315 if (ndns && !__nd_attach_ndns(&nd_pfn->dev, ndns, &nd_pfn->ndns)) {
316 dev_dbg(&ndns->dev, "%s failed, already claimed by %s\n",
317 __func__, dev_name(ndns->claim));
318 put_device(dev);
292 return NULL; 319 return NULL;
320 }
321 return dev;
322}
323
324static struct nd_pfn *nd_pfn_alloc(struct nd_region *nd_region)
325{
326 struct nd_pfn *nd_pfn;
327 struct device *dev;
293 328
294 nd_pfn = kzalloc(sizeof(*nd_pfn), GFP_KERNEL); 329 nd_pfn = kzalloc(sizeof(*nd_pfn), GFP_KERNEL);
295 if (!nd_pfn) 330 if (!nd_pfn)
@@ -301,29 +336,27 @@ static struct device *__nd_pfn_create(struct nd_region *nd_region,
301 return NULL; 336 return NULL;
302 } 337 }
303 338
304 nd_pfn->mode = PFN_MODE_NONE;
305 nd_pfn->align = HPAGE_SIZE;
306 dev = &nd_pfn->dev; 339 dev = &nd_pfn->dev;
307 dev_set_name(dev, "pfn%d.%d", nd_region->id, nd_pfn->id); 340 dev_set_name(dev, "pfn%d.%d", nd_region->id, nd_pfn->id);
308 dev->parent = &nd_region->dev;
309 dev->type = &nd_pfn_device_type;
310 dev->groups = nd_pfn_attribute_groups; 341 dev->groups = nd_pfn_attribute_groups;
311 device_initialize(&nd_pfn->dev); 342 dev->type = &nd_pfn_device_type;
312 if (ndns && !__nd_attach_ndns(&nd_pfn->dev, ndns, &nd_pfn->ndns)) { 343 dev->parent = &nd_region->dev;
313 dev_dbg(&ndns->dev, "%s failed, already claimed by %s\n", 344
314 __func__, dev_name(ndns->claim)); 345 return nd_pfn;
315 put_device(dev);
316 return NULL;
317 }
318 return dev;
319} 346}
320 347
321struct device *nd_pfn_create(struct nd_region *nd_region) 348struct device *nd_pfn_create(struct nd_region *nd_region)
322{ 349{
323 struct device *dev = __nd_pfn_create(nd_region, NULL); 350 struct nd_pfn *nd_pfn;
351 struct device *dev;
352
353 if (!is_nd_pmem(&nd_region->dev))
354 return NULL;
355
356 nd_pfn = nd_pfn_alloc(nd_region);
357 dev = nd_pfn_devinit(nd_pfn, NULL);
324 358
325 if (dev) 359 __nd_device_register(dev);
326 __nd_device_register(dev);
327 return dev; 360 return dev;
328} 361}
329 362
@@ -423,7 +456,8 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
423 return -ENODEV; 456 return -ENODEV;
424 457
425 nvdimm_bus_lock(&ndns->dev); 458 nvdimm_bus_lock(&ndns->dev);
426 pfn_dev = __nd_pfn_create(nd_region, ndns); 459 nd_pfn = nd_pfn_alloc(nd_region);
460 pfn_dev = nd_pfn_devinit(nd_pfn, ndns);
427 nvdimm_bus_unlock(&ndns->dev); 461 nvdimm_bus_unlock(&ndns->dev);
428 if (!pfn_dev) 462 if (!pfn_dev)
429 return -ENOMEM; 463 return -ENOMEM;
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c
index 4b7715e29cff..05a912359939 100644
--- a/drivers/nvdimm/region.c
+++ b/drivers/nvdimm/region.c
@@ -54,6 +54,7 @@ static int nd_region_probe(struct device *dev)
54 54
55 nd_region->btt_seed = nd_btt_create(nd_region); 55 nd_region->btt_seed = nd_btt_create(nd_region);
56 nd_region->pfn_seed = nd_pfn_create(nd_region); 56 nd_region->pfn_seed = nd_pfn_create(nd_region);
57 nd_region->dax_seed = nd_dax_create(nd_region);
57 if (err == 0) 58 if (err == 0)
58 return 0; 59 return 0;
59 60
@@ -86,6 +87,7 @@ static int nd_region_remove(struct device *dev)
86 nd_region->ns_seed = NULL; 87 nd_region->ns_seed = NULL;
87 nd_region->btt_seed = NULL; 88 nd_region->btt_seed = NULL;
88 nd_region->pfn_seed = NULL; 89 nd_region->pfn_seed = NULL;
90 nd_region->dax_seed = NULL;
89 dev_set_drvdata(dev, NULL); 91 dev_set_drvdata(dev, NULL);
90 nvdimm_bus_unlock(dev); 92 nvdimm_bus_unlock(dev);
91 93
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 139bf71ca549..9e1b054e0e61 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -306,6 +306,23 @@ static ssize_t pfn_seed_show(struct device *dev,
306} 306}
307static DEVICE_ATTR_RO(pfn_seed); 307static DEVICE_ATTR_RO(pfn_seed);
308 308
309static ssize_t dax_seed_show(struct device *dev,
310 struct device_attribute *attr, char *buf)
311{
312 struct nd_region *nd_region = to_nd_region(dev);
313 ssize_t rc;
314
315 nvdimm_bus_lock(dev);
316 if (nd_region->dax_seed)
317 rc = sprintf(buf, "%s\n", dev_name(nd_region->dax_seed));
318 else
319 rc = sprintf(buf, "\n");
320 nvdimm_bus_unlock(dev);
321
322 return rc;
323}
324static DEVICE_ATTR_RO(dax_seed);
325
309static ssize_t read_only_show(struct device *dev, 326static ssize_t read_only_show(struct device *dev,
310 struct device_attribute *attr, char *buf) 327 struct device_attribute *attr, char *buf)
311{ 328{
@@ -335,6 +352,7 @@ static struct attribute *nd_region_attributes[] = {
335 &dev_attr_mappings.attr, 352 &dev_attr_mappings.attr,
336 &dev_attr_btt_seed.attr, 353 &dev_attr_btt_seed.attr,
337 &dev_attr_pfn_seed.attr, 354 &dev_attr_pfn_seed.attr,
355 &dev_attr_dax_seed.attr,
338 &dev_attr_read_only.attr, 356 &dev_attr_read_only.attr,
339 &dev_attr_set_cookie.attr, 357 &dev_attr_set_cookie.attr,
340 &dev_attr_available_size.attr, 358 &dev_attr_available_size.attr,
@@ -353,6 +371,9 @@ static umode_t region_visible(struct kobject *kobj, struct attribute *a, int n)
353 if (!is_nd_pmem(dev) && a == &dev_attr_pfn_seed.attr) 371 if (!is_nd_pmem(dev) && a == &dev_attr_pfn_seed.attr)
354 return 0; 372 return 0;
355 373
374 if (!is_nd_pmem(dev) && a == &dev_attr_dax_seed.attr)
375 return 0;
376
356 if (a != &dev_attr_set_cookie.attr 377 if (a != &dev_attr_set_cookie.attr
357 && a != &dev_attr_available_size.attr) 378 && a != &dev_attr_available_size.attr)
358 return a->mode; 379 return a->mode;
@@ -441,6 +462,13 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus,
441 nd_region_create_pfn_seed(nd_region); 462 nd_region_create_pfn_seed(nd_region);
442 nvdimm_bus_unlock(dev); 463 nvdimm_bus_unlock(dev);
443 } 464 }
465 if (is_nd_dax(dev) && probe) {
466 nd_region = to_nd_region(dev->parent);
467 nvdimm_bus_lock(dev);
468 if (nd_region->dax_seed == dev)
469 nd_region_create_dax_seed(nd_region);
470 nvdimm_bus_unlock(dev);
471 }
444} 472}
445 473
446void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev) 474void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev)
@@ -718,6 +746,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
718 ida_init(&nd_region->ns_ida); 746 ida_init(&nd_region->ns_ida);
719 ida_init(&nd_region->btt_ida); 747 ida_init(&nd_region->btt_ida);
720 ida_init(&nd_region->pfn_ida); 748 ida_init(&nd_region->pfn_ida);
749 ida_init(&nd_region->dax_ida);
721 dev = &nd_region->dev; 750 dev = &nd_region->dev;
722 dev_set_name(dev, "region%d", nd_region->id); 751 dev_set_name(dev, "region%d", nd_region->id);
723 dev->parent = &nvdimm_bus->dev; 752 dev->parent = &nvdimm_bus->dev;