diff options
Diffstat (limited to 'drivers/nvdimm/pfn_devs.c')
-rw-r--r-- | drivers/nvdimm/pfn_devs.c | 100 |
1 files changed, 67 insertions, 33 deletions
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 | } |
55 | EXPORT_SYMBOL(to_nd_pfn); | 55 | EXPORT_SYMBOL(to_nd_pfn); |
56 | 56 | ||
57 | static 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 | |||
57 | static ssize_t mode_show(struct device *dev, | 76 | static 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, | |||
72 | static ssize_t mode_store(struct device *dev, | 91 | static 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); | |||
106 | static ssize_t align_show(struct device *dev, | 125 | static 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) | |||
134 | static ssize_t align_store(struct device *dev, | 153 | static 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); | |||
152 | static ssize_t uuid_show(struct device *dev, | 171 | static 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, | |||
162 | static ssize_t uuid_store(struct device *dev, | 181 | static 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); | |||
178 | static ssize_t namespace_show(struct device *dev, | 197 | static 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, | |||
191 | static ssize_t namespace_store(struct device *dev, | 210 | static 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); | |||
209 | static ssize_t resource_show(struct device *dev, | 228 | static 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); | |||
235 | static ssize_t size_show(struct device *dev, | 254 | static 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 | ||
273 | static struct attribute_group nd_pfn_attribute_group = { | 292 | struct 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 | ||
284 | static struct device *__nd_pfn_create(struct nd_region *nd_region, | 303 | struct 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 | |||
324 | static 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 | ||
321 | struct device *nd_pfn_create(struct nd_region *nd_region) | 348 | struct 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; |