1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Intel MIC Platform Software Stack (MPSS)
4  *
5  * Copyright(c) 2014 Intel Corporation.
6  *
7  * Intel Symmetric Communications Interface Bus driver.
8  */
9 #include <linux/slab.h>
10 #include <linux/module.h>
11 #include <linux/idr.h>
12 #include <linux/dma-mapping.h>
13 
14 #include "scif_bus.h"
15 
device_show(struct device * d,struct device_attribute * attr,char * buf)16 static ssize_t device_show(struct device *d,
17 			   struct device_attribute *attr, char *buf)
18 {
19 	struct scif_hw_dev *dev = dev_to_scif(d);
20 
21 	return sprintf(buf, "0x%04x\n", dev->id.device);
22 }
23 static DEVICE_ATTR_RO(device);
24 
vendor_show(struct device * d,struct device_attribute * attr,char * buf)25 static ssize_t vendor_show(struct device *d,
26 			   struct device_attribute *attr, char *buf)
27 {
28 	struct scif_hw_dev *dev = dev_to_scif(d);
29 
30 	return sprintf(buf, "0x%04x\n", dev->id.vendor);
31 }
32 static DEVICE_ATTR_RO(vendor);
33 
modalias_show(struct device * d,struct device_attribute * attr,char * buf)34 static ssize_t modalias_show(struct device *d,
35 			     struct device_attribute *attr, char *buf)
36 {
37 	struct scif_hw_dev *dev = dev_to_scif(d);
38 
39 	return sprintf(buf, "scif:d%08Xv%08X\n",
40 		       dev->id.device, dev->id.vendor);
41 }
42 static DEVICE_ATTR_RO(modalias);
43 
44 static struct attribute *scif_dev_attrs[] = {
45 	&dev_attr_device.attr,
46 	&dev_attr_vendor.attr,
47 	&dev_attr_modalias.attr,
48 	NULL,
49 };
50 ATTRIBUTE_GROUPS(scif_dev);
51 
scif_id_match(const struct scif_hw_dev * dev,const struct scif_hw_dev_id * id)52 static inline int scif_id_match(const struct scif_hw_dev *dev,
53 				const struct scif_hw_dev_id *id)
54 {
55 	if (id->device != dev->id.device && id->device != SCIF_DEV_ANY_ID)
56 		return 0;
57 
58 	return id->vendor == SCIF_DEV_ANY_ID || id->vendor == dev->id.vendor;
59 }
60 
61 /*
62  * This looks through all the IDs a driver claims to support.  If any of them
63  * match, we return 1 and the kernel will call scif_dev_probe().
64  */
scif_dev_match(struct device * dv,struct device_driver * dr)65 static int scif_dev_match(struct device *dv, struct device_driver *dr)
66 {
67 	unsigned int i;
68 	struct scif_hw_dev *dev = dev_to_scif(dv);
69 	const struct scif_hw_dev_id *ids;
70 
71 	ids = drv_to_scif(dr)->id_table;
72 	for (i = 0; ids[i].device; i++)
73 		if (scif_id_match(dev, &ids[i]))
74 			return 1;
75 	return 0;
76 }
77 
scif_uevent(struct device * dv,struct kobj_uevent_env * env)78 static int scif_uevent(struct device *dv, struct kobj_uevent_env *env)
79 {
80 	struct scif_hw_dev *dev = dev_to_scif(dv);
81 
82 	return add_uevent_var(env, "MODALIAS=scif:d%08Xv%08X",
83 			      dev->id.device, dev->id.vendor);
84 }
85 
scif_dev_probe(struct device * d)86 static int scif_dev_probe(struct device *d)
87 {
88 	struct scif_hw_dev *dev = dev_to_scif(d);
89 	struct scif_driver *drv = drv_to_scif(dev->dev.driver);
90 
91 	return drv->probe(dev);
92 }
93 
scif_dev_remove(struct device * d)94 static int scif_dev_remove(struct device *d)
95 {
96 	struct scif_hw_dev *dev = dev_to_scif(d);
97 	struct scif_driver *drv = drv_to_scif(dev->dev.driver);
98 
99 	drv->remove(dev);
100 	return 0;
101 }
102 
103 static struct bus_type scif_bus = {
104 	.name  = "scif_bus",
105 	.match = scif_dev_match,
106 	.dev_groups = scif_dev_groups,
107 	.uevent = scif_uevent,
108 	.probe = scif_dev_probe,
109 	.remove = scif_dev_remove,
110 };
111 
scif_register_driver(struct scif_driver * driver)112 int scif_register_driver(struct scif_driver *driver)
113 {
114 	driver->driver.bus = &scif_bus;
115 	return driver_register(&driver->driver);
116 }
117 EXPORT_SYMBOL_GPL(scif_register_driver);
118 
scif_unregister_driver(struct scif_driver * driver)119 void scif_unregister_driver(struct scif_driver *driver)
120 {
121 	driver_unregister(&driver->driver);
122 }
123 EXPORT_SYMBOL_GPL(scif_unregister_driver);
124 
scif_release_dev(struct device * d)125 static void scif_release_dev(struct device *d)
126 {
127 	struct scif_hw_dev *sdev = dev_to_scif(d);
128 
129 	kfree(sdev);
130 }
131 
132 struct scif_hw_dev *
scif_register_device(struct device * pdev,int id,const struct dma_map_ops * dma_ops,struct scif_hw_ops * hw_ops,u8 dnode,u8 snode,struct mic_mw * mmio,struct mic_mw * aper,void * dp,void __iomem * rdp,struct dma_chan ** chan,int num_chan,bool card_rel_da)133 scif_register_device(struct device *pdev, int id, const struct dma_map_ops *dma_ops,
134 		     struct scif_hw_ops *hw_ops, u8 dnode, u8 snode,
135 		     struct mic_mw *mmio, struct mic_mw *aper, void *dp,
136 		     void __iomem *rdp, struct dma_chan **chan, int num_chan,
137 		     bool card_rel_da)
138 {
139 	int ret;
140 	struct scif_hw_dev *sdev;
141 
142 	sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
143 	if (!sdev)
144 		return ERR_PTR(-ENOMEM);
145 
146 	sdev->dev.parent = pdev;
147 	sdev->id.device = id;
148 	sdev->id.vendor = SCIF_DEV_ANY_ID;
149 	sdev->dev.dma_ops = dma_ops;
150 	sdev->dev.release = scif_release_dev;
151 	sdev->hw_ops = hw_ops;
152 	sdev->dnode = dnode;
153 	sdev->snode = snode;
154 	dev_set_drvdata(&sdev->dev, sdev);
155 	sdev->dev.bus = &scif_bus;
156 	sdev->mmio = mmio;
157 	sdev->aper = aper;
158 	sdev->dp = dp;
159 	sdev->rdp = rdp;
160 	sdev->dev.dma_mask = &sdev->dev.coherent_dma_mask;
161 	dma_set_mask(&sdev->dev, DMA_BIT_MASK(64));
162 	sdev->dma_ch = chan;
163 	sdev->num_dma_ch = num_chan;
164 	sdev->card_rel_da = card_rel_da;
165 	dev_set_name(&sdev->dev, "scif-dev%u", sdev->dnode);
166 	/*
167 	 * device_register() causes the bus infrastructure to look for a
168 	 * matching driver.
169 	 */
170 	ret = device_register(&sdev->dev);
171 	if (ret)
172 		goto free_sdev;
173 	return sdev;
174 free_sdev:
175 	put_device(&sdev->dev);
176 	return ERR_PTR(ret);
177 }
178 EXPORT_SYMBOL_GPL(scif_register_device);
179 
scif_unregister_device(struct scif_hw_dev * sdev)180 void scif_unregister_device(struct scif_hw_dev *sdev)
181 {
182 	device_unregister(&sdev->dev);
183 }
184 EXPORT_SYMBOL_GPL(scif_unregister_device);
185 
scif_init(void)186 static int __init scif_init(void)
187 {
188 	return bus_register(&scif_bus);
189 }
190 
scif_exit(void)191 static void __exit scif_exit(void)
192 {
193 	bus_unregister(&scif_bus);
194 }
195 
196 core_initcall(scif_init);
197 module_exit(scif_exit);
198 
199 MODULE_AUTHOR("Intel Corporation");
200 MODULE_DESCRIPTION("Intel(R) SCIF Bus driver");
201 MODULE_LICENSE("GPL v2");
202