blob: a281c599a5040b08d77becba9627325f062a88b6 [file] [log] [blame]
Kishon Vijay Abraham I5e8cb402017-04-10 19:25:10 +05301/**
2 * PCI Endpoint *Function* (EPF) library
3 *
4 * Copyright (C) 2017 Texas Instruments
5 * Author: Kishon Vijay Abraham I <kishon@ti.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 of
9 * the License as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/device.h>
21#include <linux/dma-mapping.h>
22#include <linux/slab.h>
23#include <linux/module.h>
24
25#include <linux/pci-epc.h>
26#include <linux/pci-epf.h>
27
28static struct bus_type pci_epf_bus_type;
29static struct device_type pci_epf_type;
30
31/**
32 * pci_epf_linkup() - Notify the function driver that EPC device has
33 * established a connection with the Root Complex.
34 * @epf: the EPF device bound to the EPC device which has established
35 * the connection with the host
36 *
37 * Invoke to notify the function driver that EPC device has established
38 * a connection with the Root Complex.
39 */
40void pci_epf_linkup(struct pci_epf *epf)
41{
42 if (!epf->driver) {
43 dev_WARN(&epf->dev, "epf device not bound to driver\n");
44 return;
45 }
46
47 epf->driver->ops->linkup(epf);
48}
49EXPORT_SYMBOL_GPL(pci_epf_linkup);
50
51/**
52 * pci_epf_unbind() - Notify the function driver that the binding between the
53 * EPF device and EPC device has been lost
54 * @epf: the EPF device which has lost the binding with the EPC device
55 *
56 * Invoke to notify the function driver that the binding between the EPF device
57 * and EPC device has been lost.
58 */
59void pci_epf_unbind(struct pci_epf *epf)
60{
61 if (!epf->driver) {
62 dev_WARN(&epf->dev, "epf device not bound to driver\n");
63 return;
64 }
65
66 epf->driver->ops->unbind(epf);
67 module_put(epf->driver->owner);
68}
69EXPORT_SYMBOL_GPL(pci_epf_unbind);
70
71/**
72 * pci_epf_bind() - Notify the function driver that the EPF device has been
73 * bound to a EPC device
74 * @epf: the EPF device which has been bound to the EPC device
75 *
76 * Invoke to notify the function driver that it has been bound to a EPC device
77 */
78int pci_epf_bind(struct pci_epf *epf)
79{
80 if (!epf->driver) {
81 dev_WARN(&epf->dev, "epf device not bound to driver\n");
82 return -EINVAL;
83 }
84
85 if (!try_module_get(epf->driver->owner))
86 return -EAGAIN;
87
88 return epf->driver->ops->bind(epf);
89}
90EXPORT_SYMBOL_GPL(pci_epf_bind);
91
92/**
93 * pci_epf_free_space() - free the allocated PCI EPF register space
94 * @addr: the virtual address of the PCI EPF register space
95 * @bar: the BAR number corresponding to the register space
96 *
97 * Invoke to free the allocated PCI EPF register space.
98 */
99void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar)
100{
101 struct device *dev = &epf->dev;
102
103 if (!addr)
104 return;
105
106 dma_free_coherent(dev, epf->bar[bar].size, addr,
107 epf->bar[bar].phys_addr);
108
109 epf->bar[bar].phys_addr = 0;
110 epf->bar[bar].size = 0;
111}
112EXPORT_SYMBOL_GPL(pci_epf_free_space);
113
114/**
115 * pci_epf_alloc_space() - allocate memory for the PCI EPF register space
116 * @size: the size of the memory that has to be allocated
117 * @bar: the BAR number corresponding to the allocated register space
118 *
119 * Invoke to allocate memory for the PCI EPF register space.
120 */
121void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
122{
123 void *space;
124 struct device *dev = &epf->dev;
125 dma_addr_t phys_addr;
126
127 if (size < 128)
128 size = 128;
129 size = roundup_pow_of_two(size);
130
131 space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL);
132 if (!space) {
133 dev_err(dev, "failed to allocate mem space\n");
134 return NULL;
135 }
136
137 epf->bar[bar].phys_addr = phys_addr;
138 epf->bar[bar].size = size;
139
140 return space;
141}
142EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
143
144/**
145 * pci_epf_unregister_driver() - unregister the PCI EPF driver
146 * @driver: the PCI EPF driver that has to be unregistered
147 *
148 * Invoke to unregister the PCI EPF driver.
149 */
150void pci_epf_unregister_driver(struct pci_epf_driver *driver)
151{
152 driver_unregister(&driver->driver);
153}
154EXPORT_SYMBOL_GPL(pci_epf_unregister_driver);
155
156/**
157 * __pci_epf_register_driver() - register a new PCI EPF driver
158 * @driver: structure representing PCI EPF driver
159 * @owner: the owner of the module that registers the PCI EPF driver
160 *
161 * Invoke to register a new PCI EPF driver.
162 */
163int __pci_epf_register_driver(struct pci_epf_driver *driver,
164 struct module *owner)
165{
166 int ret;
167
168 if (!driver->ops)
169 return -EINVAL;
170
171 if (!driver->ops->bind || !driver->ops->unbind || !driver->ops->linkup)
172 return -EINVAL;
173
174 driver->driver.bus = &pci_epf_bus_type;
175 driver->driver.owner = owner;
176
177 ret = driver_register(&driver->driver);
178 if (ret)
179 return ret;
180
181 return 0;
182}
183EXPORT_SYMBOL_GPL(__pci_epf_register_driver);
184
185/**
186 * pci_epf_destroy() - destroy the created PCI EPF device
187 * @epf: the PCI EPF device that has to be destroyed.
188 *
189 * Invoke to destroy the PCI EPF device created by invoking pci_epf_create().
190 */
191void pci_epf_destroy(struct pci_epf *epf)
192{
193 device_unregister(&epf->dev);
194}
195EXPORT_SYMBOL_GPL(pci_epf_destroy);
196
197/**
198 * pci_epf_create() - create a new PCI EPF device
199 * @name: the name of the PCI EPF device. This name will be used to bind the
200 * the EPF device to a EPF driver
201 *
202 * Invoke to create a new PCI EPF device by providing the name of the function
203 * device.
204 */
205struct pci_epf *pci_epf_create(const char *name)
206{
207 int ret;
208 struct pci_epf *epf;
209 struct device *dev;
210 char *func_name;
211 char *buf;
212
213 epf = kzalloc(sizeof(*epf), GFP_KERNEL);
214 if (!epf) {
215 ret = -ENOMEM;
216 goto err_ret;
217 }
218
219 buf = kstrdup(name, GFP_KERNEL);
220 if (!buf) {
221 ret = -ENOMEM;
222 goto free_epf;
223 }
224
225 func_name = buf;
226 buf = strchrnul(buf, '.');
227 *buf = '\0';
228
229 epf->name = kstrdup(func_name, GFP_KERNEL);
230 if (!epf->name) {
231 ret = -ENOMEM;
232 goto free_func_name;
233 }
234
235 dev = &epf->dev;
236 device_initialize(dev);
237 dev->bus = &pci_epf_bus_type;
238 dev->type = &pci_epf_type;
239
240 ret = dev_set_name(dev, "%s", name);
241 if (ret)
242 goto put_dev;
243
244 ret = device_add(dev);
245 if (ret)
246 goto put_dev;
247
248 kfree(func_name);
249 return epf;
250
251put_dev:
252 put_device(dev);
253 kfree(epf->name);
254
255free_func_name:
256 kfree(func_name);
257
258free_epf:
259 kfree(epf);
260
261err_ret:
262 return ERR_PTR(ret);
263}
264EXPORT_SYMBOL_GPL(pci_epf_create);
265
266static void pci_epf_dev_release(struct device *dev)
267{
268 struct pci_epf *epf = to_pci_epf(dev);
269
270 kfree(epf->name);
271 kfree(epf);
272}
273
274static struct device_type pci_epf_type = {
275 .release = pci_epf_dev_release,
276};
277
278static int
279pci_epf_match_id(const struct pci_epf_device_id *id, const struct pci_epf *epf)
280{
281 while (id->name[0]) {
282 if (strcmp(epf->name, id->name) == 0)
283 return true;
284 id++;
285 }
286
287 return false;
288}
289
290static int pci_epf_device_match(struct device *dev, struct device_driver *drv)
291{
292 struct pci_epf *epf = to_pci_epf(dev);
293 struct pci_epf_driver *driver = to_pci_epf_driver(drv);
294
295 if (driver->id_table)
296 return pci_epf_match_id(driver->id_table, epf);
297
298 return !strcmp(epf->name, drv->name);
299}
300
301static int pci_epf_device_probe(struct device *dev)
302{
303 struct pci_epf *epf = to_pci_epf(dev);
304 struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver);
305
306 if (!driver->probe)
307 return -ENODEV;
308
309 epf->driver = driver;
310
311 return driver->probe(epf);
312}
313
314static int pci_epf_device_remove(struct device *dev)
315{
316 int ret;
317 struct pci_epf *epf = to_pci_epf(dev);
318 struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver);
319
320 ret = driver->remove(epf);
321 epf->driver = NULL;
322
323 return ret;
324}
325
326static struct bus_type pci_epf_bus_type = {
327 .name = "pci-epf",
328 .match = pci_epf_device_match,
329 .probe = pci_epf_device_probe,
330 .remove = pci_epf_device_remove,
331};
332
333static int __init pci_epf_init(void)
334{
335 int ret;
336
337 ret = bus_register(&pci_epf_bus_type);
338 if (ret) {
339 pr_err("failed to register pci epf bus --> %d\n", ret);
340 return ret;
341 }
342
343 return 0;
344}
345module_init(pci_epf_init);
346
347static void __exit pci_epf_exit(void)
348{
349 bus_unregister(&pci_epf_bus_type);
350}
351module_exit(pci_epf_exit);
352
353MODULE_DESCRIPTION("PCI EPF Library");
354MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
355MODULE_LICENSE("GPL v2");