1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc.
3219820Sjeff * Copyright (c) 2010 iX Systems, Inc.
4219820Sjeff * Copyright (c) 2010 Panasas, Inc.
5271127Shselasky * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
6219820Sjeff * All rights reserved.
7219820Sjeff *
8219820Sjeff * Redistribution and use in source and binary forms, with or without
9219820Sjeff * modification, are permitted provided that the following conditions
10219820Sjeff * are met:
11219820Sjeff * 1. Redistributions of source code must retain the above copyright
12219820Sjeff *    notice unmodified, this list of conditions, and the following
13219820Sjeff *    disclaimer.
14219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
15219820Sjeff *    notice, this list of conditions and the following disclaimer in the
16219820Sjeff *    documentation and/or other materials provided with the distribution.
17219820Sjeff *
18219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28219820Sjeff */
29219820Sjeff
30219820Sjeff#ifndef	_LINUX_PCI_H_
31219820Sjeff#define	_LINUX_PCI_H_
32219820Sjeff
33219820Sjeff#define	CONFIG_PCI_MSI
34219820Sjeff
35219820Sjeff#include <linux/types.h>
36219820Sjeff
37219820Sjeff#include <sys/param.h>
38219820Sjeff#include <sys/bus.h>
39219820Sjeff#include <sys/pciio.h>
40219820Sjeff#include <sys/rman.h>
41219820Sjeff#include <dev/pci/pcivar.h>
42219820Sjeff#include <dev/pci/pcireg.h>
43219820Sjeff#include <dev/pci/pci_private.h>
44219820Sjeff
45219820Sjeff#include <machine/resource.h>
46219820Sjeff
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
88271127Shselasky#define	PCI_VENDOR_ID		PCIR_DEVVENDOR
89271127Shselasky#define	PCI_COMMAND		PCIR_COMMAND
90271127Shselasky#define	PCI_EXP_DEVCTL		PCIER_DEVICE_CTL		/* Device Control */
91271127Shselasky#define	PCI_EXP_LNKCTL		PCIER_LINK_CTL			/* Link Control */
92271127Shselasky#define	PCI_EXP_FLAGS_TYPE	PCIEM_FLAGS_TYPE		/* Device/Port type */
93271127Shselasky#define	PCI_EXP_DEVCAP		PCIER_DEVICE_CAP		/* Device capabilities */
94271127Shselasky#define	PCI_EXP_DEVSTA		PCIER_DEVICE_STA		/* Device Status */
95271127Shselasky#define	PCI_EXP_LNKCAP		PCIER_LINK_CAP			/* Link Capabilities */
96271127Shselasky#define	PCI_EXP_LNKSTA		PCIER_LINK_STA			/* Link Status */
97271127Shselasky#define	PCI_EXP_SLTCAP		PCIER_SLOT_CAP			/* Slot Capabilities */
98271127Shselasky#define	PCI_EXP_SLTCTL		PCIER_SLOT_CTL			/* Slot Control */
99271127Shselasky#define	PCI_EXP_SLTSTA		PCIER_SLOT_STA			/* Slot Status */
100271127Shselasky#define	PCI_EXP_RTCTL		PCIER_ROOT_CTL			/* Root Control */
101271127Shselasky#define	PCI_EXP_RTCAP		PCIER_ROOT_CAP			/* Root Capabilities */
102271127Shselasky#define	PCI_EXP_RTSTA		PCIER_ROOT_STA			/* Root Status */
103271127Shselasky#define	PCI_EXP_DEVCAP2		PCIER_DEVICE_CAP2		/* Device Capabilities 2 */
104271127Shselasky#define	PCI_EXP_DEVCTL2		PCIER_DEVICE_CTL2		/* Device Control 2 */
105271127Shselasky#define	PCI_EXP_LNKCAP2		PCIER_LINK_CAP2			/* Link Capabilities 2 */
106271127Shselasky#define	PCI_EXP_LNKCTL2		PCIER_LINK_CTL2			/* Link Control 2 */
107271127Shselasky#define	PCI_EXP_LNKSTA2		PCIER_LINK_STA2			/* Link Status 2 */
108271127Shselasky#define	PCI_EXP_FLAGS		PCIER_FLAGS			/* Capabilities register */
109271127Shselasky#define	PCI_EXP_FLAGS_VERS	PCIEM_FLAGS_VERSION		/* Capability version */
110271127Shselasky#define	PCI_EXP_TYPE_ROOT_PORT	PCIEM_TYPE_ROOT_PORT		/* Root Port */
111271127Shselasky#define	PCI_EXP_TYPE_ENDPOINT	PCIEM_TYPE_ENDPOINT		/* Express Endpoint */
112271127Shselasky#define	PCI_EXP_TYPE_LEG_END	PCIEM_TYPE_LEGACY_ENDPOINT	/* Legacy Endpoint */
113271127Shselasky#define	PCI_EXP_TYPE_DOWNSTREAM PCIEM_TYPE_DOWNSTREAM_PORT	/* Downstream Port */
114271127Shselasky#define	PCI_EXP_FLAGS_SLOT	PCIEM_FLAGS_SLOT		/* Slot implemented */
115271127Shselasky#define	PCI_EXP_TYPE_RC_EC	PCIEM_TYPE_ROOT_EC		/* Root Complex Event Collector */
116219820Sjeff
117271127Shselasky
118219820Sjeff#define	IORESOURCE_MEM	SYS_RES_MEMORY
119219820Sjeff#define	IORESOURCE_IO	SYS_RES_IOPORT
120219820Sjeff#define	IORESOURCE_IRQ	SYS_RES_IRQ
121219820Sjeff
122219820Sjeffstruct pci_dev;
123219820Sjeff
124255932Salfred
125219820Sjeffstruct pci_driver {
126219820Sjeff	struct list_head		links;
127219820Sjeff	char				*name;
128271127Shselasky	const struct pci_device_id		*id_table;
129219820Sjeff	int  (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
130219820Sjeff	void (*remove)(struct pci_dev *dev);
131255932Salfred        int  (*suspend) (struct pci_dev *dev, pm_message_t state);      /* Device suspended */
132255932Salfred        int  (*resume) (struct pci_dev *dev);                   /* Device woken up */
133219820Sjeff	driver_t			driver;
134219820Sjeff	devclass_t			bsdclass;
135271127Shselasky        const struct pci_error_handlers       *err_handler;
136219820Sjeff};
137219820Sjeff
138219820Sjeffextern struct list_head pci_drivers;
139219820Sjeffextern struct list_head pci_devices;
140219820Sjeffextern spinlock_t pci_lock;
141219820Sjeff
142219820Sjeff#define	__devexit_p(x)	x
143219820Sjeff
144219820Sjeffstruct pci_dev {
145219820Sjeff	struct device		dev;
146219820Sjeff	struct list_head	links;
147219820Sjeff	struct pci_driver	*pdrv;
148219820Sjeff	uint64_t		dma_mask;
149219820Sjeff	uint16_t		device;
150219820Sjeff	uint16_t		vendor;
151219820Sjeff	unsigned int		irq;
152277139Shselasky	unsigned int		devfn;
153277139Shselasky	u8			revision;
154219820Sjeff};
155219820Sjeff
156219820Sjeffstatic inline struct resource_list_entry *
157219820Sjeff_pci_get_rle(struct pci_dev *pdev, int type, int rid)
158219820Sjeff{
159219820Sjeff	struct pci_devinfo *dinfo;
160219820Sjeff	struct resource_list *rl;
161219820Sjeff
162219820Sjeff	dinfo = device_get_ivars(pdev->dev.bsddev);
163219820Sjeff	rl = &dinfo->resources;
164219820Sjeff	return resource_list_find(rl, type, rid);
165219820Sjeff}
166219820Sjeff
167219820Sjeffstatic inline struct resource_list_entry *
168219820Sjeff_pci_get_bar(struct pci_dev *pdev, int bar)
169219820Sjeff{
170219820Sjeff	struct resource_list_entry *rle;
171219820Sjeff
172219820Sjeff	bar = PCIR_BAR(bar);
173219820Sjeff	if ((rle = _pci_get_rle(pdev, SYS_RES_MEMORY, bar)) == NULL)
174219820Sjeff		rle = _pci_get_rle(pdev, SYS_RES_IOPORT, bar);
175219820Sjeff	return (rle);
176219820Sjeff}
177219820Sjeff
178219820Sjeffstatic inline struct device *
179219820Sjeff_pci_find_irq_dev(unsigned int irq)
180219820Sjeff{
181219820Sjeff	struct pci_dev *pdev;
182219820Sjeff
183219820Sjeff	spin_lock(&pci_lock);
184219820Sjeff	list_for_each_entry(pdev, &pci_devices, links) {
185219820Sjeff		if (irq == pdev->dev.irq)
186219820Sjeff			break;
187219820Sjeff		if (irq >= pdev->dev.msix && irq < pdev->dev.msix_max)
188219820Sjeff			break;
189219820Sjeff	}
190219820Sjeff	spin_unlock(&pci_lock);
191219820Sjeff	if (pdev)
192219820Sjeff		return &pdev->dev;
193219820Sjeff	return (NULL);
194219820Sjeff}
195219820Sjeff
196219820Sjeffstatic inline unsigned long
197219820Sjeffpci_resource_start(struct pci_dev *pdev, int bar)
198219820Sjeff{
199219820Sjeff	struct resource_list_entry *rle;
200219820Sjeff
201219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
202219820Sjeff		return (0);
203219820Sjeff	return rle->start;
204219820Sjeff}
205219820Sjeff
206219820Sjeffstatic inline unsigned long
207219820Sjeffpci_resource_len(struct pci_dev *pdev, int bar)
208219820Sjeff{
209219820Sjeff	struct resource_list_entry *rle;
210219820Sjeff
211219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
212219820Sjeff		return (0);
213219820Sjeff	return rle->count;
214219820Sjeff}
215219820Sjeff
216219820Sjeff/*
217219820Sjeff * All drivers just seem to want to inspect the type not flags.
218219820Sjeff */
219219820Sjeffstatic inline int
220219820Sjeffpci_resource_flags(struct pci_dev *pdev, int bar)
221219820Sjeff{
222219820Sjeff	struct resource_list_entry *rle;
223219820Sjeff
224219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
225219820Sjeff		return (0);
226219820Sjeff	return rle->type;
227219820Sjeff}
228219820Sjeff
229219820Sjeffstatic inline const char *
230219820Sjeffpci_name(struct pci_dev *d)
231219820Sjeff{
232219820Sjeff
233219820Sjeff	return device_get_desc(d->dev.bsddev);
234219820Sjeff}
235219820Sjeff
236219820Sjeffstatic inline void *
237219820Sjeffpci_get_drvdata(struct pci_dev *pdev)
238219820Sjeff{
239219820Sjeff
240219820Sjeff	return dev_get_drvdata(&pdev->dev);
241219820Sjeff}
242219820Sjeff
243219820Sjeffstatic inline void
244219820Sjeffpci_set_drvdata(struct pci_dev *pdev, void *data)
245219820Sjeff{
246219820Sjeff
247219820Sjeff	dev_set_drvdata(&pdev->dev, data);
248219820Sjeff}
249219820Sjeff
250219820Sjeffstatic inline int
251219820Sjeffpci_enable_device(struct pci_dev *pdev)
252219820Sjeff{
253219820Sjeff
254219820Sjeff	pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT);
255219820Sjeff	pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY);
256219820Sjeff	return (0);
257219820Sjeff}
258219820Sjeff
259219820Sjeffstatic inline void
260219820Sjeffpci_disable_device(struct pci_dev *pdev)
261219820Sjeff{
262219820Sjeff}
263219820Sjeff
264219820Sjeffstatic inline int
265219820Sjeffpci_set_master(struct pci_dev *pdev)
266219820Sjeff{
267219820Sjeff
268219820Sjeff	pci_enable_busmaster(pdev->dev.bsddev);
269219820Sjeff	return (0);
270219820Sjeff}
271219820Sjeff
272219820Sjeffstatic inline int
273282513Shselaskypci_clear_master(struct pci_dev *pdev)
274282513Shselasky{
275282513Shselasky
276282513Shselasky	pci_disable_busmaster(pdev->dev.bsddev);
277282513Shselasky	return (0);
278282513Shselasky}
279282513Shselasky
280282513Shselaskystatic inline int
281219820Sjeffpci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
282219820Sjeff{
283219820Sjeff	int rid;
284219820Sjeff	int type;
285219820Sjeff
286219820Sjeff	type = pci_resource_flags(pdev, bar);
287219820Sjeff	if (type == 0)
288219820Sjeff		return (-ENODEV);
289219820Sjeff	rid = PCIR_BAR(bar);
290219820Sjeff	if (bus_alloc_resource_any(pdev->dev.bsddev, type, &rid,
291219820Sjeff	    RF_ACTIVE) == NULL)
292219820Sjeff		return (-EINVAL);
293219820Sjeff	return (0);
294219820Sjeff}
295219820Sjeff
296219820Sjeffstatic inline void
297219820Sjeffpci_release_region(struct pci_dev *pdev, int bar)
298219820Sjeff{
299219820Sjeff	struct resource_list_entry *rle;
300219820Sjeff
301219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
302219820Sjeff		return;
303219820Sjeff	bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res);
304219820Sjeff}
305219820Sjeff
306219820Sjeffstatic inline void
307219820Sjeffpci_release_regions(struct pci_dev *pdev)
308219820Sjeff{
309219820Sjeff	int i;
310219820Sjeff
311219820Sjeff	for (i = 0; i <= PCIR_MAX_BAR_0; i++)
312219820Sjeff		pci_release_region(pdev, i);
313219820Sjeff}
314219820Sjeff
315219820Sjeffstatic inline int
316219820Sjeffpci_request_regions(struct pci_dev *pdev, const char *res_name)
317219820Sjeff{
318219820Sjeff	int error;
319219820Sjeff	int i;
320219820Sjeff
321219820Sjeff	for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
322219820Sjeff		error = pci_request_region(pdev, i, res_name);
323219820Sjeff		if (error && error != -ENODEV) {
324219820Sjeff			pci_release_regions(pdev);
325219820Sjeff			return (error);
326219820Sjeff		}
327219820Sjeff	}
328219820Sjeff	return (0);
329219820Sjeff}
330219820Sjeff
331219820Sjeffstatic inline void
332219820Sjeffpci_disable_msix(struct pci_dev *pdev)
333219820Sjeff{
334219820Sjeff
335219820Sjeff	pci_release_msi(pdev->dev.bsddev);
336219820Sjeff}
337219820Sjeff
338219820Sjeff#define	PCI_CAP_ID_EXP	PCIY_EXPRESS
339219820Sjeff#define	PCI_CAP_ID_PCIX	PCIY_PCIX
340219820Sjeff
341255932Salfred
342219820Sjeffstatic inline int
343219820Sjeffpci_find_capability(struct pci_dev *pdev, int capid)
344219820Sjeff{
345219820Sjeff	int reg;
346219820Sjeff
347219902Sjhb	if (pci_find_cap(pdev->dev.bsddev, capid, &reg))
348219820Sjeff		return (0);
349219820Sjeff	return (reg);
350219820Sjeff}
351219820Sjeff
352255932Salfred
353255932Salfred
354255932Salfred
355255932Salfred/**
356255932Salfred * pci_pcie_cap - get the saved PCIe capability offset
357255932Salfred * @dev: PCI device
358255932Salfred *
359255932Salfred * PCIe capability offset is calculated at PCI device initialization
360255932Salfred * time and saved in the data structure. This function returns saved
361255932Salfred * PCIe capability offset. Using this instead of pci_find_capability()
362255932Salfred * reduces unnecessary search in the PCI configuration space. If you
363255932Salfred * need to calculate PCIe capability offset from raw device for some
364255932Salfred * reasons, please use pci_find_capability() instead.
365255932Salfred */
366255932Salfredstatic inline int pci_pcie_cap(struct pci_dev *dev)
367255932Salfred{
368255932Salfred        return pci_find_capability(dev, PCI_CAP_ID_EXP);
369255932Salfred}
370255932Salfred
371255932Salfred
372219820Sjeffstatic inline int
373219820Sjeffpci_read_config_byte(struct pci_dev *pdev, int where, u8 *val)
374219820Sjeff{
375219820Sjeff
376219820Sjeff	*val = (u8)pci_read_config(pdev->dev.bsddev, where, 1);
377219820Sjeff	return (0);
378219820Sjeff}
379219820Sjeff
380219820Sjeffstatic inline int
381219820Sjeffpci_read_config_word(struct pci_dev *pdev, int where, u16 *val)
382219820Sjeff{
383219820Sjeff
384219820Sjeff	*val = (u16)pci_read_config(pdev->dev.bsddev, where, 2);
385219820Sjeff	return (0);
386219820Sjeff}
387219820Sjeff
388219820Sjeffstatic inline int
389219820Sjeffpci_read_config_dword(struct pci_dev *pdev, int where, u32 *val)
390219820Sjeff{
391219820Sjeff
392219820Sjeff	*val = (u32)pci_read_config(pdev->dev.bsddev, where, 4);
393219820Sjeff	return (0);
394219820Sjeff}
395219820Sjeff
396219820Sjeffstatic inline int
397219820Sjeffpci_write_config_byte(struct pci_dev *pdev, int where, u8 val)
398219820Sjeff{
399219820Sjeff
400219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 1);
401219820Sjeff	return (0);
402219820Sjeff}
403219820Sjeff
404219820Sjeffstatic inline int
405219820Sjeffpci_write_config_word(struct pci_dev *pdev, int where, u16 val)
406219820Sjeff{
407219820Sjeff
408219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 2);
409219820Sjeff	return (0);
410219820Sjeff}
411219820Sjeff
412219820Sjeffstatic inline int
413219820Sjeffpci_write_config_dword(struct pci_dev *pdev, int where, u32 val)
414219820Sjeff{
415219820Sjeff
416219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 4);
417219820Sjeff	return (0);
418219820Sjeff}
419219820Sjeff
420219820Sjeffstatic struct pci_driver *
421271127Shselaskylinux_pci_find(device_t dev, const struct pci_device_id **idp)
422219820Sjeff{
423271127Shselasky	const struct pci_device_id *id;
424219820Sjeff	struct pci_driver *pdrv;
425219820Sjeff	uint16_t vendor;
426219820Sjeff	uint16_t device;
427219820Sjeff
428219820Sjeff	vendor = pci_get_vendor(dev);
429219820Sjeff	device = pci_get_device(dev);
430219820Sjeff
431219820Sjeff	spin_lock(&pci_lock);
432219820Sjeff	list_for_each_entry(pdrv, &pci_drivers, links) {
433219820Sjeff		for (id = pdrv->id_table; id->vendor != 0; id++) {
434219820Sjeff			if (vendor == id->vendor && device == id->device) {
435219820Sjeff				*idp = id;
436219820Sjeff				spin_unlock(&pci_lock);
437219820Sjeff				return (pdrv);
438219820Sjeff			}
439219820Sjeff		}
440219820Sjeff	}
441219820Sjeff	spin_unlock(&pci_lock);
442219820Sjeff	return (NULL);
443219820Sjeff}
444219820Sjeff
445219820Sjeffstatic inline int
446219820Sjefflinux_pci_probe(device_t dev)
447219820Sjeff{
448271127Shselasky	const struct pci_device_id *id;
449219820Sjeff	struct pci_driver *pdrv;
450219820Sjeff
451219820Sjeff	if ((pdrv = linux_pci_find(dev, &id)) == NULL)
452219820Sjeff		return (ENXIO);
453219820Sjeff	if (device_get_driver(dev) != &pdrv->driver)
454219820Sjeff		return (ENXIO);
455219820Sjeff	device_set_desc(dev, pdrv->name);
456219820Sjeff	return (0);
457219820Sjeff}
458219820Sjeff
459219820Sjeffstatic inline int
460219820Sjefflinux_pci_attach(device_t dev)
461219820Sjeff{
462219820Sjeff	struct resource_list_entry *rle;
463219820Sjeff	struct pci_dev *pdev;
464219820Sjeff	struct pci_driver *pdrv;
465271127Shselasky	const struct pci_device_id *id;
466219820Sjeff	int error;
467219820Sjeff
468219820Sjeff	pdrv = linux_pci_find(dev, &id);
469219820Sjeff	pdev = device_get_softc(dev);
470219820Sjeff	pdev->dev.parent = &linux_rootdev;
471219820Sjeff	pdev->dev.bsddev = dev;
472219820Sjeff	INIT_LIST_HEAD(&pdev->dev.irqents);
473219820Sjeff	pdev->device = id->device;
474219820Sjeff	pdev->vendor = id->vendor;
475219820Sjeff	pdev->dev.dma_mask = &pdev->dma_mask;
476219820Sjeff	pdev->pdrv = pdrv;
477219820Sjeff	kobject_init(&pdev->dev.kobj, &dev_ktype);
478219820Sjeff	kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
479219820Sjeff	kobject_add(&pdev->dev.kobj, &linux_rootdev.kobj,
480219820Sjeff	    kobject_name(&pdev->dev.kobj));
481219820Sjeff	rle = _pci_get_rle(pdev, SYS_RES_IRQ, 0);
482219820Sjeff	if (rle)
483219820Sjeff		pdev->dev.irq = rle->start;
484219820Sjeff	else
485219820Sjeff		pdev->dev.irq = 0;
486219820Sjeff	pdev->irq = pdev->dev.irq;
487219820Sjeff	mtx_unlock(&Giant);
488219820Sjeff	spin_lock(&pci_lock);
489219820Sjeff	list_add(&pdev->links, &pci_devices);
490219820Sjeff	spin_unlock(&pci_lock);
491219820Sjeff	error = pdrv->probe(pdev, id);
492219820Sjeff	mtx_lock(&Giant);
493219820Sjeff	if (error) {
494219820Sjeff		spin_lock(&pci_lock);
495219820Sjeff		list_del(&pdev->links);
496219820Sjeff		spin_unlock(&pci_lock);
497219820Sjeff		put_device(&pdev->dev);
498219820Sjeff		return (-error);
499219820Sjeff	}
500219820Sjeff	return (0);
501219820Sjeff}
502219820Sjeff
503219820Sjeffstatic inline int
504219820Sjefflinux_pci_detach(device_t dev)
505219820Sjeff{
506219820Sjeff	struct pci_dev *pdev;
507219820Sjeff
508219820Sjeff	pdev = device_get_softc(dev);
509219820Sjeff	mtx_unlock(&Giant);
510219820Sjeff	pdev->pdrv->remove(pdev);
511219820Sjeff	mtx_lock(&Giant);
512219820Sjeff	spin_lock(&pci_lock);
513219820Sjeff	list_del(&pdev->links);
514219820Sjeff	spin_unlock(&pci_lock);
515219820Sjeff	put_device(&pdev->dev);
516219820Sjeff
517219820Sjeff	return (0);
518219820Sjeff}
519219820Sjeff
520219820Sjeffstatic device_method_t pci_methods[] = {
521219820Sjeff	DEVMETHOD(device_probe, linux_pci_probe),
522219820Sjeff	DEVMETHOD(device_attach, linux_pci_attach),
523219820Sjeff	DEVMETHOD(device_detach, linux_pci_detach),
524219820Sjeff	{0, 0}
525219820Sjeff};
526219820Sjeff
527219820Sjeffstatic inline int
528219820Sjeffpci_register_driver(struct pci_driver *pdrv)
529219820Sjeff{
530219820Sjeff	devclass_t bus;
531219820Sjeff	int error;
532219820Sjeff
533219820Sjeff	spin_lock(&pci_lock);
534219820Sjeff	list_add(&pdrv->links, &pci_drivers);
535219820Sjeff	spin_unlock(&pci_lock);
536219820Sjeff	bus = devclass_find("pci");
537219820Sjeff	pdrv->driver.name = pdrv->name;
538219820Sjeff	pdrv->driver.methods = pci_methods;
539219820Sjeff	pdrv->driver.size = sizeof(struct pci_dev);
540219820Sjeff	mtx_lock(&Giant);
541219820Sjeff	error = devclass_add_driver(bus, &pdrv->driver, BUS_PASS_DEFAULT,
542219820Sjeff	    &pdrv->bsdclass);
543219820Sjeff	mtx_unlock(&Giant);
544219820Sjeff	if (error)
545219820Sjeff		return (-error);
546219820Sjeff	return (0);
547219820Sjeff}
548219820Sjeff
549219820Sjeffstatic inline void
550219820Sjeffpci_unregister_driver(struct pci_driver *pdrv)
551219820Sjeff{
552219820Sjeff	devclass_t bus;
553219820Sjeff
554219820Sjeff	list_del(&pdrv->links);
555219820Sjeff	bus = devclass_find("pci");
556219820Sjeff	mtx_lock(&Giant);
557219820Sjeff	devclass_delete_driver(bus, &pdrv->driver);
558219820Sjeff	mtx_unlock(&Giant);
559219820Sjeff}
560219820Sjeff
561219820Sjeffstruct msix_entry {
562219820Sjeff	int entry;
563219820Sjeff	int vector;
564219820Sjeff};
565219820Sjeff
566219820Sjeff/*
567219820Sjeff * Enable msix, positive errors indicate actual number of available
568219820Sjeff * vectors.  Negative errors are failures.
569292907Sngie *
570292907Sngie * NB: define added to prevent this definition of pci_enable_msix from
571292907Sngie * clashing with the native FreeBSD version.
572219820Sjeff */
573292907Sngie#define	pci_enable_msix		linux_pci_enable_msix
574219820Sjeffstatic inline int
575219820Sjeffpci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
576219820Sjeff{
577219820Sjeff	struct resource_list_entry *rle;
578219820Sjeff	int error;
579219820Sjeff	int avail;
580219820Sjeff	int i;
581219820Sjeff
582219820Sjeff	avail = pci_msix_count(pdev->dev.bsddev);
583219820Sjeff	if (avail < nreq) {
584219820Sjeff		if (avail == 0)
585219820Sjeff			return -EINVAL;
586219820Sjeff		return avail;
587219820Sjeff	}
588219820Sjeff	avail = nreq;
589219820Sjeff	if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
590219820Sjeff		return error;
591277139Shselasky	/*
592277139Shselasky	 * Handle case where "pci_alloc_msix()" may allocate less
593277139Shselasky	 * interrupts than available and return with no error:
594277139Shselasky	 */
595277139Shselasky	if (avail < nreq) {
596277139Shselasky		pci_release_msi(pdev->dev.bsddev);
597277139Shselasky		return avail;
598277139Shselasky	}
599219820Sjeff	rle = _pci_get_rle(pdev, SYS_RES_IRQ, 1);
600219820Sjeff	pdev->dev.msix = rle->start;
601219820Sjeff	pdev->dev.msix_max = rle->start + avail;
602219820Sjeff	for (i = 0; i < nreq; i++)
603219820Sjeff		entries[i].vector = pdev->dev.msix + i;
604219820Sjeff	return (0);
605219820Sjeff}
606219820Sjeff
607282513Shselasky#define	pci_enable_msix_range	linux_pci_enable_msix_range
608282513Shselaskystatic inline int
609282513Shselaskypci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
610282513Shselasky    int minvec, int maxvec)
611282513Shselasky{
612282513Shselasky	int nvec = maxvec;
613282513Shselasky	int rc;
614282513Shselasky
615282513Shselasky	if (maxvec < minvec)
616282513Shselasky		return (-ERANGE);
617282513Shselasky
618282513Shselasky	do {
619282513Shselasky		rc = pci_enable_msix(dev, entries, nvec);
620282513Shselasky		if (rc < 0) {
621282513Shselasky			return (rc);
622282513Shselasky		} else if (rc > 0) {
623282513Shselasky			if (rc < minvec)
624282513Shselasky				return (-ENOSPC);
625282513Shselasky			nvec = rc;
626282513Shselasky		}
627282513Shselasky	} while (rc);
628282513Shselasky	return (nvec);
629282513Shselasky}
630282513Shselasky
631255932Salfredstatic inline int pci_channel_offline(struct pci_dev *pdev)
632255932Salfred{
633255932Salfred        return false;
634255932Salfred}
635255932Salfred
636255932Salfredstatic inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
637255932Salfred{
638255932Salfred        return -ENODEV;
639255932Salfred}
640255932Salfredstatic inline void pci_disable_sriov(struct pci_dev *dev)
641255932Salfred{
642255932Salfred}
643255932Salfred
644255932Salfred/**
645255932Salfred * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table
646255932Salfred * @_table: device table name
647255932Salfred *
648255932Salfred * This macro is used to create a struct pci_device_id array (a device table)
649255932Salfred * in a generic manner.
650255932Salfred */
651255932Salfred#define DEFINE_PCI_DEVICE_TABLE(_table) \
652255932Salfred	const struct pci_device_id _table[] __devinitdata
653255932Salfred
654255932Salfred
655219820Sjeff/* XXX This should not be necessary. */
656219820Sjeff#define	pcix_set_mmrbc(d, v)	0
657219820Sjeff#define	pcix_get_max_mmrbc(d)	0
658219820Sjeff#define	pcie_set_readrq(d, v)	0
659219820Sjeff
660219820Sjeff#define	PCI_DMA_BIDIRECTIONAL	0
661219820Sjeff#define	PCI_DMA_TODEVICE	1
662219820Sjeff#define	PCI_DMA_FROMDEVICE	2
663219820Sjeff#define	PCI_DMA_NONE		3
664219820Sjeff
665219820Sjeff#define	pci_pool		dma_pool
666219820Sjeff#define pci_pool_destroy	dma_pool_destroy
667219820Sjeff#define pci_pool_alloc		dma_pool_alloc
668219820Sjeff#define pci_pool_free		dma_pool_free
669219820Sjeff#define	pci_pool_create(_name, _pdev, _size, _align, _alloc)		\
670219820Sjeff	    dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc)
671219820Sjeff#define	pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle)		\
672219820Sjeff	    dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
673219820Sjeff		_size, _vaddr, _dma_handle)
674219820Sjeff#define	pci_map_sg(_hwdev, _sg, _nents, _dir)				\
675219820Sjeff	    dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev),	\
676219820Sjeff		_sg, _nents, (enum dma_data_direction)_dir)
677219820Sjeff#define	pci_map_single(_hwdev, _ptr, _size, _dir)			\
678219820Sjeff	    dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev),	\
679219820Sjeff		(_ptr), (_size), (enum dma_data_direction)_dir)
680219820Sjeff#define	pci_unmap_single(_hwdev, _addr, _size, _dir)			\
681219820Sjeff	    dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
682219820Sjeff		_addr, _size, (enum dma_data_direction)_dir)
683219820Sjeff#define	pci_unmap_sg(_hwdev, _sg, _nents, _dir)				\
684219820Sjeff	    dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
685219820Sjeff		_sg, _nents, (enum dma_data_direction)_dir)
686219820Sjeff#define	pci_map_page(_hwdev, _page, _offset, _size, _dir)		\
687219820Sjeff	    dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\
688219820Sjeff		_offset, _size, (enum dma_data_direction)_dir)
689219820Sjeff#define	pci_unmap_page(_hwdev, _dma_address, _size, _dir)		\
690219820Sjeff	    dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
691219820Sjeff		_dma_address, _size, (enum dma_data_direction)_dir)
692219820Sjeff#define	pci_set_dma_mask(_pdev, mask)	dma_set_mask(&(_pdev)->dev, (mask))
693219820Sjeff#define	pci_dma_mapping_error(_pdev, _dma_addr)				\
694219820Sjeff	    dma_mapping_error(&(_pdev)->dev, _dma_addr)
695219820Sjeff#define	pci_set_consistent_dma_mask(_pdev, _mask)			\
696219820Sjeff	    dma_set_coherent_mask(&(_pdev)->dev, (_mask))
697219820Sjeff#define	DECLARE_PCI_UNMAP_ADDR(x)	DEFINE_DMA_UNMAP_ADDR(x);
698219820Sjeff#define	DECLARE_PCI_UNMAP_LEN(x)	DEFINE_DMA_UNMAP_LEN(x);
699219820Sjeff#define	pci_unmap_addr		dma_unmap_addr
700219820Sjeff#define	pci_unmap_addr_set	dma_unmap_addr_set
701219820Sjeff#define	pci_unmap_len		dma_unmap_len
702219820Sjeff#define	pci_unmap_len_set	dma_unmap_len_set
703219820Sjeff
704255932Salfredtypedef unsigned int __bitwise pci_channel_state_t;
705255932Salfredtypedef unsigned int __bitwise pci_ers_result_t;
706219820Sjeff
707255932Salfredenum pci_channel_state {
708255932Salfred        /* I/O channel is in normal state */
709255932Salfred        pci_channel_io_normal = (__force pci_channel_state_t) 1,
710255932Salfred
711255932Salfred        /* I/O to channel is blocked */
712255932Salfred        pci_channel_io_frozen = (__force pci_channel_state_t) 2,
713255932Salfred
714255932Salfred        /* PCI card is dead */
715255932Salfred        pci_channel_io_perm_failure = (__force pci_channel_state_t) 3,
716255932Salfred};
717255932Salfred
718255932Salfredenum pci_ers_result {
719255932Salfred        /* no result/none/not supported in device driver */
720255932Salfred        PCI_ERS_RESULT_NONE = (__force pci_ers_result_t) 1,
721255932Salfred
722255932Salfred        /* Device driver can recover without slot reset */
723255932Salfred        PCI_ERS_RESULT_CAN_RECOVER = (__force pci_ers_result_t) 2,
724255932Salfred
725255932Salfred        /* Device driver wants slot to be reset. */
726255932Salfred        PCI_ERS_RESULT_NEED_RESET = (__force pci_ers_result_t) 3,
727255932Salfred
728255932Salfred        /* Device has completely failed, is unrecoverable */
729255932Salfred        PCI_ERS_RESULT_DISCONNECT = (__force pci_ers_result_t) 4,
730255932Salfred
731255932Salfred        /* Device driver is fully recovered and operational */
732255932Salfred        PCI_ERS_RESULT_RECOVERED = (__force pci_ers_result_t) 5,
733255932Salfred};
734255932Salfred
735255932Salfred
736255932Salfred/* PCI bus error event callbacks */
737255932Salfredstruct pci_error_handlers {
738255932Salfred        /* PCI bus error detected on this device */
739255932Salfred        pci_ers_result_t (*error_detected)(struct pci_dev *dev,
740255932Salfred                        enum pci_channel_state error);
741255932Salfred
742255932Salfred        /* MMIO has been re-enabled, but not DMA */
743255932Salfred        pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
744255932Salfred
745255932Salfred        /* PCI Express link has been reset */
746255932Salfred        pci_ers_result_t (*link_reset)(struct pci_dev *dev);
747255932Salfred
748255932Salfred        /* PCI slot has been reset */
749255932Salfred        pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
750255932Salfred
751255932Salfred        /* Device driver may resume normal operations */
752255932Salfred        void (*resume)(struct pci_dev *dev);
753255932Salfred};
754255932Salfred
755271127Shselasky/* freeBSD does not support SRIOV - yet */
756271127Shselaskystatic inline struct pci_dev *pci_physfn(struct pci_dev *dev)
757271127Shselasky{
758271127Shselasky        return dev;
759271127Shselasky}
760255932Salfred
761271127Shselaskystatic inline bool pci_is_pcie(struct pci_dev *dev)
762271127Shselasky{
763271127Shselasky        return !!pci_pcie_cap(dev);
764271127Shselasky}
765255932Salfred
766271127Shselaskystatic inline u16 pcie_flags_reg(struct pci_dev *dev)
767271127Shselasky{
768271127Shselasky        int pos;
769271127Shselasky        u16 reg16;
770271127Shselasky
771271127Shselasky        pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
772271127Shselasky        if (!pos)
773271127Shselasky                return 0;
774271127Shselasky
775271127Shselasky        pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
776271127Shselasky
777271127Shselasky        return reg16;
778271127Shselasky}
779271127Shselasky
780271127Shselasky
781271127Shselaskystatic inline int pci_pcie_type(struct pci_dev *dev)
782271127Shselasky{
783271127Shselasky        return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
784271127Shselasky}
785271127Shselasky
786271127Shselaskystatic inline int pcie_cap_version(struct pci_dev *dev)
787271127Shselasky{
788271127Shselasky        return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS;
789271127Shselasky}
790271127Shselasky
791271127Shselaskystatic inline bool pcie_cap_has_lnkctl(struct pci_dev *dev)
792271127Shselasky{
793271127Shselasky        int type = pci_pcie_type(dev);
794271127Shselasky
795271127Shselasky        return pcie_cap_version(dev) > 1 ||
796271127Shselasky               type == PCI_EXP_TYPE_ROOT_PORT ||
797271127Shselasky               type == PCI_EXP_TYPE_ENDPOINT ||
798271127Shselasky               type == PCI_EXP_TYPE_LEG_END;
799271127Shselasky}
800271127Shselasky
801271127Shselaskystatic inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
802271127Shselasky{
803271127Shselasky                return true;
804271127Shselasky}
805271127Shselasky
806271127Shselaskystatic inline bool pcie_cap_has_sltctl(struct pci_dev *dev)
807271127Shselasky{
808271127Shselasky        int type = pci_pcie_type(dev);
809271127Shselasky
810271127Shselasky        return pcie_cap_version(dev) > 1 ||
811271127Shselasky               type == PCI_EXP_TYPE_ROOT_PORT ||
812271127Shselasky               (type == PCI_EXP_TYPE_DOWNSTREAM &&
813271127Shselasky                pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT);
814271127Shselasky}
815271127Shselasky
816271127Shselaskystatic inline bool pcie_cap_has_rtctl(struct pci_dev *dev)
817271127Shselasky{
818271127Shselasky        int type = pci_pcie_type(dev);
819271127Shselasky
820271127Shselasky        return pcie_cap_version(dev) > 1 ||
821271127Shselasky               type == PCI_EXP_TYPE_ROOT_PORT ||
822271127Shselasky               type == PCI_EXP_TYPE_RC_EC;
823271127Shselasky}
824271127Shselasky
825271127Shselaskystatic bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
826271127Shselasky{
827271127Shselasky        if (!pci_is_pcie(dev))
828271127Shselasky                return false;
829271127Shselasky
830271127Shselasky        switch (pos) {
831271127Shselasky        case PCI_EXP_FLAGS_TYPE:
832271127Shselasky                return true;
833271127Shselasky        case PCI_EXP_DEVCAP:
834271127Shselasky        case PCI_EXP_DEVCTL:
835271127Shselasky        case PCI_EXP_DEVSTA:
836271127Shselasky                return pcie_cap_has_devctl(dev);
837271127Shselasky        case PCI_EXP_LNKCAP:
838271127Shselasky        case PCI_EXP_LNKCTL:
839271127Shselasky        case PCI_EXP_LNKSTA:
840271127Shselasky                return pcie_cap_has_lnkctl(dev);
841271127Shselasky        case PCI_EXP_SLTCAP:
842271127Shselasky        case PCI_EXP_SLTCTL:
843271127Shselasky        case PCI_EXP_SLTSTA:
844271127Shselasky                return pcie_cap_has_sltctl(dev);
845271127Shselasky        case PCI_EXP_RTCTL:
846271127Shselasky        case PCI_EXP_RTCAP:
847271127Shselasky        case PCI_EXP_RTSTA:
848271127Shselasky                return pcie_cap_has_rtctl(dev);
849271127Shselasky        case PCI_EXP_DEVCAP2:
850271127Shselasky        case PCI_EXP_DEVCTL2:
851271127Shselasky        case PCI_EXP_LNKCAP2:
852271127Shselasky        case PCI_EXP_LNKCTL2:
853271127Shselasky        case PCI_EXP_LNKSTA2:
854271127Shselasky                return pcie_cap_version(dev) > 1;
855271127Shselasky        default:
856271127Shselasky                return false;
857271127Shselasky        }
858271127Shselasky}
859271127Shselasky
860271127Shselasky
861271127Shselaskystatic inline int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
862271127Shselasky{
863271127Shselasky        if (pos & 1)
864271127Shselasky                return -EINVAL;
865271127Shselasky
866271127Shselasky        if (!pcie_capability_reg_implemented(dev, pos))
867271127Shselasky                return 0;
868271127Shselasky
869271127Shselasky        return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
870271127Shselasky}
871271127Shselasky
872271127Shselasky
873219820Sjeff#endif	/* _LINUX_PCI_H_ */
874