diff options
author | Dan Williams <dan.j.williams@intel.com> | 2015-05-31 15:02:11 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2015-06-24 21:24:10 -0400 |
commit | 3d88002e4a7bd40f355550284c6cd140e6fe29dc (patch) | |
tree | 5934604ed6e21153ada873c7042c4037ef20ecdc /drivers/nvdimm/namespace_devs.c | |
parent | 1f7df6f88b9245a7f2d0f8ecbc97dc88c8d0d8e1 (diff) |
libnvdimm: support for legacy (non-aliasing) nvdimms
The libnvdimm region driver is an intermediary driver that translates
non-volatile "region"s into "namespace" sub-devices that are surfaced by
persistent memory block-device drivers (PMEM and BLK).
ACPI 6 introduces the concept that a given nvdimm may simultaneously
offer multiple access modes to its media through direct PMEM load/store
access, or windowed BLK mode. Existing nvdimms mostly implement a PMEM
interface, some offer a BLK-like mode, but never both as ACPI 6 defines.
If an nvdimm is single interfaced, then there is no need for dimm
metadata labels. For these devices we can take the region boundaries
directly to create a child namespace device (nd_namespace_io).
Acked-by: Christoph Hellwig <hch@lst.de>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/nvdimm/namespace_devs.c')
-rw-r--r-- | drivers/nvdimm/namespace_devs.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c new file mode 100644 index 000000000000..4f653d1e61ad --- /dev/null +++ b/drivers/nvdimm/namespace_devs.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * Copyright(c) 2013-2015 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/module.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/nd.h> | ||
17 | #include "nd.h" | ||
18 | |||
19 | static void namespace_io_release(struct device *dev) | ||
20 | { | ||
21 | struct nd_namespace_io *nsio = to_nd_namespace_io(dev); | ||
22 | |||
23 | kfree(nsio); | ||
24 | } | ||
25 | |||
26 | static struct device_type namespace_io_device_type = { | ||
27 | .name = "nd_namespace_io", | ||
28 | .release = namespace_io_release, | ||
29 | }; | ||
30 | |||
31 | static ssize_t nstype_show(struct device *dev, | ||
32 | struct device_attribute *attr, char *buf) | ||
33 | { | ||
34 | struct nd_region *nd_region = to_nd_region(dev->parent); | ||
35 | |||
36 | return sprintf(buf, "%d\n", nd_region_to_nstype(nd_region)); | ||
37 | } | ||
38 | static DEVICE_ATTR_RO(nstype); | ||
39 | |||
40 | static struct attribute *nd_namespace_attributes[] = { | ||
41 | &dev_attr_nstype.attr, | ||
42 | NULL, | ||
43 | }; | ||
44 | |||
45 | static struct attribute_group nd_namespace_attribute_group = { | ||
46 | .attrs = nd_namespace_attributes, | ||
47 | }; | ||
48 | |||
49 | static const struct attribute_group *nd_namespace_attribute_groups[] = { | ||
50 | &nd_device_attribute_group, | ||
51 | &nd_namespace_attribute_group, | ||
52 | NULL, | ||
53 | }; | ||
54 | |||
55 | static struct device **create_namespace_io(struct nd_region *nd_region) | ||
56 | { | ||
57 | struct nd_namespace_io *nsio; | ||
58 | struct device *dev, **devs; | ||
59 | struct resource *res; | ||
60 | |||
61 | nsio = kzalloc(sizeof(*nsio), GFP_KERNEL); | ||
62 | if (!nsio) | ||
63 | return NULL; | ||
64 | |||
65 | devs = kcalloc(2, sizeof(struct device *), GFP_KERNEL); | ||
66 | if (!devs) { | ||
67 | kfree(nsio); | ||
68 | return NULL; | ||
69 | } | ||
70 | |||
71 | dev = &nsio->dev; | ||
72 | dev->type = &namespace_io_device_type; | ||
73 | dev->parent = &nd_region->dev; | ||
74 | res = &nsio->res; | ||
75 | res->name = dev_name(&nd_region->dev); | ||
76 | res->flags = IORESOURCE_MEM; | ||
77 | res->start = nd_region->ndr_start; | ||
78 | res->end = res->start + nd_region->ndr_size - 1; | ||
79 | |||
80 | devs[0] = dev; | ||
81 | return devs; | ||
82 | } | ||
83 | |||
84 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err) | ||
85 | { | ||
86 | struct device **devs = NULL; | ||
87 | int i; | ||
88 | |||
89 | *err = 0; | ||
90 | switch (nd_region_to_nstype(nd_region)) { | ||
91 | case ND_DEVICE_NAMESPACE_IO: | ||
92 | devs = create_namespace_io(nd_region); | ||
93 | break; | ||
94 | default: | ||
95 | break; | ||
96 | } | ||
97 | |||
98 | if (!devs) | ||
99 | return -ENODEV; | ||
100 | |||
101 | for (i = 0; devs[i]; i++) { | ||
102 | struct device *dev = devs[i]; | ||
103 | |||
104 | dev_set_name(dev, "namespace%d.%d", nd_region->id, i); | ||
105 | dev->groups = nd_namespace_attribute_groups; | ||
106 | nd_device_register(dev); | ||
107 | } | ||
108 | kfree(devs); | ||
109 | |||
110 | return i; | ||
111 | } | ||