Skip to content

Commit 4d88a97

Browse files
committed
libnvdimm, nvdimm: dimm driver and base libnvdimm device-driver infrastructure
* Implement the device-model infrastructure for loading modules and attaching drivers to nvdimm devices. This is a simple association of a nd-device-type number with a driver that has a bitmask of supported device types. To facilitate userspace bind/unbind operations 'modalias' and 'devtype', that also appear in the uevent, are added as generic sysfs attributes for all nvdimm devices. The reason for the device-type number is to support sub-types within a given parent devtype, be it a vendor-specific sub-type or otherwise. * The first consumer of this infrastructure is the driver for dimm devices. It simply uses control messages to retrieve and store the configuration-data image (label set) from each dimm. Note: nd_device_register() arranges for asynchronous registration of nvdimm bus devices by default. Cc: Greg KH <[email protected]> Cc: Neil Brown <[email protected]> Acked-by: Christoph Hellwig <[email protected]> Tested-by: Toshi Kani <[email protected]> Signed-off-by: Dan Williams <[email protected]>
1 parent 62232e4 commit 4d88a97

File tree

11 files changed

+527
-15
lines changed

11 files changed

+527
-15
lines changed

drivers/acpi/nfit.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#include <linux/acpi.h>
1919
#include "nfit.h"
2020

21+
static bool force_enable_dimms;
22+
module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
23+
MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
24+
2125
static u8 nfit_uuid[NFIT_UUID_MAX][16];
2226

2327
static const u8 *to_nfit_uuid(enum nfit_uuids id)
@@ -633,6 +637,7 @@ static struct attribute_group acpi_nfit_dimm_attribute_group = {
633637

634638
static const struct attribute_group *acpi_nfit_dimm_attribute_groups[] = {
635639
&nvdimm_attribute_group,
640+
&nd_device_attribute_group,
636641
&acpi_nfit_dimm_attribute_group,
637642
NULL,
638643
};
@@ -669,7 +674,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
669674
if (!adev_dimm) {
670675
dev_err(dev, "no ACPI.NFIT device with _ADR %#x, disabling...\n",
671676
device_handle);
672-
return -ENODEV;
677+
return force_enable_dimms ? 0 : -ENODEV;
673678
}
674679

675680
status = acpi_evaluate_integer(adev_dimm->handle, "_STA", NULL, &sta);
@@ -690,12 +695,13 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
690695
if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i))
691696
set_bit(i, &nfit_mem->dsm_mask);
692697

693-
return rc;
698+
return force_enable_dimms ? 0 : rc;
694699
}
695700

696701
static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
697702
{
698703
struct nfit_mem *nfit_mem;
704+
int dimm_count = 0;
699705

700706
list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
701707
struct nvdimm *nvdimm;
@@ -729,9 +735,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
729735
return -ENOMEM;
730736

731737
nfit_mem->nvdimm = nvdimm;
738+
dimm_count++;
732739
}
733740

734-
return 0;
741+
return nvdimm_bus_check_dimm_count(acpi_desc->nvdimm_bus, dimm_count);
735742
}
736743

737744
static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)

drivers/nvdimm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
33
libnvdimm-y := core.o
44
libnvdimm-y += bus.o
55
libnvdimm-y += dimm_devs.o
6+
libnvdimm-y += dimm.o

drivers/nvdimm/bus.c

Lines changed: 166 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,183 @@
1616
#include <linux/fcntl.h>
1717
#include <linux/async.h>
1818
#include <linux/ndctl.h>
19+
#include <linux/sched.h>
1920
#include <linux/slab.h>
2021
#include <linux/fs.h>
2122
#include <linux/io.h>
2223
#include <linux/mm.h>
24+
#include <linux/nd.h>
2325
#include "nd-core.h"
26+
#include "nd.h"
2427

2528
int nvdimm_major;
2629
static int nvdimm_bus_major;
2730
static struct class *nd_class;
2831

