diff options
| -rw-r--r-- | drivers/dax/bus.c | 145 | ||||
| -rw-r--r-- | drivers/dax/bus.h | 10 | ||||
| -rw-r--r-- | drivers/dax/device.c | 11 |
3 files changed, 156 insertions, 10 deletions
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 69aae2cbd45f..17af6fbc3be5 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c | |||
| @@ -2,11 +2,21 @@ | |||
| 2 | /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */ | 2 | /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */ |
| 3 | #include <linux/memremap.h> | 3 | #include <linux/memremap.h> |
| 4 | #include <linux/device.h> | 4 | #include <linux/device.h> |
| 5 | #include <linux/mutex.h> | ||
| 6 | #include <linux/list.h> | ||
| 5 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
| 6 | #include <linux/dax.h> | 8 | #include <linux/dax.h> |
| 7 | #include "dax-private.h" | 9 | #include "dax-private.h" |
| 8 | #include "bus.h" | 10 | #include "bus.h" |
| 9 | 11 | ||
| 12 | static DEFINE_MUTEX(dax_bus_lock); | ||
| 13 | |||
| 14 | #define DAX_NAME_LEN 30 | ||
| 15 | struct dax_id { | ||
| 16 | struct list_head list; | ||
| 17 | char dev_name[DAX_NAME_LEN]; | ||
| 18 | }; | ||
| 19 | |||
| 10 | static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env) | 20 | static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env) |
| 11 | { | 21 | { |
| 12 | /* | 22 | /* |
| @@ -16,22 +26,115 @@ static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
| 16 | return add_uevent_var(env, "MODALIAS=" DAX_DEVICE_MODALIAS_FMT, 0); | 26 | return add_uevent_var(env, "MODALIAS=" DAX_DEVICE_MODALIAS_FMT, 0); |
| 17 | } | 27 | } |
| 18 | 28 | ||
| 29 | static struct dax_device_driver *to_dax_drv(struct device_driver *drv) | ||
| 30 | { | ||
| 31 | return container_of(drv, struct dax_device_driver, drv); | ||
| 32 | } | ||
| 33 | |||
| 34 | static struct dax_id *__dax_match_id(struct dax_device_driver *dax_drv, | ||
| 35 | const char *dev_name) | ||
| 36 | { | ||
| 37 | struct dax_id *dax_id; | ||
| 38 | |||
| 39 | lockdep_assert_held(&dax_bus_lock); | ||
| 40 | |||
| 41 | list_for_each_entry(dax_id, &dax_drv->ids, list) | ||
| 42 | if (sysfs_streq(dax_id->dev_name, dev_name)) | ||
| 43 | return dax_id; | ||
| 44 | return NULL; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int dax_match_id(struct dax_device_driver *dax_drv, struct device *dev) | ||
| 48 | { | ||
| 49 | int match; | ||
| 50 | |||
| 51 | mutex_lock(&dax_bus_lock); | ||
| 52 | match = !!__dax_match_id(dax_drv, dev_name(dev)); | ||
| 53 | mutex_unlock(&dax_bus_lock); | ||
| 54 | |||
| 55 | return match; | ||
| 56 | } | ||
| 57 | |||
| 58 | static ssize_t do_id_store(struct device_driver *drv, const char *buf, | ||
| 59 | size_t count, bool add) | ||
| 60 | { | ||
| 61 | struct dax_device_driver *dax_drv = to_dax_drv(drv); | ||
| 62 | unsigned int region_id, id; | ||
| 63 | char devname[DAX_NAME_LEN]; | ||
| 64 | struct dax_id *dax_id; | ||
| 65 | ssize_t rc = count; | ||
| 66 | int fields; | ||
| 67 | |||
| 68 | fields = sscanf(buf, "dax%d.%d", ®ion_id, &id); | ||
| 69 | if (fields != 2) | ||
| 70 | return -EINVAL; | ||
| 71 | sprintf(devname, "dax%d.%d", region_id, id); | ||
| 72 | if (!sysfs_streq(buf, devname)) | ||
| 73 | return -EINVAL; | ||
| 74 | |||
| 75 | mutex_lock(&dax_bus_lock); | ||
| 76 | dax_id = __dax_match_id(dax_drv, buf); | ||
| 77 | if (!dax_id) { | ||
| 78 | if (add) { | ||
| 79 | dax_id = kzalloc(sizeof(*dax_id), GFP_KERNEL); | ||
| 80 | if (dax_id) { | ||
| 81 | strncpy(dax_id->dev_name, buf, DAX_NAME_LEN); | ||
| 82 | list_add(&dax_id->list, &dax_drv->ids); | ||
| 83 | } else | ||
| 84 | rc = -ENOMEM; | ||
| 85 | } else | ||
| 86 | /* nothing to remove */; | ||
| 87 | } else if (!add) { | ||
| 88 | list_del(&dax_id->list); | ||
| 89 | kfree(dax_id); | ||
| 90 | } else | ||
| 91 | /* dax_id already added */; | ||
| 92 | mutex_unlock(&dax_bus_lock); | ||
| 93 | return rc; | ||
| 94 | } | ||
| 95 | |||
| 96 | static ssize_t new_id_store(struct device_driver *drv, const char *buf, | ||
| 97 | size_t count) | ||
| 98 | { | ||
| 99 | return do_id_store(drv, buf, count, true); | ||
| 100 | } | ||
| 101 | static DRIVER_ATTR_WO(new_id); | ||
| 102 | |||
| 103 | static ssize_t remove_id_store(struct device_driver *drv, const char *buf, | ||
| 104 | size_t count) | ||
| 105 | { | ||
| 106 | return do_id_store(drv, buf, count, false); | ||
| 107 | } | ||
| 108 | static DRIVER_ATTR_WO(remove_id); | ||
| 109 | |||
| 110 | static struct attribute *dax_drv_attrs[] = { | ||
| 111 | &driver_attr_new_id.attr, | ||
| 112 | &driver_attr_remove_id.attr, | ||
| 113 | NULL, | ||
| 114 | }; | ||
| 115 | ATTRIBUTE_GROUPS(dax_drv); | ||
| 116 | |||
| 19 | static int dax_bus_match(struct device *dev, struct device_driver *drv); | 117 | static int dax_bus_match(struct device *dev, struct device_driver *drv); |
| 20 | 118 | ||
| 21 | static struct bus_type dax_bus_type = { | 119 | static struct bus_type dax_bus_type = { |
| 22 | .name = "dax", | 120 | .name = "dax", |
| 23 | .uevent = dax_bus_uevent, | 121 | .uevent = dax_bus_uevent, |
| 24 | .match = dax_bus_match, | 122 | .match = dax_bus_match, |
| 123 | .drv_groups = dax_drv_groups, | ||
| 25 | }; | 124 | }; |
| 26 | 125 | ||
| 27 | static int dax_bus_match(struct device *dev, struct device_driver *drv) | 126 | static int dax_bus_match(struct device *dev, struct device_driver *drv) |
| 28 | { | 127 | { |
| 128 | struct dax_device_driver *dax_drv = to_dax_drv(drv); | ||
| 129 | |||
| 29 | /* | 130 | /* |
| 30 | * The drivers that can register on the 'dax' bus are private to | 131 | * All but the 'device-dax' driver, which has 'match_always' |
| 31 | * drivers/dax/ so any device and driver on the bus always | 132 | * set, requires an exact id match. |
| 32 | * match. | ||
| 33 | */ | 133 | */ |
| 34 | return 1; | 134 | if (dax_drv->match_always) |
| 135 | return 1; | ||
| 136 | |||
| 137 | return dax_match_id(dax_drv, dev); | ||
| 35 | } | 138 | } |
| 36 | 139 | ||
| 37 | /* | 140 | /* |
| @@ -273,17 +376,49 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, | |||
| 273 | } | 376 | } |
| 274 | EXPORT_SYMBOL_GPL(devm_create_dev_dax); | 377 | EXPORT_SYMBOL_GPL(devm_create_dev_dax); |
| 275 | 378 | ||
| 276 | int __dax_driver_register(struct device_driver *drv, | 379 | static int match_always_count; |
| 380 | |||
| 381 | int __dax_driver_register(struct dax_device_driver *dax_drv, | ||
| 277 | struct module *module, const char *mod_name) | 382 | struct module *module, const char *mod_name) |
| 278 | { | 383 | { |
| 384 | struct device_driver *drv = &dax_drv->drv; | ||
| 385 | int rc = 0; | ||
| 386 | |||
| 387 | INIT_LIST_HEAD(&dax_drv->ids); | ||
| 279 | drv->owner = module; | 388 | drv->owner = module; |
| 280 | drv->name = mod_name; | 389 | drv->name = mod_name; |
| 281 | drv->mod_name = mod_name; | 390 | drv->mod_name = mod_name; |
| 282 | drv->bus = &dax_bus_type; | 391 | drv->bus = &dax_bus_type; |
| 392 | |||
| 393 | /* there can only be one default driver */ | ||
| 394 | mutex_lock(&dax_bus_lock); | ||
| 395 | match_always_count += dax_drv->match_always; | ||
| 396 | if (match_always_count > 1) { | ||
| 397 | match_always_count--; | ||
| 398 | WARN_ON(1); | ||
| 399 | rc = -EINVAL; | ||
| 400 | } | ||
| 401 | mutex_unlock(&dax_bus_lock); | ||
| 402 | if (rc) | ||
| 403 | return rc; | ||
| 283 | return driver_register(drv); | 404 | return driver_register(drv); |
| 284 | } | 405 | } |
| 285 | EXPORT_SYMBOL_GPL(__dax_driver_register); | 406 | EXPORT_SYMBOL_GPL(__dax_driver_register); |
| 286 | 407 | ||
| 408 | void dax_driver_unregister(struct dax_device_driver *dax_drv) | ||
| 409 | { | ||
| 410 | struct dax_id *dax_id, *_id; | ||
| 411 | |||
| 412 | mutex_lock(&dax_bus_lock); | ||
| 413 | match_always_count -= dax_drv->match_always; | ||
| 414 | list_for_each_entry_safe(dax_id, _id, &dax_drv->ids, list) { | ||
| 415 | list_del(&dax_id->list); | ||
| 416 | kfree(dax_id); | ||
| 417 | } | ||
| 418 | mutex_unlock(&dax_bus_lock); | ||
| 419 | } | ||
| 420 | EXPORT_SYMBOL_GPL(dax_driver_unregister); | ||
| 421 | |||
| 287 | int __init dax_bus_init(void) | 422 | int __init dax_bus_init(void) |
| 288 | { | 423 | { |
| 289 | return bus_register(&dax_bus_type); | 424 | return bus_register(&dax_bus_type); |
diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index e08e0c394983..395ab812367c 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h | |||
| @@ -12,10 +12,18 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, | |||
| 12 | struct resource *res, unsigned int align, unsigned long flags); | 12 | struct resource *res, unsigned int align, unsigned long flags); |
| 13 | struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, | 13 | struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, |
| 14 | struct dev_pagemap *pgmap); | 14 | struct dev_pagemap *pgmap); |
| 15 | int __dax_driver_register(struct device_driver *drv, | 15 | |
| 16 | struct dax_device_driver { | ||
| 17 | struct device_driver drv; | ||
| 18 | struct list_head ids; | ||
| 19 | int match_always; | ||
| 20 | }; | ||
| 21 | |||
| 22 | int __dax_driver_register(struct dax_device_driver *dax_drv, | ||
| 16 | struct module *module, const char *mod_name); | 23 | struct module *module, const char *mod_name); |
| 17 | #define dax_driver_register(driver) \ | 24 | #define dax_driver_register(driver) \ |
| 18 | __dax_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) | 25 | __dax_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) |
| 26 | void dax_driver_unregister(struct dax_device_driver *dax_drv); | ||
| 19 | void kill_dev_dax(struct dev_dax *dev_dax); | 27 | void kill_dev_dax(struct dev_dax *dev_dax); |
| 20 | 28 | ||
| 21 | /* | 29 | /* |
diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 6ad964d7b077..ad3120395f7a 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c | |||
| @@ -504,9 +504,12 @@ static int dev_dax_remove(struct device *dev) | |||
| 504 | return 0; | 504 | return 0; |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | static struct device_driver device_dax_driver = { | 507 | static struct dax_device_driver device_dax_driver = { |
| 508 | .probe = dev_dax_probe, | 508 | .drv = { |
| 509 | .remove = dev_dax_remove, | 509 | .probe = dev_dax_probe, |
| 510 | .remove = dev_dax_remove, | ||
| 511 | }, | ||
| 512 | .match_always = 1, | ||
| 510 | }; | 513 | }; |
| 511 | 514 | ||
| 512 | static int __init dax_init(void) | 515 | static int __init dax_init(void) |
| @@ -516,7 +519,7 @@ static int __init dax_init(void) | |||
| 516 | 519 | ||
| 517 | static void __exit dax_exit(void) | 520 | static void __exit dax_exit(void) |
| 518 | { | 521 | { |
| 519 | driver_unregister(&device_dax_driver); | 522 | dax_driver_unregister(&device_dax_driver); |
| 520 | } | 523 | } |
| 521 | 524 | ||
| 522 | MODULE_AUTHOR("Intel Corporation"); | 525 | MODULE_AUTHOR("Intel Corporation"); |
