18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky  * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Panasas, Inc.
5bdff61f8SHans Petter Selasky  * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky  * All rights reserved.
78d59ecb2SHans Petter Selasky  *
88d59ecb2SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
98d59ecb2SHans Petter Selasky  * modification, are permitted provided that the following conditions
108d59ecb2SHans Petter Selasky  * are met:
118d59ecb2SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
128d59ecb2SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
138d59ecb2SHans Petter Selasky  *    disclaimer.
148d59ecb2SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
158d59ecb2SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
168d59ecb2SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
178d59ecb2SHans Petter Selasky  *
188d59ecb2SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
198d59ecb2SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
208d59ecb2SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
218d59ecb2SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
228d59ecb2SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
238d59ecb2SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
248d59ecb2SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
258d59ecb2SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268d59ecb2SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278d59ecb2SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288d59ecb2SHans Petter Selasky  *
298d59ecb2SHans Petter Selasky  * $FreeBSD$
308d59ecb2SHans Petter Selasky  */
318d59ecb2SHans Petter Selasky #ifndef	_LINUX_PCI_H_
328d59ecb2SHans Petter Selasky #define	_LINUX_PCI_H_
338d59ecb2SHans Petter Selasky 
348d59ecb2SHans Petter Selasky #define	CONFIG_PCI_MSI
358d59ecb2SHans Petter Selasky 
368d59ecb2SHans Petter Selasky #include <linux/types.h>
378d59ecb2SHans Petter Selasky 
388d59ecb2SHans Petter Selasky #include <sys/param.h>
398d59ecb2SHans Petter Selasky #include <sys/bus.h>
402928e60eSKonstantin Belousov #include <sys/nv.h>
418d59ecb2SHans Petter Selasky #include <sys/pciio.h>
428d59ecb2SHans Petter Selasky #include <sys/rman.h>
439275cd0dSWarner Losh #include <sys/bus.h>
448d59ecb2SHans Petter Selasky #include <dev/pci/pcivar.h>
458d59ecb2SHans Petter Selasky #include <dev/pci/pcireg.h>
468d59ecb2SHans Petter Selasky #include <dev/pci/pci_private.h>
478d59ecb2SHans Petter Selasky 
488d59ecb2SHans Petter Selasky #include <machine/resource.h>
498d59ecb2SHans Petter Selasky 
508d59ecb2SHans Petter Selasky #include <linux/list.h>
518d59ecb2SHans Petter Selasky #include <linux/dmapool.h>
528d59ecb2SHans Petter Selasky #include <linux/dma-mapping.h>
538d59ecb2SHans Petter Selasky #include <linux/compiler.h>
548d59ecb2SHans Petter Selasky #include <linux/errno.h>
558d59ecb2SHans Petter Selasky #include <asm/atomic.h>
568d59ecb2SHans Petter Selasky #include <linux/device.h>
575a402a3aSBjoern A. Zeeb #include <linux/pci_ids.h>
588d59ecb2SHans Petter Selasky 
598d59ecb2SHans Petter Selasky struct pci_device_id {
608d59ecb2SHans Petter Selasky 	uint32_t	vendor;
618d59ecb2SHans Petter Selasky 	uint32_t	device;
628d59ecb2SHans Petter Selasky 	uint32_t	subvendor;
638d59ecb2SHans Petter Selasky 	uint32_t	subdevice;
646373e95eSMark Johnston 	uint32_t	class;
658d59ecb2SHans Petter Selasky 	uint32_t	class_mask;
668d59ecb2SHans Petter Selasky 	uintptr_t	driver_data;
678d59ecb2SHans Petter Selasky };
688d59ecb2SHans Petter Selasky 
698d59ecb2SHans Petter Selasky #define	MODULE_DEVICE_TABLE(bus, table)
70ecf29cf1SMark Johnston 
71232028b3SHans Petter Selasky #define	PCI_ANY_ID			-1U
728d59ecb2SHans Petter Selasky 
738d59ecb2SHans Petter Selasky #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
748d59ecb2SHans Petter Selasky #define PCI_SLOT(devfn)		(((devfn) >> 3) & 0x1f)
758d59ecb2SHans Petter Selasky #define PCI_FUNC(devfn)		((devfn) & 0x07)
7613a5c70bSHans Petter Selasky #define	PCI_BUS_NUM(devfn)	(((devfn) >> 8) & 0xff)
778d59ecb2SHans Petter Selasky 
788d59ecb2SHans Petter Selasky #define PCI_VDEVICE(_vendor, _device)					\
798d59ecb2SHans Petter Selasky 	    .vendor = PCI_VENDOR_ID_##_vendor, .device = (_device),	\
808d59ecb2SHans Petter Selasky 	    .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
818d59ecb2SHans Petter Selasky #define	PCI_DEVICE(_vendor, _device)					\
828d59ecb2SHans Petter Selasky 	    .vendor = (_vendor), .device = (_device),			\
838d59ecb2SHans Petter Selasky 	    .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
848d59ecb2SHans Petter Selasky 
858d59ecb2SHans Petter Selasky #define	to_pci_dev(n)	container_of(n, struct pci_dev, dev)
868d59ecb2SHans Petter Selasky 
878d59ecb2SHans Petter Selasky #define	PCI_VENDOR_ID		PCIR_DEVVENDOR
888d59ecb2SHans Petter Selasky #define	PCI_COMMAND		PCIR_COMMAND
89fc1d8409SBjoern A. Zeeb #define	PCI_COMMAND_INTX_DISABLE	PCIM_CMD_INTxDIS
908d59ecb2SHans Petter Selasky #define	PCI_EXP_DEVCTL		PCIER_DEVICE_CTL		/* Device Control */
918d59ecb2SHans Petter Selasky #define	PCI_EXP_LNKCTL		PCIER_LINK_CTL			/* Link Control */
92fc1d8409SBjoern A. Zeeb #define	PCI_EXP_LNKCTL_ASPM_L0S	PCIEM_LINK_CTL_ASPMC_L0S
93fc1d8409SBjoern A. Zeeb #define	PCI_EXP_LNKCTL_ASPM_L1	PCIEM_LINK_CTL_ASPMC_L1
94fc1d8409SBjoern A. Zeeb #define	PCI_EXP_LNKCTL_CLKREQ_EN PCIEM_LINK_CTL_ECPM		/* Enable clock PM */
958d59ecb2SHans Petter Selasky #define	PCI_EXP_FLAGS_TYPE	PCIEM_FLAGS_TYPE		/* Device/Port type */
968d59ecb2SHans Petter Selasky #define	PCI_EXP_DEVCAP		PCIER_DEVICE_CAP		/* Device capabilities */
978d59ecb2SHans Petter Selasky #define	PCI_EXP_DEVSTA		PCIER_DEVICE_STA		/* Device Status */
988d59ecb2SHans Petter Selasky #define	PCI_EXP_LNKCAP		PCIER_LINK_CAP			/* Link Capabilities */
998d59ecb2SHans Petter Selasky #define	PCI_EXP_LNKSTA		PCIER_LINK_STA			/* Link Status */
1008d59ecb2SHans Petter Selasky #define	PCI_EXP_SLTCAP		PCIER_SLOT_CAP			/* Slot Capabilities */
1018d59ecb2SHans Petter Selasky #define	PCI_EXP_SLTCTL		PCIER_SLOT_CTL			/* Slot Control */
1028d59ecb2SHans Petter Selasky #define	PCI_EXP_SLTSTA		PCIER_SLOT_STA			/* Slot Status */
1038d59ecb2SHans Petter Selasky #define	PCI_EXP_RTCTL		PCIER_ROOT_CTL			/* Root Control */
1048d59ecb2SHans Petter Selasky #define	PCI_EXP_RTCAP		PCIER_ROOT_CAP			/* Root Capabilities */
1058d59ecb2SHans Petter Selasky #define	PCI_EXP_RTSTA		PCIER_ROOT_STA			/* Root Status */
1068d59ecb2SHans Petter Selasky #define	PCI_EXP_DEVCAP2		PCIER_DEVICE_CAP2		/* Device Capabilities 2 */
1078d59ecb2SHans Petter Selasky #define	PCI_EXP_DEVCTL2		PCIER_DEVICE_CTL2		/* Device Control 2 */
108fc1d8409SBjoern A. Zeeb #define	PCI_EXP_DEVCTL2_LTR_EN	PCIEM_CTL2_LTR_ENABLE
1098d59ecb2SHans Petter Selasky #define	PCI_EXP_LNKCAP2		PCIER_LINK_CAP2			/* Link Capabilities 2 */
1108d59ecb2SHans Petter Selasky #define	PCI_EXP_LNKCTL2		PCIER_LINK_CTL2			/* Link Control 2 */
1118d59ecb2SHans Petter Selasky #define	PCI_EXP_LNKSTA2		PCIER_LINK_STA2			/* Link Status 2 */
1128d59ecb2SHans Petter Selasky #define	PCI_EXP_FLAGS		PCIER_FLAGS			/* Capabilities register */
1138d59ecb2SHans Petter Selasky #define	PCI_EXP_FLAGS_VERS	PCIEM_FLAGS_VERSION		/* Capability version */
1148d59ecb2SHans Petter Selasky #define	PCI_EXP_TYPE_ROOT_PORT	PCIEM_TYPE_ROOT_PORT		/* Root Port */
1158d59ecb2SHans Petter Selasky #define	PCI_EXP_TYPE_ENDPOINT	PCIEM_TYPE_ENDPOINT		/* Express Endpoint */
1168d59ecb2SHans Petter Selasky #define	PCI_EXP_TYPE_LEG_END	PCIEM_TYPE_LEGACY_ENDPOINT	/* Legacy Endpoint */
1178d59ecb2SHans Petter Selasky #define	PCI_EXP_TYPE_DOWNSTREAM PCIEM_TYPE_DOWNSTREAM_PORT	/* Downstream Port */
1188d59ecb2SHans Petter Selasky #define	PCI_EXP_FLAGS_SLOT	PCIEM_FLAGS_SLOT		/* Slot implemented */
1198d59ecb2SHans Petter Selasky #define	PCI_EXP_TYPE_RC_EC	PCIEM_TYPE_ROOT_EC		/* Root Complex Event Collector */
120a65ef215SHans Petter Selasky #define	PCI_EXP_LNKCAP_SLS_2_5GB 0x01	/* Supported Link Speed 2.5GT/s */
121a65ef215SHans Petter Selasky #define	PCI_EXP_LNKCAP_SLS_5_0GB 0x02	/* Supported Link Speed 5.0GT/s */
122ab62989aSHans Petter Selasky #define	PCI_EXP_LNKCAP_SLS_8_0GB 0x04	/* Supported Link Speed 8.0GT/s */
123ab62989aSHans Petter Selasky #define	PCI_EXP_LNKCAP_SLS_16_0GB 0x08	/* Supported Link Speed 16.0GT/s */
124a65ef215SHans Petter Selasky #define	PCI_EXP_LNKCAP_MLW	0x03f0	/* Maximum Link Width */
125a65ef215SHans Petter Selasky #define	PCI_EXP_LNKCAP2_SLS_2_5GB 0x02	/* Supported Link Speed 2.5GT/s */
126a65ef215SHans Petter Selasky #define	PCI_EXP_LNKCAP2_SLS_5_0GB 0x04	/* Supported Link Speed 5.0GT/s */
127a65ef215SHans Petter Selasky #define	PCI_EXP_LNKCAP2_SLS_8_0GB 0x08	/* Supported Link Speed 8.0GT/s */
128ab62989aSHans Petter Selasky #define	PCI_EXP_LNKCAP2_SLS_16_0GB 0x10	/* Supported Link Speed 16.0GT/s */
1298d59ecb2SHans Petter Selasky 
13012af734dSHans Petter Selasky #define PCI_EXP_LNKCTL_HAWD	PCIEM_LINK_CTL_HAWD
13112af734dSHans Petter Selasky #define PCI_EXP_LNKCAP_CLKPM	0x00040000
13212af734dSHans Petter Selasky #define PCI_EXP_DEVSTA_TRPND	0x0020
13312af734dSHans Petter Selasky 
134bdff61f8SHans Petter Selasky #define	IORESOURCE_MEM	(1 << SYS_RES_MEMORY)
135bdff61f8SHans Petter Selasky #define	IORESOURCE_IO	(1 << SYS_RES_IOPORT)
136bdff61f8SHans Petter Selasky #define	IORESOURCE_IRQ	(1 << SYS_RES_IRQ)
1378d59ecb2SHans Petter Selasky 
138a65ef215SHans Petter Selasky enum pci_bus_speed {
139a65ef215SHans Petter Selasky 	PCI_SPEED_UNKNOWN = -1,
140a65ef215SHans Petter Selasky 	PCIE_SPEED_2_5GT,
141a65ef215SHans Petter Selasky 	PCIE_SPEED_5_0GT,
142a65ef215SHans Petter Selasky 	PCIE_SPEED_8_0GT,
143ab62989aSHans Petter Selasky 	PCIE_SPEED_16_0GT,
144a65ef215SHans Petter Selasky };
1458d59ecb2SHans Petter Selasky 
146a65ef215SHans Petter Selasky enum pcie_link_width {
147ab62989aSHans Petter Selasky 	PCIE_LNK_WIDTH_RESRV	= 0x00,
148ab62989aSHans Petter Selasky 	PCIE_LNK_X1		= 0x01,
149ab62989aSHans Petter Selasky 	PCIE_LNK_X2		= 0x02,
150ab62989aSHans Petter Selasky 	PCIE_LNK_X4		= 0x04,
151ab62989aSHans Petter Selasky 	PCIE_LNK_X8		= 0x08,
152ab62989aSHans Petter Selasky 	PCIE_LNK_X12		= 0x0c,
153ab62989aSHans Petter Selasky 	PCIE_LNK_X16		= 0x10,
154ab62989aSHans Petter Selasky 	PCIE_LNK_X32		= 0x20,
155ab62989aSHans Petter Selasky 	PCIE_LNK_WIDTH_UNKNOWN	= 0xff,
156a65ef215SHans Petter Selasky };
157a65ef215SHans Petter Selasky 
158fc1d8409SBjoern A. Zeeb #define	PCIE_LINK_STATE_L0S		0x00000001
159fc1d8409SBjoern A. Zeeb #define	PCIE_LINK_STATE_L1		0x00000002
160fc1d8409SBjoern A. Zeeb #define	PCIE_LINK_STATE_CLKPM		0x00000004
161fc1d8409SBjoern A. Zeeb 
16212af734dSHans Petter Selasky typedef int pci_power_t;
16312af734dSHans Petter Selasky 
16412af734dSHans Petter Selasky #define PCI_D0	PCI_POWERSTATE_D0
16512af734dSHans Petter Selasky #define PCI_D1	PCI_POWERSTATE_D1
16612af734dSHans Petter Selasky #define PCI_D2	PCI_POWERSTATE_D2
16712af734dSHans Petter Selasky #define PCI_D3hot	PCI_POWERSTATE_D3
16812af734dSHans Petter Selasky #define PCI_D3cold	4
16912af734dSHans Petter Selasky 
17012af734dSHans Petter Selasky #define PCI_POWER_ERROR	PCI_POWERSTATE_UNKNOWN
17112af734dSHans Petter Selasky 
172fc1d8409SBjoern A. Zeeb #define	PCI_ERR_ROOT_COMMAND		PCIR_AER_ROOTERR_CMD
173fc1d8409SBjoern A. Zeeb #define	PCI_ERR_ROOT_ERR_SRC		PCIR_AER_COR_SOURCE_ID
174fc1d8409SBjoern A. Zeeb 
175fc1d8409SBjoern A. Zeeb #define	PCI_EXT_CAP_ID_ERR		PCIZ_AER
176fc1d8409SBjoern A. Zeeb 
177a65ef215SHans Petter Selasky struct pci_dev;
1788d59ecb2SHans Petter Selasky 
1798d59ecb2SHans Petter Selasky struct pci_driver {
1808d59ecb2SHans Petter Selasky 	struct list_head		links;
1818d59ecb2SHans Petter Selasky 	char				*name;
1828d59ecb2SHans Petter Selasky 	const struct pci_device_id		*id_table;
1838d59ecb2SHans Petter Selasky 	int  (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
1848d59ecb2SHans Petter Selasky 	void (*remove)(struct pci_dev *dev);
1858d59ecb2SHans Petter Selasky 	int  (*suspend) (struct pci_dev *dev, pm_message_t state);	/* Device suspended */
1868d59ecb2SHans Petter Selasky 	int  (*resume) (struct pci_dev *dev);		/* Device woken up */
1877d133393SHans Petter Selasky 	void (*shutdown) (struct pci_dev *dev);		/* Device shutdown */
188b38dc0a1SMark Johnston 	driver_t			bsddriver;
1898d59ecb2SHans Petter Selasky 	devclass_t			bsdclass;
19088156ba5SMark Johnston 	struct device_driver		driver;
1918d59ecb2SHans Petter Selasky 	const struct pci_error_handlers       *err_handler;
1920b7bd01aSMark Johnston 	bool				isdrm;
1932928e60eSKonstantin Belousov 	int  (*bsd_iov_init)(device_t dev, uint16_t num_vfs,
1942928e60eSKonstantin Belousov 	    const nvlist_t *pf_config);
1952928e60eSKonstantin Belousov 	void  (*bsd_iov_uninit)(device_t dev);
1962928e60eSKonstantin Belousov 	int  (*bsd_iov_add_vf)(device_t dev, uint16_t vfnum,
1972928e60eSKonstantin Belousov 	    const nvlist_t *vf_config);
1980b7bd01aSMark Johnston };
1990b7bd01aSMark Johnston 
2000b7bd01aSMark Johnston struct pci_bus {
2010b7bd01aSMark Johnston 	struct pci_dev	*self;
202937a05baSJustin Hibbits 	int		domain;
2030b7bd01aSMark Johnston 	int		number;
2048d59ecb2SHans Petter Selasky };
2058d59ecb2SHans Petter Selasky 
2068d59ecb2SHans Petter Selasky extern struct list_head pci_drivers;
2078d59ecb2SHans Petter Selasky extern struct list_head pci_devices;
2088d59ecb2SHans Petter Selasky extern spinlock_t pci_lock;
2098d59ecb2SHans Petter Selasky 
2108d59ecb2SHans Petter Selasky #define	__devexit_p(x)	x
2118d59ecb2SHans Petter Selasky 
2124c274849SEmmanuel Vadot struct pci_mmio_region {
2134c274849SEmmanuel Vadot 	TAILQ_ENTRY(pci_mmio_region)	next;
2144c274849SEmmanuel Vadot 	struct resource			*res;
2154c274849SEmmanuel Vadot 	int				rid;
2164c274849SEmmanuel Vadot 	int				type;
2174c274849SEmmanuel Vadot };
2184c274849SEmmanuel Vadot 
2198d59ecb2SHans Petter Selasky struct pci_dev {
2208d59ecb2SHans Petter Selasky 	struct device		dev;
2218d59ecb2SHans Petter Selasky 	struct list_head	links;
2228d59ecb2SHans Petter Selasky 	struct pci_driver	*pdrv;
2230b7bd01aSMark Johnston 	struct pci_bus		*bus;
2248e106c52SBjoern A. Zeeb 	struct pci_dev		*root;
2258d59ecb2SHans Petter Selasky 	uint16_t		device;
2268d59ecb2SHans Petter Selasky 	uint16_t		vendor;
227f2ec04a3SMark Johnston 	uint16_t		subsystem_vendor;
228f2ec04a3SMark Johnston 	uint16_t		subsystem_device;
2298d59ecb2SHans Petter Selasky 	unsigned int		irq;
2308d59ecb2SHans Petter Selasky 	unsigned int		devfn;
2316373e95eSMark Johnston 	uint32_t		class;
2326373e95eSMark Johnston 	uint8_t			revision;
2334f109faaSHans Petter Selasky 	bool			msi_enabled;
234096104e7SNeel Chauhan 	phys_addr_t		rom;
235096104e7SNeel Chauhan 	size_t			romlen;
2364c274849SEmmanuel Vadot 
2374c274849SEmmanuel Vadot 	TAILQ_HEAD(, pci_mmio_region)	mmio;
2388d59ecb2SHans Petter Selasky };
2398d59ecb2SHans Petter Selasky 
2408e106c52SBjoern A. Zeeb /* Internal helper function(s). */
2418e106c52SBjoern A. Zeeb struct pci_dev *lkpinew_pci_dev(device_t);
2428e106c52SBjoern A. Zeeb 
2438e106c52SBjoern A. Zeeb 
2448d59ecb2SHans Petter Selasky static inline struct resource_list_entry *
245e996b07cSHans Petter Selasky linux_pci_get_rle(struct pci_dev *pdev, int type, int rid)
2468d59ecb2SHans Petter Selasky {
2478d59ecb2SHans Petter Selasky 	struct pci_devinfo *dinfo;
2488d59ecb2SHans Petter Selasky 	struct resource_list *rl;
2498d59ecb2SHans Petter Selasky 
2508d59ecb2SHans Petter Selasky 	dinfo = device_get_ivars(pdev->dev.bsddev);
2518d59ecb2SHans Petter Selasky 	rl = &dinfo->resources;
2528d59ecb2SHans Petter Selasky 	return resource_list_find(rl, type, rid);
2538d59ecb2SHans Petter Selasky }
2548d59ecb2SHans Petter Selasky 
2558d59ecb2SHans Petter Selasky static inline struct resource_list_entry *
256e996b07cSHans Petter Selasky linux_pci_get_bar(struct pci_dev *pdev, int bar)
2578d59ecb2SHans Petter Selasky {
2588d59ecb2SHans Petter Selasky 	struct resource_list_entry *rle;
2598d59ecb2SHans Petter Selasky 
2608d59ecb2SHans Petter Selasky 	bar = PCIR_BAR(bar);
261e996b07cSHans Petter Selasky 	if ((rle = linux_pci_get_rle(pdev, SYS_RES_MEMORY, bar)) == NULL)
262e996b07cSHans Petter Selasky 		rle = linux_pci_get_rle(pdev, SYS_RES_IOPORT, bar);
2638d59ecb2SHans Petter Selasky 	return (rle);
2648d59ecb2SHans Petter Selasky }
2658d59ecb2SHans Petter Selasky 
2668d59ecb2SHans Petter Selasky static inline struct device *
267e996b07cSHans Petter Selasky linux_pci_find_irq_dev(unsigned int irq)
2688d59ecb2SHans Petter Selasky {
2698d59ecb2SHans Petter Selasky 	struct pci_dev *pdev;
2702f02a9e1SConrad Meyer 	struct device *found;
2718d59ecb2SHans Petter Selasky 
2722f02a9e1SConrad Meyer 	found = NULL;
2738d59ecb2SHans Petter Selasky 	spin_lock(&pci_lock);
2748d59ecb2SHans Petter Selasky 	list_for_each_entry(pdev, &pci_devices, links) {
2752f02a9e1SConrad Meyer 		if (irq == pdev->dev.irq ||
2764f109faaSHans Petter Selasky 		    (irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) {
2772f02a9e1SConrad Meyer 			found = &pdev->dev;
2788d59ecb2SHans Petter Selasky 			break;
2798d59ecb2SHans Petter Selasky 		}
2802f02a9e1SConrad Meyer 	}
2818d59ecb2SHans Petter Selasky 	spin_unlock(&pci_lock);
2822f02a9e1SConrad Meyer 	return (found);
2838d59ecb2SHans Petter Selasky }
2848d59ecb2SHans Petter Selasky 
285bdff61f8SHans Petter Selasky static inline int
286bdff61f8SHans Petter Selasky pci_resource_type(struct pci_dev *pdev, int bar)
287bdff61f8SHans Petter Selasky {
2886faefea0SSepherosa Ziehau 	struct pci_map *pm;
289bdff61f8SHans Petter Selasky 
2906faefea0SSepherosa Ziehau 	pm = pci_find_bar(pdev->dev.bsddev, PCIR_BAR(bar));
2916faefea0SSepherosa Ziehau 	if (!pm)
292bdff61f8SHans Petter Selasky 		return (-1);
2936faefea0SSepherosa Ziehau 
2946faefea0SSepherosa Ziehau 	if (PCI_BAR_IO(pm->pm_value))
2956faefea0SSepherosa Ziehau 		return (SYS_RES_IOPORT);
2966faefea0SSepherosa Ziehau 	else
2976faefea0SSepherosa Ziehau 		return (SYS_RES_MEMORY);
298bdff61f8SHans Petter Selasky }
299bdff61f8SHans Petter Selasky 
3008d59ecb2SHans Petter Selasky /*
3018d59ecb2SHans Petter Selasky  * All drivers just seem to want to inspect the type not flags.
3028d59ecb2SHans Petter Selasky  */
3038d59ecb2SHans Petter Selasky static inline int
3048d59ecb2SHans Petter Selasky pci_resource_flags(struct pci_dev *pdev, int bar)
3058d59ecb2SHans Petter Selasky {
306bdff61f8SHans Petter Selasky 	int type;
3078d59ecb2SHans Petter Selasky 
308bdff61f8SHans Petter Selasky 	type = pci_resource_type(pdev, bar);
309bdff61f8SHans Petter Selasky 	if (type < 0)
3108d59ecb2SHans Petter Selasky 		return (0);
311bdff61f8SHans Petter Selasky 	return (1 << type);
3128d59ecb2SHans Petter Selasky }
3138d59ecb2SHans Petter Selasky 
3148d59ecb2SHans Petter Selasky static inline const char *
3158d59ecb2SHans Petter Selasky pci_name(struct pci_dev *d)
3168d59ecb2SHans Petter Selasky {
3178d59ecb2SHans Petter Selasky 
3188d59ecb2SHans Petter Selasky 	return device_get_desc(d->dev.bsddev);
3198d59ecb2SHans Petter Selasky }
3208d59ecb2SHans Petter Selasky 
3218d59ecb2SHans Petter Selasky static inline void *
3228d59ecb2SHans Petter Selasky pci_get_drvdata(struct pci_dev *pdev)
3238d59ecb2SHans Petter Selasky {
3248d59ecb2SHans Petter Selasky 
3258d59ecb2SHans Petter Selasky 	return dev_get_drvdata(&pdev->dev);
3268d59ecb2SHans Petter Selasky }
3278d59ecb2SHans Petter Selasky 
3288d59ecb2SHans Petter Selasky static inline void
3298d59ecb2SHans Petter Selasky pci_set_drvdata(struct pci_dev *pdev, void *data)
3308d59ecb2SHans Petter Selasky {
3318d59ecb2SHans Petter Selasky 
3328d59ecb2SHans Petter Selasky 	dev_set_drvdata(&pdev->dev, data);
3338d59ecb2SHans Petter Selasky }
3348d59ecb2SHans Petter Selasky 
3358e106c52SBjoern A. Zeeb static inline struct pci_dev *
3368e106c52SBjoern A. Zeeb pci_dev_get(struct pci_dev *pdev)
3378e106c52SBjoern A. Zeeb {
3388e106c52SBjoern A. Zeeb 
3398e106c52SBjoern A. Zeeb 	if (pdev != NULL)
3408e106c52SBjoern A. Zeeb 		get_device(&pdev->dev);
3418e106c52SBjoern A. Zeeb 	return (pdev);
3428e106c52SBjoern A. Zeeb }
3438e106c52SBjoern A. Zeeb 
3441fac2cb4SBjoern A. Zeeb static __inline void
3451fac2cb4SBjoern A. Zeeb pci_dev_put(struct pci_dev *pdev)
3461fac2cb4SBjoern A. Zeeb {
3471fac2cb4SBjoern A. Zeeb 
3481fac2cb4SBjoern A. Zeeb 	if (pdev != NULL)
3491fac2cb4SBjoern A. Zeeb 		put_device(&pdev->dev);
3501fac2cb4SBjoern A. Zeeb }
3511fac2cb4SBjoern A. Zeeb 
3528d59ecb2SHans Petter Selasky static inline int
3538d59ecb2SHans Petter Selasky pci_enable_device(struct pci_dev *pdev)
3548d59ecb2SHans Petter Selasky {
3558d59ecb2SHans Petter Selasky 
3568d59ecb2SHans Petter Selasky 	pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT);
3578d59ecb2SHans Petter Selasky 	pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY);
3588d59ecb2SHans Petter Selasky 	return (0);
3598d59ecb2SHans Petter Selasky }
3608d59ecb2SHans Petter Selasky 
3618d59ecb2SHans Petter Selasky static inline void
3628d59ecb2SHans Petter Selasky pci_disable_device(struct pci_dev *pdev)
3638d59ecb2SHans Petter Selasky {
364f67b5de7SMark Johnston 
365555deb3cSHans Petter Selasky 	pci_disable_busmaster(pdev->dev.bsddev);
3668d59ecb2SHans Petter Selasky }
3678d59ecb2SHans Petter Selasky 
3688d59ecb2SHans Petter Selasky static inline int
3698d59ecb2SHans Petter Selasky pci_set_master(struct pci_dev *pdev)
3708d59ecb2SHans Petter Selasky {
3718d59ecb2SHans Petter Selasky 
3728d59ecb2SHans Petter Selasky 	pci_enable_busmaster(pdev->dev.bsddev);
3738d59ecb2SHans Petter Selasky 	return (0);
3748d59ecb2SHans Petter Selasky }
3758d59ecb2SHans Petter Selasky 
3768d59ecb2SHans Petter Selasky static inline int
37712af734dSHans Petter Selasky pci_set_power_state(struct pci_dev *pdev, int state)
37812af734dSHans Petter Selasky {
37912af734dSHans Petter Selasky 
38012af734dSHans Petter Selasky 	pci_set_powerstate(pdev->dev.bsddev, state);
38112af734dSHans Petter Selasky 	return (0);
38212af734dSHans Petter Selasky }
38312af734dSHans Petter Selasky 
38412af734dSHans Petter Selasky static inline int
3858d59ecb2SHans Petter Selasky pci_clear_master(struct pci_dev *pdev)
3868d59ecb2SHans Petter Selasky {
3878d59ecb2SHans Petter Selasky 
3888d59ecb2SHans Petter Selasky 	pci_disable_busmaster(pdev->dev.bsddev);
3898d59ecb2SHans Petter Selasky 	return (0);
3908d59ecb2SHans Petter Selasky }
3918d59ecb2SHans Petter Selasky 
3928d59ecb2SHans Petter Selasky static inline int
3938d59ecb2SHans Petter Selasky pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
3948d59ecb2SHans Petter Selasky {
3958d59ecb2SHans Petter Selasky 	int rid;
3968d59ecb2SHans Petter Selasky 	int type;
3978d59ecb2SHans Petter Selasky 
398bdff61f8SHans Petter Selasky 	type = pci_resource_type(pdev, bar);
399bdff61f8SHans Petter Selasky 	if (type < 0)
4008d59ecb2SHans Petter Selasky 		return (-ENODEV);
4018d59ecb2SHans Petter Selasky 	rid = PCIR_BAR(bar);
4028d59ecb2SHans Petter Selasky 	if (bus_alloc_resource_any(pdev->dev.bsddev, type, &rid,
4038d59ecb2SHans Petter Selasky 	    RF_ACTIVE) == NULL)
4048d59ecb2SHans Petter Selasky 		return (-EINVAL);
4058d59ecb2SHans Petter Selasky 	return (0);
4068d59ecb2SHans Petter Selasky }
4078d59ecb2SHans Petter Selasky 
4088d59ecb2SHans Petter Selasky static inline void
4098d59ecb2SHans Petter Selasky pci_release_region(struct pci_dev *pdev, int bar)
4108d59ecb2SHans Petter Selasky {
4118d59ecb2SHans Petter Selasky 	struct resource_list_entry *rle;
4128d59ecb2SHans Petter Selasky 
413e996b07cSHans Petter Selasky 	if ((rle = linux_pci_get_bar(pdev, bar)) == NULL)
4148d59ecb2SHans Petter Selasky 		return;
4158d59ecb2SHans Petter Selasky 	bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res);
4168d59ecb2SHans Petter Selasky }
4178d59ecb2SHans Petter Selasky 
4188d59ecb2SHans Petter Selasky static inline void
4198d59ecb2SHans Petter Selasky pci_release_regions(struct pci_dev *pdev)
4208d59ecb2SHans Petter Selasky {
4218d59ecb2SHans Petter Selasky 	int i;
4228d59ecb2SHans Petter Selasky 
4238d59ecb2SHans Petter Selasky 	for (i = 0; i <= PCIR_MAX_BAR_0; i++)
4248d59ecb2SHans Petter Selasky 		pci_release_region(pdev, i);
4258d59ecb2SHans Petter Selasky }
4268d59ecb2SHans Petter Selasky 
4278d59ecb2SHans Petter Selasky static inline int
4288d59ecb2SHans Petter Selasky pci_request_regions(struct pci_dev *pdev, const char *res_name)
4298d59ecb2SHans Petter Selasky {
4308d59ecb2SHans Petter Selasky 	int error;
4318d59ecb2SHans Petter Selasky 	int i;
4328d59ecb2SHans Petter Selasky 
4338d59ecb2SHans Petter Selasky 	for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
4348d59ecb2SHans Petter Selasky 		error = pci_request_region(pdev, i, res_name);
4358d59ecb2SHans Petter Selasky 		if (error && error != -ENODEV) {
4368d59ecb2SHans Petter Selasky 			pci_release_regions(pdev);
4378d59ecb2SHans Petter Selasky 			return (error);
4388d59ecb2SHans Petter Selasky 		}
4398d59ecb2SHans Petter Selasky 	}
4408d59ecb2SHans Petter Selasky 	return (0);
4418d59ecb2SHans Petter Selasky }
4428d59ecb2SHans Petter Selasky 
4438d59ecb2SHans Petter Selasky static inline void
4448d59ecb2SHans Petter Selasky pci_disable_msix(struct pci_dev *pdev)
4458d59ecb2SHans Petter Selasky {
4468d59ecb2SHans Petter Selasky 
4478d59ecb2SHans Petter Selasky 	pci_release_msi(pdev->dev.bsddev);
448e1992aa1SHans Petter Selasky 
449e1992aa1SHans Petter Selasky 	/*
450e1992aa1SHans Petter Selasky 	 * The MSIX IRQ numbers associated with this PCI device are no
451e1992aa1SHans Petter Selasky 	 * longer valid and might be re-assigned. Make sure
452e1992aa1SHans Petter Selasky 	 * linux_pci_find_irq_dev() does no longer see them by
453e1992aa1SHans Petter Selasky 	 * resetting their references to zero:
454e1992aa1SHans Petter Selasky 	 */
4554f109faaSHans Petter Selasky 	pdev->dev.irq_start = 0;
4564f109faaSHans Petter Selasky 	pdev->dev.irq_end = 0;
4574f109faaSHans Petter Selasky }
4584f109faaSHans Petter Selasky 
4594f109faaSHans Petter Selasky #define	pci_disable_msi(pdev) \
4604f109faaSHans Petter Selasky   linux_pci_disable_msi(pdev)
4614f109faaSHans Petter Selasky 
4624f109faaSHans Petter Selasky static inline void
4634f109faaSHans Petter Selasky linux_pci_disable_msi(struct pci_dev *pdev)
4644f109faaSHans Petter Selasky {
4654f109faaSHans Petter Selasky 
4664f109faaSHans Petter Selasky 	pci_release_msi(pdev->dev.bsddev);
4674f109faaSHans Petter Selasky 
4684f109faaSHans Petter Selasky 	pdev->dev.irq_start = 0;
4694f109faaSHans Petter Selasky 	pdev->dev.irq_end = 0;
4704f109faaSHans Petter Selasky 	pdev->irq = pdev->dev.irq;
4714f109faaSHans Petter Selasky 	pdev->msi_enabled = false;
4728d59ecb2SHans Petter Selasky }
4738d59ecb2SHans Petter Selasky 
474105a37caSEmmanuel Vadot #define	pci_free_irq_vectors(pdev) \
475105a37caSEmmanuel Vadot 	linux_pci_disable_msi(pdev)
476105a37caSEmmanuel Vadot 
477937a05baSJustin Hibbits unsigned long	pci_resource_start(struct pci_dev *pdev, int bar);
478937a05baSJustin Hibbits unsigned long	pci_resource_len(struct pci_dev *pdev, int bar);
479937a05baSJustin Hibbits 
48012af734dSHans Petter Selasky static inline bus_addr_t
48112af734dSHans Petter Selasky pci_bus_address(struct pci_dev *pdev, int bar)
48212af734dSHans Petter Selasky {
48312af734dSHans Petter Selasky 
48412af734dSHans Petter Selasky 	return (pci_resource_start(pdev, bar));
48512af734dSHans Petter Selasky }
48612af734dSHans Petter Selasky 
4878d59ecb2SHans Petter Selasky #define	PCI_CAP_ID_EXP	PCIY_EXPRESS
4888d59ecb2SHans Petter Selasky #define	PCI_CAP_ID_PCIX	PCIY_PCIX
48912af734dSHans Petter Selasky #define PCI_CAP_ID_AGP  PCIY_AGP
49012af734dSHans Petter Selasky #define PCI_CAP_ID_PM   PCIY_PMG
4918d59ecb2SHans Petter Selasky 
49212af734dSHans Petter Selasky #define PCI_EXP_DEVCTL		PCIER_DEVICE_CTL
49312af734dSHans Petter Selasky #define PCI_EXP_DEVCTL_PAYLOAD	PCIEM_CTL_MAX_PAYLOAD
49412af734dSHans Petter Selasky #define PCI_EXP_DEVCTL_READRQ	PCIEM_CTL_MAX_READ_REQUEST
49512af734dSHans Petter Selasky #define PCI_EXP_LNKCTL		PCIER_LINK_CTL
49612af734dSHans Petter Selasky #define PCI_EXP_LNKSTA		PCIER_LINK_STA
4978d59ecb2SHans Petter Selasky 
4988d59ecb2SHans Petter Selasky static inline int
4998d59ecb2SHans Petter Selasky pci_find_capability(struct pci_dev *pdev, int capid)
5008d59ecb2SHans Petter Selasky {
5018d59ecb2SHans Petter Selasky 	int reg;
5028d59ecb2SHans Petter Selasky 
5038d59ecb2SHans Petter Selasky 	if (pci_find_cap(pdev->dev.bsddev, capid, &reg))
5048d59ecb2SHans Petter Selasky 		return (0);
5058d59ecb2SHans Petter Selasky 	return (reg);
5068d59ecb2SHans Petter Selasky }
5078d59ecb2SHans Petter Selasky 
5088d59ecb2SHans Petter Selasky static inline int pci_pcie_cap(struct pci_dev *dev)
5098d59ecb2SHans Petter Selasky {
5108d59ecb2SHans Petter Selasky 	return pci_find_capability(dev, PCI_CAP_ID_EXP);
5118d59ecb2SHans Petter Selasky }
5128d59ecb2SHans Petter Selasky 
5138d59ecb2SHans Petter Selasky static inline int
5148e106c52SBjoern A. Zeeb pci_find_ext_capability(struct pci_dev *pdev, int capid)
5158e106c52SBjoern A. Zeeb {
5168e106c52SBjoern A. Zeeb 	int reg;
5178e106c52SBjoern A. Zeeb 
5188e106c52SBjoern A. Zeeb 	if (pci_find_extcap(pdev->dev.bsddev, capid, &reg))
5198e106c52SBjoern A. Zeeb 		return (0);
5208e106c52SBjoern A. Zeeb 	return (reg);
5218e106c52SBjoern A. Zeeb }
5228e106c52SBjoern A. Zeeb 
5238e106c52SBjoern A. Zeeb #define	PCIM_PCAP_PME_SHIFT	11
5248e106c52SBjoern A. Zeeb static __inline bool
5258e106c52SBjoern A. Zeeb pci_pme_capable(struct pci_dev *pdev, uint32_t flag)
5268e106c52SBjoern A. Zeeb {
5278e106c52SBjoern A. Zeeb 	struct pci_devinfo *dinfo;
5288e106c52SBjoern A. Zeeb 	pcicfgregs *cfg;
5298e106c52SBjoern A. Zeeb 
5308e106c52SBjoern A. Zeeb 	if (flag > (PCIM_PCAP_D3PME_COLD >> PCIM_PCAP_PME_SHIFT))
5318e106c52SBjoern A. Zeeb 		return (false);
5328e106c52SBjoern A. Zeeb 
5338e106c52SBjoern A. Zeeb 	dinfo = device_get_ivars(pdev->dev.bsddev);
5348e106c52SBjoern A. Zeeb 	cfg = &dinfo->cfg;
5358e106c52SBjoern A. Zeeb 
5368e106c52SBjoern A. Zeeb 	if (cfg->pp.pp_cap == 0)
5378e106c52SBjoern A. Zeeb 		return (false);
5388e106c52SBjoern A. Zeeb 
5398e106c52SBjoern A. Zeeb 	if ((cfg->pp.pp_cap & (1 << (PCIM_PCAP_PME_SHIFT + flag))) != 0)
5408e106c52SBjoern A. Zeeb 		return (true);
5418e106c52SBjoern A. Zeeb 
5428e106c52SBjoern A. Zeeb 	return (false);
5438e106c52SBjoern A. Zeeb }
5448e106c52SBjoern A. Zeeb 
5458e106c52SBjoern A. Zeeb static inline int
5468e106c52SBjoern A. Zeeb pci_disable_link_state(struct pci_dev *pdev, uint32_t flags)
5478e106c52SBjoern A. Zeeb {
5488e106c52SBjoern A. Zeeb 
5498e106c52SBjoern A. Zeeb 	if (!pci_enable_aspm)
5508e106c52SBjoern A. Zeeb 		return (-EPERM);
5518e106c52SBjoern A. Zeeb 
5528e106c52SBjoern A. Zeeb 	return (-ENXIO);
5538e106c52SBjoern A. Zeeb }
5548e106c52SBjoern A. Zeeb 
5558e106c52SBjoern A. Zeeb static inline int
5568d59ecb2SHans Petter Selasky pci_read_config_byte(struct pci_dev *pdev, int where, u8 *val)
5578d59ecb2SHans Petter Selasky {
5588d59ecb2SHans Petter Selasky 
5598d59ecb2SHans Petter Selasky 	*val = (u8)pci_read_config(pdev->dev.bsddev, where, 1);
5608d59ecb2SHans Petter Selasky 	return (0);
5618d59ecb2SHans Petter Selasky }
5628d59ecb2SHans Petter Selasky 
5638d59ecb2SHans Petter Selasky static inline int
5648d59ecb2SHans Petter Selasky pci_read_config_word(struct pci_dev *pdev, int where, u16 *val)
5658d59ecb2SHans Petter Selasky {
5668d59ecb2SHans Petter Selasky 
5678d59ecb2SHans Petter Selasky 	*val = (u16)pci_read_config(pdev->dev.bsddev, where, 2);
5688d59ecb2SHans Petter Selasky 	return (0);
5698d59ecb2SHans Petter Selasky }
5708d59ecb2SHans Petter Selasky 
5718d59ecb2SHans Petter Selasky static inline int
5728d59ecb2SHans Petter Selasky pci_read_config_dword(struct pci_dev *pdev, int where, u32 *val)
5738d59ecb2SHans Petter Selasky {
5748d59ecb2SHans Petter Selasky 
5758d59ecb2SHans Petter Selasky 	*val = (u32)pci_read_config(pdev->dev.bsddev, where, 4);
5768d59ecb2SHans Petter Selasky 	return (0);
5778d59ecb2SHans Petter Selasky }
5788d59ecb2SHans Petter Selasky 
5798d59ecb2SHans Petter Selasky static inline int
5808d59ecb2SHans Petter Selasky pci_write_config_byte(struct pci_dev *pdev, int where, u8 val)
5818d59ecb2SHans Petter Selasky {
5828d59ecb2SHans Petter Selasky 
5838d59ecb2SHans Petter Selasky 	pci_write_config(pdev->dev.bsddev, where, val, 1);
5848d59ecb2SHans Petter Selasky 	return (0);
5858d59ecb2SHans Petter Selasky }
5868d59ecb2SHans Petter Selasky 
5878d59ecb2SHans Petter Selasky static inline int
5888d59ecb2SHans Petter Selasky pci_write_config_word(struct pci_dev *pdev, int where, u16 val)
5898d59ecb2SHans Petter Selasky {
5908d59ecb2SHans Petter Selasky 
5918d59ecb2SHans Petter Selasky 	pci_write_config(pdev->dev.bsddev, where, val, 2);
5928d59ecb2SHans Petter Selasky 	return (0);
5938d59ecb2SHans Petter Selasky }
5948d59ecb2SHans Petter Selasky 
5958d59ecb2SHans Petter Selasky static inline int
5968d59ecb2SHans Petter Selasky pci_write_config_dword(struct pci_dev *pdev, int where, u32 val)
5978d59ecb2SHans Petter Selasky {
5988d59ecb2SHans Petter Selasky 
5998d59ecb2SHans Petter Selasky 	pci_write_config(pdev->dev.bsddev, where, val, 4);
6008d59ecb2SHans Petter Selasky 	return (0);
6018d59ecb2SHans Petter Selasky }
6028d59ecb2SHans Petter Selasky 
6030b7bd01aSMark Johnston int	linux_pci_register_driver(struct pci_driver *pdrv);
6040b7bd01aSMark Johnston int	linux_pci_register_drm_driver(struct pci_driver *pdrv);
6050b7bd01aSMark Johnston void	linux_pci_unregister_driver(struct pci_driver *pdrv);
6065098ed5fSJohannes Lundberg void	linux_pci_unregister_drm_driver(struct pci_driver *pdrv);
6070b7bd01aSMark Johnston 
6080b7bd01aSMark Johnston #define	pci_register_driver(pdrv)	linux_pci_register_driver(pdrv)
6090b7bd01aSMark Johnston #define	pci_unregister_driver(pdrv)	linux_pci_unregister_driver(pdrv)
6108d59ecb2SHans Petter Selasky 
6118d59ecb2SHans Petter Selasky struct msix_entry {
6128d59ecb2SHans Petter Selasky 	int entry;
6138d59ecb2SHans Petter Selasky 	int vector;
6148d59ecb2SHans Petter Selasky };
6158d59ecb2SHans Petter Selasky 
6168d59ecb2SHans Petter Selasky /*
6178d59ecb2SHans Petter Selasky  * Enable msix, positive errors indicate actual number of available
6188d59ecb2SHans Petter Selasky  * vectors.  Negative errors are failures.
6198d59ecb2SHans Petter Selasky  *
6208d59ecb2SHans Petter Selasky  * NB: define added to prevent this definition of pci_enable_msix from
6218d59ecb2SHans Petter Selasky  * clashing with the native FreeBSD version.
6228d59ecb2SHans Petter Selasky  */
623fa0d4f31SHans Petter Selasky #define	pci_enable_msix(...) \
624fa0d4f31SHans Petter Selasky   linux_pci_enable_msix(__VA_ARGS__)
625fa0d4f31SHans Petter Selasky 
6268d59ecb2SHans Petter Selasky static inline int
6278d59ecb2SHans Petter Selasky pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
6288d59ecb2SHans Petter Selasky {
6298d59ecb2SHans Petter Selasky 	struct resource_list_entry *rle;
6308d59ecb2SHans Petter Selasky 	int error;
6318d59ecb2SHans Petter Selasky 	int avail;
6328d59ecb2SHans Petter Selasky 	int i;
6338d59ecb2SHans Petter Selasky 
6348d59ecb2SHans Petter Selasky 	avail = pci_msix_count(pdev->dev.bsddev);
6358d59ecb2SHans Petter Selasky 	if (avail < nreq) {
6368d59ecb2SHans Petter Selasky 		if (avail == 0)
6378d59ecb2SHans Petter Selasky 			return -EINVAL;
6388d59ecb2SHans Petter Selasky 		return avail;
6398d59ecb2SHans Petter Selasky 	}
6408d59ecb2SHans Petter Selasky 	avail = nreq;
6418d59ecb2SHans Petter Selasky 	if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
6428d59ecb2SHans Petter Selasky 		return error;
6438d59ecb2SHans Petter Selasky 	/*
6448d59ecb2SHans Petter Selasky 	 * Handle case where "pci_alloc_msix()" may allocate less
6458d59ecb2SHans Petter Selasky 	 * interrupts than available and return with no error:
6468d59ecb2SHans Petter Selasky 	 */
6478d59ecb2SHans Petter Selasky 	if (avail < nreq) {
6488d59ecb2SHans Petter Selasky 		pci_release_msi(pdev->dev.bsddev);
6498d59ecb2SHans Petter Selasky 		return avail;
6508d59ecb2SHans Petter Selasky 	}
651e996b07cSHans Petter Selasky 	rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1);
6524f109faaSHans Petter Selasky 	pdev->dev.irq_start = rle->start;
6534f109faaSHans Petter Selasky 	pdev->dev.irq_end = rle->start + avail;
6548d59ecb2SHans Petter Selasky 	for (i = 0; i < nreq; i++)
6554f109faaSHans Petter Selasky 		entries[i].vector = pdev->dev.irq_start + i;
6568d59ecb2SHans Petter Selasky 	return (0);
6578d59ecb2SHans Petter Selasky }
6588d59ecb2SHans Petter Selasky 
659fa0d4f31SHans Petter Selasky #define	pci_enable_msix_range(...) \
660fa0d4f31SHans Petter Selasky   linux_pci_enable_msix_range(__VA_ARGS__)
661fa0d4f31SHans Petter Selasky 
6628d59ecb2SHans Petter Selasky static inline int
6638d59ecb2SHans Petter Selasky pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
6648d59ecb2SHans Petter Selasky     int minvec, int maxvec)
6658d59ecb2SHans Petter Selasky {
6668d59ecb2SHans Petter Selasky 	int nvec = maxvec;
6678d59ecb2SHans Petter Selasky 	int rc;
6688d59ecb2SHans Petter Selasky 
6698d59ecb2SHans Petter Selasky 	if (maxvec < minvec)
6708d59ecb2SHans Petter Selasky 		return (-ERANGE);
6718d59ecb2SHans Petter Selasky 
6728d59ecb2SHans Petter Selasky 	do {
6738d59ecb2SHans Petter Selasky 		rc = pci_enable_msix(dev, entries, nvec);
6748d59ecb2SHans Petter Selasky 		if (rc < 0) {
6758d59ecb2SHans Petter Selasky 			return (rc);
6768d59ecb2SHans Petter Selasky 		} else if (rc > 0) {
6778d59ecb2SHans Petter Selasky 			if (rc < minvec)
6788d59ecb2SHans Petter Selasky 				return (-ENOSPC);
6798d59ecb2SHans Petter Selasky 			nvec = rc;
6808d59ecb2SHans Petter Selasky 		}
6818d59ecb2SHans Petter Selasky 	} while (rc);
6828d59ecb2SHans Petter Selasky 	return (nvec);
6838d59ecb2SHans Petter Selasky }
6848d59ecb2SHans Petter Selasky 
6854f109faaSHans Petter Selasky #define	pci_enable_msi(pdev) \
6864f109faaSHans Petter Selasky   linux_pci_enable_msi(pdev)
6874f109faaSHans Petter Selasky 
6884f109faaSHans Petter Selasky static inline int
6894f109faaSHans Petter Selasky pci_enable_msi(struct pci_dev *pdev)
6904f109faaSHans Petter Selasky {
6914f109faaSHans Petter Selasky 	struct resource_list_entry *rle;
6924f109faaSHans Petter Selasky 	int error;
6934f109faaSHans Petter Selasky 	int avail;
6944f109faaSHans Petter Selasky 
6954f109faaSHans Petter Selasky 	avail = pci_msi_count(pdev->dev.bsddev);
6964f109faaSHans Petter Selasky 	if (avail < 1)
6974f109faaSHans Petter Selasky 		return -EINVAL;
6984f109faaSHans Petter Selasky 
6994f109faaSHans Petter Selasky 	avail = 1;	/* this function only enable one MSI IRQ */
7004f109faaSHans Petter Selasky 	if ((error = -pci_alloc_msi(pdev->dev.bsddev, &avail)) != 0)
7014f109faaSHans Petter Selasky 		return error;
7024f109faaSHans Petter Selasky 
7034f109faaSHans Petter Selasky 	rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1);
7044f109faaSHans Petter Selasky 	pdev->dev.irq_start = rle->start;
7054f109faaSHans Petter Selasky 	pdev->dev.irq_end = rle->start + avail;
7064f109faaSHans Petter Selasky 	pdev->irq = rle->start;
7074f109faaSHans Petter Selasky 	pdev->msi_enabled = true;
7084f109faaSHans Petter Selasky 	return (0);
7094f109faaSHans Petter Selasky }
7104f109faaSHans Petter Selasky 
711452d59e1SSlava Shwartsman static inline int
712452d59e1SSlava Shwartsman pci_channel_offline(struct pci_dev *pdev)
7138d59ecb2SHans Petter Selasky {
714452d59e1SSlava Shwartsman 
715c5161386SHans Petter Selasky 	return (pci_read_config(pdev->dev.bsddev, PCIR_VENDOR, 2) == PCIV_INVALID);
7168d59ecb2SHans Petter Selasky }
7178d59ecb2SHans Petter Selasky 
7188d59ecb2SHans Petter Selasky static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
7198d59ecb2SHans Petter Selasky {
7208d59ecb2SHans Petter Selasky 	return -ENODEV;
7218d59ecb2SHans Petter Selasky }
7228d59ecb2SHans Petter Selasky static inline void pci_disable_sriov(struct pci_dev *dev)
7238d59ecb2SHans Petter Selasky {
7248d59ecb2SHans Petter Selasky }
7258d59ecb2SHans Petter Selasky 
7264c274849SEmmanuel Vadot static inline void *
7274c274849SEmmanuel Vadot pci_iomap(struct pci_dev *dev, int mmio_bar, int mmio_size __unused)
7284c274849SEmmanuel Vadot {
7294c274849SEmmanuel Vadot 	struct pci_mmio_region *mmio;
7304c274849SEmmanuel Vadot 
7314c274849SEmmanuel Vadot 	mmio = malloc(sizeof(*mmio), M_DEVBUF, M_WAITOK | M_ZERO);
7324c274849SEmmanuel Vadot 	mmio->rid = PCIR_BAR(mmio_bar);
7334c274849SEmmanuel Vadot 	mmio->type = pci_resource_type(dev, mmio_bar);
7344c274849SEmmanuel Vadot 	mmio->res = bus_alloc_resource_any(dev->dev.bsddev, mmio->type,
7354c274849SEmmanuel Vadot 	    &mmio->rid, RF_ACTIVE);
7364c274849SEmmanuel Vadot 	if (mmio->res == NULL) {
7374c274849SEmmanuel Vadot 		free(mmio, M_DEVBUF);
7384c274849SEmmanuel Vadot 		return (NULL);
7394c274849SEmmanuel Vadot 	}
7404c274849SEmmanuel Vadot 	TAILQ_INSERT_TAIL(&dev->mmio, mmio, next);
7414c274849SEmmanuel Vadot 
7424c274849SEmmanuel Vadot 	return ((void *)rman_get_bushandle(mmio->res));
7434c274849SEmmanuel Vadot }
7444c274849SEmmanuel Vadot 
7454c274849SEmmanuel Vadot static inline void
7464c274849SEmmanuel Vadot pci_iounmap(struct pci_dev *dev, void *res)
7474c274849SEmmanuel Vadot {
7484c274849SEmmanuel Vadot 	struct pci_mmio_region *mmio, *p;
7494c274849SEmmanuel Vadot 
7504c274849SEmmanuel Vadot 	TAILQ_FOREACH_SAFE(mmio, &dev->mmio, next, p) {
7514c274849SEmmanuel Vadot 		if (res != (void *)rman_get_bushandle(mmio->res))
7524c274849SEmmanuel Vadot 			continue;
7534c274849SEmmanuel Vadot 		bus_release_resource(dev->dev.bsddev,
7544c274849SEmmanuel Vadot 		    mmio->type, mmio->rid, mmio->res);
7554c274849SEmmanuel Vadot 		TAILQ_REMOVE(&dev->mmio, mmio, next);
7564c274849SEmmanuel Vadot 		free(mmio, M_DEVBUF);
7574c274849SEmmanuel Vadot 		return;
7584c274849SEmmanuel Vadot 	}
7594c274849SEmmanuel Vadot }
7604c274849SEmmanuel Vadot 
761105a37caSEmmanuel Vadot static inline void
762105a37caSEmmanuel Vadot lkpi_pci_save_state(struct pci_dev *pdev)
763105a37caSEmmanuel Vadot {
764105a37caSEmmanuel Vadot 
765105a37caSEmmanuel Vadot 	pci_save_state(pdev->dev.bsddev);
766105a37caSEmmanuel Vadot }
767105a37caSEmmanuel Vadot 
768105a37caSEmmanuel Vadot static inline void
769105a37caSEmmanuel Vadot lkpi_pci_restore_state(struct pci_dev *pdev)
770105a37caSEmmanuel Vadot {
771105a37caSEmmanuel Vadot 
772105a37caSEmmanuel Vadot 	pci_restore_state(pdev->dev.bsddev);
773105a37caSEmmanuel Vadot }
774105a37caSEmmanuel Vadot 
775105a37caSEmmanuel Vadot #define pci_save_state(dev)	lkpi_pci_save_state(dev)
776105a37caSEmmanuel Vadot #define pci_restore_state(dev)	lkpi_pci_restore_state(dev)
777105a37caSEmmanuel Vadot 
7788d59ecb2SHans Petter Selasky #define DEFINE_PCI_DEVICE_TABLE(_table) \
7798d59ecb2SHans Petter Selasky 	const struct pci_device_id _table[] __devinitdata
7808d59ecb2SHans Petter Selasky 
7818d59ecb2SHans Petter Selasky /* XXX This should not be necessary. */
7828d59ecb2SHans Petter Selasky #define	pcix_set_mmrbc(d, v)	0
7838d59ecb2SHans Petter Selasky #define	pcix_get_max_mmrbc(d)	0
7843f322b22SMark Johnston #define	pcie_set_readrq(d, v)	pci_set_max_read_req((d)->dev.bsddev, (v))
7858d59ecb2SHans Petter Selasky 
7868d59ecb2SHans Petter Selasky #define	PCI_DMA_BIDIRECTIONAL	0
7878d59ecb2SHans Petter Selasky #define	PCI_DMA_TODEVICE	1
7888d59ecb2SHans Petter Selasky #define	PCI_DMA_FROMDEVICE	2
7898d59ecb2SHans Petter Selasky #define	PCI_DMA_NONE		3
7908d59ecb2SHans Petter Selasky 
7918d59ecb2SHans Petter Selasky #define	pci_pool		dma_pool
7921724ded4SHans Petter Selasky #define	pci_pool_destroy(...)	dma_pool_destroy(__VA_ARGS__)
7931724ded4SHans Petter Selasky #define	pci_pool_alloc(...)	dma_pool_alloc(__VA_ARGS__)
7941724ded4SHans Petter Selasky #define	pci_pool_free(...)	dma_pool_free(__VA_ARGS__)
7958d59ecb2SHans Petter Selasky #define	pci_pool_create(_name, _pdev, _size, _align, _alloc)		\
7968d59ecb2SHans Petter Selasky 	    dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc)
7978d59ecb2SHans Petter Selasky #define	pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle)		\
7988d59ecb2SHans Petter Selasky 	    dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
7998d59ecb2SHans Petter Selasky 		_size, _vaddr, _dma_handle)
8008d59ecb2SHans Petter Selasky #define	pci_map_sg(_hwdev, _sg, _nents, _dir)				\
8018d59ecb2SHans Petter Selasky 	    dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev),	\
8028d59ecb2SHans Petter Selasky 		_sg, _nents, (enum dma_data_direction)_dir)
8038d59ecb2SHans Petter Selasky #define	pci_map_single(_hwdev, _ptr, _size, _dir)			\
8048d59ecb2SHans Petter Selasky 	    dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev),	\
8058d59ecb2SHans Petter Selasky 		(_ptr), (_size), (enum dma_data_direction)_dir)
8068d59ecb2SHans Petter Selasky #define	pci_unmap_single(_hwdev, _addr, _size, _dir)			\
8078d59ecb2SHans Petter Selasky 	    dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
8088d59ecb2SHans Petter Selasky 		_addr, _size, (enum dma_data_direction)_dir)
8098d59ecb2SHans Petter Selasky #define	pci_unmap_sg(_hwdev, _sg, _nents, _dir)				\
8108d59ecb2SHans Petter Selasky 	    dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
8118d59ecb2SHans Petter Selasky 		_sg, _nents, (enum dma_data_direction)_dir)
8128d59ecb2SHans Petter Selasky #define	pci_map_page(_hwdev, _page, _offset, _size, _dir)		\
8138d59ecb2SHans Petter Selasky 	    dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\
8148d59ecb2SHans Petter Selasky 		_offset, _size, (enum dma_data_direction)_dir)
8158d59ecb2SHans Petter Selasky #define	pci_unmap_page(_hwdev, _dma_address, _size, _dir)		\
8168d59ecb2SHans Petter Selasky 	    dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev,	\
8178d59ecb2SHans Petter Selasky 		_dma_address, _size, (enum dma_data_direction)_dir)
8188d59ecb2SHans Petter Selasky #define	pci_set_dma_mask(_pdev, mask)	dma_set_mask(&(_pdev)->dev, (mask))
8198d59ecb2SHans Petter Selasky #define	pci_dma_mapping_error(_pdev, _dma_addr)				\
8208d59ecb2SHans Petter Selasky 	    dma_mapping_error(&(_pdev)->dev, _dma_addr)
8218d59ecb2SHans Petter Selasky #define	pci_set_consistent_dma_mask(_pdev, _mask)			\
8228d59ecb2SHans Petter Selasky 	    dma_set_coherent_mask(&(_pdev)->dev, (_mask))
8238d59ecb2SHans Petter Selasky #define	DECLARE_PCI_UNMAP_ADDR(x)	DEFINE_DMA_UNMAP_ADDR(x);
8248d59ecb2SHans Petter Selasky #define	DECLARE_PCI_UNMAP_LEN(x)	DEFINE_DMA_UNMAP_LEN(x);
8258d59ecb2SHans Petter Selasky #define	pci_unmap_addr		dma_unmap_addr
8268d59ecb2SHans Petter Selasky #define	pci_unmap_addr_set	dma_unmap_addr_set
8278d59ecb2SHans Petter Selasky #define	pci_unmap_len		dma_unmap_len
8288d59ecb2SHans Petter Selasky #define	pci_unmap_len_set	dma_unmap_len_set
8298d59ecb2SHans Petter Selasky 
8308d59ecb2SHans Petter Selasky typedef unsigned int __bitwise pci_channel_state_t;
8318d59ecb2SHans Petter Selasky typedef unsigned int __bitwise pci_ers_result_t;
8328d59ecb2SHans Petter Selasky 
8338d59ecb2SHans Petter Selasky enum pci_channel_state {
834a65ef215SHans Petter Selasky 	pci_channel_io_normal = 1,
835a65ef215SHans Petter Selasky 	pci_channel_io_frozen = 2,
836a65ef215SHans Petter Selasky 	pci_channel_io_perm_failure = 3,
8378d59ecb2SHans Petter Selasky };
8388d59ecb2SHans Petter Selasky 
8398d59ecb2SHans Petter Selasky enum pci_ers_result {
840a65ef215SHans Petter Selasky 	PCI_ERS_RESULT_NONE = 1,
841a65ef215SHans Petter Selasky 	PCI_ERS_RESULT_CAN_RECOVER = 2,
842a65ef215SHans Petter Selasky 	PCI_ERS_RESULT_NEED_RESET = 3,
843a65ef215SHans Petter Selasky 	PCI_ERS_RESULT_DISCONNECT = 4,
844a65ef215SHans Petter Selasky 	PCI_ERS_RESULT_RECOVERED = 5,
8458d59ecb2SHans Petter Selasky };
8468d59ecb2SHans Petter Selasky 
8478d59ecb2SHans Petter Selasky /* PCI bus error event callbacks */
8488d59ecb2SHans Petter Selasky struct pci_error_handlers {
8498d59ecb2SHans Petter Selasky 	pci_ers_result_t (*error_detected)(struct pci_dev *dev,
8508d59ecb2SHans Petter Selasky 	    enum pci_channel_state error);
8518d59ecb2SHans Petter Selasky 	pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
8528d59ecb2SHans Petter Selasky 	pci_ers_result_t (*link_reset)(struct pci_dev *dev);
8538d59ecb2SHans Petter Selasky 	pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
8548d59ecb2SHans Petter Selasky 	void (*resume)(struct pci_dev *dev);
8558d59ecb2SHans Petter Selasky };
8568d59ecb2SHans Petter Selasky 
857a65ef215SHans Petter Selasky /* FreeBSD does not support SRIOV - yet */
8588d59ecb2SHans Petter Selasky static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
8598d59ecb2SHans Petter Selasky {
8608d59ecb2SHans Petter Selasky 	return dev;
8618d59ecb2SHans Petter Selasky }
8628d59ecb2SHans Petter Selasky 
8638d59ecb2SHans Petter Selasky static inline bool pci_is_pcie(struct pci_dev *dev)
8648d59ecb2SHans Petter Selasky {
8658d59ecb2SHans Petter Selasky 	return !!pci_pcie_cap(dev);
8668d59ecb2SHans Petter Selasky }
8678d59ecb2SHans Petter Selasky 
8688d59ecb2SHans Petter Selasky static inline u16 pcie_flags_reg(struct pci_dev *dev)
8698d59ecb2SHans Petter Selasky {
8708d59ecb2SHans Petter Selasky 	int pos;
8718d59ecb2SHans Petter Selasky 	u16 reg16;
8728d59ecb2SHans Petter Selasky 
8738d59ecb2SHans Petter Selasky 	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
8748d59ecb2SHans Petter Selasky 	if (!pos)
8758d59ecb2SHans Petter Selasky 		return 0;
8768d59ecb2SHans Petter Selasky 
8778d59ecb2SHans Petter Selasky 	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
8788d59ecb2SHans Petter Selasky 
8798d59ecb2SHans Petter Selasky 	return reg16;
8808d59ecb2SHans Petter Selasky }
8818d59ecb2SHans Petter Selasky 
8828d59ecb2SHans Petter Selasky static inline int pci_pcie_type(struct pci_dev *dev)
8838d59ecb2SHans Petter Selasky {
8848d59ecb2SHans Petter Selasky 	return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
8858d59ecb2SHans Petter Selasky }
8868d59ecb2SHans Petter Selasky 
8878d59ecb2SHans Petter Selasky static inline int pcie_cap_version(struct pci_dev *dev)
8888d59ecb2SHans Petter Selasky {
8898d59ecb2SHans Petter Selasky 	return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS;
8908d59ecb2SHans Petter Selasky }
8918d59ecb2SHans Petter Selasky 
8928d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_lnkctl(struct pci_dev *dev)
8938d59ecb2SHans Petter Selasky {
8948d59ecb2SHans Petter Selasky 	int type = pci_pcie_type(dev);
8958d59ecb2SHans Petter Selasky 
8968d59ecb2SHans Petter Selasky 	return pcie_cap_version(dev) > 1 ||
8978d59ecb2SHans Petter Selasky 	       type == PCI_EXP_TYPE_ROOT_PORT ||
8988d59ecb2SHans Petter Selasky 	       type == PCI_EXP_TYPE_ENDPOINT ||
8998d59ecb2SHans Petter Selasky 	       type == PCI_EXP_TYPE_LEG_END;
9008d59ecb2SHans Petter Selasky }
9018d59ecb2SHans Petter Selasky 
9028d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
9038d59ecb2SHans Petter Selasky {
9048d59ecb2SHans Petter Selasky 		return true;
9058d59ecb2SHans Petter Selasky }
9068d59ecb2SHans Petter Selasky 
9078d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_sltctl(struct pci_dev *dev)
9088d59ecb2SHans Petter Selasky {
9098d59ecb2SHans Petter Selasky 	int type = pci_pcie_type(dev);
9108d59ecb2SHans Petter Selasky 
91183630517SEd Maste 	return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
9128d59ecb2SHans Petter Selasky 	    (type == PCI_EXP_TYPE_DOWNSTREAM &&
9138d59ecb2SHans Petter Selasky 	    pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT);
9148d59ecb2SHans Petter Selasky }
9158d59ecb2SHans Petter Selasky 
9168d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_rtctl(struct pci_dev *dev)
9178d59ecb2SHans Petter Selasky {
9188d59ecb2SHans Petter Selasky 	int type = pci_pcie_type(dev);
9198d59ecb2SHans Petter Selasky 
92083630517SEd Maste 	return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
9218d59ecb2SHans Petter Selasky 	    type == PCI_EXP_TYPE_RC_EC;
9228d59ecb2SHans Petter Selasky }
9238d59ecb2SHans Petter Selasky 
9248d59ecb2SHans Petter Selasky static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
9258d59ecb2SHans Petter Selasky {
9268d59ecb2SHans Petter Selasky 	if (!pci_is_pcie(dev))
9278d59ecb2SHans Petter Selasky 		return false;
9288d59ecb2SHans Petter Selasky 
9298d59ecb2SHans Petter Selasky 	switch (pos) {
9308d59ecb2SHans Petter Selasky 	case PCI_EXP_FLAGS_TYPE:
9318d59ecb2SHans Petter Selasky 		return true;
9328d59ecb2SHans Petter Selasky 	case PCI_EXP_DEVCAP:
9338d59ecb2SHans Petter Selasky 	case PCI_EXP_DEVCTL:
9348d59ecb2SHans Petter Selasky 	case PCI_EXP_DEVSTA:
9358d59ecb2SHans Petter Selasky 		return pcie_cap_has_devctl(dev);
9368d59ecb2SHans Petter Selasky 	case PCI_EXP_LNKCAP:
9378d59ecb2SHans Petter Selasky 	case PCI_EXP_LNKCTL:
9388d59ecb2SHans Petter Selasky 	case PCI_EXP_LNKSTA:
9398d59ecb2SHans Petter Selasky 		return pcie_cap_has_lnkctl(dev);
9408d59ecb2SHans Petter Selasky 	case PCI_EXP_SLTCAP:
9418d59ecb2SHans Petter Selasky 	case PCI_EXP_SLTCTL:
9428d59ecb2SHans Petter Selasky 	case PCI_EXP_SLTSTA:
9438d59ecb2SHans Petter Selasky 		return pcie_cap_has_sltctl(dev);
9448d59ecb2SHans Petter Selasky 	case PCI_EXP_RTCTL:
9458d59ecb2SHans Petter Selasky 	case PCI_EXP_RTCAP:
9468d59ecb2SHans Petter Selasky 	case PCI_EXP_RTSTA:
9478d59ecb2SHans Petter Selasky 		return pcie_cap_has_rtctl(dev);
9488d59ecb2SHans Petter Selasky 	case PCI_EXP_DEVCAP2:
9498d59ecb2SHans Petter Selasky 	case PCI_EXP_DEVCTL2:
9508d59ecb2SHans Petter Selasky 	case PCI_EXP_LNKCAP2:
9518d59ecb2SHans Petter Selasky 	case PCI_EXP_LNKCTL2:
9528d59ecb2SHans Petter Selasky 	case PCI_EXP_LNKSTA2:
9538d59ecb2SHans Petter Selasky 		return pcie_cap_version(dev) > 1;
9548d59ecb2SHans Petter Selasky 	default:
9558d59ecb2SHans Petter Selasky 		return false;
9568d59ecb2SHans Petter Selasky 	}
9578d59ecb2SHans Petter Selasky }
9588d59ecb2SHans Petter Selasky 
95912af734dSHans Petter Selasky static inline int
96012af734dSHans Petter Selasky pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst)
961a65ef215SHans Petter Selasky {
962a65ef215SHans Petter Selasky 	if (pos & 3)
963a65ef215SHans Petter Selasky 		return -EINVAL;
964a65ef215SHans Petter Selasky 
965a65ef215SHans Petter Selasky 	if (!pcie_capability_reg_implemented(dev, pos))
966a65ef215SHans Petter Selasky 		return -EINVAL;
967a65ef215SHans Petter Selasky 
968a65ef215SHans Petter Selasky 	return pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, dst);
969a65ef215SHans Petter Selasky }
9708d59ecb2SHans Petter Selasky 
97112af734dSHans Petter Selasky static inline int
97212af734dSHans Petter Selasky pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *dst)
97312af734dSHans Petter Selasky {
97412af734dSHans Petter Selasky 	if (pos & 3)
97512af734dSHans Petter Selasky 		return -EINVAL;
97612af734dSHans Petter Selasky 
97712af734dSHans Petter Selasky 	if (!pcie_capability_reg_implemented(dev, pos))
97812af734dSHans Petter Selasky 		return -EINVAL;
97912af734dSHans Petter Selasky 
98012af734dSHans Petter Selasky 	return pci_read_config_word(dev, pci_pcie_cap(dev) + pos, dst);
98112af734dSHans Petter Selasky }
98212af734dSHans Petter Selasky 
98312af734dSHans Petter Selasky static inline int
98412af734dSHans Petter Selasky pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
9858d59ecb2SHans Petter Selasky {
9868d59ecb2SHans Petter Selasky 	if (pos & 1)
9878d59ecb2SHans Petter Selasky 		return -EINVAL;
9888d59ecb2SHans Petter Selasky 
9898d59ecb2SHans Petter Selasky 	if (!pcie_capability_reg_implemented(dev, pos))
9908d59ecb2SHans Petter Selasky 		return 0;
9918d59ecb2SHans Petter Selasky 
9928d59ecb2SHans Petter Selasky 	return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
9938d59ecb2SHans Petter Selasky }
9948d59ecb2SHans Petter Selasky 
995a65ef215SHans Petter Selasky static inline int pcie_get_minimum_link(struct pci_dev *dev,
996a65ef215SHans Petter Selasky     enum pci_bus_speed *speed, enum pcie_link_width *width)
997a65ef215SHans Petter Selasky {
998a65ef215SHans Petter Selasky 	*speed = PCI_SPEED_UNKNOWN;
999a65ef215SHans Petter Selasky 	*width = PCIE_LNK_WIDTH_UNKNOWN;
1000a65ef215SHans Petter Selasky 	return (0);
1001a65ef215SHans Petter Selasky }
1002a65ef215SHans Petter Selasky 
1003a65ef215SHans Petter Selasky static inline int
1004a65ef215SHans Petter Selasky pci_num_vf(struct pci_dev *dev)
1005a65ef215SHans Petter Selasky {
1006a65ef215SHans Petter Selasky 	return (0);
1007a65ef215SHans Petter Selasky }
1008a65ef215SHans Petter Selasky 
1009ab62989aSHans Petter Selasky static inline enum pci_bus_speed
1010ab62989aSHans Petter Selasky pcie_get_speed_cap(struct pci_dev *dev)
1011ab62989aSHans Petter Selasky {
1012ab62989aSHans Petter Selasky 	device_t root;
1013ab62989aSHans Petter Selasky 	uint32_t lnkcap, lnkcap2;
1014ab62989aSHans Petter Selasky 	int error, pos;
1015ab62989aSHans Petter Selasky 
1016ab62989aSHans Petter Selasky 	root = device_get_parent(dev->dev.bsddev);
1017ab62989aSHans Petter Selasky 	if (root == NULL)
1018ab62989aSHans Petter Selasky 		return (PCI_SPEED_UNKNOWN);
1019ab62989aSHans Petter Selasky 	root = device_get_parent(root);
1020ab62989aSHans Petter Selasky 	if (root == NULL)
1021ab62989aSHans Petter Selasky 		return (PCI_SPEED_UNKNOWN);
1022ab62989aSHans Petter Selasky 	root = device_get_parent(root);
1023ab62989aSHans Petter Selasky 	if (root == NULL)
1024ab62989aSHans Petter Selasky 		return (PCI_SPEED_UNKNOWN);
1025ab62989aSHans Petter Selasky 
1026ab62989aSHans Petter Selasky 	if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA ||
1027ab62989aSHans Petter Selasky 	    pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS)
1028ab62989aSHans Petter Selasky 		return (PCI_SPEED_UNKNOWN);
1029ab62989aSHans Petter Selasky 
1030ab62989aSHans Petter Selasky 	if ((error = pci_find_cap(root, PCIY_EXPRESS, &pos)) != 0)
1031ab62989aSHans Petter Selasky 		return (PCI_SPEED_UNKNOWN);
1032ab62989aSHans Petter Selasky 
1033ab62989aSHans Petter Selasky 	lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4);
1034ab62989aSHans Petter Selasky 
1035ab62989aSHans Petter Selasky 	if (lnkcap2) {	/* PCIe r3.0-compliant */
1036ab62989aSHans Petter Selasky 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
1037ab62989aSHans Petter Selasky 			return (PCIE_SPEED_2_5GT);
1038ab62989aSHans Petter Selasky 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
1039ab62989aSHans Petter Selasky 			return (PCIE_SPEED_5_0GT);
1040ab62989aSHans Petter Selasky 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
1041ab62989aSHans Petter Selasky 			return (PCIE_SPEED_8_0GT);
1042ab62989aSHans Petter Selasky 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
1043ab62989aSHans Petter Selasky 			return (PCIE_SPEED_16_0GT);
1044ab62989aSHans Petter Selasky 	} else {	/* pre-r3.0 */
1045ab62989aSHans Petter Selasky 		lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4);
1046ab62989aSHans Petter Selasky 		if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
1047ab62989aSHans Petter Selasky 			return (PCIE_SPEED_2_5GT);
1048ab62989aSHans Petter Selasky 		if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
1049ab62989aSHans Petter Selasky 			return (PCIE_SPEED_5_0GT);
1050ab62989aSHans Petter Selasky 		if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB)
1051ab62989aSHans Petter Selasky 			return (PCIE_SPEED_8_0GT);
1052ab62989aSHans Petter Selasky 		if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB)
1053ab62989aSHans Petter Selasky 			return (PCIE_SPEED_16_0GT);
1054ab62989aSHans Petter Selasky 	}
1055ab62989aSHans Petter Selasky 	return (PCI_SPEED_UNKNOWN);
1056ab62989aSHans Petter Selasky }
1057ab62989aSHans Petter Selasky 
1058ab62989aSHans Petter Selasky static inline enum pcie_link_width
1059ab62989aSHans Petter Selasky pcie_get_width_cap(struct pci_dev *dev)
1060ab62989aSHans Petter Selasky {
1061ab62989aSHans Petter Selasky 	uint32_t lnkcap;
1062ab62989aSHans Petter Selasky 
1063ab62989aSHans Petter Selasky 	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
1064ab62989aSHans Petter Selasky 	if (lnkcap)
1065ab62989aSHans Petter Selasky 		return ((lnkcap & PCI_EXP_LNKCAP_MLW) >> 4);
1066ab62989aSHans Petter Selasky 
1067ab62989aSHans Petter Selasky 	return (PCIE_LNK_WIDTH_UNKNOWN);
1068ab62989aSHans Petter Selasky }
1069ab62989aSHans Petter Selasky 
1070b4edb17cSHans Petter Selasky static inline int
1071b4edb17cSHans Petter Selasky pcie_get_mps(struct pci_dev *dev)
1072b4edb17cSHans Petter Selasky {
1073b4edb17cSHans Petter Selasky 	return (pci_get_max_payload(dev->dev.bsddev));
1074b4edb17cSHans Petter Selasky }
1075b4edb17cSHans Petter Selasky 
1076b4edb17cSHans Petter Selasky static inline uint32_t
1077b4edb17cSHans Petter Selasky PCIE_SPEED2MBS_ENC(enum pci_bus_speed spd)
1078b4edb17cSHans Petter Selasky {
1079b4edb17cSHans Petter Selasky 
1080b4edb17cSHans Petter Selasky 	switch(spd) {
1081b4edb17cSHans Petter Selasky 	case PCIE_SPEED_16_0GT:
1082b4edb17cSHans Petter Selasky 		return (16000 * 128 / 130);
1083b4edb17cSHans Petter Selasky 	case PCIE_SPEED_8_0GT:
1084b4edb17cSHans Petter Selasky 		return (8000 * 128 / 130);
1085b4edb17cSHans Petter Selasky 	case PCIE_SPEED_5_0GT:
1086b4edb17cSHans Petter Selasky 		return (5000 * 8 / 10);
1087b4edb17cSHans Petter Selasky 	case PCIE_SPEED_2_5GT:
1088b4edb17cSHans Petter Selasky 		return (2500 * 8 / 10);
1089b4edb17cSHans Petter Selasky 	default:
1090b4edb17cSHans Petter Selasky 		return (0);
1091b4edb17cSHans Petter Selasky 	}
1092b4edb17cSHans Petter Selasky }
1093b4edb17cSHans Petter Selasky 
1094b4edb17cSHans Petter Selasky static inline uint32_t
1095b4edb17cSHans Petter Selasky pcie_bandwidth_available(struct pci_dev *pdev,
1096b4edb17cSHans Petter Selasky     struct pci_dev **limiting,
1097b4edb17cSHans Petter Selasky     enum pci_bus_speed *speed,
1098b4edb17cSHans Petter Selasky     enum pcie_link_width *width)
1099b4edb17cSHans Petter Selasky {
1100b4edb17cSHans Petter Selasky 	enum pci_bus_speed nspeed = pcie_get_speed_cap(pdev);
1101b4edb17cSHans Petter Selasky 	enum pcie_link_width nwidth = pcie_get_width_cap(pdev);
1102b4edb17cSHans Petter Selasky 
1103b4edb17cSHans Petter Selasky 	if (speed)
1104b4edb17cSHans Petter Selasky 		*speed = nspeed;
1105b4edb17cSHans Petter Selasky 	if (width)
1106b4edb17cSHans Petter Selasky 		*width = nwidth;
1107b4edb17cSHans Petter Selasky 
1108b4edb17cSHans Petter Selasky 	return (nwidth * PCIE_SPEED2MBS_ENC(nspeed));
1109b4edb17cSHans Petter Selasky }
1110b4edb17cSHans Petter Selasky 
11118e106c52SBjoern A. Zeeb static inline struct pci_dev *
11128e106c52SBjoern A. Zeeb pcie_find_root_port(struct pci_dev *pdev)
11138e106c52SBjoern A. Zeeb {
11148e106c52SBjoern A. Zeeb 	device_t root;
11158e106c52SBjoern A. Zeeb 
11168e106c52SBjoern A. Zeeb 	if (pdev->root != NULL)
11178e106c52SBjoern A. Zeeb 		return (pdev->root);
11188e106c52SBjoern A. Zeeb 
11198e106c52SBjoern A. Zeeb 	root = pci_find_pcie_root_port(pdev->dev.bsddev);
11208e106c52SBjoern A. Zeeb 	if (root == NULL)
11218e106c52SBjoern A. Zeeb 		return (NULL);
11228e106c52SBjoern A. Zeeb 
11238e106c52SBjoern A. Zeeb 	pdev->root = lkpinew_pci_dev(root);
11248e106c52SBjoern A. Zeeb 	return (pdev->root);
11258e106c52SBjoern A. Zeeb }
11268e106c52SBjoern A. Zeeb 
11278e106c52SBjoern A. Zeeb /* This is needed when people rip out the device "HotPlug". */
11288e106c52SBjoern A. Zeeb static inline void
11298e106c52SBjoern A. Zeeb pci_lock_rescan_remove(void)
11308e106c52SBjoern A. Zeeb {
11318e106c52SBjoern A. Zeeb }
11328e106c52SBjoern A. Zeeb 
11338e106c52SBjoern A. Zeeb static inline void
11348e106c52SBjoern A. Zeeb pci_unlock_rescan_remove(void)
11358e106c52SBjoern A. Zeeb {
11368e106c52SBjoern A. Zeeb }
11378e106c52SBjoern A. Zeeb 
11388e106c52SBjoern A. Zeeb static __inline void
11398e106c52SBjoern A. Zeeb pci_stop_and_remove_bus_device(struct pci_dev *pdev)
11408e106c52SBjoern A. Zeeb {
11418e106c52SBjoern A. Zeeb }
11428e106c52SBjoern A. Zeeb 
1143253dbe74SHans Petter Selasky /*
1144253dbe74SHans Petter Selasky  * The following functions can be used to attach/detach the LinuxKPI's
1145253dbe74SHans Petter Selasky  * PCI device runtime. The pci_driver and pci_device_id pointer is
1146253dbe74SHans Petter Selasky  * allowed to be NULL. Other pointers must be all valid.
1147253dbe74SHans Petter Selasky  * The pci_dev structure should be zero-initialized before passed
1148253dbe74SHans Petter Selasky  * to the linux_pci_attach_device function.
1149253dbe74SHans Petter Selasky  */
1150253dbe74SHans Petter Selasky extern int linux_pci_attach_device(device_t, struct pci_driver *,
1151253dbe74SHans Petter Selasky     const struct pci_device_id *, struct pci_dev *);
1152253dbe74SHans Petter Selasky extern int linux_pci_detach_device(struct pci_dev *);
1153253dbe74SHans Petter Selasky 
11545e30a739SEmmanuel Vadot static inline int
11555e30a739SEmmanuel Vadot pci_dev_present(const struct pci_device_id *cur)
11565e30a739SEmmanuel Vadot {
11575e30a739SEmmanuel Vadot 	while (cur != NULL && (cur->vendor || cur->device)) {
11585e30a739SEmmanuel Vadot 		if (pci_find_device(cur->vendor, cur->device) != NULL) {
11595e30a739SEmmanuel Vadot 			return (1);
11605e30a739SEmmanuel Vadot 		}
11615e30a739SEmmanuel Vadot 		cur++;
11625e30a739SEmmanuel Vadot 	}
11635e30a739SEmmanuel Vadot 	return (0);
11645e30a739SEmmanuel Vadot }
11655e30a739SEmmanuel Vadot 
1166105a37caSEmmanuel Vadot static inline bool
1167105a37caSEmmanuel Vadot pci_is_root_bus(struct pci_bus *pbus)
1168105a37caSEmmanuel Vadot {
1169105a37caSEmmanuel Vadot 
1170105a37caSEmmanuel Vadot 	return (pbus->self == NULL);
1171105a37caSEmmanuel Vadot }
1172105a37caSEmmanuel Vadot 
1173105a37caSEmmanuel Vadot struct pci_dev *lkpi_pci_get_domain_bus_and_slot(int domain,
1174105a37caSEmmanuel Vadot     unsigned int bus, unsigned int devfn);
1175105a37caSEmmanuel Vadot #define	pci_get_domain_bus_and_slot(domain, bus, devfn)	\
1176105a37caSEmmanuel Vadot 	lkpi_pci_get_domain_bus_and_slot(domain, bus, devfn)
1177105a37caSEmmanuel Vadot 
1178105a37caSEmmanuel Vadot static inline int
1179105a37caSEmmanuel Vadot pci_domain_nr(struct pci_bus *pbus)
1180105a37caSEmmanuel Vadot {
1181105a37caSEmmanuel Vadot 
11821fac2cb4SBjoern A. Zeeb 	return (pbus->domain);
1183105a37caSEmmanuel Vadot }
1184105a37caSEmmanuel Vadot 
1185105a37caSEmmanuel Vadot static inline int
1186105a37caSEmmanuel Vadot pci_bus_read_config(struct pci_bus *bus, unsigned int devfn,
1187105a37caSEmmanuel Vadot                     int pos, uint32_t *val, int len)
1188105a37caSEmmanuel Vadot {
1189105a37caSEmmanuel Vadot 
1190105a37caSEmmanuel Vadot 	*val = pci_read_config(bus->self->dev.bsddev, pos, len);
1191105a37caSEmmanuel Vadot 	return (0);
1192105a37caSEmmanuel Vadot }
1193105a37caSEmmanuel Vadot 
1194105a37caSEmmanuel Vadot static inline int
1195105a37caSEmmanuel Vadot pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, int pos, u16 *val)
1196105a37caSEmmanuel Vadot {
1197105a37caSEmmanuel Vadot 	uint32_t tmp;
1198105a37caSEmmanuel Vadot 	int ret;
1199105a37caSEmmanuel Vadot 
1200105a37caSEmmanuel Vadot 	ret = pci_bus_read_config(bus, devfn, pos, &tmp, 2);
1201105a37caSEmmanuel Vadot 	*val = (u16)tmp;
1202105a37caSEmmanuel Vadot 	return (ret);
1203105a37caSEmmanuel Vadot }
1204105a37caSEmmanuel Vadot 
1205105a37caSEmmanuel Vadot static inline int
1206105a37caSEmmanuel Vadot pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, int pos, u8 *val)
1207105a37caSEmmanuel Vadot {
1208105a37caSEmmanuel Vadot 	uint32_t tmp;
1209105a37caSEmmanuel Vadot 	int ret;
1210105a37caSEmmanuel Vadot 
1211105a37caSEmmanuel Vadot 	ret = pci_bus_read_config(bus, devfn, pos, &tmp, 1);
1212105a37caSEmmanuel Vadot 	*val = (u8)tmp;
1213105a37caSEmmanuel Vadot 	return (ret);
1214105a37caSEmmanuel Vadot }
1215105a37caSEmmanuel Vadot 
1216105a37caSEmmanuel Vadot static inline int
1217105a37caSEmmanuel Vadot pci_bus_write_config(struct pci_bus *bus, unsigned int devfn, int pos,
1218105a37caSEmmanuel Vadot     uint32_t val, int size)
1219105a37caSEmmanuel Vadot {
1220105a37caSEmmanuel Vadot 
1221105a37caSEmmanuel Vadot 	pci_write_config(bus->self->dev.bsddev, pos, val, size);
1222105a37caSEmmanuel Vadot 	return (0);
1223105a37caSEmmanuel Vadot }
1224105a37caSEmmanuel Vadot 
1225105a37caSEmmanuel Vadot static inline int
1226105a37caSEmmanuel Vadot pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int pos,
1227105a37caSEmmanuel Vadot     uint8_t val)
1228105a37caSEmmanuel Vadot {
1229105a37caSEmmanuel Vadot 	return (pci_bus_write_config(bus, devfn, pos, val, 1));
1230105a37caSEmmanuel Vadot }
1231105a37caSEmmanuel Vadot 
1232105a37caSEmmanuel Vadot static inline int
1233105a37caSEmmanuel Vadot pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int pos,
1234105a37caSEmmanuel Vadot     uint16_t val)
1235105a37caSEmmanuel Vadot {
1236105a37caSEmmanuel Vadot 	return (pci_bus_write_config(bus, devfn, pos, val, 2));
1237105a37caSEmmanuel Vadot }
1238105a37caSEmmanuel Vadot 
1239105a37caSEmmanuel Vadot struct pci_dev *lkpi_pci_get_class(unsigned int class, struct pci_dev *from);
1240105a37caSEmmanuel Vadot #define	pci_get_class(class, from)	lkpi_pci_get_class(class, from)
1241105a37caSEmmanuel Vadot 
12428d59ecb2SHans Petter Selasky #endif	/* _LINUX_PCI_H_ */
1243