29-
struct bus_type nvdimm_bus_type = {
32+
static int to_nd_device_type(struct device *dev)
33+
{
34+
if (is_nvdimm(dev))
35+
return ND_DEVICE_DIMM;
36+
37+
return 0;
38+
}
39+
40+
static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
41+
{
42+
return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT,
43+
to_nd_device_type(dev));
44+
}
45+
46+
static int nvdimm_bus_match(struct device *dev, struct device_driver *drv)
47+
{
48+
struct nd_device_driver *nd_drv = to_nd_device_driver(drv);
49+
50+
return test_bit(to_nd_device_type(dev), &nd_drv->type);
51+
}
52+
53+
static int nvdimm_bus_probe(struct device *dev)
54+
{
55+
struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver);
56+
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
57+
int rc;
58+
59+
rc = nd_drv->probe(dev);
60+
dev_dbg(&nvdimm_bus->dev, "%s.probe(%s) = %d\n", dev->driver->name,
61+
dev_name(dev), rc);
62+
return rc;
63+
}
64+
65+
static int nvdimm_bus_remove(struct device *dev)
66+
{
67+
struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver);
68+
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
69+
int rc;
70+
71+
rc = nd_drv->remove(dev);
72+
dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name,
73+
dev_name(dev), rc);
74+
return rc;
75+
}
76+
77+
static struct bus_type nvdimm_bus_type = {
3078
.name = "nd",
79+
.uevent = nvdimm_bus_uevent,
80+
.match = nvdimm_bus_match,
81+
.probe = nvdimm_bus_probe,
82+
.remove = nvdimm_bus_remove,
83+
};
84+
85+
static ASYNC_DOMAIN_EXCLUSIVE(nd_async_domain);
86+
87+
void nd_synchronize(void)
88+
{
89+
async_synchronize_full_domain(&nd_async_domain);
90+
}
91+
EXPORT_SYMBOL_GPL(nd_synchronize);
92+
93+
static void nd_async_device_register(void *d, async_cookie_t cookie)
94+
{
95+
struct device *dev = d;
96+
97+
if (device_add(dev) != 0) {
98+
dev_err(dev, "%s: failed\n", __func__);
99+
put_device(dev);
100+
}
101+
put_device(dev);
102+
}
103+
104+
static void nd_async_device_unregister(void *d, async_cookie_t cookie)
105+
{
106+
struct device *dev = d;
107+
108+
device_unregister(dev);
109+
put_device(dev);
110+
}
111+
112+
void nd_device_register(struct device *dev)
113+
{
114+
dev->bus = &nvdimm_bus_type;
115+
device_initialize(dev);
116+
get_device(dev);
117+
async_schedule_domain(nd_async_device_register, dev,
118+
&nd_async_domain);
119+
}
120+
EXPORT_SYMBOL(nd_device_register);
121+
122+
void nd_device_unregister(struct device *dev, enum nd_async_mode mode)
123+
{
124+
switch (mode) {
125+
case ND_ASYNC:
126+
get_device(dev);
127+
async_schedule_domain(nd_async_device_unregister, dev,
128+
&nd_async_domain);
129+
break;
130+
case ND_SYNC:
131+
nd_synchronize();
132+
device_unregister(dev);
133+
break;
134+
}
135+
}
136+
EXPORT_SYMBOL(nd_device_unregister);
137+
138+
/**
139+
* __nd_driver_register() - register a region or a namespace driver
140+
* @nd_drv: driver to register
141+
* @owner: automatically set by nd_driver_register() macro
142+
* @mod_name: automatically set by nd_driver_register() macro
143+
*/
144+
int __nd_driver_register(struct nd_device_driver *nd_drv, struct module *owner,
145+
const char *mod_name)
146+
{
147+
struct device_driver *drv = &nd_drv->drv;
148+
149+
if (!nd_drv->type) {
150+
pr_debug("driver type bitmask not set (%pf)\n",
151+
__builtin_return_address(0));
152+
return -EINVAL;
153+
}
154+
155+
if (!nd_drv->probe || !nd_drv->remove) {
156+
pr_debug("->probe() and ->remove() must be specified\n");
157+
return -EINVAL;
158+
}
159+
160+
drv->bus = &nvdimm_bus_type;
161+
drv->owner = owner;
162+
drv->mod_name = mod_name;
163+
164+
return driver_register(drv);
165+
}
166+
EXPORT_SYMBOL(__nd_driver_register);
167+
168+
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
169+
char *buf)
170+
{
171+
return sprintf(buf, ND_DEVICE_MODALIAS_FMT "\n",
172+
to_nd_device_type(dev));
173+
}
174+
static DEVICE_ATTR_RO(modalias);
175+
176+
static ssize_t devtype_show(struct device *dev, struct device_attribute *attr,
177+
char *buf)
178+
{
179+
return sprintf(buf, "%s\n", dev->type->name);
180+
}
181+
static DEVICE_ATTR_RO(devtype);
182+
183+
static struct attribute *nd_device_attributes[] = {
184+
&dev_attr_modalias.attr,
185+
&dev_attr_devtype.attr,
186+
NULL,
187+
};
188+
189+
/**
190+
* nd_device_attribute_group - generic attributes for all devices on an nd bus
191+
*/
192+
struct attribute_group nd_device_attribute_group = {
193+
.attrs = nd_device_attributes,
31194
};
195+
EXPORT_SYMBOL_GPL(nd_device_attribute_group);
32196

