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, ®)) 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, ®)) 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, ®16); 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