Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | // SPDX-License-Identifier: GPL-2.0-only /* * Intel MIC Platform Software Stack (MPSS) * * Copyright(c) 2015 Intel Corporation. * * Intel MIC COSM Bus Driver */ #include <linux/slab.h> #include <linux/module.h> #include <linux/idr.h> #include "cosm_bus.h" /* Unique numbering for cosm devices. */ static DEFINE_IDA(cosm_index_ida); static int cosm_dev_probe(struct device *d) { struct cosm_device *dev = dev_to_cosm(d); struct cosm_driver *drv = drv_to_cosm(dev->dev.driver); return drv->probe(dev); } static int cosm_dev_remove(struct device *d) { struct cosm_device *dev = dev_to_cosm(d); struct cosm_driver *drv = drv_to_cosm(dev->dev.driver); drv->remove(dev); return 0; } static struct bus_type cosm_bus = { .name = "cosm_bus", .probe = cosm_dev_probe, .remove = cosm_dev_remove, }; int cosm_register_driver(struct cosm_driver *driver) { driver->driver.bus = &cosm_bus; return driver_register(&driver->driver); } EXPORT_SYMBOL_GPL(cosm_register_driver); void cosm_unregister_driver(struct cosm_driver *driver) { driver_unregister(&driver->driver); } EXPORT_SYMBOL_GPL(cosm_unregister_driver); static inline void cosm_release_dev(struct device *d) { struct cosm_device *cdev = dev_to_cosm(d); kfree(cdev); } struct cosm_device * cosm_register_device(struct device *pdev, struct cosm_hw_ops *hw_ops) { struct cosm_device *cdev; int ret; cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); if (!cdev) return ERR_PTR(-ENOMEM); cdev->dev.parent = pdev; cdev->dev.release = cosm_release_dev; cdev->hw_ops = hw_ops; dev_set_drvdata(&cdev->dev, cdev); cdev->dev.bus = &cosm_bus; /* Assign a unique device index and hence name */ ret = ida_simple_get(&cosm_index_ida, 0, 0, GFP_KERNEL); if (ret < 0) goto free_cdev; cdev->index = ret; cdev->dev.id = ret; dev_set_name(&cdev->dev, "cosm-dev%u", cdev->index); ret = device_register(&cdev->dev); if (ret) goto ida_remove; return cdev; ida_remove: ida_simple_remove(&cosm_index_ida, cdev->index); free_cdev: put_device(&cdev->dev); return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(cosm_register_device); void cosm_unregister_device(struct cosm_device *dev) { int index = dev->index; /* save for after device release */ device_unregister(&dev->dev); ida_simple_remove(&cosm_index_ida, index); } EXPORT_SYMBOL_GPL(cosm_unregister_device); struct cosm_device *cosm_find_cdev_by_id(int id) { struct device *dev = subsys_find_device_by_id(&cosm_bus, id, NULL); return dev ? container_of(dev, struct cosm_device, dev) : NULL; } EXPORT_SYMBOL_GPL(cosm_find_cdev_by_id); static int __init cosm_init(void) { return bus_register(&cosm_bus); } static void __exit cosm_exit(void) { bus_unregister(&cosm_bus); ida_destroy(&cosm_index_ida); } core_initcall(cosm_init); module_exit(cosm_exit); MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Intel(R) MIC card OS state management bus driver"); MODULE_LICENSE("GPL v2"); |