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