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