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;
152255932Salfred        unsigned int            devfn;
153255932Salfred        u8                      revision;
154255932Salfred        struct pci_devinfo      *bus; /* bus this device is on, equivalent to linux struct pci_bus */
155219820Sjeff};
156219820Sjeff
157219820Sjeffstatic inline struct resource_list_entry *
158219820Sjeff_pci_get_rle(struct pci_dev *pdev, int type, int rid)
159219820Sjeff{
160219820Sjeff	struct pci_devinfo *dinfo;
161219820Sjeff	struct resource_list *rl;
162219820Sjeff
163219820Sjeff	dinfo = device_get_ivars(pdev->dev.bsddev);
164219820Sjeff	rl = &dinfo->resources;
165219820Sjeff	return resource_list_find(rl, type, rid);
166219820Sjeff}
167219820Sjeff
168219820Sjeffstatic inline struct resource_list_entry *
169219820Sjeff_pci_get_bar(struct pci_dev *pdev, int bar)
170219820Sjeff{
171219820Sjeff	struct resource_list_entry *rle;
172219820Sjeff
173219820Sjeff	bar = PCIR_BAR(bar);
174219820Sjeff	if ((rle = _pci_get_rle(pdev, SYS_RES_MEMORY, bar)) == NULL)
175219820Sjeff		rle = _pci_get_rle(pdev, SYS_RES_IOPORT, bar);
176219820Sjeff	return (rle);
177219820Sjeff}
178219820Sjeff
179219820Sjeffstatic inline struct device *
180219820Sjeff_pci_find_irq_dev(unsigned int irq)
181219820Sjeff{
182219820Sjeff	struct pci_dev *pdev;
183219820Sjeff
184219820Sjeff	spin_lock(&pci_lock);
185219820Sjeff	list_for_each_entry(pdev, &pci_devices, links) {
186219820Sjeff		if (irq == pdev->dev.irq)
187219820Sjeff			break;
188219820Sjeff		if (irq >= pdev->dev.msix && irq < pdev->dev.msix_max)
189219820Sjeff			break;
190219820Sjeff	}
191219820Sjeff	spin_unlock(&pci_lock);
192219820Sjeff	if (pdev)
193219820Sjeff		return &pdev->dev;
194219820Sjeff	return (NULL);
195219820Sjeff}
196219820Sjeff
197219820Sjeffstatic inline unsigned long
198219820Sjeffpci_resource_start(struct pci_dev *pdev, int bar)
199219820Sjeff{
200219820Sjeff	struct resource_list_entry *rle;
201219820Sjeff
202219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
203219820Sjeff		return (0);
204219820Sjeff	return rle->start;
205219820Sjeff}
206219820Sjeff
207219820Sjeffstatic inline unsigned long
208219820Sjeffpci_resource_len(struct pci_dev *pdev, int bar)
209219820Sjeff{
210219820Sjeff	struct resource_list_entry *rle;
211219820Sjeff
212219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
213219820Sjeff		return (0);
214219820Sjeff	return rle->count;
215219820Sjeff}
216219820Sjeff
217219820Sjeff/*
218219820Sjeff * All drivers just seem to want to inspect the type not flags.
219219820Sjeff */
220219820Sjeffstatic inline int
221219820Sjeffpci_resource_flags(struct pci_dev *pdev, int bar)
222219820Sjeff{
223219820Sjeff	struct resource_list_entry *rle;
224219820Sjeff
225219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
226219820Sjeff		return (0);
227219820Sjeff	return rle->type;
228219820Sjeff}
229219820Sjeff
230219820Sjeffstatic inline const char *
231219820Sjeffpci_name(struct pci_dev *d)
232219820Sjeff{
233219820Sjeff
234219820Sjeff	return device_get_desc(d->dev.bsddev);
235219820Sjeff}
236219820Sjeff
237219820Sjeffstatic inline void *
238219820Sjeffpci_get_drvdata(struct pci_dev *pdev)
239219820Sjeff{
240219820Sjeff
241219820Sjeff	return dev_get_drvdata(&pdev->dev);
242219820Sjeff}
243219820Sjeff
244219820Sjeffstatic inline void
245219820Sjeffpci_set_drvdata(struct pci_dev *pdev, void *data)
246219820Sjeff{
247219820Sjeff
248219820Sjeff	dev_set_drvdata(&pdev->dev, data);
249219820Sjeff}
250219820Sjeff
251219820Sjeffstatic inline int
252219820Sjeffpci_enable_device(struct pci_dev *pdev)
253219820Sjeff{
254219820Sjeff
255219820Sjeff	pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT);
256219820Sjeff	pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY);
257219820Sjeff	return (0);
258219820Sjeff}
259219820Sjeff
260219820Sjeffstatic inline void
261219820Sjeffpci_disable_device(struct pci_dev *pdev)
262219820Sjeff{
263219820Sjeff}
264219820Sjeff
265219820Sjeffstatic inline int
266219820Sjeffpci_set_master(struct pci_dev *pdev)
267219820Sjeff{
268219820Sjeff
269219820Sjeff	pci_enable_busmaster(pdev->dev.bsddev);
270219820Sjeff	return (0);
271219820Sjeff}
272219820Sjeff
273219820Sjeffstatic inline int
274219820Sjeffpci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
275219820Sjeff{
276219820Sjeff	int rid;
277219820Sjeff	int type;
278219820Sjeff
279219820Sjeff	type = pci_resource_flags(pdev, bar);
280219820Sjeff	if (type == 0)
281219820Sjeff		return (-ENODEV);
282219820Sjeff	rid = PCIR_BAR(bar);
283219820Sjeff	if (bus_alloc_resource_any(pdev->dev.bsddev, type, &rid,
284219820Sjeff	    RF_ACTIVE) == NULL)
285219820Sjeff		return (-EINVAL);
286219820Sjeff	return (0);
287219820Sjeff}
288219820Sjeff
289219820Sjeffstatic inline void
290219820Sjeffpci_release_region(struct pci_dev *pdev, int bar)
291219820Sjeff{
292219820Sjeff	struct resource_list_entry *rle;
293219820Sjeff
294219820Sjeff	if ((rle = _pci_get_bar(pdev, bar)) == NULL)
295219820Sjeff		return;
296219820Sjeff	bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res);
297219820Sjeff}
298219820Sjeff
299219820Sjeffstatic inline void
300219820Sjeffpci_release_regions(struct pci_dev *pdev)
301219820Sjeff{
302219820Sjeff	int i;
303219820Sjeff
304219820Sjeff	for (i = 0; i <= PCIR_MAX_BAR_0; i++)
305219820Sjeff		pci_release_region(pdev, i);
306219820Sjeff}
307219820Sjeff
308219820Sjeffstatic inline int
309219820Sjeffpci_request_regions(struct pci_dev *pdev, const char *res_name)
310219820Sjeff{
311219820Sjeff	int error;
312219820Sjeff	int i;
313219820Sjeff
314219820Sjeff	for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
315219820Sjeff		error = pci_request_region(pdev, i, res_name);
316219820Sjeff		if (error && error != -ENODEV) {
317219820Sjeff			pci_release_regions(pdev);
318219820Sjeff			return (error);
319219820Sjeff		}
320219820Sjeff	}
321219820Sjeff	return (0);
322219820Sjeff}
323219820Sjeff
324219820Sjeffstatic inline void
325219820Sjeffpci_disable_msix(struct pci_dev *pdev)
326219820Sjeff{
327219820Sjeff
328219820Sjeff	pci_release_msi(pdev->dev.bsddev);
329219820Sjeff}
330219820Sjeff
331219820Sjeff#define	PCI_CAP_ID_EXP	PCIY_EXPRESS
332219820Sjeff#define	PCI_CAP_ID_PCIX	PCIY_PCIX
333219820Sjeff
334255932Salfred
335219820Sjeffstatic inline int
336219820Sjeffpci_find_capability(struct pci_dev *pdev, int capid)
337219820Sjeff{
338219820Sjeff	int reg;
339219820Sjeff
340219902Sjhb	if (pci_find_cap(pdev->dev.bsddev, capid, &reg))
341219820Sjeff		return (0);
342219820Sjeff	return (reg);
343219820Sjeff}
344219820Sjeff
345255932Salfred
346255932Salfred
347255932Salfred
348255932Salfred/**
349255932Salfred * pci_pcie_cap - get the saved PCIe capability offset
350255932Salfred * @dev: PCI device
351255932Salfred *
352255932Salfred * PCIe capability offset is calculated at PCI device initialization
353255932Salfred * time and saved in the data structure. This function returns saved
354255932Salfred * PCIe capability offset. Using this instead of pci_find_capability()
355255932Salfred * reduces unnecessary search in the PCI configuration space. If you
356255932Salfred * need to calculate PCIe capability offset from raw device for some
357255932Salfred * reasons, please use pci_find_capability() instead.
358255932Salfred */
359255932Salfredstatic inline int pci_pcie_cap(struct pci_dev *dev)
360255932Salfred{
361255932Salfred        return pci_find_capability(dev, PCI_CAP_ID_EXP);
362255932Salfred}
363255932Salfred
364255932Salfred
365219820Sjeffstatic inline int
366219820Sjeffpci_read_config_byte(struct pci_dev *pdev, int where, u8 *val)
367219820Sjeff{
368219820Sjeff
369219820Sjeff	*val = (u8)pci_read_config(pdev->dev.bsddev, where, 1);
370219820Sjeff	return (0);
371219820Sjeff}
372219820Sjeff
373219820Sjeffstatic inline int
374219820Sjeffpci_read_config_word(struct pci_dev *pdev, int where, u16 *val)
375219820Sjeff{
376219820Sjeff
377219820Sjeff	*val = (u16)pci_read_config(pdev->dev.bsddev, where, 2);
378219820Sjeff	return (0);
379219820Sjeff}
380219820Sjeff
381219820Sjeffstatic inline int
382219820Sjeffpci_read_config_dword(struct pci_dev *pdev, int where, u32 *val)
383219820Sjeff{
384219820Sjeff
385219820Sjeff	*val = (u32)pci_read_config(pdev->dev.bsddev, where, 4);
386219820Sjeff	return (0);
387219820Sjeff}
388219820Sjeff
389219820Sjeffstatic inline int
390219820Sjeffpci_write_config_byte(struct pci_dev *pdev, int where, u8 val)
391219820Sjeff{
392219820Sjeff
393219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 1);
394219820Sjeff	return (0);
395219820Sjeff}
396219820Sjeff
397219820Sjeffstatic inline int
398219820Sjeffpci_write_config_word(struct pci_dev *pdev, int where, u16 val)
399219820Sjeff{
400219820Sjeff
401219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 2);
402219820Sjeff	return (0);
403219820Sjeff}
404219820Sjeff
405219820Sjeffstatic inline int
406219820Sjeffpci_write_config_dword(struct pci_dev *pdev, int where, u32 val)
407219820Sjeff{
408219820Sjeff
409219820Sjeff	pci_write_config(pdev->dev.bsddev, where, val, 4);
410219820Sjeff	return (0);
411219820Sjeff}
412219820Sjeff
413219820Sjeffstatic struct pci_driver *
414271127Shselaskylinux_pci_find(device_t dev, const struct pci_device_id **idp)
415219820Sjeff{
416271127Shselasky	const struct pci_device_id *id;
417219820Sjeff	struct pci_driver *pdrv;
418219820Sjeff	uint16_t vendor;
419219820Sjeff	uint16_t device;
420219820Sjeff
421219820Sjeff	vendor = pci_get_vendor(dev);
422219820Sjeff	device = pci_get_device(dev);
423219820Sjeff
424219820Sjeff	spin_lock(&pci_lock);
425219820Sjeff	list_for_each_entry(pdrv, &pci_drivers, links) {
426219820Sjeff		for (id = pdrv->id_table; id->vendor != 0; id++) {
427219820Sjeff			if (vendor == id->vendor && device == id->device) {
428219820Sjeff				*idp = id;
429219820Sjeff				spin_unlock(&pci_lock);
430219820Sjeff				return (pdrv);
431219820Sjeff			}
432219820Sjeff		}
433219820Sjeff	}
434219820Sjeff	spin_unlock(&pci_lock);
435219820Sjeff	return (NULL);
436219820Sjeff}
437219820Sjeff
438219820Sjeffstatic inline int
439219820Sjefflinux_pci_probe(device_t dev)
440219820Sjeff{
441271127Shselasky	const struct pci_device_id *id;
442219820Sjeff	struct pci_driver *pdrv;
443219820Sjeff
444219820Sjeff	if ((pdrv = linux_pci_find(dev, &id)) == NULL)
445219820Sjeff		return (ENXIO);
446219820Sjeff	if (device_get_driver(dev) != &pdrv->driver)
447219820Sjeff		return (ENXIO);
448219820Sjeff	device_set_desc(dev, pdrv->name);
449219820Sjeff	return (0);
450219820Sjeff}
451219820Sjeff
452219820Sjeffstatic inline int
453219820Sjefflinux_pci_attach(device_t dev)
454219820Sjeff{
455219820Sjeff	struct resource_list_entry *rle;
456219820Sjeff	struct pci_dev *pdev;
457219820Sjeff	struct pci_driver *pdrv;
458271127Shselasky	const struct pci_device_id *id;
459219820Sjeff	int error;
460219820Sjeff
461219820Sjeff	pdrv = linux_pci_find(dev, &id);
462219820Sjeff	pdev = device_get_softc(dev);
463219820Sjeff	pdev->dev.parent = &linux_rootdev;
464219820Sjeff	pdev->dev.bsddev = dev;
465219820Sjeff	INIT_LIST_HEAD(&pdev->dev.irqents);
466219820Sjeff	pdev->device = id->device;
467219820Sjeff	pdev->vendor = id->vendor;
468219820Sjeff	pdev->dev.dma_mask = &pdev->dma_mask;
469219820Sjeff	pdev->pdrv = pdrv;
470219820Sjeff	kobject_init(&pdev->dev.kobj, &dev_ktype);
471219820Sjeff	kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
472219820Sjeff	kobject_add(&pdev->dev.kobj, &linux_rootdev.kobj,
473219820Sjeff	    kobject_name(&pdev->dev.kobj));
474219820Sjeff	rle = _pci_get_rle(pdev, SYS_RES_IRQ, 0);
475219820Sjeff	if (rle)
476219820Sjeff		pdev->dev.irq = rle->start;
477219820Sjeff	else
478219820Sjeff		pdev->dev.irq = 0;
479219820Sjeff	pdev->irq = pdev->dev.irq;
480219820Sjeff	mtx_unlock(&Giant);
481219820Sjeff	spin_lock(&pci_lock);
482219820Sjeff	list_add(&pdev->links, &pci_devices);
483219820Sjeff	spin_unlock(&pci_lock);
484219820Sjeff	error = pdrv->probe(pdev, id);
485219820Sjeff	mtx_lock(&Giant);
486219820Sjeff	if (error) {
487219820Sjeff		spin_lock(&pci_lock);
488219820Sjeff		list_del(&pdev->links);
489219820Sjeff		spin_unlock(&pci_lock);
490219820Sjeff		put_device(&pdev->dev);
491219820Sjeff		return (-error);
492219820Sjeff	}
493219820Sjeff	return (0);
494219820Sjeff}
495219820Sjeff
496219820Sjeffstatic inline int
497219820Sjefflinux_pci_detach(device_t dev)
498219820Sjeff{
499219820Sjeff	struct pci_dev *pdev;
500219820Sjeff
501219820Sjeff	pdev = device_get_softc(dev);
502219820Sjeff	mtx_unlock(&Giant);
503219820Sjeff	pdev->pdrv->remove(pdev);
504219820Sjeff	mtx_lock(&Giant);
505219820Sjeff	spin_lock(&pci_lock);
506219820Sjeff	list_del(&pdev->links);
507219820Sjeff	spin_unlock(&pci_lock);
508219820Sjeff	put_device(&pdev->dev);
509219820Sjeff
510219820Sjeff	return (0);
511219820Sjeff}
512219820Sjeff
513219820Sjeffstatic device_method_t pci_methods[] = {
514219820Sjeff	DEVMETHOD(device_probe, linux_pci_probe),
515219820Sjeff	DEVMETHOD(device_attach, linux_pci_attach),
516219820Sjeff	DEVMETHOD(device_detach, linux_pci_detach),
517219820Sjeff	{0, 0}
518219820Sjeff};
519219820Sjeff
520219820Sjeffstatic inline int
521219820Sjeffpci_register_driver(struct pci_driver *pdrv)
522219820Sjeff{
523219820Sjeff	devclass_t bus;
524219820Sjeff	int error;
525219820Sjeff
526219820Sjeff	spin_lock(&pci_lock);
527219820Sjeff	list_add(&pdrv->links, &pci_drivers);
528219820Sjeff	spin_unlock(&pci_lock);
529219820Sjeff	bus = devclass_find("pci");
530219820Sjeff	pdrv->driver.name = pdrv->name;
531219820Sjeff	pdrv->driver.methods = pci_methods;
532219820Sjeff	pdrv->driver.size = sizeof(struct pci_dev);
533219820Sjeff	mtx_lock(&Giant);
534219820Sjeff	error = devclass_add_driver(bus, &pdrv->driver, BUS_PASS_DEFAULT,
535219820Sjeff	    &pdrv->bsdclass);
536219820Sjeff	mtx_unlock(&Giant);
537219820Sjeff	if (error)
538219820Sjeff		return (-error);
539219820Sjeff	return (0);
540219820Sjeff}
541219820Sjeff
542219820Sjeffstatic inline void
543219820Sjeffpci_unregister_driver(struct pci_driver *pdrv)
544219820Sjeff{
545219820Sjeff	devclass_t bus;
546219820Sjeff
547219820Sjeff	list_del(&pdrv->links);
548219820Sjeff	bus = devclass_find("pci");
549219820Sjeff	mtx_lock(&Giant);
550219820Sjeff	devclass_delete_driver(bus, &pdrv->driver);
551219820Sjeff	mtx_unlock(&Giant);
552219820Sjeff}
553219820Sjeff
554219820Sjeffstruct msix_entry {
555219820Sjeff	int entry;
556219820Sjeff	int vector;
557219820Sjeff};
558219820Sjeff
559219820Sjeff/*
560219820Sjeff * Enable msix, positive errors indicate actual number of available
561219820Sjeff * vectors.  Negative errors are failures.
562219820Sjeff */
563219820Sjeffstatic inline int
564219820Sjeffpci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
565219820Sjeff{
566219820Sjeff	struct resource_list_entry *rle;
567219820Sjeff	int error;
568219820Sjeff	int avail;
569219820Sjeff	int i;
570219820Sjeff
571219820Sjeff	avail = pci_msix_count(pdev->dev.bsddev);
572219820Sjeff	if (avail < nreq) {
573219820Sjeff		if (avail == 0)
574219820Sjeff			return -EINVAL;
575219820Sjeff		return avail;
576219820Sjeff	}
577219820Sjeff	avail = nreq;
578219820Sjeff	if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
579219820Sjeff		return error;
580219820Sjeff	rle = _pci_get_rle(pdev, SYS_RES_IRQ, 1);
581219820Sjeff	pdev->dev.msix = rle->start;
582219820Sjeff	pdev->dev.msix_max = rle->start + avail;
583219820Sjeff	for (i = 0; i < nreq; i++)
584219820Sjeff		entries[i].vector = pdev->dev.msix + i;
585219820Sjeff	return (0);
586219820Sjeff}
587219820Sjeff
588255932Salfredstatic inline int pci_channel_offline(struct pci_dev *pdev)
589255932Salfred{
590255932Salfred        return false;
591255932Salfred}
592255932Salfred
593255932Salfredstatic inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
594255932Salfred{
595255932Salfred        return -ENODEV;
596255932Salfred}
597255932Salfredstatic inline void pci_disable_sriov(struct pci_dev *dev)
598255932Salfred{
599255932Salfred}
600255932Salfred
601255932Salfred/**
602255932Salfred * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table
603255932Salfred * @_table: device table name
604255932Salfred *
605255932Salfred * This macro is used to create a struct pci_device_id array (a device table)
606255932Salfred * in a generic manner.
607255932Salfred */
608255932Salfred#define DEFINE_PCI_DEVICE_TABLE(_table) \
609255932Salfred	const struct pci_device_id _table[] __devinitdata
610255932Salfred
611255932Salfred
612219820Sjeff/* XXX This should not be necessary. */
613219820Sjeff#define	pcix_set_mmrbc(d, v)	0
614219820Sjeff#define	pcix_get_max_mmrbc(d)	0
615219820Sjeff#define	pcie_set_readrq(d, v)	0
616219820Sjeff
617219820Sjeff#define	PCI_DMA_BIDIRECTIONAL	0
618219820Sjeff#define	PCI_DMA_TODEVICE	1
619219820Sjeff#define	PCI_DMA_FROMDEVICE	2
620219820Sjeff#define	PCI_DMA_NONE		3
621219820Sjeff
622219820Sjeff#define	pci_pool		dma_pool
623219820Sjeff#define pci_pool_destroy	dma_pool_destroy
624219820Sjeff#define pci_pool_alloc		dma_pool_alloc
625219820Sjeff#define pci_pool_free		dma_pool_free
626219820Sjeff#define	pci_pool_create(_name, _pdev, _size, _align, _alloc)		\
627219820Sjeff	    dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc)
628219820Sjeff#define	pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle)		\
629219820Sjeff	    dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
630219820Sjeff		_size, _vaddr, _dma_handle)
631219820Sjeff#define	pci_map_sg(_hwdev, _sg, _nents, _dir)				\
632219820Sjeff	    dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev),	\
633219820Sjeff		_sg, _nents, (enum dma_data_direction)_dir)
634219820Sjeff#define	pci_map_single(_hwdev, _ptr, _size, _dir)			\
635219820Sjeff	    dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev),	\
636219820Sjeff		(_ptr), (_size), (enum dma_data_direction)_dir)
637219820Sjeff#define	pci_unmap_single(_hwdev, _addr, _size, _dir)			\
638219820Sjeff	    dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
639219820Sjeff		_addr, _size, (enum dma_data_direction)_dir)
640219820Sjeff#define	pci_unmap_sg(_hwdev, _sg, _nents, _dir)				\
641219820Sjeff	    dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
642219820Sjeff		_sg, _nents, (enum dma_data_direction)_dir)
643219820Sjeff#define	pci_map_page(_hwdev, _page, _offset, _size, _dir)		\
644219820Sjeff	    dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\
645219820Sjeff		_offset, _size, (enum dma_data_direction)_dir)
646219820Sjeff#define	pci_unmap_page(_hwdev, _dma_address, _size, _dir)		\
647219820Sjeff	    dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
648219820Sjeff		_dma_address, _size, (enum dma_data_direction)_dir)
649219820Sjeff#define	pci_set_dma_mask(_pdev, mask)	dma_set_mask(&(_pdev)->dev, (mask))
650219820Sjeff#define	pci_dma_mapping_error(_pdev, _dma_addr)				\
651219820Sjeff	    dma_mapping_error(&(_pdev)->dev, _dma_addr)
652219820Sjeff#define	pci_set_consistent_dma_mask(_pdev, _mask)			\
653219820Sjeff	    dma_set_coherent_mask(&(_pdev)->dev, (_mask))
654219820Sjeff#define	DECLARE_PCI_UNMAP_ADDR(x)	DEFINE_DMA_UNMAP_ADDR(x);
655219820Sjeff#define	DECLARE_PCI_UNMAP_LEN(x)	DEFINE_DMA_UNMAP_LEN(x);
656219820Sjeff#define	pci_unmap_addr		dma_unmap_addr
657219820Sjeff#define	pci_unmap_addr_set	dma_unmap_addr_set
658219820Sjeff#define	pci_unmap_len		dma_unmap_len
659219820Sjeff#define	pci_unmap_len_set	dma_unmap_len_set
660219820Sjeff
661255932Salfredtypedef unsigned int __bitwise pci_channel_state_t;
662255932Salfredtypedef unsigned int __bitwise pci_ers_result_t;
663219820Sjeff
664255932Salfredenum pci_channel_state {
665255932Salfred        /* I/O channel is in normal state */
666255932Salfred        pci_channel_io_normal = (__force pci_channel_state_t) 1,
667255932Salfred
668255932Salfred        /* I/O to channel is blocked */
669255932Salfred        pci_channel_io_frozen = (__force pci_channel_state_t) 2,
670255932Salfred
671255932Salfred        /* PCI card is dead */
672255932Salfred        pci_channel_io_perm_failure = (__force pci_channel_state_t) 3,
673255932Salfred};
674255932Salfred
675255932Salfredenum pci_ers_result {
676255932Salfred        /* no result/none/not supported in device driver */
677255932Salfred        PCI_ERS_RESULT_NONE = (__force pci_ers_result_t) 1,
678255932Salfred
679255932Salfred        /* Device driver can recover without slot reset */
680255932Salfred        PCI_ERS_RESULT_CAN_RECOVER = (__force pci_ers_result_t) 2,
681255932Salfred
682255932Salfred        /* Device driver wants slot to be reset. */
683255932Salfred        PCI_ERS_RESULT_NEED_RESET = (__force pci_ers_result_t) 3,
684255932Salfred
685255932Salfred        /* Device has completely failed, is unrecoverable */
686255932Salfred        PCI_ERS_RESULT_DISCONNECT = (__force pci_ers_result_t) 4,
687255932Salfred
688255932Salfred        /* Device driver is fully recovered and operational */
689255932Salfred        PCI_ERS_RESULT_RECOVERED = (__force pci_ers_result_t) 5,
690255932Salfred};
691255932Salfred
692255932Salfred
693255932Salfred/* PCI bus error event callbacks */
694255932Salfredstruct pci_error_handlers {
695255932Salfred        /* PCI bus error detected on this device */
696255932Salfred        pci_ers_result_t (*error_detected)(struct pci_dev *dev,
697255932Salfred                        enum pci_channel_state error);
698255932Salfred
699255932Salfred        /* MMIO has been re-enabled, but not DMA */
700255932Salfred        pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
701255932Salfred
702255932Salfred        /* PCI Express link has been reset */
703255932Salfred        pci_ers_result_t (*link_reset)(struct pci_dev *dev);
704255932Salfred
705255932Salfred        /* PCI slot has been reset */
706255932Salfred        pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
707255932Salfred
708255932Salfred        /* Device driver may resume normal operations */
709255932Salfred        void (*resume)(struct pci_dev *dev);
710255932Salfred};
711255932Salfred
712271127Shselasky/* freeBSD does not support SRIOV - yet */
713271127Shselaskystatic inline struct pci_dev *pci_physfn(struct pci_dev *dev)
714271127Shselasky{
715271127Shselasky        return dev;
716271127Shselasky}
717255932Salfred
718271127Shselaskystatic inline bool pci_is_pcie(struct pci_dev *dev)
719271127Shselasky{
720271127Shselasky        return !!pci_pcie_cap(dev);
721271127Shselasky}
722255932Salfred
723271127Shselaskystatic inline u16 pcie_flags_reg(struct pci_dev *dev)
724271127Shselasky{
725271127Shselasky        int pos;
726271127Shselasky        u16 reg16;
727271127Shselasky
728271127Shselasky        pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
729271127Shselasky        if (!pos)
730271127Shselasky                return 0;
731271127Shselasky
732271127Shselasky        pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
733271127Shselasky
734271127Shselasky        return reg16;
735271127Shselasky}
736271127Shselasky
737271127Shselasky
738271127Shselaskystatic inline int pci_pcie_type(struct pci_dev *dev)
739271127Shselasky{
740271127Shselasky        return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
741271127Shselasky}
742271127Shselasky
743271127Shselaskystatic inline int pcie_cap_version(struct pci_dev *dev)
744271127Shselasky{
745271127Shselasky        return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS;
746271127Shselasky}
747271127Shselasky
748271127Shselaskystatic inline bool pcie_cap_has_lnkctl(struct pci_dev *dev)
749271127Shselasky{
750271127Shselasky        int type = pci_pcie_type(dev);
751271127Shselasky
752271127Shselasky        return pcie_cap_version(dev) > 1 ||
753271127Shselasky               type == PCI_EXP_TYPE_ROOT_PORT ||
754271127Shselasky               type == PCI_EXP_TYPE_ENDPOINT ||
755271127Shselasky               type == PCI_EXP_TYPE_LEG_END;
756271127Shselasky}
757271127Shselasky
758271127Shselaskystatic inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
759271127Shselasky{
760271127Shselasky                return true;
761271127Shselasky}
762271127Shselasky
763271127Shselaskystatic inline bool pcie_cap_has_sltctl(struct pci_dev *dev)
764271127Shselasky{
765271127Shselasky        int type = pci_pcie_type(dev);
766271127Shselasky
767271127Shselasky        return pcie_cap_version(dev) > 1 ||
768271127Shselasky               type == PCI_EXP_TYPE_ROOT_PORT ||
769271127Shselasky               (type == PCI_EXP_TYPE_DOWNSTREAM &&
770271127Shselasky                pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT);
771271127Shselasky}
772271127Shselasky
773271127Shselaskystatic inline bool pcie_cap_has_rtctl(struct pci_dev *dev)
774271127Shselasky{
775271127Shselasky        int type = pci_pcie_type(dev);
776271127Shselasky
777271127Shselasky        return pcie_cap_version(dev) > 1 ||
778271127Shselasky               type == PCI_EXP_TYPE_ROOT_PORT ||
779271127Shselasky               type == PCI_EXP_TYPE_RC_EC;
780271127Shselasky}
781271127Shselasky
782271127Shselaskystatic bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
783271127Shselasky{
784271127Shselasky        if (!pci_is_pcie(dev))
785271127Shselasky                return false;
786271127Shselasky
787271127Shselasky        switch (pos) {
788271127Shselasky        case PCI_EXP_FLAGS_TYPE:
789271127Shselasky                return true;
790271127Shselasky        case PCI_EXP_DEVCAP:
791271127Shselasky        case PCI_EXP_DEVCTL:
792271127Shselasky        case PCI_EXP_DEVSTA:
793271127Shselasky                return pcie_cap_has_devctl(dev);
794271127Shselasky        case PCI_EXP_LNKCAP:
795271127Shselasky        case PCI_EXP_LNKCTL:
796271127Shselasky        case PCI_EXP_LNKSTA:
797271127Shselasky                return pcie_cap_has_lnkctl(dev);
798271127Shselasky        case PCI_EXP_SLTCAP:
799271127Shselasky        case PCI_EXP_SLTCTL:
800271127Shselasky        case PCI_EXP_SLTSTA:
801271127Shselasky                return pcie_cap_has_sltctl(dev);
802271127Shselasky        case PCI_EXP_RTCTL:
803271127Shselasky        case PCI_EXP_RTCAP:
804271127Shselasky        case PCI_EXP_RTSTA:
805271127Shselasky                return pcie_cap_has_rtctl(dev);
806271127Shselasky        case PCI_EXP_DEVCAP2:
807271127Shselasky        case PCI_EXP_DEVCTL2:
808271127Shselasky        case PCI_EXP_LNKCAP2:
809271127Shselasky        case PCI_EXP_LNKCTL2:
810271127Shselasky        case PCI_EXP_LNKSTA2:
811271127Shselasky                return pcie_cap_version(dev) > 1;
812271127Shselasky        default:
813271127Shselasky                return false;
814271127Shselasky        }
815271127Shselasky}
816271127Shselasky
817271127Shselasky
818271127Shselaskystatic inline int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
819271127Shselasky{
820271127Shselasky        if (pos & 1)
821271127Shselasky                return -EINVAL;
822271127Shselasky
823271127Shselasky        if (!pcie_capability_reg_implemented(dev, pos))
824271127Shselasky                return 0;
825271127Shselasky
826271127Shselasky        return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
827271127Shselasky}
828271127Shselasky
829271127Shselasky
830219820Sjeff#endif	/* _LINUX_PCI_H_ */
831