Commit | Line | Data |
---|---|---|
1802d0be | 1 | // SPDX-License-Identifier: GPL-2.0-only |
5ec4ca6a SD |
2 | /* |
3 | * Intel MIC Platform Software Stack (MPSS) | |
4 | * | |
5 | * Copyright(c) 2014 Intel Corporation. | |
6 | * | |
5ec4ca6a SD |
7 | * Intel Symmetric Communications Interface Bus driver. |
8 | */ | |
9 | #include <linux/slab.h> | |
10 | #include <linux/module.h> | |
11 | #include <linux/idr.h> | |
0a0f0d8b | 12 | #include <linux/dma-map-ops.h> |
5ec4ca6a SD |
13 | |
14 | #include "scif_bus.h" | |
15 | ||
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 | } | |
5ec4ca6a SD |
23 | static DEVICE_ATTR_RO(device); |
24 | ||
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 | } | |
5ec4ca6a SD |
32 | static DEVICE_ATTR_RO(vendor); |
33 | ||
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 | } | |
5ec4ca6a SD |
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 | ||
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 | */ | |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
119 | void scif_unregister_driver(struct scif_driver *driver) | |
120 | { | |
121 | driver_unregister(&driver->driver); | |
122 | } | |
123 | EXPORT_SYMBOL_GPL(scif_unregister_driver); | |
124 | ||
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 * | |
5299709d | 133 | scif_register_device(struct device *pdev, int id, const struct dma_map_ops *dma_ops, |
5ec4ca6a SD |
134 | struct scif_hw_ops *hw_ops, u8 dnode, u8 snode, |
135 | struct mic_mw *mmio, struct mic_mw *aper, void *dp, | |
f4a66c20 AD |
136 | void __iomem *rdp, struct dma_chan **chan, int num_chan, |
137 | bool card_rel_da) | |
5ec4ca6a SD |
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; | |
5657933d | 149 | sdev->dev.dma_ops = dma_ops; |
5ec4ca6a SD |
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; | |
f4a66c20 | 164 | sdev->card_rel_da = card_rel_da; |
5ec4ca6a SD |
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: | |
82ff3ac7 | 175 | put_device(&sdev->dev); |
5ec4ca6a SD |
176 | return ERR_PTR(ret); |
177 | } | |
178 | EXPORT_SYMBOL_GPL(scif_register_device); | |
179 | ||
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 | ||
186 | static int __init scif_init(void) | |
187 | { | |
188 | return bus_register(&scif_bus); | |
189 | } | |
190 | ||
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"); |