]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linuxkpi/common/src/linux_pci.c
Add full support for PCI_ANY_ID when matching PCI IDs in the LinuxKPI.
[FreeBSD/FreeBSD.git] / sys / compat / linuxkpi / common / src / linux_pci.c
1 /*-
2  * Copyright (c) 2015-2016 Mellanox Technologies, Ltd.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/malloc.h>
33 #include <sys/kernel.h>
34 #include <sys/sysctl.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/bus.h>
38 #include <sys/fcntl.h>
39 #include <sys/file.h>
40 #include <sys/filio.h>
41 #include <sys/rwlock.h>
42
43 #include <vm/vm.h>
44 #include <vm/pmap.h>
45
46 #include <machine/stdarg.h>
47
48 #include <linux/kobject.h>
49 #include <linux/device.h>
50 #include <linux/slab.h>
51 #include <linux/module.h>
52 #include <linux/cdev.h>
53 #include <linux/file.h>
54 #include <linux/sysfs.h>
55 #include <linux/mm.h>
56 #include <linux/io.h>
57 #include <linux/vmalloc.h>
58 #include <linux/pci.h>
59 #include <linux/compat.h>
60
61 static device_probe_t linux_pci_probe;
62 static device_attach_t linux_pci_attach;
63 static device_detach_t linux_pci_detach;
64 static device_suspend_t linux_pci_suspend;
65 static device_resume_t linux_pci_resume;
66 static device_shutdown_t linux_pci_shutdown;
67
68 static device_method_t pci_methods[] = {
69         DEVMETHOD(device_probe, linux_pci_probe),
70         DEVMETHOD(device_attach, linux_pci_attach),
71         DEVMETHOD(device_detach, linux_pci_detach),
72         DEVMETHOD(device_suspend, linux_pci_suspend),
73         DEVMETHOD(device_resume, linux_pci_resume),
74         DEVMETHOD(device_shutdown, linux_pci_shutdown),
75         DEVMETHOD_END
76 };
77
78 static struct pci_driver *
79 linux_pci_find(device_t dev, const struct pci_device_id **idp)
80 {
81         const struct pci_device_id *id;
82         struct pci_driver *pdrv;
83         uint16_t vendor;
84         uint16_t device;
85         uint16_t subvendor;
86         uint16_t subdevice;
87
88         vendor = pci_get_vendor(dev);
89         device = pci_get_device(dev);
90         subvendor = pci_get_subvendor(dev);
91         subdevice = pci_get_subdevice(dev);
92
93         spin_lock(&pci_lock);
94         list_for_each_entry(pdrv, &pci_drivers, links) {
95                 for (id = pdrv->id_table; id->vendor != 0; id++) {
96                         if (vendor == id->vendor &&
97                             (PCI_ANY_ID == id->device || device == id->device) &&
98                             (PCI_ANY_ID == id->subvendor || subvendor == id->subvendor) &&
99                             (PCI_ANY_ID == id->subdevice || subdevice == id->subdevice)) {
100                                 *idp = id;
101                                 spin_unlock(&pci_lock);
102                                 return (pdrv);
103                         }
104                 }
105         }
106         spin_unlock(&pci_lock);
107         return (NULL);
108 }
109
110 static int
111 linux_pci_probe(device_t dev)
112 {
113         const struct pci_device_id *id;
114         struct pci_driver *pdrv;
115
116         if ((pdrv = linux_pci_find(dev, &id)) == NULL)
117                 return (ENXIO);
118         if (device_get_driver(dev) != &pdrv->bsddriver)
119                 return (ENXIO);
120         device_set_desc(dev, pdrv->name);
121         return (0);
122 }
123
124 static int
125 linux_pci_attach(device_t dev)
126 {
127         struct resource_list_entry *rle;
128         struct pci_bus *pbus;
129         struct pci_dev *pdev;
130         struct pci_devinfo *dinfo;
131         struct pci_driver *pdrv;
132         const struct pci_device_id *id;
133         device_t parent;
134         devclass_t devclass;
135         int error;
136
137         linux_set_current(curthread);
138
139         pdrv = linux_pci_find(dev, &id);
140         pdev = device_get_softc(dev);
141
142         parent = device_get_parent(dev);
143         devclass = device_get_devclass(parent);
144         if (pdrv->isdrm) {
145                 dinfo = device_get_ivars(parent);
146                 device_set_ivars(dev, dinfo);
147         } else {
148                 dinfo = device_get_ivars(dev);
149         }
150
151         pdev->dev.parent = &linux_root_device;
152         pdev->dev.bsddev = dev;
153         INIT_LIST_HEAD(&pdev->dev.irqents);
154         pdev->devfn = PCI_DEVFN(pci_get_slot(dev), pci_get_function(dev));
155         pdev->device = dinfo->cfg.device;
156         pdev->vendor = dinfo->cfg.vendor;
157         pdev->subsystem_vendor = dinfo->cfg.subvendor;
158         pdev->subsystem_device = dinfo->cfg.subdevice;
159         pdev->class = pci_get_class(dev);
160         pdev->revision = pci_get_revid(dev);
161         pdev->dev.dma_mask = &pdev->dma_mask;
162         pdev->pdrv = pdrv;
163         kobject_init(&pdev->dev.kobj, &linux_dev_ktype);
164         kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
165         kobject_add(&pdev->dev.kobj, &linux_root_device.kobj,
166             kobject_name(&pdev->dev.kobj));
167         rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 0);
168         if (rle != NULL)
169                 pdev->dev.irq = rle->start;
170         else
171                 pdev->dev.irq = LINUX_IRQ_INVALID;
172         pdev->irq = pdev->dev.irq;
173
174         if (pdev->bus == NULL) {
175                 pbus = malloc(sizeof(*pbus), M_DEVBUF, M_WAITOK | M_ZERO);
176                 pbus->self = pdev;
177                 pbus->number = pci_get_bus(dev);
178                 pdev->bus = pbus;
179         }
180
181         spin_lock(&pci_lock);
182         list_add(&pdev->links, &pci_devices);
183         spin_unlock(&pci_lock);
184
185         error = pdrv->probe(pdev, id);
186         if (error) {
187                 spin_lock(&pci_lock);
188                 list_del(&pdev->links);
189                 spin_unlock(&pci_lock);
190                 put_device(&pdev->dev);
191                 error = -error;
192         }
193         return (error);
194 }
195
196 static int
197 linux_pci_detach(device_t dev)
198 {
199         struct pci_dev *pdev;
200
201         linux_set_current(curthread);
202         pdev = device_get_softc(dev);
203
204         pdev->pdrv->remove(pdev);
205
206         spin_lock(&pci_lock);
207         list_del(&pdev->links);
208         spin_unlock(&pci_lock);
209         device_set_desc(dev, NULL);
210         put_device(&pdev->dev);
211
212         return (0);
213 }
214
215 static int
216 linux_pci_suspend(device_t dev)
217 {
218         const struct dev_pm_ops *pmops;
219         struct pm_message pm = { };
220         struct pci_dev *pdev;
221         int error;
222
223         error = 0;
224         linux_set_current(curthread);
225         pdev = device_get_softc(dev);
226         pmops = pdev->pdrv->driver.pm;
227
228         if (pdev->pdrv->suspend != NULL)
229                 error = -pdev->pdrv->suspend(pdev, pm);
230         else if (pmops != NULL && pmops->suspend != NULL) {
231                 error = -pmops->suspend(&pdev->dev);
232                 if (error == 0 && pmops->suspend_late != NULL)
233                         error = -pmops->suspend_late(&pdev->dev);
234         }
235         return (error);
236 }
237
238 static int
239 linux_pci_resume(device_t dev)
240 {
241         const struct dev_pm_ops *pmops;
242         struct pci_dev *pdev;
243         int error;
244
245         error = 0;
246         linux_set_current(curthread);
247         pdev = device_get_softc(dev);
248         pmops = pdev->pdrv->driver.pm;
249
250         if (pdev->pdrv->resume != NULL)
251                 error = -pdev->pdrv->resume(pdev);
252         else if (pmops != NULL && pmops->resume != NULL) {
253                 if (pmops->resume_early != NULL)
254                         error = -pmops->resume_early(&pdev->dev);
255                 if (error == 0 && pmops->resume != NULL)
256                         error = -pmops->resume(&pdev->dev);
257         }
258         return (error);
259 }
260
261 static int
262 linux_pci_shutdown(device_t dev)
263 {
264         struct pci_dev *pdev;
265
266         linux_set_current(curthread);
267         pdev = device_get_softc(dev);
268         if (pdev->pdrv->shutdown != NULL)
269                 pdev->pdrv->shutdown(pdev);
270         return (0);
271 }
272
273 static int
274 _linux_pci_register_driver(struct pci_driver *pdrv, devclass_t dc)
275 {
276         int error;
277
278         linux_set_current(curthread);
279         spin_lock(&pci_lock);
280         list_add(&pdrv->links, &pci_drivers);
281         spin_unlock(&pci_lock);
282         pdrv->bsddriver.name = pdrv->name;
283         pdrv->bsddriver.methods = pci_methods;
284         pdrv->bsddriver.size = sizeof(struct pci_dev);
285
286         mtx_lock(&Giant);
287         error = devclass_add_driver(dc, &pdrv->bsddriver,
288             BUS_PASS_DEFAULT, &pdrv->bsdclass);
289         mtx_unlock(&Giant);
290         return (-error);
291 }
292
293 int
294 linux_pci_register_driver(struct pci_driver *pdrv)
295 {
296         devclass_t dc;
297
298         dc = devclass_find("pci");
299         if (dc == NULL)
300                 return (-ENXIO);
301         pdrv->isdrm = false;
302         return (_linux_pci_register_driver(pdrv, dc));
303 }
304
305 int
306 linux_pci_register_drm_driver(struct pci_driver *pdrv)
307 {
308         devclass_t dc;
309
310         dc = devclass_create("vgapci");
311         if (dc == NULL)
312                 return (-ENXIO);
313         pdrv->isdrm = true;
314         pdrv->name = "drmn";
315         return (_linux_pci_register_driver(pdrv, dc));
316 }
317
318 void
319 linux_pci_unregister_driver(struct pci_driver *pdrv)
320 {
321         devclass_t bus;
322
323         bus = devclass_find("pci");
324
325         spin_lock(&pci_lock);
326         list_del(&pdrv->links);
327         spin_unlock(&pci_lock);
328         mtx_lock(&Giant);
329         if (bus != NULL)
330                 devclass_delete_driver(bus, &pdrv->bsddriver);
331         mtx_unlock(&Giant);
332 }