diff options
author | Dan Williams <dan.j.williams@intel.com> | 2015-05-01 13:11:27 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2015-06-24 21:24:10 -0400 |
commit | eaf961536e1622ad21247ac8d44acd48ba65566e (patch) | |
tree | 479b1d2f81f9f8cc9abf99fa8f9b6496cbc88a25 /drivers/nvdimm | |
parent | 9f53f9fa4ad1d8bddd4d14359cdabc531aedffe8 (diff) |
libnvdimm, nfit: add interleave-set state-tracking infrastructure
On platforms that have firmware support for reading/writing per-dimm
label space, a portion of the dimm may be accessible via an interleave
set PMEM mapping in addition to the dimm's BLK (block-data-window
aperture(s)) interface. A label, stored in a "configuration data
region" on the dimm, disambiguates which dimm addresses are accessed
through which exclusive interface.
Add infrastructure that allows the kernel to block modifications to a
label in the set while any member dimm is active. Note that this is
meant only for enforcing "no modifications of active labels" via the
coarse ioctl command. Adding/deleting namespaces from an active
interleave set is always possible via sysfs.
Another aspect of tracking interleave sets is tracking their integrity
when DIMMs in a set are physically re-ordered. For this purpose we
generate an "interleave-set cookie" that can be recorded in a label and
validated against the current configuration. It is the bus provider
implementation's responsibility to calculate the interleave set cookie
and attach it to a given region.
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/nvdimm')
-rw-r--r-- | drivers/nvdimm/bus.c | 59 | ||||
-rw-r--r-- | drivers/nvdimm/core.c | 17 | ||||
-rw-r--r-- | drivers/nvdimm/dimm_devs.c | 19 | ||||
-rw-r--r-- | drivers/nvdimm/nd-core.h | 10 | ||||
-rw-r--r-- | drivers/nvdimm/nd.h | 1 | ||||
-rw-r--r-- | drivers/nvdimm/region_devs.c | 69 |
6 files changed, 172 insertions, 3 deletions
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 4b77665a6cc8..ffb43cada625 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c | |||
@@ -68,6 +68,21 @@ static struct module *to_bus_provider(struct device *dev) | |||
68 | return NULL; | 68 | return NULL; |
69 | } | 69 | } |
70 | 70 | ||
71 | static void nvdimm_bus_probe_start(struct nvdimm_bus *nvdimm_bus) | ||
72 | { | ||
73 | nvdimm_bus_lock(&nvdimm_bus->dev); | ||
74 | nvdimm_bus->probe_active++; | ||
75 | nvdimm_bus_unlock(&nvdimm_bus->dev); | ||
76 | } | ||
77 | |||
78 | static void nvdimm_bus_probe_end(struct nvdimm_bus *nvdimm_bus) | ||
79 | { | ||
80 | nvdimm_bus_lock(&nvdimm_bus->dev); | ||
81 | if (--nvdimm_bus->probe_active == 0) | ||
82 | wake_up(&nvdimm_bus->probe_wait); | ||
83 | nvdimm_bus_unlock(&nvdimm_bus->dev); | ||
84 | } | ||
85 | |||
71 | static int nvdimm_bus_probe(struct device *dev) | 86 | static int nvdimm_bus_probe(struct device *dev) |
72 | { | 87 | { |
73 | struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver); | 88 | struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver); |
@@ -78,7 +93,12 @@ static int nvdimm_bus_probe(struct device *dev) | |||
78 | if (!try_module_get(provider)) | 93 | if (!try_module_get(provider)) |
79 | return -ENXIO; | 94 | return -ENXIO; |
80 | 95 | ||
96 | nvdimm_bus_probe_start(nvdimm_bus); | ||
81 | rc = nd_drv->probe(dev); | 97 | rc = nd_drv->probe(dev); |
98 | if (rc == 0) | ||
99 | nd_region_probe_success(nvdimm_bus, dev); | ||
100 | nvdimm_bus_probe_end(nvdimm_bus); | ||
101 | |||
82 | dev_dbg(&nvdimm_bus->dev, "%s.probe(%s) = %d\n", dev->driver->name, | 102 | dev_dbg(&nvdimm_bus->dev, "%s.probe(%s) = %d\n", dev->driver->name, |
83 | dev_name(dev), rc); | 103 | dev_name(dev), rc); |
84 | if (rc != 0) | 104 | if (rc != 0) |
@@ -94,6 +114,8 @@ static int nvdimm_bus_remove(struct device *dev) | |||
94 | int rc; | 114 | int rc; |
95 | 115 | ||
96 | rc = nd_drv->remove(dev); | 116 | rc = nd_drv->remove(dev); |
117 | nd_region_disable(nvdimm_bus, dev); | ||
118 | |||
97 | dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name, | 119 | dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name, |
98 | dev_name(dev), rc); | 120 | dev_name(dev), rc); |
99 | module_put(provider); | 121 | module_put(provider); |
@@ -359,6 +381,34 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd, | |||
359 | } | 381 | } |
360 | EXPORT_SYMBOL_GPL(nd_cmd_out_size); | 382 | EXPORT_SYMBOL_GPL(nd_cmd_out_size); |
361 | 383 | ||
384 | static void wait_nvdimm_bus_probe_idle(struct nvdimm_bus *nvdimm_bus) | ||
385 | { | ||
386 | do { | ||
387 | if (nvdimm_bus->probe_active == 0) | ||
388 | break; | ||
389 | nvdimm_bus_unlock(&nvdimm_bus->dev); | ||
390 | wait_event(nvdimm_bus->probe_wait, | ||
391 | nvdimm_bus->probe_active == 0); | ||
392 | nvdimm_bus_lock(&nvdimm_bus->dev); | ||
393 | } while (true); | ||
394 | } | ||
395 | |||
396 | /* set_config requires an idle interleave set */ | ||
397 | static int nd_cmd_clear_to_send(struct nvdimm *nvdimm, unsigned int cmd) | ||
398 | { | ||
399 | struct nvdimm_bus *nvdimm_bus; | ||
400 | |||
401 | if (!nvdimm || cmd != ND_CMD_SET_CONFIG_DATA) | ||
402 | return 0; | ||
403 | |||
404 | nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev); | ||
405 | wait_nvdimm_bus_probe_idle(nvdimm_bus); | ||
406 | |||
407 | if (atomic_read(&nvdimm->busy)) | ||
408 | return -EBUSY; | ||
409 | return 0; | ||
410 | } | ||
411 | |||
362 | static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | 412 | static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, |
363 | int read_only, unsigned int ioctl_cmd, unsigned long arg) | 413 | int read_only, unsigned int ioctl_cmd, unsigned long arg) |
364 | { | 414 | { |
@@ -469,11 +519,18 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
469 | goto out; | 519 | goto out; |
470 | } | 520 | } |
471 | 521 | ||
522 | nvdimm_bus_lock(&nvdimm_bus->dev); | ||
523 | rc = nd_cmd_clear_to_send(nvdimm, cmd); | ||
524 | if (rc) | ||
525 | goto out_unlock; | ||
526 | |||
472 | rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len); | 527 | rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len); |
473 | if (rc < 0) | 528 | if (rc < 0) |
474 | goto out; | 529 | goto out_unlock; |
475 | if (copy_to_user(p, buf, buf_len)) | 530 | if (copy_to_user(p, buf, buf_len)) |
476 | rc = -EFAULT; | 531 | rc = -EFAULT; |
532 | out_unlock: | ||
533 | nvdimm_bus_unlock(&nvdimm_bus->dev); | ||
477 | out: | 534 | out: |
478 | vfree(buf); | 535 | vfree(buf); |
479 | return rc; | 536 | return rc; |
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index 1b6b15d11f54..7806eaaf4707 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c | |||
@@ -54,6 +54,22 @@ bool is_nvdimm_bus_locked(struct device *dev) | |||
54 | } | 54 | } |
55 | EXPORT_SYMBOL(is_nvdimm_bus_locked); | 55 | EXPORT_SYMBOL(is_nvdimm_bus_locked); |
56 | 56 | ||
57 | u64 nd_fletcher64(void *addr, size_t len, bool le) | ||
58 | { | ||
59 | u32 *buf = addr; | ||
60 | u32 lo32 = 0; | ||
61 | u64 hi32 = 0; | ||
62 | int i; | ||
63 | |||
64 | for (i = 0; i < len / sizeof(u32); i++) { | ||
65 | lo32 += le ? le32_to_cpu((__le32) buf[i]) : buf[i]; | ||
66 | hi32 += lo32; | ||
67 | } | ||
68 | |||
69 | return hi32 << 32 | lo32; | ||
70 | } | ||
71 | EXPORT_SYMBOL_GPL(nd_fletcher64); | ||
72 | |||
57 | static void nvdimm_bus_release(struct device *dev) | 73 | static void nvdimm_bus_release(struct device *dev) |
58 | { | 74 | { |
59 | struct nvdimm_bus *nvdimm_bus; | 75 | struct nvdimm_bus *nvdimm_bus; |
@@ -175,6 +191,7 @@ struct nvdimm_bus *__nvdimm_bus_register(struct device *parent, | |||
175 | if (!nvdimm_bus) | 191 | if (!nvdimm_bus) |
176 | return NULL; | 192 | return NULL; |
177 | INIT_LIST_HEAD(&nvdimm_bus->list); | 193 | INIT_LIST_HEAD(&nvdimm_bus->list); |
194 | init_waitqueue_head(&nvdimm_bus->probe_wait); | ||
178 | nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL); | 195 | nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL); |
179 | mutex_init(&nvdimm_bus->reconfig_mutex); | 196 | mutex_init(&nvdimm_bus->reconfig_mutex); |
180 | if (nvdimm_bus->id < 0) { | 197 | if (nvdimm_bus->id < 0) { |
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index b3ae86f2e1da..bdf8241b6525 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c | |||
@@ -185,7 +185,24 @@ static ssize_t commands_show(struct device *dev, | |||
185 | } | 185 | } |
186 | static DEVICE_ATTR_RO(commands); | 186 | static DEVICE_ATTR_RO(commands); |
187 | 187 | ||
188 | static ssize_t state_show(struct device *dev, struct device_attribute *attr, | ||
189 | char *buf) | ||
190 | { | ||
191 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
192 | |||
193 | /* | ||
194 | * The state may be in the process of changing, userspace should | ||
195 | * quiesce probing if it wants a static answer | ||
196 | */ | ||
197 | nvdimm_bus_lock(dev); | ||
198 | nvdimm_bus_unlock(dev); | ||
199 | return sprintf(buf, "%s\n", atomic_read(&nvdimm->busy) | ||
200 | ? "active" : "idle"); | ||
201 | } | ||
202 | static DEVICE_ATTR_RO(state); | ||
203 | |||
188 | static struct attribute *nvdimm_attributes[] = { | 204 | static struct attribute *nvdimm_attributes[] = { |
205 | &dev_attr_state.attr, | ||
189 | &dev_attr_commands.attr, | 206 | &dev_attr_commands.attr, |
190 | NULL, | 207 | NULL, |
191 | }; | 208 | }; |
@@ -213,7 +230,7 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, | |||
213 | nvdimm->provider_data = provider_data; | 230 | nvdimm->provider_data = provider_data; |
214 | nvdimm->flags = flags; | 231 | nvdimm->flags = flags; |
215 | nvdimm->dsm_mask = dsm_mask; | 232 | nvdimm->dsm_mask = dsm_mask; |
216 | 233 | atomic_set(&nvdimm->busy, 0); | |
217 | dev = &nvdimm->dev; | 234 | dev = &nvdimm->dev; |
218 | dev_set_name(dev, "nmem%d", nvdimm->id); | 235 | dev_set_name(dev, "nmem%d", nvdimm->id); |
219 | dev->parent = &nvdimm_bus->dev; | 236 | dev->parent = &nvdimm_bus->dev; |
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 0e9b41fd2546..6a4b2c066ee7 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h | |||
@@ -14,6 +14,9 @@ | |||
14 | #define __ND_CORE_H__ | 14 | #define __ND_CORE_H__ |
15 | #include <linux/libnvdimm.h> | 15 | #include <linux/libnvdimm.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/libnvdimm.h> | ||
18 | #include <linux/sizes.h> | ||
19 | #include <linux/mutex.h> | ||
17 | 20 | ||
18 | extern struct list_head nvdimm_bus_list; | 21 | extern struct list_head nvdimm_bus_list; |
19 | extern struct mutex nvdimm_bus_list_mutex; | 22 | extern struct mutex nvdimm_bus_list_mutex; |
@@ -21,10 +24,11 @@ extern int nvdimm_major; | |||
21 | 24 | ||
22 | struct nvdimm_bus { | 25 | struct nvdimm_bus { |
23 | struct nvdimm_bus_descriptor *nd_desc; | 26 | struct nvdimm_bus_descriptor *nd_desc; |
27 | wait_queue_head_t probe_wait; | ||
24 | struct module *module; | 28 | struct module *module; |
25 | struct list_head list; | 29 | struct list_head list; |
26 | struct device dev; | 30 | struct device dev; |
27 | int id; | 31 | int id, probe_active; |
28 | struct mutex reconfig_mutex; | 32 | struct mutex reconfig_mutex; |
29 | }; | 33 | }; |
30 | 34 | ||
@@ -33,6 +37,7 @@ struct nvdimm { | |||
33 | void *provider_data; | 37 | void *provider_data; |
34 | unsigned long *dsm_mask; | 38 | unsigned long *dsm_mask; |
35 | struct device dev; | 39 | struct device dev; |
40 | atomic_t busy; | ||
36 | int id; | 41 | int id; |
37 | }; | 42 | }; |
38 | 43 | ||
@@ -42,10 +47,13 @@ bool is_nd_pmem(struct device *dev); | |||
42 | struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev); | 47 | struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev); |
43 | int __init nvdimm_bus_init(void); | 48 | int __init nvdimm_bus_init(void); |
44 | void nvdimm_bus_exit(void); | 49 | void nvdimm_bus_exit(void); |
50 | void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev); | ||
51 | void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev); | ||
45 | int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus); | 52 | int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus); |
46 | void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); | 53 | void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); |
47 | void nd_synchronize(void); | 54 | void nd_synchronize(void); |
48 | int nvdimm_bus_register_dimms(struct nvdimm_bus *nvdimm_bus); | 55 | int nvdimm_bus_register_dimms(struct nvdimm_bus *nvdimm_bus); |
49 | int nvdimm_bus_register_regions(struct nvdimm_bus *nvdimm_bus); | 56 | int nvdimm_bus_register_regions(struct nvdimm_bus *nvdimm_bus); |
57 | int nvdimm_bus_init_interleave_sets(struct nvdimm_bus *nvdimm_bus); | ||
50 | int nd_match_dimm(struct device *dev, void *data); | 58 | int nd_match_dimm(struct device *dev, void *data); |
51 | #endif /* __ND_CORE_H__ */ | 59 | #endif /* __ND_CORE_H__ */ |
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index bc5a08e36a25..0285e4588b03 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h | |||
@@ -35,6 +35,7 @@ struct nd_region { | |||
35 | u64 ndr_start; | 35 | u64 ndr_start; |
36 | int id; | 36 | int id; |
37 | void *provider_data; | 37 | void *provider_data; |
38 | struct nd_interleave_set *nd_set; | ||
38 | struct nd_mapping mapping[0]; | 39 | struct nd_mapping mapping[0]; |
39 | }; | 40 | }; |
40 | 41 | ||
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index b5c5b9095b28..1571424578f0 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c | |||
@@ -10,7 +10,10 @@ | |||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
11 | * General Public License for more details. | 11 | * General Public License for more details. |
12 | */ | 12 | */ |
13 | #include <linux/scatterlist.h> | ||
14 | #include <linux/sched.h> | ||
13 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/sort.h> | ||
14 | #include <linux/io.h> | 17 | #include <linux/io.h> |
15 | #include "nd-core.h" | 18 | #include "nd-core.h" |
16 | #include "nd.h" | 19 | #include "nd.h" |
@@ -133,6 +136,21 @@ static ssize_t nstype_show(struct device *dev, | |||
133 | } | 136 | } |
134 | static DEVICE_ATTR_RO(nstype); | 137 | static DEVICE_ATTR_RO(nstype); |
135 | 138 | ||
139 | static ssize_t set_cookie_show(struct device *dev, | ||
140 | struct device_attribute *attr, char *buf) | ||
141 | { | ||
142 | struct nd_region *nd_region = to_nd_region(dev); | ||
143 | struct nd_interleave_set *nd_set = nd_region->nd_set; | ||
144 | |||
145 | if (is_nd_pmem(dev) && nd_set) | ||
146 | /* pass, should be precluded by region_visible */; | ||
147 | else | ||
148 | return -ENXIO; | ||
149 | |||
150 | return sprintf(buf, "%#llx\n", nd_set->cookie); | ||
151 | } | ||
152 | static DEVICE_ATTR_RO(set_cookie); | ||
153 | |||
136 | static ssize_t init_namespaces_show(struct device *dev, | 154 | static ssize_t init_namespaces_show(struct device *dev, |
137 | struct device_attribute *attr, char *buf) | 155 | struct device_attribute *attr, char *buf) |
138 | { | 156 | { |
@@ -154,15 +172,65 @@ static struct attribute *nd_region_attributes[] = { | |||
154 | &dev_attr_size.attr, | 172 | &dev_attr_size.attr, |
155 | &dev_attr_nstype.attr, | 173 | &dev_attr_nstype.attr, |
156 | &dev_attr_mappings.attr, | 174 | &dev_attr_mappings.attr, |
175 | &dev_attr_set_cookie.attr, | ||
157 | &dev_attr_init_namespaces.attr, | 176 | &dev_attr_init_namespaces.attr, |
158 | NULL, | 177 | NULL, |
159 | }; | 178 | }; |
160 | 179 | ||
180 | static umode_t region_visible(struct kobject *kobj, struct attribute *a, int n) | ||
181 | { | ||
182 | struct device *dev = container_of(kobj, typeof(*dev), kobj); | ||
183 | struct nd_region *nd_region = to_nd_region(dev); | ||
184 | struct nd_interleave_set *nd_set = nd_region->nd_set; | ||
185 | |||
186 | if (a != &dev_attr_set_cookie.attr) | ||
187 | return a->mode; | ||
188 | |||
189 | if (is_nd_pmem(dev) && nd_set) | ||
190 | return a->mode; | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
161 | struct attribute_group nd_region_attribute_group = { | 195 | struct attribute_group nd_region_attribute_group = { |
162 | .attrs = nd_region_attributes, | 196 | .attrs = nd_region_attributes, |
197 | .is_visible = region_visible, | ||
163 | }; | 198 | }; |
164 | EXPORT_SYMBOL_GPL(nd_region_attribute_group); | 199 | EXPORT_SYMBOL_GPL(nd_region_attribute_group); |
165 | 200 | ||
201 | /* | ||
202 | * Upon successful probe/remove, take/release a reference on the | ||
203 | * associated interleave set (if present) | ||
204 | */ | ||
205 | static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus, | ||
206 | struct device *dev, bool probe) | ||
207 | { | ||
208 | if (is_nd_pmem(dev) || is_nd_blk(dev)) { | ||
209 | struct nd_region *nd_region = to_nd_region(dev); | ||
210 | int i; | ||
211 | |||
212 | for (i = 0; i < nd_region->ndr_mappings; i++) { | ||
213 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; | ||
214 | struct nvdimm *nvdimm = nd_mapping->nvdimm; | ||
215 | |||
216 | if (probe) | ||
217 | atomic_inc(&nvdimm->busy); | ||
218 | else | ||
219 | atomic_dec(&nvdimm->busy); | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev) | ||
225 | { | ||
226 | nd_region_notify_driver_action(nvdimm_bus, dev, true); | ||
227 | } | ||
228 | |||
229 | void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev) | ||
230 | { | ||
231 | nd_region_notify_driver_action(nvdimm_bus, dev, false); | ||
232 | } | ||
233 | |||
166 | static ssize_t mappingN(struct device *dev, char *buf, int n) | 234 | static ssize_t mappingN(struct device *dev, char *buf, int n) |
167 | { | 235 | { |
168 | struct nd_region *nd_region = to_nd_region(dev); | 236 | struct nd_region *nd_region = to_nd_region(dev); |
@@ -322,6 +390,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, | |||
322 | } | 390 | } |
323 | nd_region->ndr_mappings = ndr_desc->num_mappings; | 391 | nd_region->ndr_mappings = ndr_desc->num_mappings; |
324 | nd_region->provider_data = ndr_desc->provider_data; | 392 | nd_region->provider_data = ndr_desc->provider_data; |
393 | nd_region->nd_set = ndr_desc->nd_set; | ||
325 | dev = &nd_region->dev; | 394 | dev = &nd_region->dev; |
326 | dev_set_name(dev, "region%d", nd_region->id); | 395 | dev_set_name(dev, "region%d", nd_region->id); |
327 | dev->parent = &nvdimm_bus->dev; | 396 | dev->parent = &nvdimm_bus->dev; |