33197
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus)
34198
{
@@ -404,7 +568,7 @@ int __init nvdimm_bus_init(void)
404568
return rc;
405569
}
406570

407-
void __exit nvdimm_bus_exit(void)
571+
void nvdimm_bus_exit(void)
408572
{
409573
class_destroy(nd_class);
410574
unregister_chrdev(nvdimm_bus_major, "ndctl");

drivers/nvdimm/core.c

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/mutex.h>
1919
#include <linux/slab.h>
2020
#include "nd-core.h"
21+
#include "nd.h"
2122

2223
LIST_HEAD(nvdimm_bus_list);
2324
DEFINE_MUTEX(nvdimm_bus_list_mutex);
@@ -98,8 +99,33 @@ static ssize_t provider_show(struct device *dev,
9899
}
99100
static DEVICE_ATTR_RO(provider);
100101

102+
static int flush_namespaces(struct device *dev, void *data)
103+
{
104+
device_lock(dev);
105+
device_unlock(dev);
106+
return 0;
107+
}
108+
109+
static int flush_regions_dimms(struct device *dev, void *data)
110+
{
111+
device_lock(dev);
112+
device_unlock(dev);
113+
device_for_each_child(dev, NULL, flush_namespaces);
114+
return 0;
115+
}
116+
117+
static ssize_t wait_probe_show(struct device *dev,
118+
struct device_attribute *attr, char *buf)
119+
{
120+
nd_synchronize();
121+
device_for_each_child(dev, NULL, flush_regions_dimms);
122+
return sprintf(buf, "1\n");
123+
}
124+
static DEVICE_ATTR_RO(wait_probe);
125+
101126
static struct attribute *nvdimm_bus_attributes[] = {
102127
&dev_attr_commands.attr,
128+
&dev_attr_wait_probe.attr,
103129
&dev_attr_provider.attr,
104130
NULL,
105131
};
@@ -161,7 +187,7 @@ static int child_unregister(struct device *dev, void *data)
161187
if (dev->class)
162188
/* pass */;
163189
else
164-
device_unregister(dev);
190+
nd_device_unregister(dev, ND_SYNC);
165191
return 0;
166192
}
167193

@@ -174,6 +200,7 @@ void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
174200
list_del_init(&nvdimm_bus->list);
175201
mutex_unlock(&nvdimm_bus_list_mutex);
176202

203+
nd_synchronize();
177204
device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
178205
nvdimm_bus_destroy_ndctl(nvdimm_bus);
179206

@@ -183,12 +210,24 @@ EXPORT_SYMBOL_GPL(nvdimm_bus_unregister);
183210

184211
static __init int libnvdimm_init(void)
185212
{
186-
return nvdimm_bus_init();
213+
int rc;
214+
215+
rc = nvdimm_bus_init();
216+
if (rc)
217+
return rc;
218+
rc = nvdimm_init();
219+
if (rc)
220+
goto err_dimm;
221+
return 0;
222+
err_dimm:
223+
nvdimm_bus_exit();
224+
return rc;
187225
}
188226

189227
static __exit void libnvdimm_exit(void)
190228
{
191229
WARN_ON(!list_empty(&nvdimm_bus_list));
230+
nvdimm_exit();
192231
nvdimm_bus_exit();
193232
}
194233

0 commit comments

Comments
 (0)