diff options
author | Dan Williams <dan.j.williams@intel.com> | 2016-05-18 17:50:12 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2016-05-21 01:02:57 -0400 |
commit | c5ed9268643c7c4c9f2aaa0fd4c936095e6480ef (patch) | |
tree | 5fc22cf3fddd4ddad159edfaa4ee83430c0c820f | |
parent | b354aba0165519a74f540f2ba89d7ec78efca21d (diff) |
libnvdimm, dax: autodetect support
For autodetecting a previously established dax configuration we need the
info block to indicate block-device vs device-dax mode, and we need to
have the default namespace probe hand-off the configuration to the
dax_pmem driver.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | drivers/nvdimm/dax_devs.c | 35 | ||||
-rw-r--r-- | drivers/nvdimm/nd.h | 11 | ||||
-rw-r--r-- | drivers/nvdimm/pfn.h | 1 | ||||
-rw-r--r-- | drivers/nvdimm/pfn_devs.c | 15 | ||||
-rw-r--r-- | drivers/nvdimm/pmem.c | 3 |
5 files changed, 57 insertions, 8 deletions
diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c index f90f7549e7f4..45fa82cae87c 100644 --- a/drivers/nvdimm/dax_devs.c +++ b/drivers/nvdimm/dax_devs.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
17 | #include "nd-core.h" | 17 | #include "nd-core.h" |
18 | #include "pfn.h" | ||
18 | #include "nd.h" | 19 | #include "nd.h" |
19 | 20 | ||
20 | static void nd_dax_release(struct device *dev) | 21 | static void nd_dax_release(struct device *dev) |
@@ -97,3 +98,37 @@ struct device *nd_dax_create(struct nd_region *nd_region) | |||
97 | __nd_device_register(dev); | 98 | __nd_device_register(dev); |
98 | return dev; | 99 | return dev; |
99 | } | 100 | } |
101 | |||
102 | int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns) | ||
103 | { | ||
104 | int rc; | ||
105 | struct nd_dax *nd_dax; | ||
106 | struct device *dax_dev; | ||
107 | struct nd_pfn *nd_pfn; | ||
108 | struct nd_pfn_sb *pfn_sb; | ||
109 | struct nd_region *nd_region = to_nd_region(ndns->dev.parent); | ||
110 | |||
111 | if (ndns->force_raw) | ||
112 | return -ENODEV; | ||
113 | |||
114 | nvdimm_bus_lock(&ndns->dev); | ||
115 | nd_dax = nd_dax_alloc(nd_region); | ||
116 | nd_pfn = &nd_dax->nd_pfn; | ||
117 | dax_dev = nd_pfn_devinit(nd_pfn, ndns); | ||
118 | nvdimm_bus_unlock(&ndns->dev); | ||
119 | if (!dax_dev) | ||
120 | return -ENOMEM; | ||
121 | pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); | ||
122 | nd_pfn->pfn_sb = pfn_sb; | ||
123 | rc = nd_pfn_validate(nd_pfn, DAX_SIG); | ||
124 | dev_dbg(dev, "%s: dax: %s\n", __func__, | ||
125 | rc == 0 ? dev_name(dax_dev) : "<none>"); | ||
126 | if (rc < 0) { | ||
127 | __nd_detach_ndns(dax_dev, &nd_pfn->ndns); | ||
128 | put_device(dax_dev); | ||
129 | } else | ||
130 | __nd_device_register(dax_dev); | ||
131 | |||
132 | return rc; | ||
133 | } | ||
134 | EXPORT_SYMBOL(nd_dax_probe); | ||
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 46910b8f32b1..d0ac93c31dda 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h | |||
@@ -232,7 +232,7 @@ bool is_nd_pfn(struct device *dev); | |||
232 | struct device *nd_pfn_create(struct nd_region *nd_region); | 232 | struct device *nd_pfn_create(struct nd_region *nd_region); |
233 | struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn, | 233 | struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn, |
234 | struct nd_namespace_common *ndns); | 234 | struct nd_namespace_common *ndns); |
235 | int nd_pfn_validate(struct nd_pfn *nd_pfn); | 235 | int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig); |
236 | extern struct attribute_group nd_pfn_attribute_group; | 236 | extern struct attribute_group nd_pfn_attribute_group; |
237 | #else | 237 | #else |
238 | static inline int nd_pfn_probe(struct device *dev, | 238 | static inline int nd_pfn_probe(struct device *dev, |
@@ -251,7 +251,7 @@ static inline struct device *nd_pfn_create(struct nd_region *nd_region) | |||
251 | return NULL; | 251 | return NULL; |
252 | } | 252 | } |
253 | 253 | ||
254 | static inline int nd_pfn_validate(struct nd_pfn *nd_pfn) | 254 | static inline int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) |
255 | { | 255 | { |
256 | return -ENODEV; | 256 | return -ENODEV; |
257 | } | 257 | } |
@@ -259,9 +259,16 @@ static inline int nd_pfn_validate(struct nd_pfn *nd_pfn) | |||
259 | 259 | ||
260 | struct nd_dax *to_nd_dax(struct device *dev); | 260 | struct nd_dax *to_nd_dax(struct device *dev); |
261 | #if IS_ENABLED(CONFIG_NVDIMM_DAX) | 261 | #if IS_ENABLED(CONFIG_NVDIMM_DAX) |
262 | int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns); | ||
262 | bool is_nd_dax(struct device *dev); | 263 | bool is_nd_dax(struct device *dev); |
263 | struct device *nd_dax_create(struct nd_region *nd_region); | 264 | struct device *nd_dax_create(struct nd_region *nd_region); |
264 | #else | 265 | #else |
266 | static inline int nd_dax_probe(struct device *dev, | ||
267 | struct nd_namespace_common *ndns) | ||
268 | { | ||
269 | return -ENODEV; | ||
270 | } | ||
271 | |||
265 | static inline bool is_nd_dax(struct device *dev) | 272 | static inline bool is_nd_dax(struct device *dev) |
266 | { | 273 | { |
267 | return false; | 274 | return false; |
diff --git a/drivers/nvdimm/pfn.h b/drivers/nvdimm/pfn.h index 9d2704c83fa7..dde9853453d3 100644 --- a/drivers/nvdimm/pfn.h +++ b/drivers/nvdimm/pfn.h | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #define PFN_SIG_LEN 16 | 20 | #define PFN_SIG_LEN 16 |
21 | #define PFN_SIG "NVDIMM_PFN_INFO\0" | 21 | #define PFN_SIG "NVDIMM_PFN_INFO\0" |
22 | #define DAX_SIG "NVDIMM_DAX_INFO\0" | ||
22 | 23 | ||
23 | struct nd_pfn_sb { | 24 | struct nd_pfn_sb { |
24 | u8 signature[PFN_SIG_LEN]; | 25 | u8 signature[PFN_SIG_LEN]; |
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 58740d7ce81b..816cd9828ca5 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c | |||
@@ -360,7 +360,7 @@ struct device *nd_pfn_create(struct nd_region *nd_region) | |||
360 | return dev; | 360 | return dev; |
361 | } | 361 | } |
362 | 362 | ||
363 | int nd_pfn_validate(struct nd_pfn *nd_pfn) | 363 | int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) |
364 | { | 364 | { |
365 | u64 checksum, offset; | 365 | u64 checksum, offset; |
366 | struct nd_namespace_io *nsio; | 366 | struct nd_namespace_io *nsio; |
@@ -377,7 +377,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn) | |||
377 | if (nvdimm_read_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb))) | 377 | if (nvdimm_read_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb))) |
378 | return -ENXIO; | 378 | return -ENXIO; |
379 | 379 | ||
380 | if (memcmp(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN) != 0) | 380 | if (memcmp(pfn_sb->signature, sig, PFN_SIG_LEN) != 0) |
381 | return -ENODEV; | 381 | return -ENODEV; |
382 | 382 | ||
383 | checksum = le64_to_cpu(pfn_sb->checksum); | 383 | checksum = le64_to_cpu(pfn_sb->checksum); |
@@ -467,7 +467,7 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns) | |||
467 | pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); | 467 | pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); |
468 | nd_pfn = to_nd_pfn(pfn_dev); | 468 | nd_pfn = to_nd_pfn(pfn_dev); |
469 | nd_pfn->pfn_sb = pfn_sb; | 469 | nd_pfn->pfn_sb = pfn_sb; |
470 | rc = nd_pfn_validate(nd_pfn); | 470 | rc = nd_pfn_validate(nd_pfn, PFN_SIG); |
471 | dev_dbg(dev, "%s: pfn: %s\n", __func__, | 471 | dev_dbg(dev, "%s: pfn: %s\n", __func__, |
472 | rc == 0 ? dev_name(pfn_dev) : "<none>"); | 472 | rc == 0 ? dev_name(pfn_dev) : "<none>"); |
473 | if (rc < 0) { | 473 | if (rc < 0) { |
@@ -552,6 +552,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) | |||
552 | struct nd_pfn_sb *pfn_sb; | 552 | struct nd_pfn_sb *pfn_sb; |
553 | unsigned long npfns; | 553 | unsigned long npfns; |
554 | phys_addr_t offset; | 554 | phys_addr_t offset; |
555 | const char *sig; | ||
555 | u64 checksum; | 556 | u64 checksum; |
556 | int rc; | 557 | int rc; |
557 | 558 | ||
@@ -560,7 +561,11 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) | |||
560 | return -ENOMEM; | 561 | return -ENOMEM; |
561 | 562 | ||
562 | nd_pfn->pfn_sb = pfn_sb; | 563 | nd_pfn->pfn_sb = pfn_sb; |
563 | rc = nd_pfn_validate(nd_pfn); | 564 | if (is_nd_dax(&nd_pfn->dev)) |
565 | sig = DAX_SIG; | ||
566 | else | ||
567 | sig = PFN_SIG; | ||
568 | rc = nd_pfn_validate(nd_pfn, sig); | ||
564 | if (rc != -ENODEV) | 569 | if (rc != -ENODEV) |
565 | return rc; | 570 | return rc; |
566 | 571 | ||
@@ -628,7 +633,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) | |||
628 | pfn_sb->mode = cpu_to_le32(nd_pfn->mode); | 633 | pfn_sb->mode = cpu_to_le32(nd_pfn->mode); |
629 | pfn_sb->dataoff = cpu_to_le64(offset); | 634 | pfn_sb->dataoff = cpu_to_le64(offset); |
630 | pfn_sb->npfns = cpu_to_le64(npfns); | 635 | pfn_sb->npfns = cpu_to_le64(npfns); |
631 | memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN); | 636 | memcpy(pfn_sb->signature, sig, PFN_SIG_LEN); |
632 | memcpy(pfn_sb->uuid, nd_pfn->uuid, 16); | 637 | memcpy(pfn_sb->uuid, nd_pfn->uuid, 16); |
633 | memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16); | 638 | memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16); |
634 | pfn_sb->version_major = cpu_to_le16(1); | 639 | pfn_sb->version_major = cpu_to_le16(1); |
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index d9a0dbc2d023..042baec56931 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c | |||
@@ -320,7 +320,8 @@ static int nd_pmem_probe(struct device *dev) | |||
320 | return pmem_attach_disk(dev, ndns); | 320 | return pmem_attach_disk(dev, ndns); |
321 | 321 | ||
322 | /* if we find a valid info-block we'll come back as that personality */ | 322 | /* if we find a valid info-block we'll come back as that personality */ |
323 | if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0) | 323 | if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0 |
324 | || nd_dax_probe(dev, ndns) == 0) | ||
324 | return -ENXIO; | 325 | return -ENXIO; |
325 | 326 | ||
326 | /* ...otherwise we're just a raw pmem device */ | 327 | /* ...otherwise we're just a raw pmem device */ |