1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc.
3219820Sjeff * Copyright (c) 2010 iX Systems, Inc.
4219820Sjeff * Copyright (c) 2010 Panasas, Inc.
5219820Sjeff * All rights reserved.
6219820Sjeff *
7219820Sjeff * Redistribution and use in source and binary forms, with or without
8219820Sjeff * modification, are permitted provided that the following conditions
9219820Sjeff * are met:
10219820Sjeff * 1. Redistributions of source code must retain the above copyright
11219820Sjeff *    notice unmodified, this list of conditions, and the following
12219820Sjeff *    disclaimer.
13219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
14219820Sjeff *    notice, this list of conditions and the following disclaimer in the
15219820Sjeff *    documentation and/or other materials provided with the distribution.
16219820Sjeff *
17219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27219820Sjeff */
28219820Sjeff
29219820Sjeff#ifndef	_LINUX_PCI_H_
30219820Sjeff#define	_LINUX_PCI_H_
31219820Sjeff
32219820Sjeff#define	CONFIG_PCI_MSI
33219820Sjeff
34219820Sjeff#include <linux/types.h>
35219820Sjeff
36219820Sjeff#include <sys/param.h>
37219820Sjeff#include <sys/bus.h>
38219820Sjeff#include <sys/pciio.h>
39219820Sjeff#include <sys/rman.h>
40219820Sjeff#include <dev/pci/pcivar.h>
41219820Sjeff#include <dev/pci/pcireg.h>
42219820Sjeff#include <dev/pci/pci_private.h>
43219820Sjeff
44219820Sjeff#include <machine/resource.h>
45219820Sjeff
46219820Sjeff#include <linux/init.h>
47219820Sjeff#include <linux/list.h>
48219820Sjeff#include <linux/dmapool.h>
49219820Sjeff#include <linux/dma-mapping.h>
50219820Sjeff#include <linux/compiler.h>
51219820Sjeff#include <linux/errno.h>
52219820Sjeff#include <asm/atomic.h>
53219820Sjeff#include <linux/device.h>
54219820Sjeff
55219820Sjeffstruct pci_device_id {
56219820Sjeff	uint32_t	vendor;
57219820Sjeff	uint32_t	device;
58219820Sjeff        uint32_t	subvendor;
59219820Sjeff	uint32_t	subdevice;
60219820Sjeff	uint32_t	class_mask;
61219820Sjeff	uintptr_t	driver_data;
62219820Sjeff};
63219820Sjeff
64219820Sjeff#define	MODULE_DEVICE_TABLE(bus, table)
65219820Sjeff#define	PCI_ANY_ID		(-1)
66219820Sjeff#define	PCI_VENDOR_ID_MELLANOX			0x15b3
67219820Sjeff#define	PCI_VENDOR_ID_TOPSPIN			0x1867
68219820Sjeff#define	PCI_DEVICE_ID_MELLANOX_TAVOR		0x5a44
69219820Sjeff#define	PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE	0x5a46
70219820Sjeff#define	PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT	0x6278
71219820Sjeff#define	PCI_DEVICE_ID_MELLANOX_ARBEL		0x6282
72219820Sjeff#define	PCI_DEVICE_ID_MELLANOX_SINAI_OLD	0x5e8c
73219820Sjeff#define	PCI_DEVICE_ID_MELLANOX_SINAI		0x6274
74219820Sjeff
75255932Salfred#define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
76255932Salfred#define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
77255932Salfred#define PCI_FUNC(devfn)         ((devfn) & 0x07)
78219820Sjeff
79242933Sdim#define PCI_VDEVICE(_vendor, _device)					\
80242933Sdim	    .vendor = PCI_VENDOR_ID_##_vendor, .device = (_device),	\
81242933Sdim	    .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
82242933Sdim#define	PCI_DEVICE(_vendor, _device)					\
83242933Sdim	    .vendor = (_vendor), .device = (_device),			\
84242933Sdim	    .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
85219820Sjeff
86219820Sjeff#define	to_pci_dev(n)	container_of(n, struct pci_dev, dev)
87219820Sjeff
88219820Sjeff#define	PCI_VENDOR_ID	PCIR_DEVVENDOR
89219820Sjeff#define	PCI_COMMAND	PCIR_COMMAND
90240680Sgavin#define	PCI_EXP_DEVCTL	PCIER_DEVICE_CTL
91240680Sgavin#define	PCI_EXP_LNKCTL	PCIER_LINK_CTL
92219820Sjeff
93219820Sjeff#define	IORESOURCE_MEM	SYS_RES_MEMORY
94219820Sjeff#define	IORESOURCE_IO	SYS_RES_IOPORT
95219820Sjeff#define	IORESOURCE_IRQ	SYS_RES_IRQ
96219820Sjeff
97219820Sjeffstruct pci_dev;
98219820Sjeff
99255932Salfred
100219820Sjeffstruct pci_driver {
101219820Sjeff	struct list_head		links;
102219820Sjeff	char				*name;
103219820Sjeff	struct pci_device_id		*id_table;
104219820Sjeff	int  (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
105219820Sjeff	void (*remove)(struct pci_dev *dev);
106255932Salfred        int  (*suspend) (struct pci_dev *dev, pm_message_t state);      /* Device suspended */
107255932Salfred        int  (*resume) (struct pci_dev *dev);                   /* Device woken up */
108219820Sjeff	driver_t			driver;
109219820Sjeff	devclass_t			bsdclass;
110255932Salfred        struct pci_error_handlers       *err_handler;
111219820Sjeff};
112219820Sjeff
113219820Sjeffextern struct list_head pci_drivers;
114219820Sjeffextern struct list_head pci_devices;
115219820Sjeffextern spinlock_t pci_lock;
116219820Sjeff
117219820Sjeff#define	__devexit_p(x)	x
118219820Sjeff
119219820Sjeffstruct pci_dev {
120219820Sjeff	struct device		dev;
121219820Sjeff	struct list_head	links;
122219820Sjeff	struct pci_driver	*pdrv;
123219820Sjeff	uint64_t		dma_mask;
124219820Sjeff	uint16_t		device;
125219820Sjeff	uint16_t		vendor;
126219820Sjeff	unsigned int		irq;
127255932Salfred        unsigned int            devfn;
128255932Salfred        u8                      revision;
129255932Salfred        struct pci_devinfo      *bus; /* bus this device is on, equivalent to linux struct pci_bus */
130219820Sjeff};
131219820Sjeff
132219820Sjeffstatic inline struct resource_list_entry *
133219820Sjeff_pci_get_rle(struct pci_dev *pdev, int type, int rid)
134219820Sjeff{
135219820Sjeff	struct pci_devinfo *dinfo;
136219820Sjeff	struct resource_list *rl;
137219820Sjeff
138219820Sjeff	dinfo = device_get_ivars(pdev->dev.bsddev);
139219820Sjeff	rl = &dinfo->resources;
140219820Sjeff	return resource_list_find(rl, type, rid);
141219820Sjeff}
142219820Sjeff
143219820Sjeffstatic inline struct resource_list_entry *
144219820Sjeff_pci_get_bar(struct pci_dev *pdev, int bar)
145219820Sjeff{
146219820Sjeff	struct resource_list_entry *rle;
147219820Sjeff
148219820Sjeff	bar = PCIR_BAR(bar);
149219820Sjeff	if ((rle = _pci_get_rle(pdev, SYS_RES_MEMORY, bar)) == NULL)
150219820Sjeff		rle = _pci_get_rle(pdev, SYS_RES_IOPORT, bar);
151219820Sjeff	return (rle);
152219820Sjeff}
153219820Sjeff
154219820Sjeffstatic inline struct device *
155219820Sjeff_pci_find_irq_dev(unsigned int irq)
156219820Sjeff{
157219820Sjeff	struct pci_dev *pdev;
158219820Sjeff
159219820Sjeff	spin_lock(&pci_lock);
160219820Sjeff	list_for_each_entry(pdev, &pci_devices, links) {
161219820Sjeff		if (irq == pdev->dev.irq)
162219820Sjeff			break;
163219820Sjeff		if (irq >= pdev->dev.msix && irq < pdev->dev.msix_max)
164219820Sjeff			break;
165219820Sjeff	}
166219820Sjeff	spin_unlock(&pci_lock);
167219820Sjeff	if (pdev)
168219820Sjeff		return &pdev->dev;
169219820Sjeff	return (NULL);
170219820Sjeff}
171219820Sjeff
172219820Sjeffstatic inline unsigned long
173219820Sjeffpci_resource_start(struct pci_dev *pdev, int bar)
174219820Sjeff{
175219820Sjeff	struct resource_list_entry *rle;
176219820Sjeff
177219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
178219820Sjeff		return (0);
179219820Sjeff	return rle->start;
180219820Sjeff}
181219820Sjeff
182219820Sjeffstatic inline unsigned long
183219820Sjeffpci_resource_len(struct pci_dev *pdev, int bar)
184219820Sjeff{
185219820Sjeff	struct resource_list_entry *rle;
186219820Sjeff
187219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
188219820Sjeff		return (0);
189219820Sjeff	return rle->count;
190219820Sjeff}
191219820Sjeff
192219820Sjeff/*
193219820Sjeff * All drivers just seem to want to inspect the type not flags.
194219820Sjeff */
195219820Sjeffstatic inline int
196219820Sjeffpci_resource_flags(struct pci_dev *pdev, int bar)
197219820Sjeff{
198219820Sjeff	struct resource_list_entry *rle;
199219820Sjeff
200219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
201219820Sjeff		return (0);
202219820Sjeff	return rle->type;
203219820Sjeff}
204219820Sjeff
205219820Sjeffstatic inline const char *
206219820Sjeffpci_name(struct pci_dev *d)
207219820Sjeff{
208219820Sjeff
209219820Sjeff	return device_get_desc(d->dev.bsddev);
210219820Sjeff}
211219820Sjeff
212219820Sjeffstatic inline void *
213219820Sjeffpci_get_drvdata(struct pci_dev *pdev)
214219820Sjeff{
215219820Sjeff
216219820Sjeff	return dev_get_drvdata(&pdev->dev);
217219820Sjeff}
218219820Sjeff
219219820Sjeffstatic inline void
220219820Sjeffpci_set_drvdata(struct pci_dev *pdev, void *data)
221219820Sjeff{
222219820Sjeff
223219820Sjeff	dev_set_drvdata(&pdev->dev, data);
224219820Sjeff}
225219820Sjeff
226219820Sjeffstatic inline int
227219820Sjeffpci_enable_device(struct pci_dev *pdev)
228219820Sjeff{
229219820Sjeff
230219820Sjeff	pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT);
231219820Sjeff	pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY);
232219820Sjeff	return (0);
233219820Sjeff}
234219820Sjeff
235219820Sjeffstatic inline void
236219820Sjeffpci_disable_device(struct pci_dev *pdev)
237219820Sjeff{
238219820Sjeff}
239219820Sjeff
240219820Sjeffstatic inline int
241219820Sjeffpci_set_master(struct pci_dev *pdev)
242219820Sjeff{
243219820Sjeff
244219820Sjeff	pci_enable_busmaster(pdev->dev.bsddev);
245219820Sjeff	return (0);
246219820Sjeff}
247219820Sjeff
248219820Sjeffstatic inline int
249219820Sjeffpci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
250219820Sjeff{
251219820Sjeff	int rid;
252219820Sjeff	int type;
253219820Sjeff
254219820Sjeff	type = pci_resource_flags(pdev, bar);
255219820Sjeff	if (type == 0)
256219820Sjeff		return (-ENODEV);
257219820Sjeff	rid = PCIR_BAR(bar);
258219820Sjeff	if (bus_alloc_resource_any(pdev->dev.bsddev, type, &rid,
259219820Sjeff	    RF_ACTIVE) == NULL)
260219820Sjeff		return (-EINVAL);
261219820Sjeff	return (0);
262219820Sjeff}
263219820Sjeff
264219820Sjeffstatic inline void
265219820Sjeffpci_release_region(struct pci_dev *pdev, int bar)
266219820Sjeff{
267219820Sjeff	struct resource_list_entry *rle;
268219820Sjeff
269219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
270219820Sjeff		return;
271219820Sjeff	bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res);
272219820Sjeff}
273219820Sjeff
274219820Sjeffstatic inline void
275219820Sjeffpci_release_regions(struct pci_dev *pdev)
276219820Sjeff{
277219820Sjeff	int i;
278219820Sjeff
279219820Sjeff	for (i = 0; i <= PCIR_MAX_BAR_0; i++)
280219820Sjeff		pci_release_region(pdev, i);
281219820Sjeff}
282219820Sjeff
283219820Sjeffstatic inline int
284219820Sjeffpci_request_regions(struct pci_dev *pdev, const char *res_name)
285219820Sjeff{
286219820Sjeff	int error;
287219820Sjeff	int i;
288219820Sjeff
289219820Sjeff	for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
290219820Sjeff		error = pci_request_region(pdev, i, res_name);
291219820Sjeff		if (error && error != -ENODEV) {
292219820Sjeff			pci_release_regions(pdev);
293219820Sjeff			return (error);
294219820Sjeff		}
295219820Sjeff	}
296219820Sjeff	return (0);
297219820Sjeff}
298219820Sjeff
299219820Sjeffstatic inline void
300219820Sjeffpci_disable_msix(struct pci_dev *pdev)
301219820Sjeff{
302219820Sjeff
303219820Sjeff	pci_release_msi(pdev->dev.bsddev);
304219820Sjeff}
305219820Sjeff
306219820Sjeff#define	PCI_CAP_ID_EXP	PCIY_EXPRESS
307219820Sjeff#define	PCI_CAP_ID_PCIX	PCIY_PCIX
308219820Sjeff
309255932Salfred
310219820Sjeffstatic inline int
311219820Sjeffpci_find_capability(struct pci_dev *pdev, int capid)
312219820Sjeff{
313219820Sjeff	int reg;
314219820Sjeff
315219902Sjhb	if (pci_find_cap(pdev->dev.bsddev, capid, &reg))
316219820Sjeff		return (0);
317219820Sjeff	return (reg);
318219820Sjeff}
319219820Sjeff
320255932Salfred
321255932Salfred
322255932Salfred
323255932Salfred/**
324255932Salfred * pci_pcie_cap - get the saved PCIe capability offset
325255932Salfred * @dev: PCI device
326255932Salfred *
327255932Salfred * PCIe capability offset is calculated at PCI device initialization
328255932Salfred * time and saved in the data structure. This function returns saved
329255932Salfred * PCIe capability offset. Using this instead of pci_find_capability()
330255932Salfred * reduces unnecessary search in the PCI configuration space. If you
331255932Salfred * need to calculate PCIe capability offset from raw device for some
332255932Salfred * reasons, please use pci_find_capability() instead.
333255932Salfred */
334255932Salfredstatic inline int pci_pcie_cap(struct pci_dev *dev)
335255932Salfred{
336255932Salfred        return pci_find_capability(dev, PCI_CAP_ID_EXP);
337255932Salfred}
338255932Salfred
339255932Salfred
340219820Sjeffstatic inline int
341219820Sjeffpci_read_config_byte(struct pci_dev *pdev, int where, u8 *val)
342219820Sjeff{
343219820Sjeff
344219820Sjeff	*val = (u8)pci_read_config(pdev->dev.bsddev, where, 1);
345219820Sjeff	return (0);
346219820Sjeff}
347219820Sjeff
348219820Sjeffstatic inline int
349219820Sjeffpci_read_config_word(struct pci_dev *pdev, int where, u16 *val)
350219820Sjeff{
351219820Sjeff
352219820Sjeff	*val = (u16)pci_read_config(pdev->dev.bsddev, where, 2);
353219820Sjeff	return (0);
354219820Sjeff}
355219820Sjeff
356219820Sjeffstatic inline int
357219820Sjeffpci_read_config_dword(struct pci_dev *pdev, int where, u32 *val)
358219820Sjeff{
359219820Sjeff
360219820Sjeff	*val = (u32)pci_read_config(pdev->dev.bsddev, where, 4);
361219820Sjeff	return (0);
362219820Sjeff}
363219820Sjeff
364219820Sjeffstatic inline int
365219820Sjeffpci_write_config_byte(struct pci_dev *pdev, int where, u8 val)
366219820Sjeff{
367219820Sjeff
368219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 1);
369219820Sjeff	return (0);
370219820Sjeff}
371219820Sjeff
372219820Sjeffstatic inline int
373219820Sjeffpci_write_config_word(struct pci_dev *pdev, int where, u16 val)
374219820Sjeff{
375219820Sjeff
376219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 2);
377219820Sjeff	return (0);
378219820Sjeff}
379219820Sjeff
380219820Sjeffstatic inline int
381219820Sjeffpci_write_config_dword(struct pci_dev *pdev, int where, u32 val)
382219820Sjeff{
383219820Sjeff
384219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 4);
385219820Sjeff	return (0);
386219820Sjeff}
387219820Sjeff
388219820Sjeffstatic struct pci_driver *
389219820Sjefflinux_pci_find(device_t dev, struct pci_device_id **idp)
390219820Sjeff{
391219820Sjeff	struct pci_device_id *id;
392219820Sjeff	struct pci_driver *pdrv;
393219820Sjeff	uint16_t vendor;
394219820Sjeff	uint16_t device;
395219820Sjeff
396219820Sjeff	vendor = pci_get_vendor(dev);
397219820Sjeff	device = pci_get_device(dev);
398219820Sjeff
399219820Sjeff	spin_lock(&pci_lock);
400219820Sjeff	list_for_each_entry(pdrv, &pci_drivers, links) {
401219820Sjeff		for (id = pdrv->id_table; id->vendor != 0; id++) {
402219820Sjeff			if (vendor == id->vendor && device == id->device) {
403219820Sjeff				*idp = id;
404219820Sjeff				spin_unlock(&pci_lock);
405219820Sjeff				return (pdrv);
406219820Sjeff			}
407219820Sjeff		}
408219820Sjeff	}
409219820Sjeff	spin_unlock(&pci_lock);
410219820Sjeff	return (NULL);
411219820Sjeff}
412219820Sjeff
413219820Sjeffstatic inline int
414219820Sjefflinux_pci_probe(device_t dev)
415219820Sjeff{
416219820Sjeff	struct pci_device_id *id;
417219820Sjeff	struct pci_driver *pdrv;
418219820Sjeff
419219820Sjeff	if ((pdrv = linux_pci_find(dev, &id)) == NULL)
420219820Sjeff		return (ENXIO);
421219820Sjeff	if (device_get_driver(dev) != &pdrv->driver)
422219820Sjeff		return (ENXIO);
423219820Sjeff	device_set_desc(dev, pdrv->name);
424219820Sjeff	return (0);
425219820Sjeff}
426219820Sjeff
427219820Sjeffstatic inline int
428219820Sjefflinux_pci_attach(device_t dev)
429219820Sjeff{
430219820Sjeff	struct resource_list_entry *rle;
431219820Sjeff	struct pci_dev *pdev;
432219820Sjeff	struct pci_driver *pdrv;
433219820Sjeff	struct pci_device_id *id;
434219820Sjeff	int error;
435219820Sjeff
436219820Sjeff	pdrv = linux_pci_find(dev, &id);
437219820Sjeff	pdev = device_get_softc(dev);
438219820Sjeff	pdev->dev.parent = &linux_rootdev;
439219820Sjeff	pdev->dev.bsddev = dev;
440219820Sjeff	INIT_LIST_HEAD(&pdev->dev.irqents);
441219820Sjeff	pdev->device = id->device;
442219820Sjeff	pdev->vendor = id->vendor;
443219820Sjeff	pdev->dev.dma_mask = &pdev->dma_mask;
444219820Sjeff	pdev->pdrv = pdrv;
445219820Sjeff	kobject_init(&pdev->dev.kobj, &dev_ktype);
446219820Sjeff	kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
447219820Sjeff	kobject_add(&pdev->dev.kobj, &linux_rootdev.kobj,
448219820Sjeff	    kobject_name(&pdev->dev.kobj));
449219820Sjeff	rle = _pci_get_rle(pdev, SYS_RES_IRQ, 0);
450219820Sjeff	if (rle)
451219820Sjeff		pdev->dev.irq = rle->start;
452219820Sjeff	else
453219820Sjeff		pdev->dev.irq = 0;
454219820Sjeff	pdev->irq = pdev->dev.irq;
455219820Sjeff	mtx_unlock(&Giant);
456219820Sjeff	spin_lock(&pci_lock);
457219820Sjeff	list_add(&pdev->links, &pci_devices);
458219820Sjeff	spin_unlock(&pci_lock);
459219820Sjeff	error = pdrv->probe(pdev, id);
460219820Sjeff	mtx_lock(&Giant);
461219820Sjeff	if (error) {
462219820Sjeff		spin_lock(&pci_lock);
463219820Sjeff		list_del(&pdev->links);
464219820Sjeff		spin_unlock(&pci_lock);
465219820Sjeff		put_device(&pdev->dev);
466219820Sjeff		return (-error);
467219820Sjeff	}
468219820Sjeff	return (0);
469219820Sjeff}
470219820Sjeff
471219820Sjeffstatic inline int
472219820Sjefflinux_pci_detach(device_t dev)
473219820Sjeff{
474219820Sjeff	struct pci_dev *pdev;
475219820Sjeff
476219820Sjeff	pdev = device_get_softc(dev);
477219820Sjeff	mtx_unlock(&Giant);
478219820Sjeff	pdev->pdrv->remove(pdev);
479219820Sjeff	mtx_lock(&Giant);
480219820Sjeff	spin_lock(&pci_lock);
481219820Sjeff	list_del(&pdev->links);
482219820Sjeff	spin_unlock(&pci_lock);
483219820Sjeff	put_device(&pdev->dev);
484219820Sjeff
485219820Sjeff	return (0);
486219820Sjeff}
487219820Sjeff
488219820Sjeffstatic device_method_t pci_methods[] = {
489219820Sjeff	DEVMETHOD(device_probe, linux_pci_probe),
490219820Sjeff	DEVMETHOD(device_attach, linux_pci_attach),
491219820Sjeff	DEVMETHOD(device_detach, linux_pci_detach),
492219820Sjeff	{0, 0}
493219820Sjeff};
494219820Sjeff
495219820Sjeffstatic inline int
496219820Sjeffpci_register_driver(struct pci_driver *pdrv)
497219820Sjeff{
498219820Sjeff	devclass_t bus;
499219820Sjeff	int error;
500219820Sjeff
501219820Sjeff	spin_lock(&pci_lock);
502219820Sjeff	list_add(&pdrv->links, &pci_drivers);
503219820Sjeff	spin_unlock(&pci_lock);
504219820Sjeff	bus = devclass_find("pci");
505219820Sjeff	pdrv->driver.name = pdrv->name;
506219820Sjeff	pdrv->driver.methods = pci_methods;
507219820Sjeff	pdrv->driver.size = sizeof(struct pci_dev);
508219820Sjeff	mtx_lock(&Giant);
509219820Sjeff	error = devclass_add_driver(bus, &pdrv->driver, BUS_PASS_DEFAULT,
510219820Sjeff	    &pdrv->bsdclass);
511219820Sjeff	mtx_unlock(&Giant);
512219820Sjeff	if (error)
513219820Sjeff		return (-error);
514219820Sjeff	return (0);
515219820Sjeff}
516219820Sjeff
517219820Sjeffstatic inline void
518219820Sjeffpci_unregister_driver(struct pci_driver *pdrv)
519219820Sjeff{
520219820Sjeff	devclass_t bus;
521219820Sjeff
522219820Sjeff	list_del(&pdrv->links);
523219820Sjeff	bus = devclass_find("pci");
524219820Sjeff	mtx_lock(&Giant);
525219820Sjeff	devclass_delete_driver(bus, &pdrv->driver);
526219820Sjeff	mtx_unlock(&Giant);
527219820Sjeff}
528219820Sjeff
529219820Sjeffstruct msix_entry {
530219820Sjeff	int entry;
531219820Sjeff	int vector;
532219820Sjeff};
533219820Sjeff
534219820Sjeff/*
535219820Sjeff * Enable msix, positive errors indicate actual number of available
536219820Sjeff * vectors.  Negative errors are failures.
537219820Sjeff */
538219820Sjeffstatic inline int
539219820Sjeffpci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
540219820Sjeff{
541219820Sjeff	struct resource_list_entry *rle;
542219820Sjeff	int error;
543219820Sjeff	int avail;
544219820Sjeff	int i;
545219820Sjeff
546219820Sjeff	avail = pci_msix_count(pdev->dev.bsddev);
547219820Sjeff	if (avail < nreq) {
548219820Sjeff		if (avail == 0)
549219820Sjeff			return -EINVAL;
550219820Sjeff		return avail;
551219820Sjeff	}
552219820Sjeff	avail = nreq;
553219820Sjeff	if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
554219820Sjeff		return error;
555219820Sjeff	rle = _pci_get_rle(pdev, SYS_RES_IRQ, 1);
556219820Sjeff	pdev->dev.msix = rle->start;
557219820Sjeff	pdev->dev.msix_max = rle->start + avail;
558219820Sjeff	for (i = 0; i < nreq; i++)
559219820Sjeff		entries[i].vector = pdev->dev.msix + i;
560219820Sjeff	return (0);
561219820Sjeff}
562219820Sjeff
563255932Salfredstatic inline int pci_channel_offline(struct pci_dev *pdev)
564255932Salfred{
565255932Salfred        return false;
566255932Salfred}
567255932Salfred
568255932Salfredstatic inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
569255932Salfred{
570255932Salfred        return -ENODEV;
571255932Salfred}
572255932Salfredstatic inline void pci_disable_sriov(struct pci_dev *dev)
573255932Salfred{
574255932Salfred}
575255932Salfred
576255932Salfred/**
577255932Salfred * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table
578255932Salfred * @_table: device table name
579255932Salfred *
580255932Salfred * This macro is used to create a struct pci_device_id array (a device table)
581255932Salfred * in a generic manner.
582255932Salfred */
583255932Salfred#define DEFINE_PCI_DEVICE_TABLE(_table) \
584255932Salfred	const struct pci_device_id _table[] __devinitdata
585255932Salfred
586255932Salfred
587219820Sjeff/* XXX This should not be necessary. */
588219820Sjeff#define	pcix_set_mmrbc(d, v)	0
589219820Sjeff#define	pcix_get_max_mmrbc(d)	0
590219820Sjeff#define	pcie_set_readrq(d, v)	0
591219820Sjeff
592219820Sjeff#define	PCI_DMA_BIDIRECTIONAL	0
593219820Sjeff#define	PCI_DMA_TODEVICE	1
594219820Sjeff#define	PCI_DMA_FROMDEVICE	2
595219820Sjeff#define	PCI_DMA_NONE		3
596219820Sjeff
597219820Sjeff#define	pci_pool		dma_pool
598219820Sjeff#define pci_pool_destroy	dma_pool_destroy
599219820Sjeff#define pci_pool_alloc		dma_pool_alloc
600219820Sjeff#define pci_pool_free		dma_pool_free
601219820Sjeff#define	pci_pool_create(_name, _pdev, _size, _align, _alloc)		\
602219820Sjeff	    dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc)
603219820Sjeff#define	pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle)		\
604219820Sjeff	    dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
605219820Sjeff		_size, _vaddr, _dma_handle)
606219820Sjeff#define	pci_map_sg(_hwdev, _sg, _nents, _dir)				\
607219820Sjeff	    dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev),	\
608219820Sjeff		_sg, _nents, (enum dma_data_direction)_dir)
609219820Sjeff#define	pci_map_single(_hwdev, _ptr, _size, _dir)			\
610219820Sjeff	    dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev),	\
611219820Sjeff		(_ptr), (_size), (enum dma_data_direction)_dir)
612219820Sjeff#define	pci_unmap_single(_hwdev, _addr, _size, _dir)			\
613219820Sjeff	    dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
614219820Sjeff		_addr, _size, (enum dma_data_direction)_dir)
615219820Sjeff#define	pci_unmap_sg(_hwdev, _sg, _nents, _dir)				\
616219820Sjeff	    dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
617219820Sjeff		_sg, _nents, (enum dma_data_direction)_dir)
618219820Sjeff#define	pci_map_page(_hwdev, _page, _offset, _size, _dir)		\
619219820Sjeff	    dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\
620219820Sjeff		_offset, _size, (enum dma_data_direction)_dir)
621219820Sjeff#define	pci_unmap_page(_hwdev, _dma_address, _size, _dir)		\
622219820Sjeff	    dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
623219820Sjeff		_dma_address, _size, (enum dma_data_direction)_dir)
624219820Sjeff#define	pci_set_dma_mask(_pdev, mask)	dma_set_mask(&(_pdev)->dev, (mask))
625219820Sjeff#define	pci_dma_mapping_error(_pdev, _dma_addr)				\
626219820Sjeff	    dma_mapping_error(&(_pdev)->dev, _dma_addr)
627219820Sjeff#define	pci_set_consistent_dma_mask(_pdev, _mask)			\
628219820Sjeff	    dma_set_coherent_mask(&(_pdev)->dev, (_mask))
629219820Sjeff#define	DECLARE_PCI_UNMAP_ADDR(x)	DEFINE_DMA_UNMAP_ADDR(x);
630219820Sjeff#define	DECLARE_PCI_UNMAP_LEN(x)	DEFINE_DMA_UNMAP_LEN(x);
631219820Sjeff#define	pci_unmap_addr		dma_unmap_addr
632219820Sjeff#define	pci_unmap_addr_set	dma_unmap_addr_set
633219820Sjeff#define	pci_unmap_len		dma_unmap_len
634219820Sjeff#define	pci_unmap_len_set	dma_unmap_len_set
635219820Sjeff
636255932Salfredtypedef unsigned int __bitwise pci_channel_state_t;
637255932Salfredtypedef unsigned int __bitwise pci_ers_result_t;
638219820Sjeff
639255932Salfredenum pci_channel_state {
640255932Salfred        /* I/O channel is in normal state */
641255932Salfred        pci_channel_io_normal = (__force pci_channel_state_t) 1,
642255932Salfred
643255932Salfred        /* I/O to channel is blocked */
644255932Salfred        pci_channel_io_frozen = (__force pci_channel_state_t) 2,
645255932Salfred
646255932Salfred        /* PCI card is dead */
647255932Salfred        pci_channel_io_perm_failure = (__force pci_channel_state_t) 3,
648255932Salfred};
649255932Salfred
650255932Salfredenum pci_ers_result {
651255932Salfred        /* no result/none/not supported in device driver */
652255932Salfred        PCI_ERS_RESULT_NONE = (__force pci_ers_result_t) 1,
653255932Salfred
654255932Salfred        /* Device driver can recover without slot reset */
655255932Salfred        PCI_ERS_RESULT_CAN_RECOVER = (__force pci_ers_result_t) 2,
656255932Salfred
657255932Salfred        /* Device driver wants slot to be reset. */
658255932Salfred        PCI_ERS_RESULT_NEED_RESET = (__force pci_ers_result_t) 3,
659255932Salfred
660255932Salfred        /* Device has completely failed, is unrecoverable */
661255932Salfred        PCI_ERS_RESULT_DISCONNECT = (__force pci_ers_result_t) 4,
662255932Salfred
663255932Salfred        /* Device driver is fully recovered and operational */
664255932Salfred        PCI_ERS_RESULT_RECOVERED = (__force pci_ers_result_t) 5,
665255932Salfred};
666255932Salfred
667255932Salfred
668255932Salfred/* PCI bus error event callbacks */
669255932Salfredstruct pci_error_handlers {
670255932Salfred        /* PCI bus error detected on this device */
671255932Salfred        pci_ers_result_t (*error_detected)(struct pci_dev *dev,
672255932Salfred                        enum pci_channel_state error);
673255932Salfred
674255932Salfred        /* MMIO has been re-enabled, but not DMA */
675255932Salfred        pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
676255932Salfred
677255932Salfred        /* PCI Express link has been reset */
678255932Salfred        pci_ers_result_t (*link_reset)(struct pci_dev *dev);
679255932Salfred
680255932Salfred        /* PCI slot has been reset */
681255932Salfred        pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
682255932Salfred
683255932Salfred        /* Device driver may resume normal operations */
684255932Salfred        void (*resume)(struct pci_dev *dev);
685255932Salfred};
686255932Salfred
687255932Salfred
688255932Salfred
689219820Sjeff#endif	/* _LINUX_PCI_H_ */
690