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. 7d4a4960cSBjoern A. Zeeb * Copyright (c) 2020-2021 The FreeBSD Foundation 8d4a4960cSBjoern A. Zeeb * 9d4a4960cSBjoern A. Zeeb * Portions of this software were developed by Björn Zeeb 10d4a4960cSBjoern A. Zeeb * under sponsorship from the FreeBSD Foundation. 118d59ecb2SHans Petter Selasky * 128d59ecb2SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 138d59ecb2SHans Petter Selasky * modification, are permitted provided that the following conditions 148d59ecb2SHans Petter Selasky * are met: 158d59ecb2SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 168d59ecb2SHans Petter Selasky * notice unmodified, this list of conditions, and the following 178d59ecb2SHans Petter Selasky * disclaimer. 188d59ecb2SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 198d59ecb2SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 208d59ecb2SHans Petter Selasky * documentation and/or other materials provided with the distribution. 218d59ecb2SHans Petter Selasky * 228d59ecb2SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 238d59ecb2SHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 248d59ecb2SHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 258d59ecb2SHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 268d59ecb2SHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 278d59ecb2SHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 288d59ecb2SHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 298d59ecb2SHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 308d59ecb2SHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 318d59ecb2SHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 328d59ecb2SHans Petter Selasky * 338d59ecb2SHans Petter Selasky * $FreeBSD$ 348d59ecb2SHans Petter Selasky */ 358d59ecb2SHans Petter Selasky #ifndef _LINUX_PCI_H_ 368d59ecb2SHans Petter Selasky #define _LINUX_PCI_H_ 378d59ecb2SHans Petter Selasky 388d59ecb2SHans Petter Selasky #define CONFIG_PCI_MSI 398d59ecb2SHans Petter Selasky 408d59ecb2SHans Petter Selasky #include <linux/types.h> 418d59ecb2SHans Petter Selasky 428d59ecb2SHans Petter Selasky #include <sys/param.h> 438d59ecb2SHans Petter Selasky #include <sys/bus.h> 442928e60eSKonstantin Belousov #include <sys/nv.h> 458d59ecb2SHans Petter Selasky #include <sys/pciio.h> 468d59ecb2SHans Petter Selasky #include <sys/rman.h> 479275cd0dSWarner Losh #include <sys/bus.h> 488d59ecb2SHans Petter Selasky #include <dev/pci/pcivar.h> 498d59ecb2SHans Petter Selasky #include <dev/pci/pcireg.h> 508d59ecb2SHans Petter Selasky #include <dev/pci/pci_private.h> 518d59ecb2SHans Petter Selasky 528d59ecb2SHans Petter Selasky #include <machine/resource.h> 538d59ecb2SHans Petter Selasky 548d59ecb2SHans Petter Selasky #include <linux/list.h> 558d59ecb2SHans Petter Selasky #include <linux/dmapool.h> 568d59ecb2SHans Petter Selasky #include <linux/dma-mapping.h> 578d59ecb2SHans Petter Selasky #include <linux/compiler.h> 588d59ecb2SHans Petter Selasky #include <linux/errno.h> 598d59ecb2SHans Petter Selasky #include <asm/atomic.h> 608d59ecb2SHans Petter Selasky #include <linux/device.h> 615a402a3aSBjoern A. Zeeb #include <linux/pci_ids.h> 628d59ecb2SHans Petter Selasky 638d59ecb2SHans Petter Selasky struct pci_device_id { 648d59ecb2SHans Petter Selasky uint32_t vendor; 658d59ecb2SHans Petter Selasky uint32_t device; 668d59ecb2SHans Petter Selasky uint32_t subvendor; 678d59ecb2SHans Petter Selasky uint32_t subdevice; 686373e95eSMark Johnston uint32_t class; 698d59ecb2SHans Petter Selasky uint32_t class_mask; 708d59ecb2SHans Petter Selasky uintptr_t driver_data; 718d59ecb2SHans Petter Selasky }; 728d59ecb2SHans Petter Selasky 738d59ecb2SHans Petter Selasky #define MODULE_DEVICE_TABLE(bus, table) 74ecf29cf1SMark Johnston 75232028b3SHans Petter Selasky #define PCI_ANY_ID -1U 768d59ecb2SHans Petter Selasky 778d59ecb2SHans Petter Selasky #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 788d59ecb2SHans Petter Selasky #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) 798d59ecb2SHans Petter Selasky #define PCI_FUNC(devfn) ((devfn) & 0x07) 8013a5c70bSHans Petter Selasky #define PCI_BUS_NUM(devfn) (((devfn) >> 8) & 0xff) 818d59ecb2SHans Petter Selasky 828d59ecb2SHans Petter Selasky #define PCI_VDEVICE(_vendor, _device) \ 838d59ecb2SHans Petter Selasky .vendor = PCI_VENDOR_ID_##_vendor, .device = (_device), \ 848d59ecb2SHans Petter Selasky .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID 858d59ecb2SHans Petter Selasky #define PCI_DEVICE(_vendor, _device) \ 868d59ecb2SHans Petter Selasky .vendor = (_vendor), .device = (_device), \ 878d59ecb2SHans Petter Selasky .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID 888d59ecb2SHans Petter Selasky 898d59ecb2SHans Petter Selasky #define to_pci_dev(n) container_of(n, struct pci_dev, dev) 908d59ecb2SHans Petter Selasky 918d59ecb2SHans Petter Selasky #define PCI_VENDOR_ID PCIR_DEVVENDOR 928d59ecb2SHans Petter Selasky #define PCI_COMMAND PCIR_COMMAND 93fc1d8409SBjoern A. Zeeb #define PCI_COMMAND_INTX_DISABLE PCIM_CMD_INTxDIS 948d59ecb2SHans Petter Selasky #define PCI_EXP_DEVCTL PCIER_DEVICE_CTL /* Device Control */ 958d59ecb2SHans Petter Selasky #define PCI_EXP_LNKCTL PCIER_LINK_CTL /* Link Control */ 96fc1d8409SBjoern A. Zeeb #define PCI_EXP_LNKCTL_ASPM_L0S PCIEM_LINK_CTL_ASPMC_L0S 97fc1d8409SBjoern A. Zeeb #define PCI_EXP_LNKCTL_ASPM_L1 PCIEM_LINK_CTL_ASPMC_L1 98fc1d8409SBjoern A. Zeeb #define PCI_EXP_LNKCTL_CLKREQ_EN PCIEM_LINK_CTL_ECPM /* Enable clock PM */ 998d59ecb2SHans Petter Selasky #define PCI_EXP_FLAGS_TYPE PCIEM_FLAGS_TYPE /* Device/Port type */ 1008d59ecb2SHans Petter Selasky #define PCI_EXP_DEVCAP PCIER_DEVICE_CAP /* Device capabilities */ 1018d59ecb2SHans Petter Selasky #define PCI_EXP_DEVSTA PCIER_DEVICE_STA /* Device Status */ 1028d59ecb2SHans Petter Selasky #define PCI_EXP_LNKCAP PCIER_LINK_CAP /* Link Capabilities */ 1038d59ecb2SHans Petter Selasky #define PCI_EXP_LNKSTA PCIER_LINK_STA /* Link Status */ 1048d59ecb2SHans Petter Selasky #define PCI_EXP_SLTCAP PCIER_SLOT_CAP /* Slot Capabilities */ 1058d59ecb2SHans Petter Selasky #define PCI_EXP_SLTCTL PCIER_SLOT_CTL /* Slot Control */ 1068d59ecb2SHans Petter Selasky #define PCI_EXP_SLTSTA PCIER_SLOT_STA /* Slot Status */ 1078d59ecb2SHans Petter Selasky #define PCI_EXP_RTCTL PCIER_ROOT_CTL /* Root Control */ 1088d59ecb2SHans Petter Selasky #define PCI_EXP_RTCAP PCIER_ROOT_CAP /* Root Capabilities */ 1098d59ecb2SHans Petter Selasky #define PCI_EXP_RTSTA PCIER_ROOT_STA /* Root Status */ 1108d59ecb2SHans Petter Selasky #define PCI_EXP_DEVCAP2 PCIER_DEVICE_CAP2 /* Device Capabilities 2 */ 1118d59ecb2SHans Petter Selasky #define PCI_EXP_DEVCTL2 PCIER_DEVICE_CTL2 /* Device Control 2 */ 112fc1d8409SBjoern A. Zeeb #define PCI_EXP_DEVCTL2_LTR_EN PCIEM_CTL2_LTR_ENABLE 1138d59ecb2SHans Petter Selasky #define PCI_EXP_LNKCAP2 PCIER_LINK_CAP2 /* Link Capabilities 2 */ 1148d59ecb2SHans Petter Selasky #define PCI_EXP_LNKCTL2 PCIER_LINK_CTL2 /* Link Control 2 */ 1158d59ecb2SHans Petter Selasky #define PCI_EXP_LNKSTA2 PCIER_LINK_STA2 /* Link Status 2 */ 1168d59ecb2SHans Petter Selasky #define PCI_EXP_FLAGS PCIER_FLAGS /* Capabilities register */ 1178d59ecb2SHans Petter Selasky #define PCI_EXP_FLAGS_VERS PCIEM_FLAGS_VERSION /* Capability version */ 1188d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_ROOT_PORT PCIEM_TYPE_ROOT_PORT /* Root Port */ 1198d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_ENDPOINT PCIEM_TYPE_ENDPOINT /* Express Endpoint */ 1208d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_LEG_END PCIEM_TYPE_LEGACY_ENDPOINT /* Legacy Endpoint */ 1218d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_DOWNSTREAM PCIEM_TYPE_DOWNSTREAM_PORT /* Downstream Port */ 1228d59ecb2SHans Petter Selasky #define PCI_EXP_FLAGS_SLOT PCIEM_FLAGS_SLOT /* Slot implemented */ 1238d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_RC_EC PCIEM_TYPE_ROOT_EC /* Root Complex Event Collector */ 124a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP_SLS_2_5GB 0x01 /* Supported Link Speed 2.5GT/s */ 125a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP_SLS_5_0GB 0x02 /* Supported Link Speed 5.0GT/s */ 126ab62989aSHans Petter Selasky #define PCI_EXP_LNKCAP_SLS_8_0GB 0x04 /* Supported Link Speed 8.0GT/s */ 127ab62989aSHans Petter Selasky #define PCI_EXP_LNKCAP_SLS_16_0GB 0x08 /* Supported Link Speed 16.0GT/s */ 128a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP_MLW 0x03f0 /* Maximum Link Width */ 129a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */ 130a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */ 131a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */ 132ab62989aSHans Petter Selasky #define PCI_EXP_LNKCAP2_SLS_16_0GB 0x10 /* Supported Link Speed 16.0GT/s */ 1338d59ecb2SHans Petter Selasky 13412af734dSHans Petter Selasky #define PCI_EXP_LNKCTL_HAWD PCIEM_LINK_CTL_HAWD 13512af734dSHans Petter Selasky #define PCI_EXP_LNKCAP_CLKPM 0x00040000 13612af734dSHans Petter Selasky #define PCI_EXP_DEVSTA_TRPND 0x0020 13712af734dSHans Petter Selasky 138bdff61f8SHans Petter Selasky #define IORESOURCE_MEM (1 << SYS_RES_MEMORY) 139bdff61f8SHans Petter Selasky #define IORESOURCE_IO (1 << SYS_RES_IOPORT) 140bdff61f8SHans Petter Selasky #define IORESOURCE_IRQ (1 << SYS_RES_IRQ) 1418d59ecb2SHans Petter Selasky 142a65ef215SHans Petter Selasky enum pci_bus_speed { 143a65ef215SHans Petter Selasky PCI_SPEED_UNKNOWN = -1, 144a65ef215SHans Petter Selasky PCIE_SPEED_2_5GT, 145a65ef215SHans Petter Selasky PCIE_SPEED_5_0GT, 146a65ef215SHans Petter Selasky PCIE_SPEED_8_0GT, 147ab62989aSHans Petter Selasky PCIE_SPEED_16_0GT, 148a65ef215SHans Petter Selasky }; 1498d59ecb2SHans Petter Selasky 150a65ef215SHans Petter Selasky enum pcie_link_width { 151ab62989aSHans Petter Selasky PCIE_LNK_WIDTH_RESRV = 0x00, 152ab62989aSHans Petter Selasky PCIE_LNK_X1 = 0x01, 153ab62989aSHans Petter Selasky PCIE_LNK_X2 = 0x02, 154ab62989aSHans Petter Selasky PCIE_LNK_X4 = 0x04, 155ab62989aSHans Petter Selasky PCIE_LNK_X8 = 0x08, 156ab62989aSHans Petter Selasky PCIE_LNK_X12 = 0x0c, 157ab62989aSHans Petter Selasky PCIE_LNK_X16 = 0x10, 158ab62989aSHans Petter Selasky PCIE_LNK_X32 = 0x20, 159ab62989aSHans Petter Selasky PCIE_LNK_WIDTH_UNKNOWN = 0xff, 160a65ef215SHans Petter Selasky }; 161a65ef215SHans Petter Selasky 162fc1d8409SBjoern A. Zeeb #define PCIE_LINK_STATE_L0S 0x00000001 163fc1d8409SBjoern A. Zeeb #define PCIE_LINK_STATE_L1 0x00000002 164fc1d8409SBjoern A. Zeeb #define PCIE_LINK_STATE_CLKPM 0x00000004 165fc1d8409SBjoern A. Zeeb 16612af734dSHans Petter Selasky typedef int pci_power_t; 16712af734dSHans Petter Selasky 16812af734dSHans Petter Selasky #define PCI_D0 PCI_POWERSTATE_D0 16912af734dSHans Petter Selasky #define PCI_D1 PCI_POWERSTATE_D1 17012af734dSHans Petter Selasky #define PCI_D2 PCI_POWERSTATE_D2 17112af734dSHans Petter Selasky #define PCI_D3hot PCI_POWERSTATE_D3 17212af734dSHans Petter Selasky #define PCI_D3cold 4 17312af734dSHans Petter Selasky 17412af734dSHans Petter Selasky #define PCI_POWER_ERROR PCI_POWERSTATE_UNKNOWN 17512af734dSHans Petter Selasky 176fc1d8409SBjoern A. Zeeb #define PCI_ERR_ROOT_COMMAND PCIR_AER_ROOTERR_CMD 177fc1d8409SBjoern A. Zeeb #define PCI_ERR_ROOT_ERR_SRC PCIR_AER_COR_SOURCE_ID 178fc1d8409SBjoern A. Zeeb 179fc1d8409SBjoern A. Zeeb #define PCI_EXT_CAP_ID_ERR PCIZ_AER 180fc1d8409SBjoern A. Zeeb 181a65ef215SHans Petter Selasky struct pci_dev; 1828d59ecb2SHans Petter Selasky 1838d59ecb2SHans Petter Selasky struct pci_driver { 1848d59ecb2SHans Petter Selasky struct list_head links; 1858d59ecb2SHans Petter Selasky char *name; 1868d59ecb2SHans Petter Selasky const struct pci_device_id *id_table; 1878d59ecb2SHans Petter Selasky int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); 1888d59ecb2SHans Petter Selasky void (*remove)(struct pci_dev *dev); 1898d59ecb2SHans Petter Selasky int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */ 1908d59ecb2SHans Petter Selasky int (*resume) (struct pci_dev *dev); /* Device woken up */ 1917d133393SHans Petter Selasky void (*shutdown) (struct pci_dev *dev); /* Device shutdown */ 192b38dc0a1SMark Johnston driver_t bsddriver; 1938d59ecb2SHans Petter Selasky devclass_t bsdclass; 19488156ba5SMark Johnston struct device_driver driver; 1958d59ecb2SHans Petter Selasky const struct pci_error_handlers *err_handler; 1960b7bd01aSMark Johnston bool isdrm; 1972928e60eSKonstantin Belousov int (*bsd_iov_init)(device_t dev, uint16_t num_vfs, 1982928e60eSKonstantin Belousov const nvlist_t *pf_config); 1992928e60eSKonstantin Belousov void (*bsd_iov_uninit)(device_t dev); 2002928e60eSKonstantin Belousov int (*bsd_iov_add_vf)(device_t dev, uint16_t vfnum, 2012928e60eSKonstantin Belousov const nvlist_t *vf_config); 2020b7bd01aSMark Johnston }; 2030b7bd01aSMark Johnston 2040b7bd01aSMark Johnston struct pci_bus { 2050b7bd01aSMark Johnston struct pci_dev *self; 206937a05baSJustin Hibbits int domain; 2070b7bd01aSMark Johnston int number; 2088d59ecb2SHans Petter Selasky }; 2098d59ecb2SHans Petter Selasky 2108d59ecb2SHans Petter Selasky extern struct list_head pci_drivers; 2118d59ecb2SHans Petter Selasky extern struct list_head pci_devices; 2128d59ecb2SHans Petter Selasky extern spinlock_t pci_lock; 2138d59ecb2SHans Petter Selasky 2148d59ecb2SHans Petter Selasky #define __devexit_p(x) x 2158d59ecb2SHans Petter Selasky 216d4a4960cSBjoern A. Zeeb /* 217d4a4960cSBjoern A. Zeeb * If we find drivers accessing this from multiple KPIs we may have to 218d4a4960cSBjoern A. Zeeb * refcount objects of this structure. 219d4a4960cSBjoern A. Zeeb */ 2204c274849SEmmanuel Vadot struct pci_mmio_region { 2214c274849SEmmanuel Vadot TAILQ_ENTRY(pci_mmio_region) next; 2224c274849SEmmanuel Vadot struct resource *res; 2234c274849SEmmanuel Vadot int rid; 2244c274849SEmmanuel Vadot int type; 2254c274849SEmmanuel Vadot }; 2264c274849SEmmanuel Vadot 2278d59ecb2SHans Petter Selasky struct pci_dev { 2288d59ecb2SHans Petter Selasky struct device dev; 2298d59ecb2SHans Petter Selasky struct list_head links; 2308d59ecb2SHans Petter Selasky struct pci_driver *pdrv; 2310b7bd01aSMark Johnston struct pci_bus *bus; 2328e106c52SBjoern A. Zeeb struct pci_dev *root; 2338d59ecb2SHans Petter Selasky uint16_t device; 2348d59ecb2SHans Petter Selasky uint16_t vendor; 235f2ec04a3SMark Johnston uint16_t subsystem_vendor; 236f2ec04a3SMark Johnston uint16_t subsystem_device; 2378d59ecb2SHans Petter Selasky unsigned int irq; 2388d59ecb2SHans Petter Selasky unsigned int devfn; 2396373e95eSMark Johnston uint32_t class; 2406373e95eSMark Johnston uint8_t revision; 241d4a4960cSBjoern A. Zeeb bool managed; /* devres "pcim_*(). */ 242d4a4960cSBjoern A. Zeeb bool want_iomap_res; 2434f109faaSHans Petter Selasky bool msi_enabled; 244d4a4960cSBjoern A. Zeeb bool msix_enabled; 245096104e7SNeel Chauhan phys_addr_t rom; 246096104e7SNeel Chauhan size_t romlen; 2474c274849SEmmanuel Vadot 2484c274849SEmmanuel Vadot TAILQ_HEAD(, pci_mmio_region) mmio; 2498d59ecb2SHans Petter Selasky }; 2508d59ecb2SHans Petter Selasky 251d4a4960cSBjoern A. Zeeb /* We need some meta-struct to keep track of these for devres. */ 252d4a4960cSBjoern A. Zeeb struct pci_devres { 253d4a4960cSBjoern A. Zeeb bool enable_io; 254d4a4960cSBjoern A. Zeeb /* PCIR_MAX_BAR_0 + 1 = 6 => BIT(0..5). */ 255d4a4960cSBjoern A. Zeeb uint8_t region_mask; 256d4a4960cSBjoern A. Zeeb struct resource *region_table[PCIR_MAX_BAR_0 + 1]; /* Not needed. */ 257d4a4960cSBjoern A. Zeeb }; 258d4a4960cSBjoern A. Zeeb struct pcim_iomap_devres { 259d4a4960cSBjoern A. Zeeb void *mmio_table[PCIR_MAX_BAR_0 + 1]; 260d4a4960cSBjoern A. Zeeb struct resource *res_table[PCIR_MAX_BAR_0 + 1]; 261d4a4960cSBjoern A. Zeeb }; 262d4a4960cSBjoern A. Zeeb 2638e106c52SBjoern A. Zeeb /* Internal helper function(s). */ 2648e106c52SBjoern A. Zeeb struct pci_dev *lkpinew_pci_dev(device_t); 265d4a4960cSBjoern A. Zeeb void lkpi_pci_devres_release(struct device *, void *); 266d4a4960cSBjoern A. Zeeb void lkpi_pcim_iomap_table_release(struct device *, void *); 2678e106c52SBjoern A. Zeeb 268d4a4960cSBjoern A. Zeeb static inline int 269d4a4960cSBjoern A. Zeeb pci_resource_type(struct pci_dev *pdev, int bar) 270d4a4960cSBjoern A. Zeeb { 271d4a4960cSBjoern A. Zeeb struct pci_map *pm; 272d4a4960cSBjoern A. Zeeb 273d4a4960cSBjoern A. Zeeb pm = pci_find_bar(pdev->dev.bsddev, PCIR_BAR(bar)); 274d4a4960cSBjoern A. Zeeb if (!pm) 275d4a4960cSBjoern A. Zeeb return (-1); 276d4a4960cSBjoern A. Zeeb 277d4a4960cSBjoern A. Zeeb if (PCI_BAR_IO(pm->pm_value)) 278d4a4960cSBjoern A. Zeeb return (SYS_RES_IOPORT); 279d4a4960cSBjoern A. Zeeb else 280d4a4960cSBjoern A. Zeeb return (SYS_RES_MEMORY); 281d4a4960cSBjoern A. Zeeb } 2828e106c52SBjoern A. Zeeb 2838d59ecb2SHans Petter Selasky static inline struct resource_list_entry * 284e996b07cSHans Petter Selasky linux_pci_get_rle(struct pci_dev *pdev, int type, int rid) 2858d59ecb2SHans Petter Selasky { 2868d59ecb2SHans Petter Selasky struct pci_devinfo *dinfo; 2878d59ecb2SHans Petter Selasky struct resource_list *rl; 2888d59ecb2SHans Petter Selasky 2898d59ecb2SHans Petter Selasky dinfo = device_get_ivars(pdev->dev.bsddev); 2908d59ecb2SHans Petter Selasky rl = &dinfo->resources; 2918d59ecb2SHans Petter Selasky return resource_list_find(rl, type, rid); 2928d59ecb2SHans Petter Selasky } 2938d59ecb2SHans Petter Selasky 2948d59ecb2SHans Petter Selasky static inline struct resource_list_entry * 295e996b07cSHans Petter Selasky linux_pci_get_bar(struct pci_dev *pdev, int bar) 2968d59ecb2SHans Petter Selasky { 297d4a4960cSBjoern A. Zeeb int type; 2988d59ecb2SHans Petter Selasky 299d4a4960cSBjoern A. Zeeb type = pci_resource_type(pdev, bar); 300d4a4960cSBjoern A. Zeeb if (type < 0) 301d4a4960cSBjoern A. Zeeb return (NULL); 3028d59ecb2SHans Petter Selasky bar = PCIR_BAR(bar); 303d4a4960cSBjoern A. Zeeb return (linux_pci_get_rle(pdev, type, bar)); 3048d59ecb2SHans Petter Selasky } 3058d59ecb2SHans Petter Selasky 3068d59ecb2SHans Petter Selasky static inline struct device * 307e996b07cSHans Petter Selasky linux_pci_find_irq_dev(unsigned int irq) 3088d59ecb2SHans Petter Selasky { 3098d59ecb2SHans Petter Selasky struct pci_dev *pdev; 3102f02a9e1SConrad Meyer struct device *found; 3118d59ecb2SHans Petter Selasky 3122f02a9e1SConrad Meyer found = NULL; 3138d59ecb2SHans Petter Selasky spin_lock(&pci_lock); 3148d59ecb2SHans Petter Selasky list_for_each_entry(pdev, &pci_devices, links) { 3152f02a9e1SConrad Meyer if (irq == pdev->dev.irq || 3164f109faaSHans Petter Selasky (irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) { 3172f02a9e1SConrad Meyer found = &pdev->dev; 3188d59ecb2SHans Petter Selasky break; 3198d59ecb2SHans Petter Selasky } 3202f02a9e1SConrad Meyer } 3218d59ecb2SHans Petter Selasky spin_unlock(&pci_lock); 3222f02a9e1SConrad Meyer return (found); 3238d59ecb2SHans Petter Selasky } 3248d59ecb2SHans Petter Selasky 3258d59ecb2SHans Petter Selasky /* 3268d59ecb2SHans Petter Selasky * All drivers just seem to want to inspect the type not flags. 3278d59ecb2SHans Petter Selasky */ 3288d59ecb2SHans Petter Selasky static inline int 3298d59ecb2SHans Petter Selasky pci_resource_flags(struct pci_dev *pdev, int bar) 3308d59ecb2SHans Petter Selasky { 331bdff61f8SHans Petter Selasky int type; 3328d59ecb2SHans Petter Selasky 333bdff61f8SHans Petter Selasky type = pci_resource_type(pdev, bar); 334bdff61f8SHans Petter Selasky if (type < 0) 3358d59ecb2SHans Petter Selasky return (0); 336bdff61f8SHans Petter Selasky return (1 << type); 3378d59ecb2SHans Petter Selasky } 3388d59ecb2SHans Petter Selasky 3398d59ecb2SHans Petter Selasky static inline const char * 3408d59ecb2SHans Petter Selasky pci_name(struct pci_dev *d) 3418d59ecb2SHans Petter Selasky { 3428d59ecb2SHans Petter Selasky 3438d59ecb2SHans Petter Selasky return device_get_desc(d->dev.bsddev); 3448d59ecb2SHans Petter Selasky } 3458d59ecb2SHans Petter Selasky 3468d59ecb2SHans Petter Selasky static inline void * 3478d59ecb2SHans Petter Selasky pci_get_drvdata(struct pci_dev *pdev) 3488d59ecb2SHans Petter Selasky { 3498d59ecb2SHans Petter Selasky 3508d59ecb2SHans Petter Selasky return dev_get_drvdata(&pdev->dev); 3518d59ecb2SHans Petter Selasky } 3528d59ecb2SHans Petter Selasky 3538d59ecb2SHans Petter Selasky static inline void 3548d59ecb2SHans Petter Selasky pci_set_drvdata(struct pci_dev *pdev, void *data) 3558d59ecb2SHans Petter Selasky { 3568d59ecb2SHans Petter Selasky 3578d59ecb2SHans Petter Selasky dev_set_drvdata(&pdev->dev, data); 3588d59ecb2SHans Petter Selasky } 3598d59ecb2SHans Petter Selasky 3608e106c52SBjoern A. Zeeb static inline struct pci_dev * 3618e106c52SBjoern A. Zeeb pci_dev_get(struct pci_dev *pdev) 3628e106c52SBjoern A. Zeeb { 3638e106c52SBjoern A. Zeeb 3648e106c52SBjoern A. Zeeb if (pdev != NULL) 3658e106c52SBjoern A. Zeeb get_device(&pdev->dev); 3668e106c52SBjoern A. Zeeb return (pdev); 3678e106c52SBjoern A. Zeeb } 3688e106c52SBjoern A. Zeeb 3691fac2cb4SBjoern A. Zeeb static __inline void 3701fac2cb4SBjoern A. Zeeb pci_dev_put(struct pci_dev *pdev) 3711fac2cb4SBjoern A. Zeeb { 3721fac2cb4SBjoern A. Zeeb 3731fac2cb4SBjoern A. Zeeb if (pdev != NULL) 3741fac2cb4SBjoern A. Zeeb put_device(&pdev->dev); 3751fac2cb4SBjoern A. Zeeb } 3761fac2cb4SBjoern A. Zeeb 3778d59ecb2SHans Petter Selasky static inline int 3788d59ecb2SHans Petter Selasky pci_enable_device(struct pci_dev *pdev) 3798d59ecb2SHans Petter Selasky { 3808d59ecb2SHans Petter Selasky 3818d59ecb2SHans Petter Selasky pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT); 3828d59ecb2SHans Petter Selasky pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY); 3838d59ecb2SHans Petter Selasky return (0); 3848d59ecb2SHans Petter Selasky } 3858d59ecb2SHans Petter Selasky 3868d59ecb2SHans Petter Selasky static inline void 3878d59ecb2SHans Petter Selasky pci_disable_device(struct pci_dev *pdev) 3888d59ecb2SHans Petter Selasky { 389f67b5de7SMark Johnston 390555deb3cSHans Petter Selasky pci_disable_busmaster(pdev->dev.bsddev); 3918d59ecb2SHans Petter Selasky } 3928d59ecb2SHans Petter Selasky 3938d59ecb2SHans Petter Selasky static inline int 3948d59ecb2SHans Petter Selasky pci_set_master(struct pci_dev *pdev) 3958d59ecb2SHans Petter Selasky { 3968d59ecb2SHans Petter Selasky 3978d59ecb2SHans Petter Selasky pci_enable_busmaster(pdev->dev.bsddev); 3988d59ecb2SHans Petter Selasky return (0); 3998d59ecb2SHans Petter Selasky } 4008d59ecb2SHans Petter Selasky 4018d59ecb2SHans Petter Selasky static inline int 40212af734dSHans Petter Selasky pci_set_power_state(struct pci_dev *pdev, int state) 40312af734dSHans Petter Selasky { 40412af734dSHans Petter Selasky 40512af734dSHans Petter Selasky pci_set_powerstate(pdev->dev.bsddev, state); 40612af734dSHans Petter Selasky return (0); 40712af734dSHans Petter Selasky } 40812af734dSHans Petter Selasky 40912af734dSHans Petter Selasky static inline int 4108d59ecb2SHans Petter Selasky pci_clear_master(struct pci_dev *pdev) 4118d59ecb2SHans Petter Selasky { 4128d59ecb2SHans Petter Selasky 4138d59ecb2SHans Petter Selasky pci_disable_busmaster(pdev->dev.bsddev); 4148d59ecb2SHans Petter Selasky return (0); 4158d59ecb2SHans Petter Selasky } 4168d59ecb2SHans Petter Selasky 417d4a4960cSBjoern A. Zeeb static inline struct pci_devres * 418d4a4960cSBjoern A. Zeeb lkpi_pci_devres_get_alloc(struct pci_dev *pdev) 419d4a4960cSBjoern A. Zeeb { 420d4a4960cSBjoern A. Zeeb struct pci_devres *dr; 421d4a4960cSBjoern A. Zeeb 422d4a4960cSBjoern A. Zeeb dr = lkpi_devres_find(&pdev->dev, lkpi_pci_devres_release, NULL, NULL); 423d4a4960cSBjoern A. Zeeb if (dr == NULL) { 424d4a4960cSBjoern A. Zeeb dr = lkpi_devres_alloc(lkpi_pci_devres_release, sizeof(*dr), 425d4a4960cSBjoern A. Zeeb GFP_KERNEL | __GFP_ZERO); 426d4a4960cSBjoern A. Zeeb if (dr != NULL) 427d4a4960cSBjoern A. Zeeb lkpi_devres_add(&pdev->dev, dr); 428d4a4960cSBjoern A. Zeeb } 429d4a4960cSBjoern A. Zeeb 430d4a4960cSBjoern A. Zeeb return (dr); 431d4a4960cSBjoern A. Zeeb } 432d4a4960cSBjoern A. Zeeb static inline struct pci_devres * 433d4a4960cSBjoern A. Zeeb lkpi_pci_devres_find(struct pci_dev *pdev) 434d4a4960cSBjoern A. Zeeb { 435d4a4960cSBjoern A. Zeeb 436d4a4960cSBjoern A. Zeeb if (!pdev->managed) 437d4a4960cSBjoern A. Zeeb return (NULL); 438d4a4960cSBjoern A. Zeeb 439d4a4960cSBjoern A. Zeeb return (lkpi_pci_devres_get_alloc(pdev)); 440d4a4960cSBjoern A. Zeeb } 441d4a4960cSBjoern A. Zeeb 4428d59ecb2SHans Petter Selasky static inline int 4438d59ecb2SHans Petter Selasky pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) 4448d59ecb2SHans Petter Selasky { 445d4a4960cSBjoern A. Zeeb struct resource *res; 446d4a4960cSBjoern A. Zeeb struct pci_devres *dr; 447d4a4960cSBjoern A. Zeeb struct pci_mmio_region *mmio; 4488d59ecb2SHans Petter Selasky int rid; 4498d59ecb2SHans Petter Selasky int type; 4508d59ecb2SHans Petter Selasky 451bdff61f8SHans Petter Selasky type = pci_resource_type(pdev, bar); 452bdff61f8SHans Petter Selasky if (type < 0) 4538d59ecb2SHans Petter Selasky return (-ENODEV); 4548d59ecb2SHans Petter Selasky rid = PCIR_BAR(bar); 455d4a4960cSBjoern A. Zeeb res = bus_alloc_resource_any(pdev->dev.bsddev, type, &rid, 456d4a4960cSBjoern A. Zeeb RF_ACTIVE|RF_SHAREABLE); 457d4a4960cSBjoern A. Zeeb if (res == NULL) { 458d4a4960cSBjoern A. Zeeb device_printf(pdev->dev.bsddev, "%s: failed to alloc " 459d4a4960cSBjoern A. Zeeb "bar %d type %d rid %d\n", 460d4a4960cSBjoern A. Zeeb __func__, bar, type, PCIR_BAR(bar)); 461d4a4960cSBjoern A. Zeeb return (-ENODEV); 462d4a4960cSBjoern A. Zeeb } 463d4a4960cSBjoern A. Zeeb 464d4a4960cSBjoern A. Zeeb /* 465d4a4960cSBjoern A. Zeeb * It seems there is an implicit devres tracking on these if the device 466d4a4960cSBjoern A. Zeeb * is managed; otherwise the resources are not automatiaclly freed on 467d4a4960cSBjoern A. Zeeb * FreeBSD/LinuxKPI tough they should be/are expected to be by Linux 468d4a4960cSBjoern A. Zeeb * drivers. 469d4a4960cSBjoern A. Zeeb */ 470d4a4960cSBjoern A. Zeeb dr = lkpi_pci_devres_find(pdev); 471d4a4960cSBjoern A. Zeeb if (dr != NULL) { 472d4a4960cSBjoern A. Zeeb dr->region_mask |= (1 << bar); 473d4a4960cSBjoern A. Zeeb dr->region_table[bar] = res; 474d4a4960cSBjoern A. Zeeb } 475d4a4960cSBjoern A. Zeeb 476d4a4960cSBjoern A. Zeeb /* Even if the device is not managed we need to track it for iomap. */ 477d4a4960cSBjoern A. Zeeb mmio = malloc(sizeof(*mmio), M_DEVBUF, M_WAITOK | M_ZERO); 478d4a4960cSBjoern A. Zeeb mmio->rid = PCIR_BAR(bar); 479d4a4960cSBjoern A. Zeeb mmio->type = type; 480d4a4960cSBjoern A. Zeeb mmio->res = res; 481d4a4960cSBjoern A. Zeeb TAILQ_INSERT_TAIL(&pdev->mmio, mmio, next); 482d4a4960cSBjoern A. Zeeb 4838d59ecb2SHans Petter Selasky return (0); 4848d59ecb2SHans Petter Selasky } 4858d59ecb2SHans Petter Selasky 4868d59ecb2SHans Petter Selasky static inline void 4878d59ecb2SHans Petter Selasky pci_release_region(struct pci_dev *pdev, int bar) 4888d59ecb2SHans Petter Selasky { 4898d59ecb2SHans Petter Selasky struct resource_list_entry *rle; 490d4a4960cSBjoern A. Zeeb struct pci_devres *dr; 491d4a4960cSBjoern A. Zeeb struct pci_mmio_region *mmio, *p; 4928d59ecb2SHans Petter Selasky 493e996b07cSHans Petter Selasky if ((rle = linux_pci_get_bar(pdev, bar)) == NULL) 4948d59ecb2SHans Petter Selasky return; 495d4a4960cSBjoern A. Zeeb 496d4a4960cSBjoern A. Zeeb /* 497d4a4960cSBjoern A. Zeeb * As we implicitly track the requests we also need to clear them on 498d4a4960cSBjoern A. Zeeb * release. Do clear before resource release. 499d4a4960cSBjoern A. Zeeb */ 500d4a4960cSBjoern A. Zeeb dr = lkpi_pci_devres_find(pdev); 501d4a4960cSBjoern A. Zeeb if (dr != NULL) { 502d4a4960cSBjoern A. Zeeb KASSERT(dr->region_table[bar] == rle->res, ("%s: pdev %p bar %d" 503d4a4960cSBjoern A. Zeeb " region_table res %p != rel->res %p\n", __func__, pdev, 504d4a4960cSBjoern A. Zeeb bar, dr->region_table[bar], rle->res)); 505d4a4960cSBjoern A. Zeeb dr->region_table[bar] = NULL; 506d4a4960cSBjoern A. Zeeb dr->region_mask &= ~(1 << bar); 507d4a4960cSBjoern A. Zeeb } 508d4a4960cSBjoern A. Zeeb 509d4a4960cSBjoern A. Zeeb TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { 510d4a4960cSBjoern A. Zeeb if (rle->res != (void *)rman_get_bushandle(mmio->res)) 511d4a4960cSBjoern A. Zeeb continue; 512d4a4960cSBjoern A. Zeeb TAILQ_REMOVE(&pdev->mmio, mmio, next); 513d4a4960cSBjoern A. Zeeb free(mmio, M_DEVBUF); 514d4a4960cSBjoern A. Zeeb } 515d4a4960cSBjoern A. Zeeb 5168d59ecb2SHans Petter Selasky bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res); 5178d59ecb2SHans Petter Selasky } 5188d59ecb2SHans Petter Selasky 5198d59ecb2SHans Petter Selasky static inline void 5208d59ecb2SHans Petter Selasky pci_release_regions(struct pci_dev *pdev) 5218d59ecb2SHans Petter Selasky { 5228d59ecb2SHans Petter Selasky int i; 5238d59ecb2SHans Petter Selasky 5248d59ecb2SHans Petter Selasky for (i = 0; i <= PCIR_MAX_BAR_0; i++) 5258d59ecb2SHans Petter Selasky pci_release_region(pdev, i); 5268d59ecb2SHans Petter Selasky } 5278d59ecb2SHans Petter Selasky 5288d59ecb2SHans Petter Selasky static inline int 5298d59ecb2SHans Petter Selasky pci_request_regions(struct pci_dev *pdev, const char *res_name) 5308d59ecb2SHans Petter Selasky { 5318d59ecb2SHans Petter Selasky int error; 5328d59ecb2SHans Petter Selasky int i; 5338d59ecb2SHans Petter Selasky 5348d59ecb2SHans Petter Selasky for (i = 0; i <= PCIR_MAX_BAR_0; i++) { 5358d59ecb2SHans Petter Selasky error = pci_request_region(pdev, i, res_name); 5368d59ecb2SHans Petter Selasky if (error && error != -ENODEV) { 5378d59ecb2SHans Petter Selasky pci_release_regions(pdev); 5388d59ecb2SHans Petter Selasky return (error); 5398d59ecb2SHans Petter Selasky } 5408d59ecb2SHans Petter Selasky } 5418d59ecb2SHans Petter Selasky return (0); 5428d59ecb2SHans Petter Selasky } 5438d59ecb2SHans Petter Selasky 5448d59ecb2SHans Petter Selasky static inline void 545d4a4960cSBjoern A. Zeeb lkpi_pci_disable_msix(struct pci_dev *pdev) 5468d59ecb2SHans Petter Selasky { 5478d59ecb2SHans Petter Selasky 5488d59ecb2SHans Petter Selasky pci_release_msi(pdev->dev.bsddev); 549e1992aa1SHans Petter Selasky 550e1992aa1SHans Petter Selasky /* 551e1992aa1SHans Petter Selasky * The MSIX IRQ numbers associated with this PCI device are no 552e1992aa1SHans Petter Selasky * longer valid and might be re-assigned. Make sure 553e1992aa1SHans Petter Selasky * linux_pci_find_irq_dev() does no longer see them by 554e1992aa1SHans Petter Selasky * resetting their references to zero: 555e1992aa1SHans Petter Selasky */ 5564f109faaSHans Petter Selasky pdev->dev.irq_start = 0; 5574f109faaSHans Petter Selasky pdev->dev.irq_end = 0; 558d4a4960cSBjoern A. Zeeb pdev->msix_enabled = false; 5594f109faaSHans Petter Selasky } 560d4a4960cSBjoern A. Zeeb /* Only for consistency. No conflict on that one. */ 561d4a4960cSBjoern A. Zeeb #define pci_disable_msix(pdev) lkpi_pci_disable_msix(pdev) 5624f109faaSHans Petter Selasky 5634f109faaSHans Petter Selasky static inline void 564d4a4960cSBjoern A. Zeeb lkpi_pci_disable_msi(struct pci_dev *pdev) 5654f109faaSHans Petter Selasky { 5664f109faaSHans Petter Selasky 5674f109faaSHans Petter Selasky pci_release_msi(pdev->dev.bsddev); 5684f109faaSHans Petter Selasky 5694f109faaSHans Petter Selasky pdev->dev.irq_start = 0; 5704f109faaSHans Petter Selasky pdev->dev.irq_end = 0; 5714f109faaSHans Petter Selasky pdev->irq = pdev->dev.irq; 5724f109faaSHans Petter Selasky pdev->msi_enabled = false; 5738d59ecb2SHans Petter Selasky } 574d4a4960cSBjoern A. Zeeb #define pci_disable_msi(pdev) lkpi_pci_disable_msi(pdev) 575539228d3SBjoern A. Zeeb #define pci_free_irq_vectors(pdev) lkpi_pci_disable_msi(pdev) 576105a37caSEmmanuel Vadot 577937a05baSJustin Hibbits unsigned long pci_resource_start(struct pci_dev *pdev, int bar); 578937a05baSJustin Hibbits unsigned long pci_resource_len(struct pci_dev *pdev, int bar); 579937a05baSJustin Hibbits 58012af734dSHans Petter Selasky static inline bus_addr_t 58112af734dSHans Petter Selasky pci_bus_address(struct pci_dev *pdev, int bar) 58212af734dSHans Petter Selasky { 58312af734dSHans Petter Selasky 58412af734dSHans Petter Selasky return (pci_resource_start(pdev, bar)); 58512af734dSHans Petter Selasky } 58612af734dSHans Petter Selasky 5878d59ecb2SHans Petter Selasky #define PCI_CAP_ID_EXP PCIY_EXPRESS 5888d59ecb2SHans Petter Selasky #define PCI_CAP_ID_PCIX PCIY_PCIX 58912af734dSHans Petter Selasky #define PCI_CAP_ID_AGP PCIY_AGP 59012af734dSHans Petter Selasky #define PCI_CAP_ID_PM PCIY_PMG 5918d59ecb2SHans Petter Selasky 59212af734dSHans Petter Selasky #define PCI_EXP_DEVCTL PCIER_DEVICE_CTL 59312af734dSHans Petter Selasky #define PCI_EXP_DEVCTL_PAYLOAD PCIEM_CTL_MAX_PAYLOAD 59412af734dSHans Petter Selasky #define PCI_EXP_DEVCTL_READRQ PCIEM_CTL_MAX_READ_REQUEST 59512af734dSHans Petter Selasky #define PCI_EXP_LNKCTL PCIER_LINK_CTL 59612af734dSHans Petter Selasky #define PCI_EXP_LNKSTA PCIER_LINK_STA 5978d59ecb2SHans Petter Selasky 5988d59ecb2SHans Petter Selasky static inline int 5998d59ecb2SHans Petter Selasky pci_find_capability(struct pci_dev *pdev, int capid) 6008d59ecb2SHans Petter Selasky { 6018d59ecb2SHans Petter Selasky int reg; 6028d59ecb2SHans Petter Selasky 6038d59ecb2SHans Petter Selasky if (pci_find_cap(pdev->dev.bsddev, capid, ®)) 6048d59ecb2SHans Petter Selasky return (0); 6058d59ecb2SHans Petter Selasky return (reg); 6068d59ecb2SHans Petter Selasky } 6078d59ecb2SHans Petter Selasky 6088d59ecb2SHans Petter Selasky static inline int pci_pcie_cap(struct pci_dev *dev) 6098d59ecb2SHans Petter Selasky { 6108d59ecb2SHans Petter Selasky return pci_find_capability(dev, PCI_CAP_ID_EXP); 6118d59ecb2SHans Petter Selasky } 6128d59ecb2SHans Petter Selasky 6138d59ecb2SHans Petter Selasky static inline int 6148e106c52SBjoern A. Zeeb pci_find_ext_capability(struct pci_dev *pdev, int capid) 6158e106c52SBjoern A. Zeeb { 6168e106c52SBjoern A. Zeeb int reg; 6178e106c52SBjoern A. Zeeb 6188e106c52SBjoern A. Zeeb if (pci_find_extcap(pdev->dev.bsddev, capid, ®)) 6198e106c52SBjoern A. Zeeb return (0); 6208e106c52SBjoern A. Zeeb return (reg); 6218e106c52SBjoern A. Zeeb } 6228e106c52SBjoern A. Zeeb 6238e106c52SBjoern A. Zeeb #define PCIM_PCAP_PME_SHIFT 11 6248e106c52SBjoern A. Zeeb static __inline bool 6258e106c52SBjoern A. Zeeb pci_pme_capable(struct pci_dev *pdev, uint32_t flag) 6268e106c52SBjoern A. Zeeb { 6278e106c52SBjoern A. Zeeb struct pci_devinfo *dinfo; 6288e106c52SBjoern A. Zeeb pcicfgregs *cfg; 6298e106c52SBjoern A. Zeeb 6308e106c52SBjoern A. Zeeb if (flag > (PCIM_PCAP_D3PME_COLD >> PCIM_PCAP_PME_SHIFT)) 6318e106c52SBjoern A. Zeeb return (false); 6328e106c52SBjoern A. Zeeb 6338e106c52SBjoern A. Zeeb dinfo = device_get_ivars(pdev->dev.bsddev); 6348e106c52SBjoern A. Zeeb cfg = &dinfo->cfg; 6358e106c52SBjoern A. Zeeb 6368e106c52SBjoern A. Zeeb if (cfg->pp.pp_cap == 0) 6378e106c52SBjoern A. Zeeb return (false); 6388e106c52SBjoern A. Zeeb 6398e106c52SBjoern A. Zeeb if ((cfg->pp.pp_cap & (1 << (PCIM_PCAP_PME_SHIFT + flag))) != 0) 6408e106c52SBjoern A. Zeeb return (true); 6418e106c52SBjoern A. Zeeb 6428e106c52SBjoern A. Zeeb return (false); 6438e106c52SBjoern A. Zeeb } 6448e106c52SBjoern A. Zeeb 6458e106c52SBjoern A. Zeeb static inline int 6468e106c52SBjoern A. Zeeb pci_disable_link_state(struct pci_dev *pdev, uint32_t flags) 6478e106c52SBjoern A. Zeeb { 6488e106c52SBjoern A. Zeeb 6498e106c52SBjoern A. Zeeb if (!pci_enable_aspm) 6508e106c52SBjoern A. Zeeb return (-EPERM); 6518e106c52SBjoern A. Zeeb 6528e106c52SBjoern A. Zeeb return (-ENXIO); 6538e106c52SBjoern A. Zeeb } 6548e106c52SBjoern A. Zeeb 6558e106c52SBjoern A. Zeeb static inline int 6568d59ecb2SHans Petter Selasky pci_read_config_byte(struct pci_dev *pdev, int where, u8 *val) 6578d59ecb2SHans Petter Selasky { 6588d59ecb2SHans Petter Selasky 6598d59ecb2SHans Petter Selasky *val = (u8)pci_read_config(pdev->dev.bsddev, where, 1); 6608d59ecb2SHans Petter Selasky return (0); 6618d59ecb2SHans Petter Selasky } 6628d59ecb2SHans Petter Selasky 6638d59ecb2SHans Petter Selasky static inline int 6648d59ecb2SHans Petter Selasky pci_read_config_word(struct pci_dev *pdev, int where, u16 *val) 6658d59ecb2SHans Petter Selasky { 6668d59ecb2SHans Petter Selasky 6678d59ecb2SHans Petter Selasky *val = (u16)pci_read_config(pdev->dev.bsddev, where, 2); 6688d59ecb2SHans Petter Selasky return (0); 6698d59ecb2SHans Petter Selasky } 6708d59ecb2SHans Petter Selasky 6718d59ecb2SHans Petter Selasky static inline int 6728d59ecb2SHans Petter Selasky pci_read_config_dword(struct pci_dev *pdev, int where, u32 *val) 6738d59ecb2SHans Petter Selasky { 6748d59ecb2SHans Petter Selasky 6758d59ecb2SHans Petter Selasky *val = (u32)pci_read_config(pdev->dev.bsddev, where, 4); 6768d59ecb2SHans Petter Selasky return (0); 6778d59ecb2SHans Petter Selasky } 6788d59ecb2SHans Petter Selasky 6798d59ecb2SHans Petter Selasky static inline int 6808d59ecb2SHans Petter Selasky pci_write_config_byte(struct pci_dev *pdev, int where, u8 val) 6818d59ecb2SHans Petter Selasky { 6828d59ecb2SHans Petter Selasky 6838d59ecb2SHans Petter Selasky pci_write_config(pdev->dev.bsddev, where, val, 1); 6848d59ecb2SHans Petter Selasky return (0); 6858d59ecb2SHans Petter Selasky } 6868d59ecb2SHans Petter Selasky 6878d59ecb2SHans Petter Selasky static inline int 6888d59ecb2SHans Petter Selasky pci_write_config_word(struct pci_dev *pdev, int where, u16 val) 6898d59ecb2SHans Petter Selasky { 6908d59ecb2SHans Petter Selasky 6918d59ecb2SHans Petter Selasky pci_write_config(pdev->dev.bsddev, where, val, 2); 6928d59ecb2SHans Petter Selasky return (0); 6938d59ecb2SHans Petter Selasky } 6948d59ecb2SHans Petter Selasky 6958d59ecb2SHans Petter Selasky static inline int 6968d59ecb2SHans Petter Selasky pci_write_config_dword(struct pci_dev *pdev, int where, u32 val) 6978d59ecb2SHans Petter Selasky { 6988d59ecb2SHans Petter Selasky 6998d59ecb2SHans Petter Selasky pci_write_config(pdev->dev.bsddev, where, val, 4); 7008d59ecb2SHans Petter Selasky return (0); 7018d59ecb2SHans Petter Selasky } 7028d59ecb2SHans Petter Selasky 7030b7bd01aSMark Johnston int linux_pci_register_driver(struct pci_driver *pdrv); 7040b7bd01aSMark Johnston int linux_pci_register_drm_driver(struct pci_driver *pdrv); 7050b7bd01aSMark Johnston void linux_pci_unregister_driver(struct pci_driver *pdrv); 7065098ed5fSJohannes Lundberg void linux_pci_unregister_drm_driver(struct pci_driver *pdrv); 7070b7bd01aSMark Johnston 7080b7bd01aSMark Johnston #define pci_register_driver(pdrv) linux_pci_register_driver(pdrv) 7090b7bd01aSMark Johnston #define pci_unregister_driver(pdrv) linux_pci_unregister_driver(pdrv) 7108d59ecb2SHans Petter Selasky 7118d59ecb2SHans Petter Selasky struct msix_entry { 7128d59ecb2SHans Petter Selasky int entry; 7138d59ecb2SHans Petter Selasky int vector; 7148d59ecb2SHans Petter Selasky }; 7158d59ecb2SHans Petter Selasky 7168d59ecb2SHans Petter Selasky /* 7178d59ecb2SHans Petter Selasky * Enable msix, positive errors indicate actual number of available 7188d59ecb2SHans Petter Selasky * vectors. Negative errors are failures. 7198d59ecb2SHans Petter Selasky * 7208d59ecb2SHans Petter Selasky * NB: define added to prevent this definition of pci_enable_msix from 7218d59ecb2SHans Petter Selasky * clashing with the native FreeBSD version. 7228d59ecb2SHans Petter Selasky */ 723fa0d4f31SHans Petter Selasky #define pci_enable_msix(...) \ 724fa0d4f31SHans Petter Selasky linux_pci_enable_msix(__VA_ARGS__) 725fa0d4f31SHans Petter Selasky 7268d59ecb2SHans Petter Selasky static inline int 7278d59ecb2SHans Petter Selasky pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq) 7288d59ecb2SHans Petter Selasky { 7298d59ecb2SHans Petter Selasky struct resource_list_entry *rle; 7308d59ecb2SHans Petter Selasky int error; 7318d59ecb2SHans Petter Selasky int avail; 7328d59ecb2SHans Petter Selasky int i; 7338d59ecb2SHans Petter Selasky 7348d59ecb2SHans Petter Selasky avail = pci_msix_count(pdev->dev.bsddev); 7358d59ecb2SHans Petter Selasky if (avail < nreq) { 7368d59ecb2SHans Petter Selasky if (avail == 0) 7378d59ecb2SHans Petter Selasky return -EINVAL; 7388d59ecb2SHans Petter Selasky return avail; 7398d59ecb2SHans Petter Selasky } 7408d59ecb2SHans Petter Selasky avail = nreq; 7418d59ecb2SHans Petter Selasky if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0) 7428d59ecb2SHans Petter Selasky return error; 7438d59ecb2SHans Petter Selasky /* 7448d59ecb2SHans Petter Selasky * Handle case where "pci_alloc_msix()" may allocate less 7458d59ecb2SHans Petter Selasky * interrupts than available and return with no error: 7468d59ecb2SHans Petter Selasky */ 7478d59ecb2SHans Petter Selasky if (avail < nreq) { 7488d59ecb2SHans Petter Selasky pci_release_msi(pdev->dev.bsddev); 7498d59ecb2SHans Petter Selasky return avail; 7508d59ecb2SHans Petter Selasky } 751e996b07cSHans Petter Selasky rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1); 7524f109faaSHans Petter Selasky pdev->dev.irq_start = rle->start; 7534f109faaSHans Petter Selasky pdev->dev.irq_end = rle->start + avail; 7548d59ecb2SHans Petter Selasky for (i = 0; i < nreq; i++) 7554f109faaSHans Petter Selasky entries[i].vector = pdev->dev.irq_start + i; 756d4a4960cSBjoern A. Zeeb pdev->msix_enabled = true; 7578d59ecb2SHans Petter Selasky return (0); 7588d59ecb2SHans Petter Selasky } 7598d59ecb2SHans Petter Selasky 760fa0d4f31SHans Petter Selasky #define pci_enable_msix_range(...) \ 761fa0d4f31SHans Petter Selasky linux_pci_enable_msix_range(__VA_ARGS__) 762fa0d4f31SHans Petter Selasky 7638d59ecb2SHans Petter Selasky static inline int 7648d59ecb2SHans Petter Selasky pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, 7658d59ecb2SHans Petter Selasky int minvec, int maxvec) 7668d59ecb2SHans Petter Selasky { 7678d59ecb2SHans Petter Selasky int nvec = maxvec; 7688d59ecb2SHans Petter Selasky int rc; 7698d59ecb2SHans Petter Selasky 7708d59ecb2SHans Petter Selasky if (maxvec < minvec) 7718d59ecb2SHans Petter Selasky return (-ERANGE); 7728d59ecb2SHans Petter Selasky 7738d59ecb2SHans Petter Selasky do { 7748d59ecb2SHans Petter Selasky rc = pci_enable_msix(dev, entries, nvec); 7758d59ecb2SHans Petter Selasky if (rc < 0) { 7768d59ecb2SHans Petter Selasky return (rc); 7778d59ecb2SHans Petter Selasky } else if (rc > 0) { 7788d59ecb2SHans Petter Selasky if (rc < minvec) 7798d59ecb2SHans Petter Selasky return (-ENOSPC); 7808d59ecb2SHans Petter Selasky nvec = rc; 7818d59ecb2SHans Petter Selasky } 7828d59ecb2SHans Petter Selasky } while (rc); 7838d59ecb2SHans Petter Selasky return (nvec); 7848d59ecb2SHans Petter Selasky } 7858d59ecb2SHans Petter Selasky 7864f109faaSHans Petter Selasky #define pci_enable_msi(pdev) \ 7874f109faaSHans Petter Selasky linux_pci_enable_msi(pdev) 7884f109faaSHans Petter Selasky 7894f109faaSHans Petter Selasky static inline int 7904f109faaSHans Petter Selasky pci_enable_msi(struct pci_dev *pdev) 7914f109faaSHans Petter Selasky { 7924f109faaSHans Petter Selasky struct resource_list_entry *rle; 7934f109faaSHans Petter Selasky int error; 7944f109faaSHans Petter Selasky int avail; 7954f109faaSHans Petter Selasky 7964f109faaSHans Petter Selasky avail = pci_msi_count(pdev->dev.bsddev); 7974f109faaSHans Petter Selasky if (avail < 1) 7984f109faaSHans Petter Selasky return -EINVAL; 7994f109faaSHans Petter Selasky 8004f109faaSHans Petter Selasky avail = 1; /* this function only enable one MSI IRQ */ 8014f109faaSHans Petter Selasky if ((error = -pci_alloc_msi(pdev->dev.bsddev, &avail)) != 0) 8024f109faaSHans Petter Selasky return error; 8034f109faaSHans Petter Selasky 8044f109faaSHans Petter Selasky rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1); 8054f109faaSHans Petter Selasky pdev->dev.irq_start = rle->start; 8064f109faaSHans Petter Selasky pdev->dev.irq_end = rle->start + avail; 8074f109faaSHans Petter Selasky pdev->irq = rle->start; 8084f109faaSHans Petter Selasky pdev->msi_enabled = true; 8094f109faaSHans Petter Selasky return (0); 8104f109faaSHans Petter Selasky } 8114f109faaSHans Petter Selasky 812452d59e1SSlava Shwartsman static inline int 813452d59e1SSlava Shwartsman pci_channel_offline(struct pci_dev *pdev) 8148d59ecb2SHans Petter Selasky { 815452d59e1SSlava Shwartsman 816c5161386SHans Petter Selasky return (pci_read_config(pdev->dev.bsddev, PCIR_VENDOR, 2) == PCIV_INVALID); 8178d59ecb2SHans Petter Selasky } 8188d59ecb2SHans Petter Selasky 8198d59ecb2SHans Petter Selasky static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) 8208d59ecb2SHans Petter Selasky { 8218d59ecb2SHans Petter Selasky return -ENODEV; 8228d59ecb2SHans Petter Selasky } 8238d59ecb2SHans Petter Selasky static inline void pci_disable_sriov(struct pci_dev *dev) 8248d59ecb2SHans Petter Selasky { 8258d59ecb2SHans Petter Selasky } 8268d59ecb2SHans Petter Selasky 827d4a4960cSBjoern A. Zeeb static inline struct resource * 828d4a4960cSBjoern A. Zeeb _lkpi_pci_iomap(struct pci_dev *pdev, int bar, int mmio_size __unused) 8294c274849SEmmanuel Vadot { 830d4a4960cSBjoern A. Zeeb struct pci_mmio_region *mmio, *p; 831d4a4960cSBjoern A. Zeeb int type; 832d4a4960cSBjoern A. Zeeb 833d4a4960cSBjoern A. Zeeb type = pci_resource_type(pdev, bar); 834d4a4960cSBjoern A. Zeeb if (type < 0) { 835d4a4960cSBjoern A. Zeeb device_printf(pdev->dev.bsddev, "%s: bar %d type %d\n", 836d4a4960cSBjoern A. Zeeb __func__, bar, type); 837d4a4960cSBjoern A. Zeeb return (NULL); 838d4a4960cSBjoern A. Zeeb } 839d4a4960cSBjoern A. Zeeb 840d4a4960cSBjoern A. Zeeb /* 841d4a4960cSBjoern A. Zeeb * Check for duplicate mappings. 842d4a4960cSBjoern A. Zeeb * This can happen if a driver calls pci_request_region() first. 843d4a4960cSBjoern A. Zeeb */ 844d4a4960cSBjoern A. Zeeb TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { 845d4a4960cSBjoern A. Zeeb if (mmio->type == type && mmio->rid == PCIR_BAR(bar)) { 846d4a4960cSBjoern A. Zeeb return (mmio->res); 847d4a4960cSBjoern A. Zeeb } 848d4a4960cSBjoern A. Zeeb } 8494c274849SEmmanuel Vadot 8504c274849SEmmanuel Vadot mmio = malloc(sizeof(*mmio), M_DEVBUF, M_WAITOK | M_ZERO); 851d4a4960cSBjoern A. Zeeb mmio->rid = PCIR_BAR(bar); 852d4a4960cSBjoern A. Zeeb mmio->type = type; 853d4a4960cSBjoern A. Zeeb mmio->res = bus_alloc_resource_any(pdev->dev.bsddev, mmio->type, 854d4a4960cSBjoern A. Zeeb &mmio->rid, RF_ACTIVE|RF_SHAREABLE); 8554c274849SEmmanuel Vadot if (mmio->res == NULL) { 856d4a4960cSBjoern A. Zeeb device_printf(pdev->dev.bsddev, "%s: failed to alloc " 857d4a4960cSBjoern A. Zeeb "bar %d type %d rid %d\n", 858d4a4960cSBjoern A. Zeeb __func__, bar, type, PCIR_BAR(bar)); 8594c274849SEmmanuel Vadot free(mmio, M_DEVBUF); 8604c274849SEmmanuel Vadot return (NULL); 8614c274849SEmmanuel Vadot } 862d4a4960cSBjoern A. Zeeb TAILQ_INSERT_TAIL(&pdev->mmio, mmio, next); 8634c274849SEmmanuel Vadot 864d4a4960cSBjoern A. Zeeb return (mmio->res); 865d4a4960cSBjoern A. Zeeb } 866d4a4960cSBjoern A. Zeeb 867d4a4960cSBjoern A. Zeeb static inline void * 868d4a4960cSBjoern A. Zeeb pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size) 869d4a4960cSBjoern A. Zeeb { 870d4a4960cSBjoern A. Zeeb struct resource *res; 871d4a4960cSBjoern A. Zeeb 872d4a4960cSBjoern A. Zeeb res = _lkpi_pci_iomap(pdev, mmio_bar, mmio_size); 873d4a4960cSBjoern A. Zeeb if (res == NULL) 874d4a4960cSBjoern A. Zeeb return (NULL); 875d4a4960cSBjoern A. Zeeb /* This is a FreeBSD extension so we can use bus_*(). */ 876d4a4960cSBjoern A. Zeeb if (pdev->want_iomap_res) 877d4a4960cSBjoern A. Zeeb return (res); 878d4a4960cSBjoern A. Zeeb return ((void *)rman_get_bushandle(res)); 8794c274849SEmmanuel Vadot } 8804c274849SEmmanuel Vadot 8814c274849SEmmanuel Vadot static inline void 882d4a4960cSBjoern A. Zeeb pci_iounmap(struct pci_dev *pdev, void *res) 8834c274849SEmmanuel Vadot { 8844c274849SEmmanuel Vadot struct pci_mmio_region *mmio, *p; 8854c274849SEmmanuel Vadot 886d4a4960cSBjoern A. Zeeb TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { 8874c274849SEmmanuel Vadot if (res != (void *)rman_get_bushandle(mmio->res)) 8884c274849SEmmanuel Vadot continue; 889d4a4960cSBjoern A. Zeeb bus_release_resource(pdev->dev.bsddev, 8904c274849SEmmanuel Vadot mmio->type, mmio->rid, mmio->res); 891d4a4960cSBjoern A. Zeeb TAILQ_REMOVE(&pdev->mmio, mmio, next); 8924c274849SEmmanuel Vadot free(mmio, M_DEVBUF); 8934c274849SEmmanuel Vadot return; 8944c274849SEmmanuel Vadot } 8954c274849SEmmanuel Vadot } 8964c274849SEmmanuel Vadot 897105a37caSEmmanuel Vadot static inline void 898105a37caSEmmanuel Vadot lkpi_pci_save_state(struct pci_dev *pdev) 899105a37caSEmmanuel Vadot { 900105a37caSEmmanuel Vadot 901105a37caSEmmanuel Vadot pci_save_state(pdev->dev.bsddev); 902105a37caSEmmanuel Vadot } 903105a37caSEmmanuel Vadot 904105a37caSEmmanuel Vadot static inline void 905105a37caSEmmanuel Vadot lkpi_pci_restore_state(struct pci_dev *pdev) 906105a37caSEmmanuel Vadot { 907105a37caSEmmanuel Vadot 908105a37caSEmmanuel Vadot pci_restore_state(pdev->dev.bsddev); 909105a37caSEmmanuel Vadot } 910105a37caSEmmanuel Vadot 911105a37caSEmmanuel Vadot #define pci_save_state(dev) lkpi_pci_save_state(dev) 912105a37caSEmmanuel Vadot #define pci_restore_state(dev) lkpi_pci_restore_state(dev) 913105a37caSEmmanuel Vadot 9148d59ecb2SHans Petter Selasky #define DEFINE_PCI_DEVICE_TABLE(_table) \ 9158d59ecb2SHans Petter Selasky const struct pci_device_id _table[] __devinitdata 9168d59ecb2SHans Petter Selasky 9178d59ecb2SHans Petter Selasky /* XXX This should not be necessary. */ 9188d59ecb2SHans Petter Selasky #define pcix_set_mmrbc(d, v) 0 9198d59ecb2SHans Petter Selasky #define pcix_get_max_mmrbc(d) 0 9203f322b22SMark Johnston #define pcie_set_readrq(d, v) pci_set_max_read_req((d)->dev.bsddev, (v)) 9218d59ecb2SHans Petter Selasky 9228d59ecb2SHans Petter Selasky #define PCI_DMA_BIDIRECTIONAL 0 9238d59ecb2SHans Petter Selasky #define PCI_DMA_TODEVICE 1 9248d59ecb2SHans Petter Selasky #define PCI_DMA_FROMDEVICE 2 9258d59ecb2SHans Petter Selasky #define PCI_DMA_NONE 3 9268d59ecb2SHans Petter Selasky 9278d59ecb2SHans Petter Selasky #define pci_pool dma_pool 9281724ded4SHans Petter Selasky #define pci_pool_destroy(...) dma_pool_destroy(__VA_ARGS__) 9291724ded4SHans Petter Selasky #define pci_pool_alloc(...) dma_pool_alloc(__VA_ARGS__) 9301724ded4SHans Petter Selasky #define pci_pool_free(...) dma_pool_free(__VA_ARGS__) 9318d59ecb2SHans Petter Selasky #define pci_pool_create(_name, _pdev, _size, _align, _alloc) \ 9328d59ecb2SHans Petter Selasky dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc) 9338d59ecb2SHans Petter Selasky #define pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle) \ 9348d59ecb2SHans Petter Selasky dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ 9358d59ecb2SHans Petter Selasky _size, _vaddr, _dma_handle) 9368d59ecb2SHans Petter Selasky #define pci_map_sg(_hwdev, _sg, _nents, _dir) \ 9378d59ecb2SHans Petter Selasky dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev), \ 9388d59ecb2SHans Petter Selasky _sg, _nents, (enum dma_data_direction)_dir) 9398d59ecb2SHans Petter Selasky #define pci_map_single(_hwdev, _ptr, _size, _dir) \ 9408d59ecb2SHans Petter Selasky dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev), \ 9418d59ecb2SHans Petter Selasky (_ptr), (_size), (enum dma_data_direction)_dir) 9428d59ecb2SHans Petter Selasky #define pci_unmap_single(_hwdev, _addr, _size, _dir) \ 9438d59ecb2SHans Petter Selasky dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ 9448d59ecb2SHans Petter Selasky _addr, _size, (enum dma_data_direction)_dir) 9458d59ecb2SHans Petter Selasky #define pci_unmap_sg(_hwdev, _sg, _nents, _dir) \ 9468d59ecb2SHans Petter Selasky dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ 9478d59ecb2SHans Petter Selasky _sg, _nents, (enum dma_data_direction)_dir) 9488d59ecb2SHans Petter Selasky #define pci_map_page(_hwdev, _page, _offset, _size, _dir) \ 9498d59ecb2SHans Petter Selasky dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\ 9508d59ecb2SHans Petter Selasky _offset, _size, (enum dma_data_direction)_dir) 9518d59ecb2SHans Petter Selasky #define pci_unmap_page(_hwdev, _dma_address, _size, _dir) \ 9528d59ecb2SHans Petter Selasky dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ 9538d59ecb2SHans Petter Selasky _dma_address, _size, (enum dma_data_direction)_dir) 9548d59ecb2SHans Petter Selasky #define pci_set_dma_mask(_pdev, mask) dma_set_mask(&(_pdev)->dev, (mask)) 9558d59ecb2SHans Petter Selasky #define pci_dma_mapping_error(_pdev, _dma_addr) \ 9568d59ecb2SHans Petter Selasky dma_mapping_error(&(_pdev)->dev, _dma_addr) 9578d59ecb2SHans Petter Selasky #define pci_set_consistent_dma_mask(_pdev, _mask) \ 9588d59ecb2SHans Petter Selasky dma_set_coherent_mask(&(_pdev)->dev, (_mask)) 9598d59ecb2SHans Petter Selasky #define DECLARE_PCI_UNMAP_ADDR(x) DEFINE_DMA_UNMAP_ADDR(x); 9608d59ecb2SHans Petter Selasky #define DECLARE_PCI_UNMAP_LEN(x) DEFINE_DMA_UNMAP_LEN(x); 9618d59ecb2SHans Petter Selasky #define pci_unmap_addr dma_unmap_addr 9628d59ecb2SHans Petter Selasky #define pci_unmap_addr_set dma_unmap_addr_set 9638d59ecb2SHans Petter Selasky #define pci_unmap_len dma_unmap_len 9648d59ecb2SHans Petter Selasky #define pci_unmap_len_set dma_unmap_len_set 9658d59ecb2SHans Petter Selasky 9668d59ecb2SHans Petter Selasky typedef unsigned int __bitwise pci_channel_state_t; 9678d59ecb2SHans Petter Selasky typedef unsigned int __bitwise pci_ers_result_t; 9688d59ecb2SHans Petter Selasky 9698d59ecb2SHans Petter Selasky enum pci_channel_state { 970a65ef215SHans Petter Selasky pci_channel_io_normal = 1, 971a65ef215SHans Petter Selasky pci_channel_io_frozen = 2, 972a65ef215SHans Petter Selasky pci_channel_io_perm_failure = 3, 9738d59ecb2SHans Petter Selasky }; 9748d59ecb2SHans Petter Selasky 9758d59ecb2SHans Petter Selasky enum pci_ers_result { 976a65ef215SHans Petter Selasky PCI_ERS_RESULT_NONE = 1, 977a65ef215SHans Petter Selasky PCI_ERS_RESULT_CAN_RECOVER = 2, 978a65ef215SHans Petter Selasky PCI_ERS_RESULT_NEED_RESET = 3, 979a65ef215SHans Petter Selasky PCI_ERS_RESULT_DISCONNECT = 4, 980a65ef215SHans Petter Selasky PCI_ERS_RESULT_RECOVERED = 5, 9818d59ecb2SHans Petter Selasky }; 9828d59ecb2SHans Petter Selasky 9838d59ecb2SHans Petter Selasky /* PCI bus error event callbacks */ 9848d59ecb2SHans Petter Selasky struct pci_error_handlers { 9858d59ecb2SHans Petter Selasky pci_ers_result_t (*error_detected)(struct pci_dev *dev, 9868d59ecb2SHans Petter Selasky enum pci_channel_state error); 9878d59ecb2SHans Petter Selasky pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev); 9888d59ecb2SHans Petter Selasky pci_ers_result_t (*link_reset)(struct pci_dev *dev); 9898d59ecb2SHans Petter Selasky pci_ers_result_t (*slot_reset)(struct pci_dev *dev); 9908d59ecb2SHans Petter Selasky void (*resume)(struct pci_dev *dev); 9918d59ecb2SHans Petter Selasky }; 9928d59ecb2SHans Petter Selasky 993a65ef215SHans Petter Selasky /* FreeBSD does not support SRIOV - yet */ 9948d59ecb2SHans Petter Selasky static inline struct pci_dev *pci_physfn(struct pci_dev *dev) 9958d59ecb2SHans Petter Selasky { 9968d59ecb2SHans Petter Selasky return dev; 9978d59ecb2SHans Petter Selasky } 9988d59ecb2SHans Petter Selasky 9998d59ecb2SHans Petter Selasky static inline bool pci_is_pcie(struct pci_dev *dev) 10008d59ecb2SHans Petter Selasky { 10018d59ecb2SHans Petter Selasky return !!pci_pcie_cap(dev); 10028d59ecb2SHans Petter Selasky } 10038d59ecb2SHans Petter Selasky 10048d59ecb2SHans Petter Selasky static inline u16 pcie_flags_reg(struct pci_dev *dev) 10058d59ecb2SHans Petter Selasky { 10068d59ecb2SHans Petter Selasky int pos; 10078d59ecb2SHans Petter Selasky u16 reg16; 10088d59ecb2SHans Petter Selasky 10098d59ecb2SHans Petter Selasky pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 10108d59ecb2SHans Petter Selasky if (!pos) 10118d59ecb2SHans Petter Selasky return 0; 10128d59ecb2SHans Petter Selasky 10138d59ecb2SHans Petter Selasky pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); 10148d59ecb2SHans Petter Selasky 10158d59ecb2SHans Petter Selasky return reg16; 10168d59ecb2SHans Petter Selasky } 10178d59ecb2SHans Petter Selasky 10188d59ecb2SHans Petter Selasky static inline int pci_pcie_type(struct pci_dev *dev) 10198d59ecb2SHans Petter Selasky { 10208d59ecb2SHans Petter Selasky return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4; 10218d59ecb2SHans Petter Selasky } 10228d59ecb2SHans Petter Selasky 10238d59ecb2SHans Petter Selasky static inline int pcie_cap_version(struct pci_dev *dev) 10248d59ecb2SHans Petter Selasky { 10258d59ecb2SHans Petter Selasky return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS; 10268d59ecb2SHans Petter Selasky } 10278d59ecb2SHans Petter Selasky 10288d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_lnkctl(struct pci_dev *dev) 10298d59ecb2SHans Petter Selasky { 10308d59ecb2SHans Petter Selasky int type = pci_pcie_type(dev); 10318d59ecb2SHans Petter Selasky 10328d59ecb2SHans Petter Selasky return pcie_cap_version(dev) > 1 || 10338d59ecb2SHans Petter Selasky type == PCI_EXP_TYPE_ROOT_PORT || 10348d59ecb2SHans Petter Selasky type == PCI_EXP_TYPE_ENDPOINT || 10358d59ecb2SHans Petter Selasky type == PCI_EXP_TYPE_LEG_END; 10368d59ecb2SHans Petter Selasky } 10378d59ecb2SHans Petter Selasky 10388d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_devctl(const struct pci_dev *dev) 10398d59ecb2SHans Petter Selasky { 10408d59ecb2SHans Petter Selasky return true; 10418d59ecb2SHans Petter Selasky } 10428d59ecb2SHans Petter Selasky 10438d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_sltctl(struct pci_dev *dev) 10448d59ecb2SHans Petter Selasky { 10458d59ecb2SHans Petter Selasky int type = pci_pcie_type(dev); 10468d59ecb2SHans Petter Selasky 104783630517SEd Maste return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT || 10488d59ecb2SHans Petter Selasky (type == PCI_EXP_TYPE_DOWNSTREAM && 10498d59ecb2SHans Petter Selasky pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT); 10508d59ecb2SHans Petter Selasky } 10518d59ecb2SHans Petter Selasky 10528d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_rtctl(struct pci_dev *dev) 10538d59ecb2SHans Petter Selasky { 10548d59ecb2SHans Petter Selasky int type = pci_pcie_type(dev); 10558d59ecb2SHans Petter Selasky 105683630517SEd Maste return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT || 10578d59ecb2SHans Petter Selasky type == PCI_EXP_TYPE_RC_EC; 10588d59ecb2SHans Petter Selasky } 10598d59ecb2SHans Petter Selasky 10608d59ecb2SHans Petter Selasky static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos) 10618d59ecb2SHans Petter Selasky { 10628d59ecb2SHans Petter Selasky if (!pci_is_pcie(dev)) 10638d59ecb2SHans Petter Selasky return false; 10648d59ecb2SHans Petter Selasky 10658d59ecb2SHans Petter Selasky switch (pos) { 10668d59ecb2SHans Petter Selasky case PCI_EXP_FLAGS_TYPE: 10678d59ecb2SHans Petter Selasky return true; 10688d59ecb2SHans Petter Selasky case PCI_EXP_DEVCAP: 10698d59ecb2SHans Petter Selasky case PCI_EXP_DEVCTL: 10708d59ecb2SHans Petter Selasky case PCI_EXP_DEVSTA: 10718d59ecb2SHans Petter Selasky return pcie_cap_has_devctl(dev); 10728d59ecb2SHans Petter Selasky case PCI_EXP_LNKCAP: 10738d59ecb2SHans Petter Selasky case PCI_EXP_LNKCTL: 10748d59ecb2SHans Petter Selasky case PCI_EXP_LNKSTA: 10758d59ecb2SHans Petter Selasky return pcie_cap_has_lnkctl(dev); 10768d59ecb2SHans Petter Selasky case PCI_EXP_SLTCAP: 10778d59ecb2SHans Petter Selasky case PCI_EXP_SLTCTL: 10788d59ecb2SHans Petter Selasky case PCI_EXP_SLTSTA: 10798d59ecb2SHans Petter Selasky return pcie_cap_has_sltctl(dev); 10808d59ecb2SHans Petter Selasky case PCI_EXP_RTCTL: 10818d59ecb2SHans Petter Selasky case PCI_EXP_RTCAP: 10828d59ecb2SHans Petter Selasky case PCI_EXP_RTSTA: 10838d59ecb2SHans Petter Selasky return pcie_cap_has_rtctl(dev); 10848d59ecb2SHans Petter Selasky case PCI_EXP_DEVCAP2: 10858d59ecb2SHans Petter Selasky case PCI_EXP_DEVCTL2: 10868d59ecb2SHans Petter Selasky case PCI_EXP_LNKCAP2: 10878d59ecb2SHans Petter Selasky case PCI_EXP_LNKCTL2: 10888d59ecb2SHans Petter Selasky case PCI_EXP_LNKSTA2: 10898d59ecb2SHans Petter Selasky return pcie_cap_version(dev) > 1; 10908d59ecb2SHans Petter Selasky default: 10918d59ecb2SHans Petter Selasky return false; 10928d59ecb2SHans Petter Selasky } 10938d59ecb2SHans Petter Selasky } 10948d59ecb2SHans Petter Selasky 109512af734dSHans Petter Selasky static inline int 109612af734dSHans Petter Selasky pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst) 1097a65ef215SHans Petter Selasky { 1098a65ef215SHans Petter Selasky if (pos & 3) 1099a65ef215SHans Petter Selasky return -EINVAL; 1100a65ef215SHans Petter Selasky 1101a65ef215SHans Petter Selasky if (!pcie_capability_reg_implemented(dev, pos)) 1102a65ef215SHans Petter Selasky return -EINVAL; 1103a65ef215SHans Petter Selasky 1104a65ef215SHans Petter Selasky return pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, dst); 1105a65ef215SHans Petter Selasky } 11068d59ecb2SHans Petter Selasky 110712af734dSHans Petter Selasky static inline int 110812af734dSHans Petter Selasky pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *dst) 110912af734dSHans Petter Selasky { 111012af734dSHans Petter Selasky if (pos & 3) 111112af734dSHans Petter Selasky return -EINVAL; 111212af734dSHans Petter Selasky 111312af734dSHans Petter Selasky if (!pcie_capability_reg_implemented(dev, pos)) 111412af734dSHans Petter Selasky return -EINVAL; 111512af734dSHans Petter Selasky 111612af734dSHans Petter Selasky return pci_read_config_word(dev, pci_pcie_cap(dev) + pos, dst); 111712af734dSHans Petter Selasky } 111812af734dSHans Petter Selasky 111912af734dSHans Petter Selasky static inline int 112012af734dSHans Petter Selasky pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val) 11218d59ecb2SHans Petter Selasky { 11228d59ecb2SHans Petter Selasky if (pos & 1) 11238d59ecb2SHans Petter Selasky return -EINVAL; 11248d59ecb2SHans Petter Selasky 11258d59ecb2SHans Petter Selasky if (!pcie_capability_reg_implemented(dev, pos)) 11268d59ecb2SHans Petter Selasky return 0; 11278d59ecb2SHans Petter Selasky 11288d59ecb2SHans Petter Selasky return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val); 11298d59ecb2SHans Petter Selasky } 11308d59ecb2SHans Petter Selasky 1131a65ef215SHans Petter Selasky static inline int pcie_get_minimum_link(struct pci_dev *dev, 1132a65ef215SHans Petter Selasky enum pci_bus_speed *speed, enum pcie_link_width *width) 1133a65ef215SHans Petter Selasky { 1134a65ef215SHans Petter Selasky *speed = PCI_SPEED_UNKNOWN; 1135a65ef215SHans Petter Selasky *width = PCIE_LNK_WIDTH_UNKNOWN; 1136a65ef215SHans Petter Selasky return (0); 1137a65ef215SHans Petter Selasky } 1138a65ef215SHans Petter Selasky 1139a65ef215SHans Petter Selasky static inline int 1140a65ef215SHans Petter Selasky pci_num_vf(struct pci_dev *dev) 1141a65ef215SHans Petter Selasky { 1142a65ef215SHans Petter Selasky return (0); 1143a65ef215SHans Petter Selasky } 1144a65ef215SHans Petter Selasky 1145ab62989aSHans Petter Selasky static inline enum pci_bus_speed 1146ab62989aSHans Petter Selasky pcie_get_speed_cap(struct pci_dev *dev) 1147ab62989aSHans Petter Selasky { 1148ab62989aSHans Petter Selasky device_t root; 1149ab62989aSHans Petter Selasky uint32_t lnkcap, lnkcap2; 1150ab62989aSHans Petter Selasky int error, pos; 1151ab62989aSHans Petter Selasky 1152ab62989aSHans Petter Selasky root = device_get_parent(dev->dev.bsddev); 1153ab62989aSHans Petter Selasky if (root == NULL) 1154ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1155ab62989aSHans Petter Selasky root = device_get_parent(root); 1156ab62989aSHans Petter Selasky if (root == NULL) 1157ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1158ab62989aSHans Petter Selasky root = device_get_parent(root); 1159ab62989aSHans Petter Selasky if (root == NULL) 1160ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1161ab62989aSHans Petter Selasky 1162ab62989aSHans Petter Selasky if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA || 1163ab62989aSHans Petter Selasky pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS) 1164ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1165ab62989aSHans Petter Selasky 1166ab62989aSHans Petter Selasky if ((error = pci_find_cap(root, PCIY_EXPRESS, &pos)) != 0) 1167ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1168ab62989aSHans Petter Selasky 1169ab62989aSHans Petter Selasky lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4); 1170ab62989aSHans Petter Selasky 1171ab62989aSHans Petter Selasky if (lnkcap2) { /* PCIe r3.0-compliant */ 1172ab62989aSHans Petter Selasky if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB) 1173ab62989aSHans Petter Selasky return (PCIE_SPEED_2_5GT); 1174ab62989aSHans Petter Selasky if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB) 1175ab62989aSHans Petter Selasky return (PCIE_SPEED_5_0GT); 1176ab62989aSHans Petter Selasky if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) 1177ab62989aSHans Petter Selasky return (PCIE_SPEED_8_0GT); 1178ab62989aSHans Petter Selasky if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB) 1179ab62989aSHans Petter Selasky return (PCIE_SPEED_16_0GT); 1180ab62989aSHans Petter Selasky } else { /* pre-r3.0 */ 1181ab62989aSHans Petter Selasky lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4); 1182ab62989aSHans Petter Selasky if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB) 1183ab62989aSHans Petter Selasky return (PCIE_SPEED_2_5GT); 1184ab62989aSHans Petter Selasky if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB) 1185ab62989aSHans Petter Selasky return (PCIE_SPEED_5_0GT); 1186ab62989aSHans Petter Selasky if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB) 1187ab62989aSHans Petter Selasky return (PCIE_SPEED_8_0GT); 1188ab62989aSHans Petter Selasky if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB) 1189ab62989aSHans Petter Selasky return (PCIE_SPEED_16_0GT); 1190ab62989aSHans Petter Selasky } 1191ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1192ab62989aSHans Petter Selasky } 1193ab62989aSHans Petter Selasky 1194ab62989aSHans Petter Selasky static inline enum pcie_link_width 1195ab62989aSHans Petter Selasky pcie_get_width_cap(struct pci_dev *dev) 1196ab62989aSHans Petter Selasky { 1197ab62989aSHans Petter Selasky uint32_t lnkcap; 1198ab62989aSHans Petter Selasky 1199ab62989aSHans Petter Selasky pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap); 1200ab62989aSHans Petter Selasky if (lnkcap) 1201ab62989aSHans Petter Selasky return ((lnkcap & PCI_EXP_LNKCAP_MLW) >> 4); 1202ab62989aSHans Petter Selasky 1203ab62989aSHans Petter Selasky return (PCIE_LNK_WIDTH_UNKNOWN); 1204ab62989aSHans Petter Selasky } 1205ab62989aSHans Petter Selasky 1206b4edb17cSHans Petter Selasky static inline int 1207b4edb17cSHans Petter Selasky pcie_get_mps(struct pci_dev *dev) 1208b4edb17cSHans Petter Selasky { 1209b4edb17cSHans Petter Selasky return (pci_get_max_payload(dev->dev.bsddev)); 1210b4edb17cSHans Petter Selasky } 1211b4edb17cSHans Petter Selasky 1212b4edb17cSHans Petter Selasky static inline uint32_t 1213b4edb17cSHans Petter Selasky PCIE_SPEED2MBS_ENC(enum pci_bus_speed spd) 1214b4edb17cSHans Petter Selasky { 1215b4edb17cSHans Petter Selasky 1216b4edb17cSHans Petter Selasky switch(spd) { 1217b4edb17cSHans Petter Selasky case PCIE_SPEED_16_0GT: 1218b4edb17cSHans Petter Selasky return (16000 * 128 / 130); 1219b4edb17cSHans Petter Selasky case PCIE_SPEED_8_0GT: 1220b4edb17cSHans Petter Selasky return (8000 * 128 / 130); 1221b4edb17cSHans Petter Selasky case PCIE_SPEED_5_0GT: 1222b4edb17cSHans Petter Selasky return (5000 * 8 / 10); 1223b4edb17cSHans Petter Selasky case PCIE_SPEED_2_5GT: 1224b4edb17cSHans Petter Selasky return (2500 * 8 / 10); 1225b4edb17cSHans Petter Selasky default: 1226b4edb17cSHans Petter Selasky return (0); 1227b4edb17cSHans Petter Selasky } 1228b4edb17cSHans Petter Selasky } 1229b4edb17cSHans Petter Selasky 1230b4edb17cSHans Petter Selasky static inline uint32_t 1231b4edb17cSHans Petter Selasky pcie_bandwidth_available(struct pci_dev *pdev, 1232b4edb17cSHans Petter Selasky struct pci_dev **limiting, 1233b4edb17cSHans Petter Selasky enum pci_bus_speed *speed, 1234b4edb17cSHans Petter Selasky enum pcie_link_width *width) 1235b4edb17cSHans Petter Selasky { 1236b4edb17cSHans Petter Selasky enum pci_bus_speed nspeed = pcie_get_speed_cap(pdev); 1237b4edb17cSHans Petter Selasky enum pcie_link_width nwidth = pcie_get_width_cap(pdev); 1238b4edb17cSHans Petter Selasky 1239b4edb17cSHans Petter Selasky if (speed) 1240b4edb17cSHans Petter Selasky *speed = nspeed; 1241b4edb17cSHans Petter Selasky if (width) 1242b4edb17cSHans Petter Selasky *width = nwidth; 1243b4edb17cSHans Petter Selasky 1244b4edb17cSHans Petter Selasky return (nwidth * PCIE_SPEED2MBS_ENC(nspeed)); 1245b4edb17cSHans Petter Selasky } 1246b4edb17cSHans Petter Selasky 12478e106c52SBjoern A. Zeeb static inline struct pci_dev * 12488e106c52SBjoern A. Zeeb pcie_find_root_port(struct pci_dev *pdev) 12498e106c52SBjoern A. Zeeb { 12508e106c52SBjoern A. Zeeb device_t root; 12518e106c52SBjoern A. Zeeb 12528e106c52SBjoern A. Zeeb if (pdev->root != NULL) 12538e106c52SBjoern A. Zeeb return (pdev->root); 12548e106c52SBjoern A. Zeeb 12558e106c52SBjoern A. Zeeb root = pci_find_pcie_root_port(pdev->dev.bsddev); 12568e106c52SBjoern A. Zeeb if (root == NULL) 12578e106c52SBjoern A. Zeeb return (NULL); 12588e106c52SBjoern A. Zeeb 12598e106c52SBjoern A. Zeeb pdev->root = lkpinew_pci_dev(root); 12608e106c52SBjoern A. Zeeb return (pdev->root); 12618e106c52SBjoern A. Zeeb } 12628e106c52SBjoern A. Zeeb 12638e106c52SBjoern A. Zeeb /* This is needed when people rip out the device "HotPlug". */ 12648e106c52SBjoern A. Zeeb static inline void 12658e106c52SBjoern A. Zeeb pci_lock_rescan_remove(void) 12668e106c52SBjoern A. Zeeb { 12678e106c52SBjoern A. Zeeb } 12688e106c52SBjoern A. Zeeb 12698e106c52SBjoern A. Zeeb static inline void 12708e106c52SBjoern A. Zeeb pci_unlock_rescan_remove(void) 12718e106c52SBjoern A. Zeeb { 12728e106c52SBjoern A. Zeeb } 12738e106c52SBjoern A. Zeeb 12748e106c52SBjoern A. Zeeb static __inline void 12758e106c52SBjoern A. Zeeb pci_stop_and_remove_bus_device(struct pci_dev *pdev) 12768e106c52SBjoern A. Zeeb { 12778e106c52SBjoern A. Zeeb } 12788e106c52SBjoern A. Zeeb 1279253dbe74SHans Petter Selasky /* 1280253dbe74SHans Petter Selasky * The following functions can be used to attach/detach the LinuxKPI's 1281253dbe74SHans Petter Selasky * PCI device runtime. The pci_driver and pci_device_id pointer is 1282253dbe74SHans Petter Selasky * allowed to be NULL. Other pointers must be all valid. 1283253dbe74SHans Petter Selasky * The pci_dev structure should be zero-initialized before passed 1284253dbe74SHans Petter Selasky * to the linux_pci_attach_device function. 1285253dbe74SHans Petter Selasky */ 1286253dbe74SHans Petter Selasky extern int linux_pci_attach_device(device_t, struct pci_driver *, 1287253dbe74SHans Petter Selasky const struct pci_device_id *, struct pci_dev *); 1288253dbe74SHans Petter Selasky extern int linux_pci_detach_device(struct pci_dev *); 1289253dbe74SHans Petter Selasky 12905e30a739SEmmanuel Vadot static inline int 12915e30a739SEmmanuel Vadot pci_dev_present(const struct pci_device_id *cur) 12925e30a739SEmmanuel Vadot { 12935e30a739SEmmanuel Vadot while (cur != NULL && (cur->vendor || cur->device)) { 12945e30a739SEmmanuel Vadot if (pci_find_device(cur->vendor, cur->device) != NULL) { 12955e30a739SEmmanuel Vadot return (1); 12965e30a739SEmmanuel Vadot } 12975e30a739SEmmanuel Vadot cur++; 12985e30a739SEmmanuel Vadot } 12995e30a739SEmmanuel Vadot return (0); 13005e30a739SEmmanuel Vadot } 13015e30a739SEmmanuel Vadot 1302105a37caSEmmanuel Vadot static inline bool 1303105a37caSEmmanuel Vadot pci_is_root_bus(struct pci_bus *pbus) 1304105a37caSEmmanuel Vadot { 1305105a37caSEmmanuel Vadot 1306105a37caSEmmanuel Vadot return (pbus->self == NULL); 1307105a37caSEmmanuel Vadot } 1308105a37caSEmmanuel Vadot 1309105a37caSEmmanuel Vadot struct pci_dev *lkpi_pci_get_domain_bus_and_slot(int domain, 1310105a37caSEmmanuel Vadot unsigned int bus, unsigned int devfn); 1311105a37caSEmmanuel Vadot #define pci_get_domain_bus_and_slot(domain, bus, devfn) \ 1312105a37caSEmmanuel Vadot lkpi_pci_get_domain_bus_and_slot(domain, bus, devfn) 1313105a37caSEmmanuel Vadot 1314105a37caSEmmanuel Vadot static inline int 1315105a37caSEmmanuel Vadot pci_domain_nr(struct pci_bus *pbus) 1316105a37caSEmmanuel Vadot { 1317105a37caSEmmanuel Vadot 13181fac2cb4SBjoern A. Zeeb return (pbus->domain); 1319105a37caSEmmanuel Vadot } 1320105a37caSEmmanuel Vadot 1321105a37caSEmmanuel Vadot static inline int 1322105a37caSEmmanuel Vadot pci_bus_read_config(struct pci_bus *bus, unsigned int devfn, 1323105a37caSEmmanuel Vadot int pos, uint32_t *val, int len) 1324105a37caSEmmanuel Vadot { 1325105a37caSEmmanuel Vadot 1326105a37caSEmmanuel Vadot *val = pci_read_config(bus->self->dev.bsddev, pos, len); 1327105a37caSEmmanuel Vadot return (0); 1328105a37caSEmmanuel Vadot } 1329105a37caSEmmanuel Vadot 1330105a37caSEmmanuel Vadot static inline int 1331105a37caSEmmanuel Vadot pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, int pos, u16 *val) 1332105a37caSEmmanuel Vadot { 1333105a37caSEmmanuel Vadot uint32_t tmp; 1334105a37caSEmmanuel Vadot int ret; 1335105a37caSEmmanuel Vadot 1336105a37caSEmmanuel Vadot ret = pci_bus_read_config(bus, devfn, pos, &tmp, 2); 1337105a37caSEmmanuel Vadot *val = (u16)tmp; 1338105a37caSEmmanuel Vadot return (ret); 1339105a37caSEmmanuel Vadot } 1340105a37caSEmmanuel Vadot 1341105a37caSEmmanuel Vadot static inline int 1342105a37caSEmmanuel Vadot pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, int pos, u8 *val) 1343105a37caSEmmanuel Vadot { 1344105a37caSEmmanuel Vadot uint32_t tmp; 1345105a37caSEmmanuel Vadot int ret; 1346105a37caSEmmanuel Vadot 1347105a37caSEmmanuel Vadot ret = pci_bus_read_config(bus, devfn, pos, &tmp, 1); 1348105a37caSEmmanuel Vadot *val = (u8)tmp; 1349105a37caSEmmanuel Vadot return (ret); 1350105a37caSEmmanuel Vadot } 1351105a37caSEmmanuel Vadot 1352105a37caSEmmanuel Vadot static inline int 1353105a37caSEmmanuel Vadot pci_bus_write_config(struct pci_bus *bus, unsigned int devfn, int pos, 1354105a37caSEmmanuel Vadot uint32_t val, int size) 1355105a37caSEmmanuel Vadot { 1356105a37caSEmmanuel Vadot 1357105a37caSEmmanuel Vadot pci_write_config(bus->self->dev.bsddev, pos, val, size); 1358105a37caSEmmanuel Vadot return (0); 1359105a37caSEmmanuel Vadot } 1360105a37caSEmmanuel Vadot 1361105a37caSEmmanuel Vadot static inline int 1362105a37caSEmmanuel Vadot pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int pos, 1363105a37caSEmmanuel Vadot uint8_t val) 1364105a37caSEmmanuel Vadot { 1365105a37caSEmmanuel Vadot return (pci_bus_write_config(bus, devfn, pos, val, 1)); 1366105a37caSEmmanuel Vadot } 1367105a37caSEmmanuel Vadot 1368105a37caSEmmanuel Vadot static inline int 1369105a37caSEmmanuel Vadot pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int pos, 1370105a37caSEmmanuel Vadot uint16_t val) 1371105a37caSEmmanuel Vadot { 1372105a37caSEmmanuel Vadot return (pci_bus_write_config(bus, devfn, pos, val, 2)); 1373105a37caSEmmanuel Vadot } 1374105a37caSEmmanuel Vadot 1375105a37caSEmmanuel Vadot struct pci_dev *lkpi_pci_get_class(unsigned int class, struct pci_dev *from); 1376105a37caSEmmanuel Vadot #define pci_get_class(class, from) lkpi_pci_get_class(class, from) 1377105a37caSEmmanuel Vadot 1378d4a4960cSBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 1379d4a4960cSBjoern A. Zeeb 1380d4a4960cSBjoern A. Zeeb static inline int 1381d4a4960cSBjoern A. Zeeb pcim_enable_device(struct pci_dev *pdev) 1382d4a4960cSBjoern A. Zeeb { 1383d4a4960cSBjoern A. Zeeb struct pci_devres *dr; 1384d4a4960cSBjoern A. Zeeb int error; 1385d4a4960cSBjoern A. Zeeb 1386d4a4960cSBjoern A. Zeeb /* Here we cannot run through the pdev->managed check. */ 1387d4a4960cSBjoern A. Zeeb dr = lkpi_pci_devres_get_alloc(pdev); 1388d4a4960cSBjoern A. Zeeb if (dr == NULL) 1389d4a4960cSBjoern A. Zeeb return (-ENOMEM); 1390d4a4960cSBjoern A. Zeeb 1391d4a4960cSBjoern A. Zeeb /* If resources were enabled before do not do it again. */ 1392d4a4960cSBjoern A. Zeeb if (dr->enable_io) 1393d4a4960cSBjoern A. Zeeb return (0); 1394d4a4960cSBjoern A. Zeeb 1395d4a4960cSBjoern A. Zeeb error = pci_enable_device(pdev); 1396d4a4960cSBjoern A. Zeeb if (error == 0) 1397d4a4960cSBjoern A. Zeeb dr->enable_io = true; 1398d4a4960cSBjoern A. Zeeb 1399d4a4960cSBjoern A. Zeeb /* This device is not managed. */ 1400d4a4960cSBjoern A. Zeeb pdev->managed = true; 1401d4a4960cSBjoern A. Zeeb 1402d4a4960cSBjoern A. Zeeb return (error); 1403d4a4960cSBjoern A. Zeeb } 1404d4a4960cSBjoern A. Zeeb 1405d4a4960cSBjoern A. Zeeb static inline struct pcim_iomap_devres * 1406d4a4960cSBjoern A. Zeeb lkpi_pcim_iomap_devres_find(struct pci_dev *pdev) 1407d4a4960cSBjoern A. Zeeb { 1408d4a4960cSBjoern A. Zeeb struct pcim_iomap_devres *dr; 1409d4a4960cSBjoern A. Zeeb 1410d4a4960cSBjoern A. Zeeb dr = lkpi_devres_find(&pdev->dev, lkpi_pcim_iomap_table_release, 1411d4a4960cSBjoern A. Zeeb NULL, NULL); 1412d4a4960cSBjoern A. Zeeb if (dr == NULL) { 1413d4a4960cSBjoern A. Zeeb dr = lkpi_devres_alloc(lkpi_pcim_iomap_table_release, 1414d4a4960cSBjoern A. Zeeb sizeof(*dr), GFP_KERNEL | __GFP_ZERO); 1415d4a4960cSBjoern A. Zeeb if (dr != NULL) 1416d4a4960cSBjoern A. Zeeb lkpi_devres_add(&pdev->dev, dr); 1417d4a4960cSBjoern A. Zeeb } 1418d4a4960cSBjoern A. Zeeb 1419d4a4960cSBjoern A. Zeeb if (dr == NULL) 1420d4a4960cSBjoern A. Zeeb device_printf(pdev->dev.bsddev, "%s: NULL\n", __func__); 1421d4a4960cSBjoern A. Zeeb 1422d4a4960cSBjoern A. Zeeb return (dr); 1423d4a4960cSBjoern A. Zeeb } 1424d4a4960cSBjoern A. Zeeb 1425d4a4960cSBjoern A. Zeeb static inline void __iomem ** 1426d4a4960cSBjoern A. Zeeb pcim_iomap_table(struct pci_dev *pdev) 1427d4a4960cSBjoern A. Zeeb { 1428d4a4960cSBjoern A. Zeeb struct pcim_iomap_devres *dr; 1429d4a4960cSBjoern A. Zeeb 1430d4a4960cSBjoern A. Zeeb dr = lkpi_pcim_iomap_devres_find(pdev); 1431d4a4960cSBjoern A. Zeeb if (dr == NULL) 1432d4a4960cSBjoern A. Zeeb return (NULL); 1433d4a4960cSBjoern A. Zeeb 1434d4a4960cSBjoern A. Zeeb /* 1435d4a4960cSBjoern A. Zeeb * If the driver has manually set a flag to be able to request the 1436d4a4960cSBjoern A. Zeeb * resource to use bus_read/write_<n>, return the shadow table. 1437d4a4960cSBjoern A. Zeeb */ 1438d4a4960cSBjoern A. Zeeb if (pdev->want_iomap_res) 1439d4a4960cSBjoern A. Zeeb return ((void **)dr->res_table); 1440d4a4960cSBjoern A. Zeeb 1441d4a4960cSBjoern A. Zeeb /* This is the Linux default. */ 1442d4a4960cSBjoern A. Zeeb return (dr->mmio_table); 1443d4a4960cSBjoern A. Zeeb } 1444d4a4960cSBjoern A. Zeeb 1445d4a4960cSBjoern A. Zeeb static inline int 1446d4a4960cSBjoern A. Zeeb pcim_iomap_regions_request_all(struct pci_dev *pdev, uint32_t mask, char *name) 1447d4a4960cSBjoern A. Zeeb { 1448d4a4960cSBjoern A. Zeeb struct pcim_iomap_devres *dr; 1449d4a4960cSBjoern A. Zeeb void *res; 1450d4a4960cSBjoern A. Zeeb uint32_t mappings, requests, req_mask; 1451d4a4960cSBjoern A. Zeeb int bar, error; 1452d4a4960cSBjoern A. Zeeb 1453d4a4960cSBjoern A. Zeeb dr = lkpi_pcim_iomap_devres_find(pdev); 1454d4a4960cSBjoern A. Zeeb if (dr == NULL) 1455d4a4960cSBjoern A. Zeeb return (-ENOMEM); 1456d4a4960cSBjoern A. Zeeb 1457d4a4960cSBjoern A. Zeeb /* Request all the BARs ("regions") we do not iomap. */ 1458d4a4960cSBjoern A. Zeeb req_mask = ((1 << (PCIR_MAX_BAR_0 + 1)) - 1) & ~mask; 1459d4a4960cSBjoern A. Zeeb for (bar = requests = 0; requests != req_mask; bar++) { 1460d4a4960cSBjoern A. Zeeb if ((req_mask & (1 << bar)) == 0) 1461d4a4960cSBjoern A. Zeeb continue; 1462d4a4960cSBjoern A. Zeeb error = pci_request_region(pdev, bar, name); 1463d4a4960cSBjoern A. Zeeb if (error != 0 && error != -ENODEV) 1464d4a4960cSBjoern A. Zeeb goto err; 1465d4a4960cSBjoern A. Zeeb requests |= (1 << bar); 1466d4a4960cSBjoern A. Zeeb } 1467d4a4960cSBjoern A. Zeeb 1468d4a4960cSBjoern A. Zeeb /* Now iomap all the requested (by "mask") ones. */ 1469d4a4960cSBjoern A. Zeeb for (bar = mappings = 0; mappings != mask; bar++) { 1470d4a4960cSBjoern A. Zeeb if ((mask & (1 << bar)) == 0) 1471d4a4960cSBjoern A. Zeeb continue; 1472d4a4960cSBjoern A. Zeeb 1473d4a4960cSBjoern A. Zeeb /* Request double is not allowed. */ 1474d4a4960cSBjoern A. Zeeb if (dr->mmio_table[bar] != NULL) { 1475d4a4960cSBjoern A. Zeeb device_printf(pdev->dev.bsddev, "%s: bar %d %p\n", 1476d4a4960cSBjoern A. Zeeb __func__, bar, dr->mmio_table[bar]); 1477d4a4960cSBjoern A. Zeeb goto err; 1478d4a4960cSBjoern A. Zeeb } 1479d4a4960cSBjoern A. Zeeb 1480d4a4960cSBjoern A. Zeeb res = _lkpi_pci_iomap(pdev, bar, 0); 1481d4a4960cSBjoern A. Zeeb if (res == NULL) 1482d4a4960cSBjoern A. Zeeb goto err; 1483d4a4960cSBjoern A. Zeeb dr->mmio_table[bar] = (void *)rman_get_bushandle(res); 1484d4a4960cSBjoern A. Zeeb dr->res_table[bar] = res; 1485d4a4960cSBjoern A. Zeeb 1486d4a4960cSBjoern A. Zeeb mappings |= (1 << bar); 1487d4a4960cSBjoern A. Zeeb } 1488d4a4960cSBjoern A. Zeeb 1489d4a4960cSBjoern A. Zeeb return (0); 1490d4a4960cSBjoern A. Zeeb 1491d4a4960cSBjoern A. Zeeb err: 1492d4a4960cSBjoern A. Zeeb for (bar = PCIR_MAX_BAR_0; bar >= 0; bar--) { 1493d4a4960cSBjoern A. Zeeb if ((mappings & (1 << bar)) != 0) { 1494d4a4960cSBjoern A. Zeeb res = dr->mmio_table[bar]; 1495d4a4960cSBjoern A. Zeeb if (res == NULL) 1496d4a4960cSBjoern A. Zeeb continue; 1497d4a4960cSBjoern A. Zeeb pci_iounmap(pdev, res); 1498d4a4960cSBjoern A. Zeeb } else if ((requests & (1 << bar)) != 0) { 1499d4a4960cSBjoern A. Zeeb pci_release_region(pdev, bar); 1500d4a4960cSBjoern A. Zeeb } 1501d4a4960cSBjoern A. Zeeb } 1502d4a4960cSBjoern A. Zeeb 1503d4a4960cSBjoern A. Zeeb return (-EINVAL); 1504d4a4960cSBjoern A. Zeeb } 1505d4a4960cSBjoern A. Zeeb 1506d4a4960cSBjoern A. Zeeb /* This is a FreeBSD extension so we can use bus_*(). */ 1507d4a4960cSBjoern A. Zeeb static inline void 1508d4a4960cSBjoern A. Zeeb linuxkpi_pcim_want_to_use_bus_functions(struct pci_dev *pdev) 1509d4a4960cSBjoern A. Zeeb { 1510d4a4960cSBjoern A. Zeeb pdev->want_iomap_res = true; 1511d4a4960cSBjoern A. Zeeb } 1512d4a4960cSBjoern A. Zeeb 15138d59ecb2SHans Petter Selasky #endif /* _LINUX_PCI_H_ */ 1514