linux_pci.c revision 310250
1179189Sjb/*-
2179189Sjb * Copyright (c) 2015-2016 Mellanox Technologies, Ltd.
3204597Suqs * All rights reserved.
4204597Suqs *
5179189Sjb * Redistribution and use in source and binary forms, with or without
6179189Sjb * modification, are permitted provided that the following conditions
7179189Sjb * are met:
8179189Sjb * 1. Redistributions of source code must retain the above copyright
9179189Sjb *    notice unmodified, this list of conditions, and the following
10179189Sjb *    disclaimer.
11179189Sjb * 2. Redistributions in binary form must reproduce the above copyright
12179189Sjb *    notice, this list of conditions and the following disclaimer in the
13179189Sjb *    documentation and/or other materials provided with the distribution.
14179189Sjb *
15179189Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16179189Sjb * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17179189Sjb * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18179189Sjb * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19179189Sjb * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20179189Sjb * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21211554Srpaulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22179189Sjb * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23179189Sjb * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24179189Sjb * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25179189Sjb */
26179189Sjb
27179189Sjb#include <sys/cdefs.h>
28179189Sjb__FBSDID("$FreeBSD: stable/11/sys/compat/linuxkpi/common/src/linux_pci.c 310250 2016-12-19 09:47:34Z hselasky $");
29179189Sjb
30179189Sjb#include <sys/param.h>
31179189Sjb#include <sys/systm.h>
32179189Sjb#include <sys/malloc.h>
33179189Sjb#include <sys/kernel.h>
34179189Sjb#include <sys/sysctl.h>
35179189Sjb#include <sys/lock.h>
36179189Sjb#include <sys/mutex.h>
37179189Sjb#include <sys/bus.h>
38179189Sjb#include <sys/fcntl.h>
39179189Sjb#include <sys/file.h>
40179189Sjb#include <sys/filio.h>
41179189Sjb#include <sys/rwlock.h>
42179189Sjb
43179189Sjb#include <vm/vm.h>
44179189Sjb#include <vm/pmap.h>
45211554Srpaulo
46211554Srpaulo#include <machine/stdarg.h>
47179189Sjb
48179189Sjb#include <linux/kobject.h>
49179189Sjb#include <linux/device.h>
50179189Sjb#include <linux/slab.h>
51179189Sjb#include <linux/module.h>
52179189Sjb#include <linux/cdev.h>
53204597Suqs#include <linux/file.h>
54179189Sjb#include <linux/sysfs.h>
55211554Srpaulo#include <linux/mm.h>
56211554Srpaulo#include <linux/io.h>
57179189Sjb#include <linux/vmalloc.h>
58179189Sjb#include <linux/pci.h>
59179189Sjb#include <linux/compat.h>
60179189Sjb
61179189Sjbstatic device_probe_t linux_pci_probe;
62179189Sjbstatic device_attach_t linux_pci_attach;
63179189Sjbstatic device_detach_t linux_pci_detach;
64179189Sjbstatic device_suspend_t linux_pci_suspend;
65179189Sjbstatic device_resume_t linux_pci_resume;
66179189Sjbstatic device_shutdown_t linux_pci_shutdown;
67211554Srpaulo
68211554Srpaulostatic device_method_t pci_methods[] = {
69211554Srpaulo	DEVMETHOD(device_probe, linux_pci_probe),
70179189Sjb	DEVMETHOD(device_attach, linux_pci_attach),
71179189Sjb	DEVMETHOD(device_detach, linux_pci_detach),
72211554Srpaulo	DEVMETHOD(device_suspend, linux_pci_suspend),
73179189Sjb	DEVMETHOD(device_resume, linux_pci_resume),
74179189Sjb	DEVMETHOD(device_shutdown, linux_pci_shutdown),
75179189Sjb	DEVMETHOD_END
76179189Sjb};
77179189Sjb
78211554Srpaulostatic struct pci_driver *
79211554Srpaulolinux_pci_find(device_t dev, const struct pci_device_id **idp)
80211554Srpaulo{
81211554Srpaulo	const struct pci_device_id *id;
82179189Sjb	struct pci_driver *pdrv;
83179189Sjb	uint16_t vendor;
84179189Sjb	uint16_t device;
85179189Sjb
86179189Sjb	vendor = pci_get_vendor(dev);
87179189Sjb	device = pci_get_device(dev);
88179189Sjb
89179189Sjb	spin_lock(&pci_lock);
90179189Sjb	list_for_each_entry(pdrv, &pci_drivers, links) {
91179189Sjb		for (id = pdrv->id_table; id->vendor != 0; id++) {
92179189Sjb			if (vendor == id->vendor && device == id->device) {
93179189Sjb				*idp = id;
94179189Sjb				spin_unlock(&pci_lock);
95179189Sjb				return (pdrv);
96179189Sjb			}
97179189Sjb		}
98179189Sjb	}
99179189Sjb	spin_unlock(&pci_lock);
100179189Sjb	return (NULL);
101179189Sjb}
102179189Sjb
103179189Sjbstatic int
104linux_pci_probe(device_t dev)
105{
106	const struct pci_device_id *id;
107	struct pci_driver *pdrv;
108
109	if ((pdrv = linux_pci_find(dev, &id)) == NULL)
110		return (ENXIO);
111	if (device_get_driver(dev) != &pdrv->driver)
112		return (ENXIO);
113	device_set_desc(dev, pdrv->name);
114	return (0);
115}
116
117static int
118linux_pci_attach(device_t dev)
119{
120	struct resource_list_entry *rle;
121	struct pci_dev *pdev;
122	struct pci_driver *pdrv;
123	const struct pci_device_id *id;
124	struct task_struct t;
125	struct thread *td;
126	int error;
127
128	td = curthread;
129	linux_set_current(td, &t);
130	pdrv = linux_pci_find(dev, &id);
131	pdev = device_get_softc(dev);
132	pdev->dev.parent = &linux_root_device;
133	pdev->dev.bsddev = dev;
134	INIT_LIST_HEAD(&pdev->dev.irqents);
135	pdev->device = id->device;
136	pdev->vendor = id->vendor;
137	pdev->dev.dma_mask = &pdev->dma_mask;
138	pdev->pdrv = pdrv;
139	kobject_init(&pdev->dev.kobj, &linux_dev_ktype);
140	kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
141	kobject_add(&pdev->dev.kobj, &linux_root_device.kobj,
142	    kobject_name(&pdev->dev.kobj));
143	rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 0);
144	if (rle != NULL)
145		pdev->dev.irq = rle->start;
146	else
147		pdev->dev.irq = LINUX_IRQ_INVALID;
148	pdev->irq = pdev->dev.irq;
149	DROP_GIANT();
150	spin_lock(&pci_lock);
151	list_add(&pdev->links, &pci_devices);
152	spin_unlock(&pci_lock);
153	error = pdrv->probe(pdev, id);
154	PICKUP_GIANT();
155	if (error) {
156		spin_lock(&pci_lock);
157		list_del(&pdev->links);
158		spin_unlock(&pci_lock);
159		put_device(&pdev->dev);
160		error = -error;
161	}
162	linux_clear_current(td);
163	return (error);
164}
165
166static int
167linux_pci_detach(device_t dev)
168{
169	struct pci_dev *pdev;
170	struct task_struct t;
171	struct thread *td;
172
173	td = curthread;
174	linux_set_current(td, &t);
175	pdev = device_get_softc(dev);
176	DROP_GIANT();
177	pdev->pdrv->remove(pdev);
178	PICKUP_GIANT();
179	spin_lock(&pci_lock);
180	list_del(&pdev->links);
181	spin_unlock(&pci_lock);
182	put_device(&pdev->dev);
183	linux_clear_current(td);
184
185	return (0);
186}
187
188static int
189linux_pci_suspend(device_t dev)
190{
191	struct pm_message pm = { };
192	struct pci_dev *pdev;
193	struct task_struct t;
194	struct thread *td;
195	int err;
196
197	td = curthread;
198	linux_set_current(td, &t);
199	pdev = device_get_softc(dev);
200	if (pdev->pdrv->suspend != NULL)
201		err = -pdev->pdrv->suspend(pdev, pm);
202	else
203		err = 0;
204	linux_clear_current(td);
205	return (err);
206}
207
208static int
209linux_pci_resume(device_t dev)
210{
211	struct pci_dev *pdev;
212	struct task_struct t;
213	struct thread *td;
214	int err;
215
216	td = curthread;
217	linux_set_current(td, &t);
218	pdev = device_get_softc(dev);
219	if (pdev->pdrv->resume != NULL)
220		err = -pdev->pdrv->resume(pdev);
221	else
222		err = 0;
223	linux_clear_current(td);
224	return (err);
225}
226
227static int
228linux_pci_shutdown(device_t dev)
229{
230	struct pci_dev *pdev;
231	struct task_struct t;
232	struct thread *td;
233
234	td = curthread;
235	linux_set_current(td, &t);
236	pdev = device_get_softc(dev);
237	if (pdev->pdrv->shutdown != NULL) {
238		DROP_GIANT();
239		pdev->pdrv->shutdown(pdev);
240		PICKUP_GIANT();
241	}
242	linux_clear_current(td);
243	return (0);
244}
245
246int
247pci_register_driver(struct pci_driver *pdrv)
248{
249	devclass_t bus;
250	int error = 0;
251
252	bus = devclass_find("pci");
253
254	spin_lock(&pci_lock);
255	list_add(&pdrv->links, &pci_drivers);
256	spin_unlock(&pci_lock);
257	pdrv->driver.name = pdrv->name;
258	pdrv->driver.methods = pci_methods;
259	pdrv->driver.size = sizeof(struct pci_dev);
260	mtx_lock(&Giant);
261	if (bus != NULL) {
262		error = devclass_add_driver(bus, &pdrv->driver, BUS_PASS_DEFAULT,
263		    &pdrv->bsdclass);
264	}
265	mtx_unlock(&Giant);
266	return (-error);
267}
268
269void
270pci_unregister_driver(struct pci_driver *pdrv)
271{
272	devclass_t bus;
273
274	bus = devclass_find("pci");
275
276	list_del(&pdrv->links);
277	mtx_lock(&Giant);
278	if (bus != NULL)
279		devclass_delete_driver(bus, &pdrv->driver);
280	mtx_unlock(&Giant);
281}
282
283