|
16 | 16 | #include <linux/fcntl.h>
|
17 | 17 | #include <linux/async.h>
|
18 | 18 | #include <linux/ndctl.h>
|
| 19 | +#include <linux/sched.h> |
19 | 20 | #include <linux/slab.h>
|
20 | 21 | #include <linux/fs.h>
|
21 | 22 | #include <linux/io.h>
|
22 | 23 | #include <linux/mm.h>
|
| 24 | +#include <linux/nd.h> |
23 | 25 | #include "nd-core.h"
|
| 26 | +#include "nd.h" |
24 | 27 |
|
25 | 28 | int nvdimm_major;
|
26 | 29 | static int nvdimm_bus_major;
|
27 | 30 | static struct class *nd_class;
|
28 | 31 |
|
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 = { |
30 | 78 | .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, |
31 | 194 | };
|
| 195 | +EXPORT_SYMBOL_GPL(nd_device_attribute_group); |
32 | 196 |
|
33 | 197 | int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus)
|
34 | 198 | {
|
@@ -404,7 +568,7 @@ int __init nvdimm_bus_init(void)
|
404 | 568 | return rc;
|
405 | 569 | }
|
406 | 570 |
|
407 |
| -void __exit nvdimm_bus_exit(void) |
| 571 | +void nvdimm_bus_exit(void) |
408 | 572 | {
|
409 | 573 | class_destroy(nd_class);
|
410 | 574 | unregister_chrdev(nvdimm_bus_major, "ndctl");
|
|
0 commit comments