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 && dev->driver) { 24 device_driver_detach(dev); 25 rc = count; 26 } 27 28 return rc; 29 } 30 static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); 31 32 static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t count) 33 { 34 const struct bus_type *bus = drv->bus; 35 struct device *dev; 36 struct device_driver *alt_drv = NULL; 37 int rc = -ENODEV; 38 struct idxd_dev *idxd_dev; 39 40 dev = bus_find_device_by_name(bus, NULL, buf); 41 if (!dev || dev->driver || drv != &dsa_drv.drv) 42 return -ENODEV; 43 44 idxd_dev = confdev_to_idxd_dev(dev); 45 if (is_idxd_dev(idxd_dev)) { 46 alt_drv = driver_find("idxd", bus); 47 } else if (is_idxd_wq_dev(idxd_dev)) { 48 struct idxd_wq *wq = confdev_to_wq(dev); 49 50 if (is_idxd_wq_kernel(wq)) 51 alt_drv = driver_find("dmaengine", bus); 52 else if (is_idxd_wq_user(wq)) 53 alt_drv = driver_find("user", bus); 54 } 55 if (!alt_drv) 56 return -ENODEV; 57 58 rc = device_driver_attach(alt_drv, dev); 59 if (rc < 0) 60 return rc; 61 62 return count; 63 } 64 static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store); 65 66 static struct attribute *dsa_drv_compat_attrs[] = { 67 &driver_attr_bind.attr, 68 &driver_attr_unbind.attr, 69 NULL, 70 }; 71 72 static const struct attribute_group dsa_drv_compat_attr_group = { 73 .attrs = dsa_drv_compat_attrs, 74 }; 75 76 static const struct attribute_group *dsa_drv_compat_groups[] = { 77 &dsa_drv_compat_attr_group, 78 NULL, 79 }; 80 81 static int idxd_dsa_drv_probe(struct idxd_dev *idxd_dev) 82 { 83 return -ENODEV; 84 } 85 86 static void idxd_dsa_drv_remove(struct idxd_dev *idxd_dev) 87 { 88 } 89 90 static enum idxd_dev_type dev_types[] = { 91 IDXD_DEV_NONE, 92 }; 93 94 struct idxd_device_driver dsa_drv = { 95 .name = "dsa", 96 .probe = idxd_dsa_drv_probe, 97 .remove = idxd_dsa_drv_remove, 98 .type = dev_types, 99 .drv = { 100 .suppress_bind_attrs = true, 101 .groups = dsa_drv_compat_groups, 102 }, 103 }; 104 105 module_idxd_driver(dsa_drv); 106 MODULE_IMPORT_NS(IDXD); 107