1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ 3 #include <linux/init.h> 4 #include <linux/kernel.h> 5 #include <linux/module.h> 6 #include <linux/device.h> 7 #include <linux/device/bus.h> 8 #include "idxd.h" 9 10 extern void device_driver_detach(struct device *dev); 11 12 #define DRIVER_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \ 13 struct driver_attribute driver_attr_##_name = \ 14 __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) 15 16 static ssize_t unbind_store(struct device_driver *drv, const char *buf, size_t count) 17 { 18 const struct bus_type *bus = drv->bus; 19 struct device *dev; 20 int rc = -ENODEV; 21 22 dev = bus_find_device_by_name(bus, NULL, buf); 23 if (!dev) 24 return -ENODEV; 25 26 if (dev->driver) { 27 device_driver_detach(dev); 28 rc = count; 29 } 30 31 put_device(dev); 32 33 return rc; 34 } 35 static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); 36 37 static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t count) 38 { 39 const struct bus_type *bus = drv->bus; 40 struct device *dev; 41 struct device_driver *alt_drv = NULL; 42 int rc = -ENODEV; 43 struct idxd_dev *idxd_dev; 44 45 dev = bus_find_device_by_name(bus, NULL, buf); 46 if (!dev) 47 return -ENODEV; 48 49 if (dev->driver || drv != &dsa_drv.drv) 50 goto err_put_dev; 51 52 idxd_dev = confdev_to_idxd_dev(dev); 53 if (is_idxd_dev(idxd_dev)) { 54 alt_drv = driver_find("idxd", bus); 55 } else if (is_idxd_wq_dev(idxd_dev)) { 56 struct idxd_wq *wq = confdev_to_wq(dev); 57 58 if (is_idxd_wq_kernel(wq)) 59 alt_drv = driver_find("dmaengine", bus); 60 else if (is_idxd_wq_user(wq)) 61 alt_drv = driver_find("user", bus); 62 } 63 if (!alt_drv) 64 goto err_put_dev; 65 66 rc = device_driver_attach(alt_drv, dev); 67 if (rc < 0) 68 goto err_put_dev; 69 70 put_device(dev); 71 72 return count; 73 74 err_put_dev: 75 put_device(dev); 76 77 return rc; 78 } 79 static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store); 80 81 static struct attribute *dsa_drv_compat_attrs[] = { 82 &driver_attr_bind.attr, 83 &driver_attr_unbind.attr, 84 NULL, 85 }; 86 87 static const struct attribute_group dsa_drv_compat_attr_group = { 88 .attrs = dsa_drv_compat_attrs, 89 }; 90 91 static const struct attribute_group *dsa_drv_compat_groups[] = { 92 &dsa_drv_compat_attr_group, 93 NULL, 94 }; 95 96 static int idxd_dsa_drv_probe(struct idxd_dev *idxd_dev) 97 { 98 return -ENODEV; 99 } 100 101 static void idxd_dsa_drv_remove(struct idxd_dev *idxd_dev) 102 { 103 } 104 105 static enum idxd_dev_type dev_types[] = { 106 IDXD_DEV_NONE, 107 }; 108 109 struct idxd_device_driver dsa_drv = { 110 .name = "dsa", 111 .probe = idxd_dsa_drv_probe, 112 .remove = idxd_dsa_drv_remove, 113 .type = dev_types, 114 .drv = { 115 .suppress_bind_attrs = true, 116 .groups = dsa_drv_compat_groups, 117 }, 118 }; 119 120 module_idxd_driver(dsa_drv); 121 MODULE_IMPORT_NS("IDXD"); 122