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. 7c41d8354SBjoern A. Zeeb * Copyright (c) 2020-2022 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 */ 33307f78f3SVladimir Kondratyev #ifndef _LINUXKPI_LINUX_PCI_H_ 34307f78f3SVladimir Kondratyev #define _LINUXKPI_LINUX_PCI_H_ 358d59ecb2SHans Petter Selasky 368d59ecb2SHans Petter Selasky #define CONFIG_PCI_MSI 378d59ecb2SHans Petter Selasky 388d59ecb2SHans Petter Selasky #include <linux/types.h> 39f5c7feeeSBjoern A. Zeeb #include <linux/device/driver.h> 408d59ecb2SHans Petter Selasky 418d59ecb2SHans Petter Selasky #include <sys/param.h> 428d59ecb2SHans Petter Selasky #include <sys/bus.h> 435493c627SBjoern A. Zeeb #include <sys/module.h> 442928e60eSKonstantin Belousov #include <sys/nv.h> 458d59ecb2SHans Petter Selasky #include <sys/pciio.h> 468d59ecb2SHans Petter Selasky #include <dev/pci/pcivar.h> 478d59ecb2SHans Petter Selasky #include <dev/pci/pcireg.h> 488d59ecb2SHans Petter Selasky #include <dev/pci/pci_private.h> 498d59ecb2SHans Petter Selasky 508d59ecb2SHans Petter Selasky #include <machine/resource.h> 518d59ecb2SHans Petter Selasky 528d59ecb2SHans Petter Selasky #include <linux/list.h> 538d59ecb2SHans Petter Selasky #include <linux/dmapool.h> 548d59ecb2SHans Petter Selasky #include <linux/dma-mapping.h> 558d59ecb2SHans Petter Selasky #include <linux/compiler.h> 568d59ecb2SHans Petter Selasky #include <linux/errno.h> 578d59ecb2SHans Petter Selasky #include <asm/atomic.h> 5883df72e5SJean-Sébastien Pédron #include <asm/memtype.h> 598d59ecb2SHans Petter Selasky #include <linux/device.h> 605a402a3aSBjoern A. Zeeb #include <linux/pci_ids.h> 610e981d79SBjoern A. Zeeb #include <linux/pm.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 735493c627SBjoern A. Zeeb /* Linux has an empty element at the end of the ID table -> nitems() - 1. */ 745493c627SBjoern A. Zeeb #define MODULE_DEVICE_TABLE(_bus, _table) \ 755493c627SBjoern A. Zeeb \ 765493c627SBjoern A. Zeeb static device_method_t _ ## _bus ## _ ## _table ## _methods[] = { \ 775493c627SBjoern A. Zeeb DEVMETHOD_END \ 785493c627SBjoern A. Zeeb }; \ 795493c627SBjoern A. Zeeb \ 805493c627SBjoern A. Zeeb static driver_t _ ## _bus ## _ ## _table ## _driver = { \ 815493c627SBjoern A. Zeeb "lkpi_" #_bus #_table, \ 825493c627SBjoern A. Zeeb _ ## _bus ## _ ## _table ## _methods, \ 835493c627SBjoern A. Zeeb 0 \ 845493c627SBjoern A. Zeeb }; \ 855493c627SBjoern A. Zeeb \ 865493c627SBjoern A. Zeeb DRIVER_MODULE(lkpi_ ## _table, pci, _ ## _bus ## _ ## _table ## _driver,\ 87a65d0774SJohn Baldwin 0, 0); \ 885493c627SBjoern A. Zeeb \ 895493c627SBjoern A. Zeeb MODULE_PNP_INFO("U32:vendor;U32:device;V32:subvendor;V32:subdevice", \ 905493c627SBjoern A. Zeeb _bus, lkpi_ ## _table, _table, nitems(_table) - 1) 91ecf29cf1SMark Johnston 92232028b3SHans Petter Selasky #define PCI_ANY_ID -1U 938d59ecb2SHans Petter Selasky 948d59ecb2SHans Petter Selasky #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 958d59ecb2SHans Petter Selasky #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) 968d59ecb2SHans Petter Selasky #define PCI_FUNC(devfn) ((devfn) & 0x07) 9713a5c70bSHans Petter Selasky #define PCI_BUS_NUM(devfn) (((devfn) >> 8) & 0xff) 98f1206503SVladimir Kondratyev #define PCI_DEVID(bus, devfn) ((((uint16_t)(bus)) << 8) | (devfn)) 998d59ecb2SHans Petter Selasky 1008d59ecb2SHans Petter Selasky #define PCI_VDEVICE(_vendor, _device) \ 1018d59ecb2SHans Petter Selasky .vendor = PCI_VENDOR_ID_##_vendor, .device = (_device), \ 1028d59ecb2SHans Petter Selasky .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID 1038d59ecb2SHans Petter Selasky #define PCI_DEVICE(_vendor, _device) \ 1048d59ecb2SHans Petter Selasky .vendor = (_vendor), .device = (_device), \ 1058d59ecb2SHans Petter Selasky .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID 1068d59ecb2SHans Petter Selasky 1078d59ecb2SHans Petter Selasky #define to_pci_dev(n) container_of(n, struct pci_dev, dev) 1088d59ecb2SHans Petter Selasky 10966cc55a0SJean-Sébastien Pédron #define PCI_STD_NUM_BARS 6 110a1cdddcfSBjoern A. Zeeb #define PCI_BASE_ADDRESS_0 PCIR_BARS 111a1cdddcfSBjoern A. Zeeb #define PCI_BASE_ADDRESS_MEM_TYPE_64 PCIM_BAR_MEM_64 112c41d8354SBjoern A. Zeeb #define PCI_VENDOR_ID PCIR_VENDOR 113c41d8354SBjoern A. Zeeb #define PCI_DEVICE_ID PCIR_DEVICE 1148d59ecb2SHans Petter Selasky #define PCI_COMMAND PCIR_COMMAND 115fc1d8409SBjoern A. Zeeb #define PCI_COMMAND_INTX_DISABLE PCIM_CMD_INTxDIS 1167d7d12baSBjoern A. Zeeb #define PCI_COMMAND_MEMORY PCIM_CMD_MEMEN 1178d59ecb2SHans Petter Selasky #define PCI_EXP_DEVCTL PCIER_DEVICE_CTL /* Device Control */ 1188d59ecb2SHans Petter Selasky #define PCI_EXP_LNKCTL PCIER_LINK_CTL /* Link Control */ 119fc1d8409SBjoern A. Zeeb #define PCI_EXP_LNKCTL_ASPM_L0S PCIEM_LINK_CTL_ASPMC_L0S 120fc1d8409SBjoern A. Zeeb #define PCI_EXP_LNKCTL_ASPM_L1 PCIEM_LINK_CTL_ASPMC_L1 121c4f52f71SBjoern A. Zeeb #define PCI_EXP_LNKCTL_ASPMC PCIEM_LINK_CTL_ASPMC 122fc1d8409SBjoern A. Zeeb #define PCI_EXP_LNKCTL_CLKREQ_EN PCIEM_LINK_CTL_ECPM /* Enable clock PM */ 123c4f52f71SBjoern A. Zeeb #define PCI_EXP_LNKCTL_HAWD PCIEM_LINK_CTL_HAWD 1248d59ecb2SHans Petter Selasky #define PCI_EXP_FLAGS_TYPE PCIEM_FLAGS_TYPE /* Device/Port type */ 1258d59ecb2SHans Petter Selasky #define PCI_EXP_DEVCAP PCIER_DEVICE_CAP /* Device capabilities */ 1268d59ecb2SHans Petter Selasky #define PCI_EXP_DEVSTA PCIER_DEVICE_STA /* Device Status */ 1278d59ecb2SHans Petter Selasky #define PCI_EXP_LNKCAP PCIER_LINK_CAP /* Link Capabilities */ 1288d59ecb2SHans Petter Selasky #define PCI_EXP_LNKSTA PCIER_LINK_STA /* Link Status */ 1298d59ecb2SHans Petter Selasky #define PCI_EXP_SLTCAP PCIER_SLOT_CAP /* Slot Capabilities */ 1308d59ecb2SHans Petter Selasky #define PCI_EXP_SLTCTL PCIER_SLOT_CTL /* Slot Control */ 1318d59ecb2SHans Petter Selasky #define PCI_EXP_SLTSTA PCIER_SLOT_STA /* Slot Status */ 1328d59ecb2SHans Petter Selasky #define PCI_EXP_RTCTL PCIER_ROOT_CTL /* Root Control */ 1338d59ecb2SHans Petter Selasky #define PCI_EXP_RTCAP PCIER_ROOT_CAP /* Root Capabilities */ 1348d59ecb2SHans Petter Selasky #define PCI_EXP_RTSTA PCIER_ROOT_STA /* Root Status */ 1358d59ecb2SHans Petter Selasky #define PCI_EXP_DEVCAP2 PCIER_DEVICE_CAP2 /* Device Capabilities 2 */ 1368d59ecb2SHans Petter Selasky #define PCI_EXP_DEVCTL2 PCIER_DEVICE_CTL2 /* Device Control 2 */ 137fc1d8409SBjoern A. Zeeb #define PCI_EXP_DEVCTL2_LTR_EN PCIEM_CTL2_LTR_ENABLE 13885eb99f9SBjoern A. Zeeb #define PCI_EXP_DEVCTL2_COMP_TMOUT_DIS PCIEM_CTL2_COMP_TIMO_DISABLE 1398d59ecb2SHans Petter Selasky #define PCI_EXP_LNKCAP2 PCIER_LINK_CAP2 /* Link Capabilities 2 */ 1408d59ecb2SHans Petter Selasky #define PCI_EXP_LNKCTL2 PCIER_LINK_CTL2 /* Link Control 2 */ 1418d59ecb2SHans Petter Selasky #define PCI_EXP_LNKSTA2 PCIER_LINK_STA2 /* Link Status 2 */ 1428d59ecb2SHans Petter Selasky #define PCI_EXP_FLAGS PCIER_FLAGS /* Capabilities register */ 1438d59ecb2SHans Petter Selasky #define PCI_EXP_FLAGS_VERS PCIEM_FLAGS_VERSION /* Capability version */ 1448d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_ROOT_PORT PCIEM_TYPE_ROOT_PORT /* Root Port */ 1458d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_ENDPOINT PCIEM_TYPE_ENDPOINT /* Express Endpoint */ 1468d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_LEG_END PCIEM_TYPE_LEGACY_ENDPOINT /* Legacy Endpoint */ 1478d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_DOWNSTREAM PCIEM_TYPE_DOWNSTREAM_PORT /* Downstream Port */ 1488d59ecb2SHans Petter Selasky #define PCI_EXP_FLAGS_SLOT PCIEM_FLAGS_SLOT /* Slot implemented */ 1498d59ecb2SHans Petter Selasky #define PCI_EXP_TYPE_RC_EC PCIEM_TYPE_ROOT_EC /* Root Complex Event Collector */ 150f74c09f3SBjoern A. Zeeb #define PCI_EXP_LNKSTA_CLS PCIEM_LINK_STA_SPEED 151f74c09f3SBjoern A. Zeeb #define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */ 152a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP_SLS_2_5GB 0x01 /* Supported Link Speed 2.5GT/s */ 153a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP_SLS_5_0GB 0x02 /* Supported Link Speed 5.0GT/s */ 1540adc02a9SJean-Sébastien Pédron #define PCI_EXP_LNKCAP_SLS_8_0GB 0x03 /* Supported Link Speed 8.0GT/s */ 1550adc02a9SJean-Sébastien Pédron #define PCI_EXP_LNKCAP_SLS_16_0GB 0x04 /* Supported Link Speed 16.0GT/s */ 1560adc02a9SJean-Sébastien Pédron #define PCI_EXP_LNKCAP_SLS_32_0GB 0x05 /* Supported Link Speed 32.0GT/s */ 1570adc02a9SJean-Sébastien Pédron #define PCI_EXP_LNKCAP_SLS_64_0GB 0x06 /* Supported Link Speed 64.0GT/s */ 158a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP_MLW 0x03f0 /* Maximum Link Width */ 159a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */ 160a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */ 161a65ef215SHans Petter Selasky #define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */ 162ab62989aSHans Petter Selasky #define PCI_EXP_LNKCAP2_SLS_16_0GB 0x10 /* Supported Link Speed 16.0GT/s */ 1630adc02a9SJean-Sébastien Pédron #define PCI_EXP_LNKCAP2_SLS_32_0GB 0x20 /* Supported Link Speed 32.0GT/s */ 1640adc02a9SJean-Sébastien Pédron #define PCI_EXP_LNKCAP2_SLS_64_0GB 0x40 /* Supported Link Speed 64.0GT/s */ 16578a02d8bSVladimir Kondratyev #define PCI_EXP_LNKCTL2_TLS 0x000f 16678a02d8bSVladimir Kondratyev #define PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Supported Speed 2.5GT/s */ 16778a02d8bSVladimir Kondratyev #define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Supported Speed 5GT/s */ 16878a02d8bSVladimir Kondratyev #define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */ 16978a02d8bSVladimir Kondratyev #define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */ 17078a02d8bSVladimir Kondratyev #define PCI_EXP_LNKCTL2_TLS_32_0GT 0x0005 /* Supported Speed 32GT/s */ 1710adc02a9SJean-Sébastien Pédron #define PCI_EXP_LNKCTL2_TLS_64_0GT 0x0006 /* Supported Speed 64GT/s */ 17278a02d8bSVladimir Kondratyev #define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 /* Enter Compliance */ 17378a02d8bSVladimir Kondratyev #define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */ 1748d59ecb2SHans Petter Selasky 1755f2f582cSBjoern A. Zeeb #define PCI_MSI_ADDRESS_LO PCIR_MSI_ADDR 1765f2f582cSBjoern A. Zeeb #define PCI_MSI_ADDRESS_HI PCIR_MSI_ADDR_HIGH 1775f2f582cSBjoern A. Zeeb #define PCI_MSI_FLAGS PCIR_MSI_CTRL 1785f2f582cSBjoern A. Zeeb #define PCI_MSI_FLAGS_ENABLE PCIM_MSICTRL_MSI_ENABLE 1794152ce21SJean-Sébastien Pédron #define PCI_MSIX_FLAGS PCIR_MSIX_CTRL 1804152ce21SJean-Sébastien Pédron #define PCI_MSIX_FLAGS_ENABLE PCIM_MSIXCTRL_MSIX_ENABLE 1815f2f582cSBjoern A. Zeeb 18212af734dSHans Petter Selasky #define PCI_EXP_LNKCAP_CLKPM 0x00040000 18312af734dSHans Petter Selasky #define PCI_EXP_DEVSTA_TRPND 0x0020 18412af734dSHans Petter Selasky 185bdff61f8SHans Petter Selasky #define IORESOURCE_MEM (1 << SYS_RES_MEMORY) 186bdff61f8SHans Petter Selasky #define IORESOURCE_IO (1 << SYS_RES_IOPORT) 187bdff61f8SHans Petter Selasky #define IORESOURCE_IRQ (1 << SYS_RES_IRQ) 1888d59ecb2SHans Petter Selasky 189a65ef215SHans Petter Selasky enum pci_bus_speed { 190a65ef215SHans Petter Selasky PCI_SPEED_UNKNOWN = -1, 191a65ef215SHans Petter Selasky PCIE_SPEED_2_5GT, 192a65ef215SHans Petter Selasky PCIE_SPEED_5_0GT, 193a65ef215SHans Petter Selasky PCIE_SPEED_8_0GT, 194ab62989aSHans Petter Selasky PCIE_SPEED_16_0GT, 1950adc02a9SJean-Sébastien Pédron PCIE_SPEED_32_0GT, 1960adc02a9SJean-Sébastien Pédron PCIE_SPEED_64_0GT, 197a65ef215SHans Petter Selasky }; 1988d59ecb2SHans Petter Selasky 199a65ef215SHans Petter Selasky enum pcie_link_width { 200ab62989aSHans Petter Selasky PCIE_LNK_WIDTH_RESRV = 0x00, 201ab62989aSHans Petter Selasky PCIE_LNK_X1 = 0x01, 202ab62989aSHans Petter Selasky PCIE_LNK_X2 = 0x02, 203ab62989aSHans Petter Selasky PCIE_LNK_X4 = 0x04, 204ab62989aSHans Petter Selasky PCIE_LNK_X8 = 0x08, 205ab62989aSHans Petter Selasky PCIE_LNK_X12 = 0x0c, 206ab62989aSHans Petter Selasky PCIE_LNK_X16 = 0x10, 207ab62989aSHans Petter Selasky PCIE_LNK_X32 = 0x20, 208ab62989aSHans Petter Selasky PCIE_LNK_WIDTH_UNKNOWN = 0xff, 209a65ef215SHans Petter Selasky }; 210a65ef215SHans Petter Selasky 211fc1d8409SBjoern A. Zeeb #define PCIE_LINK_STATE_L0S 0x00000001 212fc1d8409SBjoern A. Zeeb #define PCIE_LINK_STATE_L1 0x00000002 213fc1d8409SBjoern A. Zeeb #define PCIE_LINK_STATE_CLKPM 0x00000004 214fc1d8409SBjoern A. Zeeb 21512af734dSHans Petter Selasky typedef int pci_power_t; 21612af734dSHans Petter Selasky 21712af734dSHans Petter Selasky #define PCI_D0 PCI_POWERSTATE_D0 21812af734dSHans Petter Selasky #define PCI_D1 PCI_POWERSTATE_D1 21912af734dSHans Petter Selasky #define PCI_D2 PCI_POWERSTATE_D2 22012af734dSHans Petter Selasky #define PCI_D3hot PCI_POWERSTATE_D3 22112af734dSHans Petter Selasky #define PCI_D3cold 4 22212af734dSHans Petter Selasky 22312af734dSHans Petter Selasky #define PCI_POWER_ERROR PCI_POWERSTATE_UNKNOWN 22412af734dSHans Petter Selasky 2254cb3cb2dSJake Freeland extern const char *pci_power_names[6]; 2264cb3cb2dSJake Freeland 227fc1d8409SBjoern A. Zeeb #define PCI_ERR_ROOT_COMMAND PCIR_AER_ROOTERR_CMD 228fc1d8409SBjoern A. Zeeb #define PCI_ERR_ROOT_ERR_SRC PCIR_AER_COR_SOURCE_ID 229fc1d8409SBjoern A. Zeeb 230fc1d8409SBjoern A. Zeeb #define PCI_EXT_CAP_ID_ERR PCIZ_AER 231c4f52f71SBjoern A. Zeeb #define PCI_EXT_CAP_ID_L1SS PCIZ_L1PM 232c4f52f71SBjoern A. Zeeb 233c4f52f71SBjoern A. Zeeb #define PCI_L1SS_CTL1 0x8 234c4f52f71SBjoern A. Zeeb #define PCI_L1SS_CTL1_L1SS_MASK 0xf 235fc1d8409SBjoern A. Zeeb 236*157e93e0SBjoern A. Zeeb #define PCI_IRQ_INTX 0x01 237366d68f2SBjoern A. Zeeb #define PCI_IRQ_MSI 0x02 238366d68f2SBjoern A. Zeeb #define PCI_IRQ_MSIX 0x04 239*157e93e0SBjoern A. Zeeb #define PCI_IRQ_ALL_TYPES (PCI_IRQ_MSIX|PCI_IRQ_MSI|PCI_IRQ_INTX) 240*157e93e0SBjoern A. Zeeb 241*157e93e0SBjoern A. Zeeb #if defined(LINUXKPI_VERSION) && (LINUXKPI_VERSION >= 60800) 242*157e93e0SBjoern A. Zeeb #define PCI_IRQ_LEGACY PCI_IRQ_INTX 243*157e93e0SBjoern A. Zeeb #endif 244366d68f2SBjoern A. Zeeb 245a65ef215SHans Petter Selasky struct pci_dev; 2468d59ecb2SHans Petter Selasky 2478d59ecb2SHans Petter Selasky struct pci_driver { 248cf899348SBjoern A. Zeeb struct list_head node; 2498d59ecb2SHans Petter Selasky char *name; 2508d59ecb2SHans Petter Selasky const struct pci_device_id *id_table; 2518d59ecb2SHans Petter Selasky int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); 2528d59ecb2SHans Petter Selasky void (*remove)(struct pci_dev *dev); 2538d59ecb2SHans Petter Selasky int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */ 2548d59ecb2SHans Petter Selasky int (*resume) (struct pci_dev *dev); /* Device woken up */ 2557d133393SHans Petter Selasky void (*shutdown) (struct pci_dev *dev); /* Device shutdown */ 256b38dc0a1SMark Johnston driver_t bsddriver; 2578d59ecb2SHans Petter Selasky devclass_t bsdclass; 25888156ba5SMark Johnston struct device_driver driver; 2598d59ecb2SHans Petter Selasky const struct pci_error_handlers *err_handler; 2600b7bd01aSMark Johnston bool isdrm; 261b91dd79bSBjoern A. Zeeb int bsd_probe_return; 2622928e60eSKonstantin Belousov int (*bsd_iov_init)(device_t dev, uint16_t num_vfs, 2632928e60eSKonstantin Belousov const nvlist_t *pf_config); 2642928e60eSKonstantin Belousov void (*bsd_iov_uninit)(device_t dev); 2652928e60eSKonstantin Belousov int (*bsd_iov_add_vf)(device_t dev, uint16_t vfnum, 2662928e60eSKonstantin Belousov const nvlist_t *vf_config); 2670b7bd01aSMark Johnston }; 2680b7bd01aSMark Johnston 2690b7bd01aSMark Johnston struct pci_bus { 2700b7bd01aSMark Johnston struct pci_dev *self; 271525dd4acSBjoern A. Zeeb /* struct pci_bus *parent */ 272937a05baSJustin Hibbits int domain; 2730b7bd01aSMark Johnston int number; 2748d59ecb2SHans Petter Selasky }; 2758d59ecb2SHans Petter Selasky 2768d59ecb2SHans Petter Selasky extern struct list_head pci_drivers; 2778d59ecb2SHans Petter Selasky extern struct list_head pci_devices; 2788d59ecb2SHans Petter Selasky extern spinlock_t pci_lock; 2798d59ecb2SHans Petter Selasky 2808d59ecb2SHans Petter Selasky #define __devexit_p(x) x 2818d59ecb2SHans Petter Selasky 282f5c7feeeSBjoern A. Zeeb #define module_pci_driver(_drv) \ 283f5c7feeeSBjoern A. Zeeb module_driver(_drv, linux_pci_register_driver, linux_pci_unregister_driver) 284366d68f2SBjoern A. Zeeb 2854b56afafSBjoern A. Zeeb struct msi_msg { 2864b56afafSBjoern A. Zeeb uint32_t data; 2874b56afafSBjoern A. Zeeb }; 2884b56afafSBjoern A. Zeeb 28917bde9cbSBjoern A. Zeeb struct pci_msi_desc { 2904b56afafSBjoern A. Zeeb struct { 2914b56afafSBjoern A. Zeeb bool is_64; 2924b56afafSBjoern A. Zeeb } msi_attrib; 2934b56afafSBjoern A. Zeeb }; 2944b56afafSBjoern A. Zeeb 29517bde9cbSBjoern A. Zeeb struct msi_desc { 29617bde9cbSBjoern A. Zeeb struct msi_msg msg; 29717bde9cbSBjoern A. Zeeb struct pci_msi_desc pci; 29817bde9cbSBjoern A. Zeeb }; 29917bde9cbSBjoern A. Zeeb 30096ab16ebSVladimir Kondratyev struct msix_entry { 30196ab16ebSVladimir Kondratyev int entry; 30296ab16ebSVladimir Kondratyev int vector; 30396ab16ebSVladimir Kondratyev }; 30496ab16ebSVladimir Kondratyev 305d4a4960cSBjoern A. Zeeb /* 306d4a4960cSBjoern A. Zeeb * If we find drivers accessing this from multiple KPIs we may have to 307d4a4960cSBjoern A. Zeeb * refcount objects of this structure. 308d4a4960cSBjoern A. Zeeb */ 30996ab16ebSVladimir Kondratyev struct resource; 3104c274849SEmmanuel Vadot struct pci_mmio_region { 3114c274849SEmmanuel Vadot TAILQ_ENTRY(pci_mmio_region) next; 3124c274849SEmmanuel Vadot struct resource *res; 3134c274849SEmmanuel Vadot int rid; 3144c274849SEmmanuel Vadot int type; 3154c274849SEmmanuel Vadot }; 3164c274849SEmmanuel Vadot 3178d59ecb2SHans Petter Selasky struct pci_dev { 3188d59ecb2SHans Petter Selasky struct device dev; 3198d59ecb2SHans Petter Selasky struct list_head links; 3208d59ecb2SHans Petter Selasky struct pci_driver *pdrv; 3210b7bd01aSMark Johnston struct pci_bus *bus; 3228e106c52SBjoern A. Zeeb struct pci_dev *root; 3234cb3cb2dSJake Freeland pci_power_t current_state; 3248d59ecb2SHans Petter Selasky uint16_t device; 3258d59ecb2SHans Petter Selasky uint16_t vendor; 326f2ec04a3SMark Johnston uint16_t subsystem_vendor; 327f2ec04a3SMark Johnston uint16_t subsystem_device; 3288d59ecb2SHans Petter Selasky unsigned int irq; 3298d59ecb2SHans Petter Selasky unsigned int devfn; 3306373e95eSMark Johnston uint32_t class; 3316373e95eSMark Johnston uint8_t revision; 3324b56afafSBjoern A. Zeeb uint8_t msi_cap; 3334152ce21SJean-Sébastien Pédron uint8_t msix_cap; 334d4a4960cSBjoern A. Zeeb bool managed; /* devres "pcim_*(). */ 335d4a4960cSBjoern A. Zeeb bool want_iomap_res; 3364f109faaSHans Petter Selasky bool msi_enabled; 337d4a4960cSBjoern A. Zeeb bool msix_enabled; 338096104e7SNeel Chauhan phys_addr_t rom; 339096104e7SNeel Chauhan size_t romlen; 340b15491b4SBjoern A. Zeeb struct msi_desc **msi_desc; 341393b0ba2SVal Packett char *path_name; 342808ae4e2SVladimir Kondratyev spinlock_t pcie_cap_lock; 3434c274849SEmmanuel Vadot 3444c274849SEmmanuel Vadot TAILQ_HEAD(, pci_mmio_region) mmio; 3458d59ecb2SHans Petter Selasky }; 3468d59ecb2SHans Petter Selasky 3471cdb2534SWarner Losh int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name); 34836b5c440SWarner Losh int pci_alloc_irq_vectors(struct pci_dev *pdev, int minv, int maxv, 34936b5c440SWarner Losh unsigned int flags); 3500d0ca120SBjoern A. Zeeb bool pci_device_is_present(struct pci_dev *pdev); 3511cdb2534SWarner Losh 35296ab16ebSVladimir Kondratyev int linuxkpi_pcim_enable_device(struct pci_dev *pdev); 35396ab16ebSVladimir Kondratyev void __iomem **linuxkpi_pcim_iomap_table(struct pci_dev *pdev); 354fcc350c3SVladimir Kondratyev void *linuxkpi_pci_iomap_range(struct pci_dev *pdev, int mmio_bar, 355fcc350c3SVladimir Kondratyev unsigned long mmio_off, unsigned long mmio_size); 35696ab16ebSVladimir Kondratyev void *linuxkpi_pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size); 35796ab16ebSVladimir Kondratyev void linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res); 35896ab16ebSVladimir Kondratyev int linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, 35996ab16ebSVladimir Kondratyev const char *name); 36096ab16ebSVladimir Kondratyev int linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name); 36196ab16ebSVladimir Kondratyev void linuxkpi_pci_release_region(struct pci_dev *pdev, int bar); 36296ab16ebSVladimir Kondratyev void linuxkpi_pci_release_regions(struct pci_dev *pdev); 36396ab16ebSVladimir Kondratyev int linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, 36496ab16ebSVladimir Kondratyev int nreq); 36596ab16ebSVladimir Kondratyev 3668e106c52SBjoern A. Zeeb /* Internal helper function(s). */ 3678e106c52SBjoern A. Zeeb struct pci_dev *lkpinew_pci_dev(device_t); 368d4a4960cSBjoern A. Zeeb void lkpi_pci_devres_release(struct device *, void *); 3698f61992dSBjoern A. Zeeb struct pci_dev *lkpi_pci_get_device(uint16_t, uint16_t, struct pci_dev *); 3704b56afafSBjoern A. Zeeb struct msi_desc *lkpi_pci_msi_desc_alloc(int); 37196ab16ebSVladimir Kondratyev struct device *lkpi_pci_find_irq_dev(unsigned int irq); 37296ab16ebSVladimir Kondratyev int _lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec); 3738e106c52SBjoern A. Zeeb 37401e1131eSBjoern A. Zeeb #define pci_err(pdev, fmt, ...) \ 37501e1131eSBjoern A. Zeeb dev_err(&(pdev)->dev, fmt, __VA_ARGS__) 37601e1131eSBjoern A. Zeeb 377c41d8354SBjoern A. Zeeb static inline bool 378c41d8354SBjoern A. Zeeb dev_is_pci(struct device *dev) 379c41d8354SBjoern A. Zeeb { 380c41d8354SBjoern A. Zeeb 381c41d8354SBjoern A. Zeeb return (device_get_devclass(dev->bsddev) == devclass_find("pci")); 382c41d8354SBjoern A. Zeeb } 383c41d8354SBjoern A. Zeeb 384f1206503SVladimir Kondratyev static inline uint16_t 385f1206503SVladimir Kondratyev pci_dev_id(struct pci_dev *pdev) 386f1206503SVladimir Kondratyev { 387f1206503SVladimir Kondratyev return (PCI_DEVID(pdev->bus->number, pdev->devfn)); 388f1206503SVladimir Kondratyev } 389f1206503SVladimir Kondratyev 390d4a4960cSBjoern A. Zeeb static inline int 391d4a4960cSBjoern A. Zeeb pci_resource_type(struct pci_dev *pdev, int bar) 392d4a4960cSBjoern A. Zeeb { 393d4a4960cSBjoern A. Zeeb struct pci_map *pm; 394d4a4960cSBjoern A. Zeeb 395d4a4960cSBjoern A. Zeeb pm = pci_find_bar(pdev->dev.bsddev, PCIR_BAR(bar)); 396d4a4960cSBjoern A. Zeeb if (!pm) 397d4a4960cSBjoern A. Zeeb return (-1); 398d4a4960cSBjoern A. Zeeb 399d4a4960cSBjoern A. Zeeb if (PCI_BAR_IO(pm->pm_value)) 400d4a4960cSBjoern A. Zeeb return (SYS_RES_IOPORT); 401d4a4960cSBjoern A. Zeeb else 402d4a4960cSBjoern A. Zeeb return (SYS_RES_MEMORY); 403d4a4960cSBjoern A. Zeeb } 4048e106c52SBjoern A. Zeeb 4058d59ecb2SHans Petter Selasky /* 4068d59ecb2SHans Petter Selasky * All drivers just seem to want to inspect the type not flags. 4078d59ecb2SHans Petter Selasky */ 4088d59ecb2SHans Petter Selasky static inline int 4098d59ecb2SHans Petter Selasky pci_resource_flags(struct pci_dev *pdev, int bar) 4108d59ecb2SHans Petter Selasky { 411bdff61f8SHans Petter Selasky int type; 4128d59ecb2SHans Petter Selasky 413bdff61f8SHans Petter Selasky type = pci_resource_type(pdev, bar); 414bdff61f8SHans Petter Selasky if (type < 0) 4158d59ecb2SHans Petter Selasky return (0); 416bdff61f8SHans Petter Selasky return (1 << type); 4178d59ecb2SHans Petter Selasky } 4188d59ecb2SHans Petter Selasky 4198d59ecb2SHans Petter Selasky static inline const char * 4208d59ecb2SHans Petter Selasky pci_name(struct pci_dev *d) 4218d59ecb2SHans Petter Selasky { 422393b0ba2SVal Packett return d->path_name; 4238d59ecb2SHans Petter Selasky } 4248d59ecb2SHans Petter Selasky 4258d59ecb2SHans Petter Selasky static inline void * 4268d59ecb2SHans Petter Selasky pci_get_drvdata(struct pci_dev *pdev) 4278d59ecb2SHans Petter Selasky { 4288d59ecb2SHans Petter Selasky 4298d59ecb2SHans Petter Selasky return dev_get_drvdata(&pdev->dev); 4308d59ecb2SHans Petter Selasky } 4318d59ecb2SHans Petter Selasky 4328d59ecb2SHans Petter Selasky static inline void 4338d59ecb2SHans Petter Selasky pci_set_drvdata(struct pci_dev *pdev, void *data) 4348d59ecb2SHans Petter Selasky { 4358d59ecb2SHans Petter Selasky 4368d59ecb2SHans Petter Selasky dev_set_drvdata(&pdev->dev, data); 4378d59ecb2SHans Petter Selasky } 4388d59ecb2SHans Petter Selasky 4398e106c52SBjoern A. Zeeb static inline struct pci_dev * 4408e106c52SBjoern A. Zeeb pci_dev_get(struct pci_dev *pdev) 4418e106c52SBjoern A. Zeeb { 4428e106c52SBjoern A. Zeeb 4438e106c52SBjoern A. Zeeb if (pdev != NULL) 4448e106c52SBjoern A. Zeeb get_device(&pdev->dev); 4458e106c52SBjoern A. Zeeb return (pdev); 4468e106c52SBjoern A. Zeeb } 4478e106c52SBjoern A. Zeeb 4481fac2cb4SBjoern A. Zeeb static __inline void 4491fac2cb4SBjoern A. Zeeb pci_dev_put(struct pci_dev *pdev) 4501fac2cb4SBjoern A. Zeeb { 4511fac2cb4SBjoern A. Zeeb 4521fac2cb4SBjoern A. Zeeb if (pdev != NULL) 4531fac2cb4SBjoern A. Zeeb put_device(&pdev->dev); 4541fac2cb4SBjoern A. Zeeb } 4551fac2cb4SBjoern A. Zeeb 4568d59ecb2SHans Petter Selasky static inline int 4578d59ecb2SHans Petter Selasky pci_enable_device(struct pci_dev *pdev) 4588d59ecb2SHans Petter Selasky { 4598d59ecb2SHans Petter Selasky 4608d59ecb2SHans Petter Selasky pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT); 4618d59ecb2SHans Petter Selasky pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY); 4628d59ecb2SHans Petter Selasky return (0); 4638d59ecb2SHans Petter Selasky } 4648d59ecb2SHans Petter Selasky 4658d59ecb2SHans Petter Selasky static inline void 4668d59ecb2SHans Petter Selasky pci_disable_device(struct pci_dev *pdev) 4678d59ecb2SHans Petter Selasky { 468f67b5de7SMark Johnston 469555deb3cSHans Petter Selasky pci_disable_busmaster(pdev->dev.bsddev); 4708d59ecb2SHans Petter Selasky } 4718d59ecb2SHans Petter Selasky 4728d59ecb2SHans Petter Selasky static inline int 4738d59ecb2SHans Petter Selasky pci_set_master(struct pci_dev *pdev) 4748d59ecb2SHans Petter Selasky { 4758d59ecb2SHans Petter Selasky 4768d59ecb2SHans Petter Selasky pci_enable_busmaster(pdev->dev.bsddev); 4778d59ecb2SHans Petter Selasky return (0); 4788d59ecb2SHans Petter Selasky } 4798d59ecb2SHans Petter Selasky 4808d59ecb2SHans Petter Selasky static inline int 48112af734dSHans Petter Selasky pci_set_power_state(struct pci_dev *pdev, int state) 48212af734dSHans Petter Selasky { 48312af734dSHans Petter Selasky 48412af734dSHans Petter Selasky pci_set_powerstate(pdev->dev.bsddev, state); 48512af734dSHans Petter Selasky return (0); 48612af734dSHans Petter Selasky } 48712af734dSHans Petter Selasky 48812af734dSHans Petter Selasky static inline int 4898d59ecb2SHans Petter Selasky pci_clear_master(struct pci_dev *pdev) 4908d59ecb2SHans Petter Selasky { 4918d59ecb2SHans Petter Selasky 4928d59ecb2SHans Petter Selasky pci_disable_busmaster(pdev->dev.bsddev); 4938d59ecb2SHans Petter Selasky return (0); 4948d59ecb2SHans Petter Selasky } 4958d59ecb2SHans Petter Selasky 496b3b83625SBjoern A. Zeeb static inline bool 497b3b83625SBjoern A. Zeeb pci_is_root_bus(struct pci_bus *pbus) 498b3b83625SBjoern A. Zeeb { 499b3b83625SBjoern A. Zeeb 500b3b83625SBjoern A. Zeeb return (pbus->self == NULL); 501b3b83625SBjoern A. Zeeb } 502b3b83625SBjoern A. Zeeb 503b3b83625SBjoern A. Zeeb static inline struct pci_dev * 504b3b83625SBjoern A. Zeeb pci_upstream_bridge(struct pci_dev *pdev) 505b3b83625SBjoern A. Zeeb { 506b3b83625SBjoern A. Zeeb 507b3b83625SBjoern A. Zeeb if (pci_is_root_bus(pdev->bus)) 508b3b83625SBjoern A. Zeeb return (NULL); 509b3b83625SBjoern A. Zeeb 510b3b83625SBjoern A. Zeeb /* 511b3b83625SBjoern A. Zeeb * If we do not have a (proper) "upstream bridge" set, e.g., we point 512b3b83625SBjoern A. Zeeb * to ourselves, try to handle this case on the fly like we do 513b3b83625SBjoern A. Zeeb * for pcie_find_root_port(). 514b3b83625SBjoern A. Zeeb */ 515b3b83625SBjoern A. Zeeb if (pdev == pdev->bus->self) { 516b3b83625SBjoern A. Zeeb device_t bridge; 517b3b83625SBjoern A. Zeeb 518b3b83625SBjoern A. Zeeb bridge = device_get_parent(pdev->dev.bsddev); 519b3b83625SBjoern A. Zeeb if (bridge == NULL) 520b3b83625SBjoern A. Zeeb goto done; 521b3b83625SBjoern A. Zeeb bridge = device_get_parent(bridge); 522b3b83625SBjoern A. Zeeb if (bridge == NULL) 523b3b83625SBjoern A. Zeeb goto done; 524b3b83625SBjoern A. Zeeb if (device_get_devclass(device_get_parent(bridge)) != 525b3b83625SBjoern A. Zeeb devclass_find("pci")) 526b3b83625SBjoern A. Zeeb goto done; 527b3b83625SBjoern A. Zeeb 528b3b83625SBjoern A. Zeeb /* 529b3b83625SBjoern A. Zeeb * "bridge" is a PCI-to-PCI bridge. Create a Linux pci_dev 530b3b83625SBjoern A. Zeeb * for it so it can be returned. 531b3b83625SBjoern A. Zeeb */ 532b3b83625SBjoern A. Zeeb pdev->bus->self = lkpinew_pci_dev(bridge); 533b3b83625SBjoern A. Zeeb } 534b3b83625SBjoern A. Zeeb done: 535b3b83625SBjoern A. Zeeb return (pdev->bus->self); 536b3b83625SBjoern A. Zeeb } 537b3b83625SBjoern A. Zeeb 53896ab16ebSVladimir Kondratyev #define pci_release_region(pdev, bar) linuxkpi_pci_release_region(pdev, bar) 53996ab16ebSVladimir Kondratyev #define pci_release_regions(pdev) linuxkpi_pci_release_regions(pdev) 54096ab16ebSVladimir Kondratyev #define pci_request_regions(pdev, res_name) \ 54196ab16ebSVladimir Kondratyev linuxkpi_pci_request_regions(pdev, res_name) 5428d59ecb2SHans Petter Selasky 5438d59ecb2SHans Petter Selasky static inline void 544d4a4960cSBjoern A. Zeeb lkpi_pci_disable_msix(struct pci_dev *pdev) 5458d59ecb2SHans Petter Selasky { 5468d59ecb2SHans Petter Selasky 5478d59ecb2SHans Petter Selasky pci_release_msi(pdev->dev.bsddev); 548e1992aa1SHans Petter Selasky 549e1992aa1SHans Petter Selasky /* 550e1992aa1SHans Petter Selasky * The MSIX IRQ numbers associated with this PCI device are no 551e1992aa1SHans Petter Selasky * longer valid and might be re-assigned. Make sure 55296ab16ebSVladimir Kondratyev * lkpi_pci_find_irq_dev() does no longer see them by 553e1992aa1SHans Petter Selasky * resetting their references to zero: 554e1992aa1SHans Petter Selasky */ 5554f109faaSHans Petter Selasky pdev->dev.irq_start = 0; 5564f109faaSHans Petter Selasky pdev->dev.irq_end = 0; 557d4a4960cSBjoern A. Zeeb pdev->msix_enabled = false; 5584f109faaSHans Petter Selasky } 559d4a4960cSBjoern A. Zeeb /* Only for consistency. No conflict on that one. */ 560d4a4960cSBjoern A. Zeeb #define pci_disable_msix(pdev) lkpi_pci_disable_msix(pdev) 5614f109faaSHans Petter Selasky 5624f109faaSHans Petter Selasky static inline void 563d4a4960cSBjoern A. Zeeb lkpi_pci_disable_msi(struct pci_dev *pdev) 5644f109faaSHans Petter Selasky { 5654f109faaSHans Petter Selasky 5664f109faaSHans Petter Selasky pci_release_msi(pdev->dev.bsddev); 5674f109faaSHans Petter Selasky 5684f109faaSHans Petter Selasky pdev->dev.irq_start = 0; 5694f109faaSHans Petter Selasky pdev->dev.irq_end = 0; 5704f109faaSHans Petter Selasky pdev->irq = pdev->dev.irq; 5714f109faaSHans Petter Selasky pdev->msi_enabled = false; 5728d59ecb2SHans Petter Selasky } 573d4a4960cSBjoern A. Zeeb #define pci_disable_msi(pdev) lkpi_pci_disable_msi(pdev) 574539228d3SBjoern A. Zeeb #define pci_free_irq_vectors(pdev) lkpi_pci_disable_msi(pdev) 575105a37caSEmmanuel Vadot 576937a05baSJustin Hibbits unsigned long pci_resource_start(struct pci_dev *pdev, int bar); 577937a05baSJustin Hibbits unsigned long pci_resource_len(struct pci_dev *pdev, int bar); 578937a05baSJustin Hibbits 57912af734dSHans Petter Selasky static inline bus_addr_t 58012af734dSHans Petter Selasky pci_bus_address(struct pci_dev *pdev, int bar) 58112af734dSHans Petter Selasky { 58212af734dSHans Petter Selasky 58312af734dSHans Petter Selasky return (pci_resource_start(pdev, bar)); 58412af734dSHans Petter Selasky } 58512af734dSHans Petter Selasky 5868d59ecb2SHans Petter Selasky #define PCI_CAP_ID_EXP PCIY_EXPRESS 5878d59ecb2SHans Petter Selasky #define PCI_CAP_ID_PCIX PCIY_PCIX 58812af734dSHans Petter Selasky #define PCI_CAP_ID_AGP PCIY_AGP 58912af734dSHans Petter Selasky #define PCI_CAP_ID_PM PCIY_PMG 5908d59ecb2SHans Petter Selasky 59112af734dSHans Petter Selasky #define PCI_EXP_DEVCTL PCIER_DEVICE_CTL 59212af734dSHans Petter Selasky #define PCI_EXP_DEVCTL_PAYLOAD PCIEM_CTL_MAX_PAYLOAD 59312af734dSHans Petter Selasky #define PCI_EXP_DEVCTL_READRQ PCIEM_CTL_MAX_READ_REQUEST 59412af734dSHans Petter Selasky #define PCI_EXP_LNKCTL PCIER_LINK_CTL 59512af734dSHans Petter Selasky #define PCI_EXP_LNKSTA PCIER_LINK_STA 5968d59ecb2SHans Petter Selasky 5978d59ecb2SHans Petter Selasky static inline int 5988d59ecb2SHans Petter Selasky pci_find_capability(struct pci_dev *pdev, int capid) 5998d59ecb2SHans Petter Selasky { 6008d59ecb2SHans Petter Selasky int reg; 6018d59ecb2SHans Petter Selasky 6028d59ecb2SHans Petter Selasky if (pci_find_cap(pdev->dev.bsddev, capid, ®)) 6038d59ecb2SHans Petter Selasky return (0); 6048d59ecb2SHans Petter Selasky return (reg); 6058d59ecb2SHans Petter Selasky } 6068d59ecb2SHans Petter Selasky 6078d59ecb2SHans Petter Selasky static inline int pci_pcie_cap(struct pci_dev *dev) 6088d59ecb2SHans Petter Selasky { 6098d59ecb2SHans Petter Selasky return pci_find_capability(dev, PCI_CAP_ID_EXP); 6108d59ecb2SHans Petter Selasky } 6118d59ecb2SHans Petter Selasky 6128d59ecb2SHans Petter Selasky static inline int 6138e106c52SBjoern A. Zeeb pci_find_ext_capability(struct pci_dev *pdev, int capid) 6148e106c52SBjoern A. Zeeb { 6158e106c52SBjoern A. Zeeb int reg; 6168e106c52SBjoern A. Zeeb 6178e106c52SBjoern A. Zeeb if (pci_find_extcap(pdev->dev.bsddev, capid, ®)) 6188e106c52SBjoern A. Zeeb return (0); 6198e106c52SBjoern A. Zeeb return (reg); 6208e106c52SBjoern A. Zeeb } 6218e106c52SBjoern A. Zeeb 6228e106c52SBjoern A. Zeeb #define PCIM_PCAP_PME_SHIFT 11 6238e106c52SBjoern A. Zeeb static __inline bool 6248e106c52SBjoern A. Zeeb pci_pme_capable(struct pci_dev *pdev, uint32_t flag) 6258e106c52SBjoern A. Zeeb { 6268e106c52SBjoern A. Zeeb struct pci_devinfo *dinfo; 6278e106c52SBjoern A. Zeeb pcicfgregs *cfg; 6288e106c52SBjoern A. Zeeb 6298e106c52SBjoern A. Zeeb if (flag > (PCIM_PCAP_D3PME_COLD >> PCIM_PCAP_PME_SHIFT)) 6308e106c52SBjoern A. Zeeb return (false); 6318e106c52SBjoern A. Zeeb 6328e106c52SBjoern A. Zeeb dinfo = device_get_ivars(pdev->dev.bsddev); 6338e106c52SBjoern A. Zeeb cfg = &dinfo->cfg; 6348e106c52SBjoern A. Zeeb 6358e106c52SBjoern A. Zeeb if (cfg->pp.pp_cap == 0) 6368e106c52SBjoern A. Zeeb return (false); 6378e106c52SBjoern A. Zeeb 6388e106c52SBjoern A. Zeeb if ((cfg->pp.pp_cap & (1 << (PCIM_PCAP_PME_SHIFT + flag))) != 0) 6398e106c52SBjoern A. Zeeb return (true); 6408e106c52SBjoern A. Zeeb 6418e106c52SBjoern A. Zeeb return (false); 6428e106c52SBjoern A. Zeeb } 6438e106c52SBjoern A. Zeeb 6448e106c52SBjoern A. Zeeb static inline int 6458e106c52SBjoern A. Zeeb pci_disable_link_state(struct pci_dev *pdev, uint32_t flags) 6468e106c52SBjoern A. Zeeb { 6478e106c52SBjoern A. Zeeb 6488e106c52SBjoern A. Zeeb if (!pci_enable_aspm) 6498e106c52SBjoern A. Zeeb return (-EPERM); 6508e106c52SBjoern A. Zeeb 6518e106c52SBjoern A. Zeeb return (-ENXIO); 6528e106c52SBjoern A. Zeeb } 6538e106c52SBjoern A. Zeeb 6548e106c52SBjoern A. Zeeb static inline int 655ed5600f5SBjoern A. Zeeb pci_read_config_byte(const struct pci_dev *pdev, int where, u8 *val) 6568d59ecb2SHans Petter Selasky { 6578d59ecb2SHans Petter Selasky 6588d59ecb2SHans Petter Selasky *val = (u8)pci_read_config(pdev->dev.bsddev, where, 1); 6598d59ecb2SHans Petter Selasky return (0); 6608d59ecb2SHans Petter Selasky } 6618d59ecb2SHans Petter Selasky 6628d59ecb2SHans Petter Selasky static inline int 663ed5600f5SBjoern A. Zeeb pci_read_config_word(const struct pci_dev *pdev, int where, u16 *val) 6648d59ecb2SHans Petter Selasky { 6658d59ecb2SHans Petter Selasky 6668d59ecb2SHans Petter Selasky *val = (u16)pci_read_config(pdev->dev.bsddev, where, 2); 6678d59ecb2SHans Petter Selasky return (0); 6688d59ecb2SHans Petter Selasky } 6698d59ecb2SHans Petter Selasky 6708d59ecb2SHans Petter Selasky static inline int 671ed5600f5SBjoern A. Zeeb pci_read_config_dword(const struct pci_dev *pdev, int where, u32 *val) 6728d59ecb2SHans Petter Selasky { 6738d59ecb2SHans Petter Selasky 6748d59ecb2SHans Petter Selasky *val = (u32)pci_read_config(pdev->dev.bsddev, where, 4); 6758d59ecb2SHans Petter Selasky return (0); 6768d59ecb2SHans Petter Selasky } 6778d59ecb2SHans Petter Selasky 6788d59ecb2SHans Petter Selasky static inline int 679ed5600f5SBjoern A. Zeeb pci_write_config_byte(const struct pci_dev *pdev, int where, u8 val) 6808d59ecb2SHans Petter Selasky { 6818d59ecb2SHans Petter Selasky 6828d59ecb2SHans Petter Selasky pci_write_config(pdev->dev.bsddev, where, val, 1); 6838d59ecb2SHans Petter Selasky return (0); 6848d59ecb2SHans Petter Selasky } 6858d59ecb2SHans Petter Selasky 6868d59ecb2SHans Petter Selasky static inline int 687ed5600f5SBjoern A. Zeeb pci_write_config_word(const struct pci_dev *pdev, int where, u16 val) 6888d59ecb2SHans Petter Selasky { 6898d59ecb2SHans Petter Selasky 6908d59ecb2SHans Petter Selasky pci_write_config(pdev->dev.bsddev, where, val, 2); 6918d59ecb2SHans Petter Selasky return (0); 6928d59ecb2SHans Petter Selasky } 6938d59ecb2SHans Petter Selasky 6948d59ecb2SHans Petter Selasky static inline int 695ed5600f5SBjoern A. Zeeb pci_write_config_dword(const struct pci_dev *pdev, int where, u32 val) 6968d59ecb2SHans Petter Selasky { 6978d59ecb2SHans Petter Selasky 6988d59ecb2SHans Petter Selasky pci_write_config(pdev->dev.bsddev, where, val, 4); 6998d59ecb2SHans Petter Selasky return (0); 7008d59ecb2SHans Petter Selasky } 7018d59ecb2SHans Petter Selasky 7020b7bd01aSMark Johnston int linux_pci_register_driver(struct pci_driver *pdrv); 7030b7bd01aSMark Johnston int linux_pci_register_drm_driver(struct pci_driver *pdrv); 7040b7bd01aSMark Johnston void linux_pci_unregister_driver(struct pci_driver *pdrv); 7055098ed5fSJohannes Lundberg void linux_pci_unregister_drm_driver(struct pci_driver *pdrv); 7060b7bd01aSMark Johnston 7070b7bd01aSMark Johnston #define pci_register_driver(pdrv) linux_pci_register_driver(pdrv) 7080b7bd01aSMark Johnston #define pci_unregister_driver(pdrv) linux_pci_unregister_driver(pdrv) 7098d59ecb2SHans Petter Selasky 7108d59ecb2SHans Petter Selasky /* 7118d59ecb2SHans Petter Selasky * Enable msix, positive errors indicate actual number of available 7128d59ecb2SHans Petter Selasky * vectors. Negative errors are failures. 7138d59ecb2SHans Petter Selasky * 7148d59ecb2SHans Petter Selasky * NB: define added to prevent this definition of pci_enable_msix from 7158d59ecb2SHans Petter Selasky * clashing with the native FreeBSD version. 7168d59ecb2SHans Petter Selasky */ 71796ab16ebSVladimir Kondratyev #define pci_enable_msix(...) linuxkpi_pci_enable_msix(__VA_ARGS__) 7188d59ecb2SHans Petter Selasky 719fa0d4f31SHans Petter Selasky #define pci_enable_msix_range(...) \ 720fa0d4f31SHans Petter Selasky linux_pci_enable_msix_range(__VA_ARGS__) 721fa0d4f31SHans Petter Selasky 7228d59ecb2SHans Petter Selasky static inline int 7238d59ecb2SHans Petter Selasky pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, 7248d59ecb2SHans Petter Selasky int minvec, int maxvec) 7258d59ecb2SHans Petter Selasky { 7268d59ecb2SHans Petter Selasky int nvec = maxvec; 7278d59ecb2SHans Petter Selasky int rc; 7288d59ecb2SHans Petter Selasky 7298d59ecb2SHans Petter Selasky if (maxvec < minvec) 7308d59ecb2SHans Petter Selasky return (-ERANGE); 7318d59ecb2SHans Petter Selasky 7328d59ecb2SHans Petter Selasky do { 7338d59ecb2SHans Petter Selasky rc = pci_enable_msix(dev, entries, nvec); 7348d59ecb2SHans Petter Selasky if (rc < 0) { 7358d59ecb2SHans Petter Selasky return (rc); 7368d59ecb2SHans Petter Selasky } else if (rc > 0) { 7378d59ecb2SHans Petter Selasky if (rc < minvec) 7388d59ecb2SHans Petter Selasky return (-ENOSPC); 7398d59ecb2SHans Petter Selasky nvec = rc; 7408d59ecb2SHans Petter Selasky } 7418d59ecb2SHans Petter Selasky } while (rc); 7428d59ecb2SHans Petter Selasky return (nvec); 7438d59ecb2SHans Petter Selasky } 7448d59ecb2SHans Petter Selasky 7454f109faaSHans Petter Selasky #define pci_enable_msi(pdev) \ 7464f109faaSHans Petter Selasky linux_pci_enable_msi(pdev) 7474f109faaSHans Petter Selasky 7484f109faaSHans Petter Selasky static inline int 749b15491b4SBjoern A. Zeeb pci_enable_msi(struct pci_dev *pdev) 750b15491b4SBjoern A. Zeeb { 751b15491b4SBjoern A. Zeeb 752b15491b4SBjoern A. Zeeb return (_lkpi_pci_enable_msi_range(pdev, 1, 1)); 753b15491b4SBjoern A. Zeeb } 754b15491b4SBjoern A. Zeeb 755b15491b4SBjoern A. Zeeb static inline int 756452d59e1SSlava Shwartsman pci_channel_offline(struct pci_dev *pdev) 7578d59ecb2SHans Petter Selasky { 758452d59e1SSlava Shwartsman 759c5161386SHans Petter Selasky return (pci_read_config(pdev->dev.bsddev, PCIR_VENDOR, 2) == PCIV_INVALID); 7608d59ecb2SHans Petter Selasky } 7618d59ecb2SHans Petter Selasky 7628d59ecb2SHans Petter Selasky static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) 7638d59ecb2SHans Petter Selasky { 7648d59ecb2SHans Petter Selasky return -ENODEV; 7658d59ecb2SHans Petter Selasky } 7661cdb2534SWarner Losh 7678d59ecb2SHans Petter Selasky static inline void pci_disable_sriov(struct pci_dev *dev) 7688d59ecb2SHans Petter Selasky { 7698d59ecb2SHans Petter Selasky } 7708d59ecb2SHans Petter Selasky 771fcc350c3SVladimir Kondratyev #define pci_iomap_range(pdev, mmio_bar, mmio_off, mmio_size) \ 772fcc350c3SVladimir Kondratyev linuxkpi_pci_iomap_range(pdev, mmio_bar, mmio_off, mmio_size) 77396ab16ebSVladimir Kondratyev #define pci_iomap(pdev, mmio_bar, mmio_size) \ 77496ab16ebSVladimir Kondratyev linuxkpi_pci_iomap(pdev, mmio_bar, mmio_size) 77596ab16ebSVladimir Kondratyev #define pci_iounmap(pdev, res) linuxkpi_pci_iounmap(pdev, res) 7764c274849SEmmanuel Vadot 777105a37caSEmmanuel Vadot static inline void 778105a37caSEmmanuel Vadot lkpi_pci_save_state(struct pci_dev *pdev) 779105a37caSEmmanuel Vadot { 780105a37caSEmmanuel Vadot 781105a37caSEmmanuel Vadot pci_save_state(pdev->dev.bsddev); 782105a37caSEmmanuel Vadot } 783105a37caSEmmanuel Vadot 784105a37caSEmmanuel Vadot static inline void 785105a37caSEmmanuel Vadot lkpi_pci_restore_state(struct pci_dev *pdev) 786105a37caSEmmanuel Vadot { 787105a37caSEmmanuel Vadot 788105a37caSEmmanuel Vadot pci_restore_state(pdev->dev.bsddev); 789105a37caSEmmanuel Vadot } 790105a37caSEmmanuel Vadot 791105a37caSEmmanuel Vadot #define pci_save_state(dev) lkpi_pci_save_state(dev) 792105a37caSEmmanuel Vadot #define pci_restore_state(dev) lkpi_pci_restore_state(dev) 793105a37caSEmmanuel Vadot 79486a1c5d1SJean-Sébastien Pédron static inline int 79586a1c5d1SJean-Sébastien Pédron pci_reset_function(struct pci_dev *pdev) 79686a1c5d1SJean-Sébastien Pédron { 79786a1c5d1SJean-Sébastien Pédron 79886a1c5d1SJean-Sébastien Pédron return (-ENOSYS); 79986a1c5d1SJean-Sébastien Pédron } 80086a1c5d1SJean-Sébastien Pédron 8018d59ecb2SHans Petter Selasky #define DEFINE_PCI_DEVICE_TABLE(_table) \ 8028d59ecb2SHans Petter Selasky const struct pci_device_id _table[] __devinitdata 8038d59ecb2SHans Petter Selasky 8048d59ecb2SHans Petter Selasky /* XXX This should not be necessary. */ 8058d59ecb2SHans Petter Selasky #define pcix_set_mmrbc(d, v) 0 8068d59ecb2SHans Petter Selasky #define pcix_get_max_mmrbc(d) 0 8073f322b22SMark Johnston #define pcie_set_readrq(d, v) pci_set_max_read_req((d)->dev.bsddev, (v)) 8088d59ecb2SHans Petter Selasky 8098d59ecb2SHans Petter Selasky #define PCI_DMA_BIDIRECTIONAL 0 8108d59ecb2SHans Petter Selasky #define PCI_DMA_TODEVICE 1 8118d59ecb2SHans Petter Selasky #define PCI_DMA_FROMDEVICE 2 8128d59ecb2SHans Petter Selasky #define PCI_DMA_NONE 3 8138d59ecb2SHans Petter Selasky 8148d59ecb2SHans Petter Selasky #define pci_pool dma_pool 8151724ded4SHans Petter Selasky #define pci_pool_destroy(...) dma_pool_destroy(__VA_ARGS__) 8161724ded4SHans Petter Selasky #define pci_pool_alloc(...) dma_pool_alloc(__VA_ARGS__) 8171724ded4SHans Petter Selasky #define pci_pool_free(...) dma_pool_free(__VA_ARGS__) 8188d59ecb2SHans Petter Selasky #define pci_pool_create(_name, _pdev, _size, _align, _alloc) \ 8198d59ecb2SHans Petter Selasky dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc) 8208d59ecb2SHans Petter Selasky #define pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle) \ 8218d59ecb2SHans Petter Selasky dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ 8228d59ecb2SHans Petter Selasky _size, _vaddr, _dma_handle) 8238d59ecb2SHans Petter Selasky #define pci_map_sg(_hwdev, _sg, _nents, _dir) \ 8248d59ecb2SHans Petter Selasky dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev), \ 8258d59ecb2SHans Petter Selasky _sg, _nents, (enum dma_data_direction)_dir) 8268d59ecb2SHans Petter Selasky #define pci_map_single(_hwdev, _ptr, _size, _dir) \ 8278d59ecb2SHans Petter Selasky dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev), \ 8288d59ecb2SHans Petter Selasky (_ptr), (_size), (enum dma_data_direction)_dir) 8298d59ecb2SHans Petter Selasky #define pci_unmap_single(_hwdev, _addr, _size, _dir) \ 8308d59ecb2SHans Petter Selasky dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ 8318d59ecb2SHans Petter Selasky _addr, _size, (enum dma_data_direction)_dir) 8328d59ecb2SHans Petter Selasky #define pci_unmap_sg(_hwdev, _sg, _nents, _dir) \ 8338d59ecb2SHans Petter Selasky dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ 8348d59ecb2SHans Petter Selasky _sg, _nents, (enum dma_data_direction)_dir) 8358d59ecb2SHans Petter Selasky #define pci_map_page(_hwdev, _page, _offset, _size, _dir) \ 8368d59ecb2SHans Petter Selasky dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\ 8378d59ecb2SHans Petter Selasky _offset, _size, (enum dma_data_direction)_dir) 8388d59ecb2SHans Petter Selasky #define pci_unmap_page(_hwdev, _dma_address, _size, _dir) \ 8398d59ecb2SHans Petter Selasky dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ 8408d59ecb2SHans Petter Selasky _dma_address, _size, (enum dma_data_direction)_dir) 8418d59ecb2SHans Petter Selasky #define pci_set_dma_mask(_pdev, mask) dma_set_mask(&(_pdev)->dev, (mask)) 8428d59ecb2SHans Petter Selasky #define pci_dma_mapping_error(_pdev, _dma_addr) \ 8438d59ecb2SHans Petter Selasky dma_mapping_error(&(_pdev)->dev, _dma_addr) 8448d59ecb2SHans Petter Selasky #define pci_set_consistent_dma_mask(_pdev, _mask) \ 8458d59ecb2SHans Petter Selasky dma_set_coherent_mask(&(_pdev)->dev, (_mask)) 8468d59ecb2SHans Petter Selasky #define DECLARE_PCI_UNMAP_ADDR(x) DEFINE_DMA_UNMAP_ADDR(x); 8478d59ecb2SHans Petter Selasky #define DECLARE_PCI_UNMAP_LEN(x) DEFINE_DMA_UNMAP_LEN(x); 8488d59ecb2SHans Petter Selasky #define pci_unmap_addr dma_unmap_addr 8498d59ecb2SHans Petter Selasky #define pci_unmap_addr_set dma_unmap_addr_set 8508d59ecb2SHans Petter Selasky #define pci_unmap_len dma_unmap_len 8518d59ecb2SHans Petter Selasky #define pci_unmap_len_set dma_unmap_len_set 8528d59ecb2SHans Petter Selasky 8538d59ecb2SHans Petter Selasky typedef unsigned int __bitwise pci_channel_state_t; 8548d59ecb2SHans Petter Selasky typedef unsigned int __bitwise pci_ers_result_t; 8558d59ecb2SHans Petter Selasky 8568d59ecb2SHans Petter Selasky enum pci_channel_state { 857a65ef215SHans Petter Selasky pci_channel_io_normal = 1, 858a65ef215SHans Petter Selasky pci_channel_io_frozen = 2, 859a65ef215SHans Petter Selasky pci_channel_io_perm_failure = 3, 8608d59ecb2SHans Petter Selasky }; 8618d59ecb2SHans Petter Selasky 8628d59ecb2SHans Petter Selasky enum pci_ers_result { 863a65ef215SHans Petter Selasky PCI_ERS_RESULT_NONE = 1, 864a65ef215SHans Petter Selasky PCI_ERS_RESULT_CAN_RECOVER = 2, 865a65ef215SHans Petter Selasky PCI_ERS_RESULT_NEED_RESET = 3, 866a65ef215SHans Petter Selasky PCI_ERS_RESULT_DISCONNECT = 4, 867a65ef215SHans Petter Selasky PCI_ERS_RESULT_RECOVERED = 5, 8688d59ecb2SHans Petter Selasky }; 8698d59ecb2SHans Petter Selasky 8708d59ecb2SHans Petter Selasky /* PCI bus error event callbacks */ 8718d59ecb2SHans Petter Selasky struct pci_error_handlers { 8728d59ecb2SHans Petter Selasky pci_ers_result_t (*error_detected)(struct pci_dev *dev, 8738d59ecb2SHans Petter Selasky enum pci_channel_state error); 8748d59ecb2SHans Petter Selasky pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev); 8758d59ecb2SHans Petter Selasky pci_ers_result_t (*link_reset)(struct pci_dev *dev); 8768d59ecb2SHans Petter Selasky pci_ers_result_t (*slot_reset)(struct pci_dev *dev); 8778d59ecb2SHans Petter Selasky void (*resume)(struct pci_dev *dev); 8788d59ecb2SHans Petter Selasky }; 8798d59ecb2SHans Petter Selasky 880a65ef215SHans Petter Selasky /* FreeBSD does not support SRIOV - yet */ 8818d59ecb2SHans Petter Selasky static inline struct pci_dev *pci_physfn(struct pci_dev *dev) 8828d59ecb2SHans Petter Selasky { 8838d59ecb2SHans Petter Selasky return dev; 8848d59ecb2SHans Petter Selasky } 8858d59ecb2SHans Petter Selasky 8868d59ecb2SHans Petter Selasky static inline bool pci_is_pcie(struct pci_dev *dev) 8878d59ecb2SHans Petter Selasky { 8888d59ecb2SHans Petter Selasky return !!pci_pcie_cap(dev); 8898d59ecb2SHans Petter Selasky } 8908d59ecb2SHans Petter Selasky 8918d59ecb2SHans Petter Selasky static inline u16 pcie_flags_reg(struct pci_dev *dev) 8928d59ecb2SHans Petter Selasky { 8938d59ecb2SHans Petter Selasky int pos; 8948d59ecb2SHans Petter Selasky u16 reg16; 8958d59ecb2SHans Petter Selasky 8968d59ecb2SHans Petter Selasky pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 8978d59ecb2SHans Petter Selasky if (!pos) 8988d59ecb2SHans Petter Selasky return 0; 8998d59ecb2SHans Petter Selasky 9008d59ecb2SHans Petter Selasky pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); 9018d59ecb2SHans Petter Selasky 9028d59ecb2SHans Petter Selasky return reg16; 9038d59ecb2SHans Petter Selasky } 9048d59ecb2SHans Petter Selasky 9058d59ecb2SHans Petter Selasky static inline int pci_pcie_type(struct pci_dev *dev) 9068d59ecb2SHans Petter Selasky { 9078d59ecb2SHans Petter Selasky return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4; 9088d59ecb2SHans Petter Selasky } 9098d59ecb2SHans Petter Selasky 9108d59ecb2SHans Petter Selasky static inline int pcie_cap_version(struct pci_dev *dev) 9118d59ecb2SHans Petter Selasky { 9128d59ecb2SHans Petter Selasky return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS; 9138d59ecb2SHans Petter Selasky } 9148d59ecb2SHans Petter Selasky 9158d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_lnkctl(struct pci_dev *dev) 9168d59ecb2SHans Petter Selasky { 9178d59ecb2SHans Petter Selasky int type = pci_pcie_type(dev); 9188d59ecb2SHans Petter Selasky 9198d59ecb2SHans Petter Selasky return pcie_cap_version(dev) > 1 || 9208d59ecb2SHans Petter Selasky type == PCI_EXP_TYPE_ROOT_PORT || 9218d59ecb2SHans Petter Selasky type == PCI_EXP_TYPE_ENDPOINT || 9228d59ecb2SHans Petter Selasky type == PCI_EXP_TYPE_LEG_END; 9238d59ecb2SHans Petter Selasky } 9248d59ecb2SHans Petter Selasky 9258d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_devctl(const struct pci_dev *dev) 9268d59ecb2SHans Petter Selasky { 9278d59ecb2SHans Petter Selasky return true; 9288d59ecb2SHans Petter Selasky } 9298d59ecb2SHans Petter Selasky 9308d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_sltctl(struct pci_dev *dev) 9318d59ecb2SHans Petter Selasky { 9328d59ecb2SHans Petter Selasky int type = pci_pcie_type(dev); 9338d59ecb2SHans Petter Selasky 93483630517SEd Maste return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT || 9358d59ecb2SHans Petter Selasky (type == PCI_EXP_TYPE_DOWNSTREAM && 9368d59ecb2SHans Petter Selasky pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT); 9378d59ecb2SHans Petter Selasky } 9388d59ecb2SHans Petter Selasky 9398d59ecb2SHans Petter Selasky static inline bool pcie_cap_has_rtctl(struct pci_dev *dev) 9408d59ecb2SHans Petter Selasky { 9418d59ecb2SHans Petter Selasky int type = pci_pcie_type(dev); 9428d59ecb2SHans Petter Selasky 94383630517SEd Maste return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT || 9448d59ecb2SHans Petter Selasky type == PCI_EXP_TYPE_RC_EC; 9458d59ecb2SHans Petter Selasky } 9468d59ecb2SHans Petter Selasky 9478d59ecb2SHans Petter Selasky static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos) 9488d59ecb2SHans Petter Selasky { 9498d59ecb2SHans Petter Selasky if (!pci_is_pcie(dev)) 9508d59ecb2SHans Petter Selasky return false; 9518d59ecb2SHans Petter Selasky 9528d59ecb2SHans Petter Selasky switch (pos) { 9538d59ecb2SHans Petter Selasky case PCI_EXP_FLAGS_TYPE: 9548d59ecb2SHans Petter Selasky return true; 9558d59ecb2SHans Petter Selasky case PCI_EXP_DEVCAP: 9568d59ecb2SHans Petter Selasky case PCI_EXP_DEVCTL: 9578d59ecb2SHans Petter Selasky case PCI_EXP_DEVSTA: 9588d59ecb2SHans Petter Selasky return pcie_cap_has_devctl(dev); 9598d59ecb2SHans Petter Selasky case PCI_EXP_LNKCAP: 9608d59ecb2SHans Petter Selasky case PCI_EXP_LNKCTL: 9618d59ecb2SHans Petter Selasky case PCI_EXP_LNKSTA: 9628d59ecb2SHans Petter Selasky return pcie_cap_has_lnkctl(dev); 9638d59ecb2SHans Petter Selasky case PCI_EXP_SLTCAP: 9648d59ecb2SHans Petter Selasky case PCI_EXP_SLTCTL: 9658d59ecb2SHans Petter Selasky case PCI_EXP_SLTSTA: 9668d59ecb2SHans Petter Selasky return pcie_cap_has_sltctl(dev); 9678d59ecb2SHans Petter Selasky case PCI_EXP_RTCTL: 9688d59ecb2SHans Petter Selasky case PCI_EXP_RTCAP: 9698d59ecb2SHans Petter Selasky case PCI_EXP_RTSTA: 9708d59ecb2SHans Petter Selasky return pcie_cap_has_rtctl(dev); 9718d59ecb2SHans Petter Selasky case PCI_EXP_DEVCAP2: 9728d59ecb2SHans Petter Selasky case PCI_EXP_DEVCTL2: 9738d59ecb2SHans Petter Selasky case PCI_EXP_LNKCAP2: 9748d59ecb2SHans Petter Selasky case PCI_EXP_LNKCTL2: 9758d59ecb2SHans Petter Selasky case PCI_EXP_LNKSTA2: 9768d59ecb2SHans Petter Selasky return pcie_cap_version(dev) > 1; 9778d59ecb2SHans Petter Selasky default: 9788d59ecb2SHans Petter Selasky return false; 9798d59ecb2SHans Petter Selasky } 9808d59ecb2SHans Petter Selasky } 9818d59ecb2SHans Petter Selasky 98212af734dSHans Petter Selasky static inline int 98312af734dSHans Petter Selasky pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst) 984a65ef215SHans Petter Selasky { 9850e8953b9SBjoern A. Zeeb *dst = 0; 986a65ef215SHans Petter Selasky if (pos & 3) 987a65ef215SHans Petter Selasky return -EINVAL; 988a65ef215SHans Petter Selasky 989a65ef215SHans Petter Selasky if (!pcie_capability_reg_implemented(dev, pos)) 990a65ef215SHans Petter Selasky return -EINVAL; 991a65ef215SHans Petter Selasky 992a65ef215SHans Petter Selasky return pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, dst); 993a65ef215SHans Petter Selasky } 9948d59ecb2SHans Petter Selasky 99512af734dSHans Petter Selasky static inline int 99612af734dSHans Petter Selasky pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *dst) 99712af734dSHans Petter Selasky { 9980e8953b9SBjoern A. Zeeb *dst = 0; 99912af734dSHans Petter Selasky if (pos & 3) 100012af734dSHans Petter Selasky return -EINVAL; 100112af734dSHans Petter Selasky 100212af734dSHans Petter Selasky if (!pcie_capability_reg_implemented(dev, pos)) 100312af734dSHans Petter Selasky return -EINVAL; 100412af734dSHans Petter Selasky 100512af734dSHans Petter Selasky return pci_read_config_word(dev, pci_pcie_cap(dev) + pos, dst); 100612af734dSHans Petter Selasky } 100712af734dSHans Petter Selasky 100812af734dSHans Petter Selasky static inline int 100912af734dSHans Petter Selasky pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val) 10108d59ecb2SHans Petter Selasky { 10118d59ecb2SHans Petter Selasky if (pos & 1) 10128d59ecb2SHans Petter Selasky return -EINVAL; 10138d59ecb2SHans Petter Selasky 10148d59ecb2SHans Petter Selasky if (!pcie_capability_reg_implemented(dev, pos)) 10158d59ecb2SHans Petter Selasky return 0; 10168d59ecb2SHans Petter Selasky 10178d59ecb2SHans Petter Selasky return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val); 10188d59ecb2SHans Petter Selasky } 10198d59ecb2SHans Petter Selasky 102085eb99f9SBjoern A. Zeeb static inline int 1021808ae4e2SVladimir Kondratyev pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, 1022808ae4e2SVladimir Kondratyev uint16_t clear, uint16_t set) 102385eb99f9SBjoern A. Zeeb { 102485eb99f9SBjoern A. Zeeb int error; 102585eb99f9SBjoern A. Zeeb uint16_t v; 102685eb99f9SBjoern A. Zeeb 1027808ae4e2SVladimir Kondratyev if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL) 1028808ae4e2SVladimir Kondratyev spin_lock(&dev->pcie_cap_lock); 1029808ae4e2SVladimir Kondratyev 103085eb99f9SBjoern A. Zeeb error = pcie_capability_read_word(dev, pos, &v); 1031808ae4e2SVladimir Kondratyev if (error == 0) { 1032808ae4e2SVladimir Kondratyev v &= ~clear; 1033808ae4e2SVladimir Kondratyev v |= set; 103485eb99f9SBjoern A. Zeeb error = pcie_capability_write_word(dev, pos, v); 1035808ae4e2SVladimir Kondratyev } 1036808ae4e2SVladimir Kondratyev 1037808ae4e2SVladimir Kondratyev if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL) 1038808ae4e2SVladimir Kondratyev spin_unlock(&dev->pcie_cap_lock); 1039808ae4e2SVladimir Kondratyev 104085eb99f9SBjoern A. Zeeb return (error); 104185eb99f9SBjoern A. Zeeb } 104285eb99f9SBjoern A. Zeeb 1043c41d8354SBjoern A. Zeeb static inline int 1044808ae4e2SVladimir Kondratyev pcie_capability_set_word(struct pci_dev *dev, int pos, uint16_t val) 1045808ae4e2SVladimir Kondratyev { 1046808ae4e2SVladimir Kondratyev return (pcie_capability_clear_and_set_word(dev, pos, 0, val)); 1047808ae4e2SVladimir Kondratyev } 1048808ae4e2SVladimir Kondratyev 1049808ae4e2SVladimir Kondratyev static inline int 1050c41d8354SBjoern A. Zeeb pcie_capability_clear_word(struct pci_dev *dev, int pos, uint16_t val) 1051c41d8354SBjoern A. Zeeb { 1052808ae4e2SVladimir Kondratyev return (pcie_capability_clear_and_set_word(dev, pos, val, 0)); 1053c41d8354SBjoern A. Zeeb } 1054c41d8354SBjoern A. Zeeb 1055a65ef215SHans Petter Selasky static inline int pcie_get_minimum_link(struct pci_dev *dev, 1056a65ef215SHans Petter Selasky enum pci_bus_speed *speed, enum pcie_link_width *width) 1057a65ef215SHans Petter Selasky { 1058a65ef215SHans Petter Selasky *speed = PCI_SPEED_UNKNOWN; 1059a65ef215SHans Petter Selasky *width = PCIE_LNK_WIDTH_UNKNOWN; 1060a65ef215SHans Petter Selasky return (0); 1061a65ef215SHans Petter Selasky } 1062a65ef215SHans Petter Selasky 1063a65ef215SHans Petter Selasky static inline int 1064a65ef215SHans Petter Selasky pci_num_vf(struct pci_dev *dev) 1065a65ef215SHans Petter Selasky { 1066a65ef215SHans Petter Selasky return (0); 1067a65ef215SHans Petter Selasky } 1068a65ef215SHans Petter Selasky 1069ab62989aSHans Petter Selasky static inline enum pci_bus_speed 1070ab62989aSHans Petter Selasky pcie_get_speed_cap(struct pci_dev *dev) 1071ab62989aSHans Petter Selasky { 1072ab62989aSHans Petter Selasky device_t root; 1073ab62989aSHans Petter Selasky uint32_t lnkcap, lnkcap2; 1074ab62989aSHans Petter Selasky int error, pos; 1075ab62989aSHans Petter Selasky 1076ab62989aSHans Petter Selasky root = device_get_parent(dev->dev.bsddev); 1077ab62989aSHans Petter Selasky if (root == NULL) 1078ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1079ab62989aSHans Petter Selasky root = device_get_parent(root); 1080ab62989aSHans Petter Selasky if (root == NULL) 1081ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1082ab62989aSHans Petter Selasky root = device_get_parent(root); 1083ab62989aSHans Petter Selasky if (root == NULL) 1084ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1085ab62989aSHans Petter Selasky 1086ab62989aSHans Petter Selasky if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA || 1087ab62989aSHans Petter Selasky pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS) 1088ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1089ab62989aSHans Petter Selasky 1090ab62989aSHans Petter Selasky if ((error = pci_find_cap(root, PCIY_EXPRESS, &pos)) != 0) 1091ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1092ab62989aSHans Petter Selasky 1093ab62989aSHans Petter Selasky lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4); 1094ab62989aSHans Petter Selasky 1095ab62989aSHans Petter Selasky if (lnkcap2) { /* PCIe r3.0-compliant */ 1096ab62989aSHans Petter Selasky if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB) 1097ab62989aSHans Petter Selasky return (PCIE_SPEED_2_5GT); 1098ab62989aSHans Petter Selasky if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB) 1099ab62989aSHans Petter Selasky return (PCIE_SPEED_5_0GT); 1100ab62989aSHans Petter Selasky if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) 1101ab62989aSHans Petter Selasky return (PCIE_SPEED_8_0GT); 1102ab62989aSHans Petter Selasky if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB) 1103ab62989aSHans Petter Selasky return (PCIE_SPEED_16_0GT); 11040adc02a9SJean-Sébastien Pédron if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_32_0GB) 11050adc02a9SJean-Sébastien Pédron return (PCIE_SPEED_32_0GT); 11060adc02a9SJean-Sébastien Pédron if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_64_0GB) 11070adc02a9SJean-Sébastien Pédron return (PCIE_SPEED_64_0GT); 1108ab62989aSHans Petter Selasky } else { /* pre-r3.0 */ 1109ab62989aSHans Petter Selasky lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4); 1110ab62989aSHans Petter Selasky if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB) 1111ab62989aSHans Petter Selasky return (PCIE_SPEED_2_5GT); 1112ab62989aSHans Petter Selasky if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB) 1113ab62989aSHans Petter Selasky return (PCIE_SPEED_5_0GT); 1114ab62989aSHans Petter Selasky if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB) 1115ab62989aSHans Petter Selasky return (PCIE_SPEED_8_0GT); 1116ab62989aSHans Petter Selasky if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB) 1117ab62989aSHans Petter Selasky return (PCIE_SPEED_16_0GT); 11180adc02a9SJean-Sébastien Pédron if (lnkcap & PCI_EXP_LNKCAP_SLS_32_0GB) 11190adc02a9SJean-Sébastien Pédron return (PCIE_SPEED_32_0GT); 11200adc02a9SJean-Sébastien Pédron if (lnkcap & PCI_EXP_LNKCAP_SLS_64_0GB) 11210adc02a9SJean-Sébastien Pédron return (PCIE_SPEED_64_0GT); 1122ab62989aSHans Petter Selasky } 1123ab62989aSHans Petter Selasky return (PCI_SPEED_UNKNOWN); 1124ab62989aSHans Petter Selasky } 1125ab62989aSHans Petter Selasky 1126ab62989aSHans Petter Selasky static inline enum pcie_link_width 1127ab62989aSHans Petter Selasky pcie_get_width_cap(struct pci_dev *dev) 1128ab62989aSHans Petter Selasky { 1129ab62989aSHans Petter Selasky uint32_t lnkcap; 1130ab62989aSHans Petter Selasky 1131ab62989aSHans Petter Selasky pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap); 1132ab62989aSHans Petter Selasky if (lnkcap) 1133ab62989aSHans Petter Selasky return ((lnkcap & PCI_EXP_LNKCAP_MLW) >> 4); 1134ab62989aSHans Petter Selasky 1135ab62989aSHans Petter Selasky return (PCIE_LNK_WIDTH_UNKNOWN); 1136ab62989aSHans Petter Selasky } 1137ab62989aSHans Petter Selasky 1138b4edb17cSHans Petter Selasky static inline int 1139b4edb17cSHans Petter Selasky pcie_get_mps(struct pci_dev *dev) 1140b4edb17cSHans Petter Selasky { 1141b4edb17cSHans Petter Selasky return (pci_get_max_payload(dev->dev.bsddev)); 1142b4edb17cSHans Petter Selasky } 1143b4edb17cSHans Petter Selasky 1144b4edb17cSHans Petter Selasky static inline uint32_t 1145b4edb17cSHans Petter Selasky PCIE_SPEED2MBS_ENC(enum pci_bus_speed spd) 1146b4edb17cSHans Petter Selasky { 1147b4edb17cSHans Petter Selasky 1148b4edb17cSHans Petter Selasky switch(spd) { 11490adc02a9SJean-Sébastien Pédron case PCIE_SPEED_64_0GT: 11500adc02a9SJean-Sébastien Pédron return (64000 * 128 / 130); 11510adc02a9SJean-Sébastien Pédron case PCIE_SPEED_32_0GT: 11520adc02a9SJean-Sébastien Pédron return (32000 * 128 / 130); 1153b4edb17cSHans Petter Selasky case PCIE_SPEED_16_0GT: 1154b4edb17cSHans Petter Selasky return (16000 * 128 / 130); 1155b4edb17cSHans Petter Selasky case PCIE_SPEED_8_0GT: 1156b4edb17cSHans Petter Selasky return (8000 * 128 / 130); 1157b4edb17cSHans Petter Selasky case PCIE_SPEED_5_0GT: 1158b4edb17cSHans Petter Selasky return (5000 * 8 / 10); 1159b4edb17cSHans Petter Selasky case PCIE_SPEED_2_5GT: 1160b4edb17cSHans Petter Selasky return (2500 * 8 / 10); 1161b4edb17cSHans Petter Selasky default: 1162b4edb17cSHans Petter Selasky return (0); 1163b4edb17cSHans Petter Selasky } 1164b4edb17cSHans Petter Selasky } 1165b4edb17cSHans Petter Selasky 1166b4edb17cSHans Petter Selasky static inline uint32_t 1167b4edb17cSHans Petter Selasky pcie_bandwidth_available(struct pci_dev *pdev, 1168b4edb17cSHans Petter Selasky struct pci_dev **limiting, 1169b4edb17cSHans Petter Selasky enum pci_bus_speed *speed, 1170b4edb17cSHans Petter Selasky enum pcie_link_width *width) 1171b4edb17cSHans Petter Selasky { 1172b4edb17cSHans Petter Selasky enum pci_bus_speed nspeed = pcie_get_speed_cap(pdev); 1173b4edb17cSHans Petter Selasky enum pcie_link_width nwidth = pcie_get_width_cap(pdev); 1174b4edb17cSHans Petter Selasky 1175b4edb17cSHans Petter Selasky if (speed) 1176b4edb17cSHans Petter Selasky *speed = nspeed; 1177b4edb17cSHans Petter Selasky if (width) 1178b4edb17cSHans Petter Selasky *width = nwidth; 1179b4edb17cSHans Petter Selasky 1180b4edb17cSHans Petter Selasky return (nwidth * PCIE_SPEED2MBS_ENC(nspeed)); 1181b4edb17cSHans Petter Selasky } 1182b4edb17cSHans Petter Selasky 1183af19988fSJean-Sébastien Pédron static inline bool 1184af19988fSJean-Sébastien Pédron pcie_aspm_enabled(struct pci_dev *pdev) 1185af19988fSJean-Sébastien Pédron { 1186af19988fSJean-Sébastien Pédron return (false); 1187af19988fSJean-Sébastien Pédron } 1188af19988fSJean-Sébastien Pédron 11898e106c52SBjoern A. Zeeb static inline struct pci_dev * 11908e106c52SBjoern A. Zeeb pcie_find_root_port(struct pci_dev *pdev) 11918e106c52SBjoern A. Zeeb { 11928e106c52SBjoern A. Zeeb device_t root; 11938e106c52SBjoern A. Zeeb 11948e106c52SBjoern A. Zeeb if (pdev->root != NULL) 11958e106c52SBjoern A. Zeeb return (pdev->root); 11968e106c52SBjoern A. Zeeb 11978e106c52SBjoern A. Zeeb root = pci_find_pcie_root_port(pdev->dev.bsddev); 11988e106c52SBjoern A. Zeeb if (root == NULL) 11998e106c52SBjoern A. Zeeb return (NULL); 12008e106c52SBjoern A. Zeeb 12018e106c52SBjoern A. Zeeb pdev->root = lkpinew_pci_dev(root); 12028e106c52SBjoern A. Zeeb return (pdev->root); 12038e106c52SBjoern A. Zeeb } 12048e106c52SBjoern A. Zeeb 12058e106c52SBjoern A. Zeeb /* This is needed when people rip out the device "HotPlug". */ 12068e106c52SBjoern A. Zeeb static inline void 12078e106c52SBjoern A. Zeeb pci_lock_rescan_remove(void) 12088e106c52SBjoern A. Zeeb { 12098e106c52SBjoern A. Zeeb } 12108e106c52SBjoern A. Zeeb 12118e106c52SBjoern A. Zeeb static inline void 12128e106c52SBjoern A. Zeeb pci_unlock_rescan_remove(void) 12138e106c52SBjoern A. Zeeb { 12148e106c52SBjoern A. Zeeb } 12158e106c52SBjoern A. Zeeb 12168e106c52SBjoern A. Zeeb static __inline void 12178e106c52SBjoern A. Zeeb pci_stop_and_remove_bus_device(struct pci_dev *pdev) 12188e106c52SBjoern A. Zeeb { 12198e106c52SBjoern A. Zeeb } 12208e106c52SBjoern A. Zeeb 1221525dd4acSBjoern A. Zeeb static inline int 1222525dd4acSBjoern A. Zeeb pci_rescan_bus(struct pci_bus *pbus) 1223525dd4acSBjoern A. Zeeb { 1224525dd4acSBjoern A. Zeeb device_t *devlist, parent; 1225525dd4acSBjoern A. Zeeb int devcount, error; 1226525dd4acSBjoern A. Zeeb 1227525dd4acSBjoern A. Zeeb if (!device_is_attached(pbus->self->dev.bsddev)) 1228525dd4acSBjoern A. Zeeb return (0); 1229525dd4acSBjoern A. Zeeb /* pci_rescan_method() will work on the pcib (parent). */ 1230525dd4acSBjoern A. Zeeb error = BUS_RESCAN(pbus->self->dev.bsddev); 1231525dd4acSBjoern A. Zeeb if (error != 0) 1232525dd4acSBjoern A. Zeeb return (0); 1233525dd4acSBjoern A. Zeeb 1234525dd4acSBjoern A. Zeeb parent = device_get_parent(pbus->self->dev.bsddev); 1235525dd4acSBjoern A. Zeeb error = device_get_children(parent, &devlist, &devcount); 1236525dd4acSBjoern A. Zeeb if (error != 0) 1237525dd4acSBjoern A. Zeeb return (0); 1238525dd4acSBjoern A. Zeeb if (devcount != 0) 1239525dd4acSBjoern A. Zeeb free(devlist, M_TEMP); 1240525dd4acSBjoern A. Zeeb 1241525dd4acSBjoern A. Zeeb return (devcount); 1242525dd4acSBjoern A. Zeeb } 1243525dd4acSBjoern A. Zeeb 1244253dbe74SHans Petter Selasky /* 1245253dbe74SHans Petter Selasky * The following functions can be used to attach/detach the LinuxKPI's 1246253dbe74SHans Petter Selasky * PCI device runtime. The pci_driver and pci_device_id pointer is 1247253dbe74SHans Petter Selasky * allowed to be NULL. Other pointers must be all valid. 1248253dbe74SHans Petter Selasky * The pci_dev structure should be zero-initialized before passed 1249253dbe74SHans Petter Selasky * to the linux_pci_attach_device function. 1250253dbe74SHans Petter Selasky */ 1251253dbe74SHans Petter Selasky extern int linux_pci_attach_device(device_t, struct pci_driver *, 1252253dbe74SHans Petter Selasky const struct pci_device_id *, struct pci_dev *); 1253253dbe74SHans Petter Selasky extern int linux_pci_detach_device(struct pci_dev *); 1254253dbe74SHans Petter Selasky 12555e30a739SEmmanuel Vadot static inline int 12565e30a739SEmmanuel Vadot pci_dev_present(const struct pci_device_id *cur) 12575e30a739SEmmanuel Vadot { 12585e30a739SEmmanuel Vadot while (cur != NULL && (cur->vendor || cur->device)) { 12595e30a739SEmmanuel Vadot if (pci_find_device(cur->vendor, cur->device) != NULL) { 12605e30a739SEmmanuel Vadot return (1); 12615e30a739SEmmanuel Vadot } 12625e30a739SEmmanuel Vadot cur++; 12635e30a739SEmmanuel Vadot } 12645e30a739SEmmanuel Vadot return (0); 12655e30a739SEmmanuel Vadot } 12665e30a739SEmmanuel Vadot 12675b1171a0SVladimir Kondratyev static inline const struct pci_device_id * 12685b1171a0SVladimir Kondratyev pci_match_id(const struct pci_device_id *ids, struct pci_dev *pdev) 12695b1171a0SVladimir Kondratyev { 12705b1171a0SVladimir Kondratyev if (ids == NULL) 12715b1171a0SVladimir Kondratyev return (NULL); 12725b1171a0SVladimir Kondratyev 12735b1171a0SVladimir Kondratyev for (; 12745b1171a0SVladimir Kondratyev ids->vendor != 0 || ids->subvendor != 0 || ids->class_mask != 0; 12755b1171a0SVladimir Kondratyev ids++) 12765b1171a0SVladimir Kondratyev if ((ids->vendor == PCI_ANY_ID || 12775b1171a0SVladimir Kondratyev ids->vendor == pdev->vendor) && 12785b1171a0SVladimir Kondratyev (ids->device == PCI_ANY_ID || 12795b1171a0SVladimir Kondratyev ids->device == pdev->device) && 12805b1171a0SVladimir Kondratyev (ids->subvendor == PCI_ANY_ID || 12815b1171a0SVladimir Kondratyev ids->subvendor == pdev->subsystem_vendor) && 12825b1171a0SVladimir Kondratyev (ids->subdevice == PCI_ANY_ID || 12835b1171a0SVladimir Kondratyev ids->subdevice == pdev->subsystem_device) && 12845b1171a0SVladimir Kondratyev ((ids->class ^ pdev->class) & ids->class_mask) == 0) 12855b1171a0SVladimir Kondratyev return (ids); 12865b1171a0SVladimir Kondratyev 12875b1171a0SVladimir Kondratyev return (NULL); 12885b1171a0SVladimir Kondratyev } 12895b1171a0SVladimir Kondratyev 1290105a37caSEmmanuel Vadot struct pci_dev *lkpi_pci_get_domain_bus_and_slot(int domain, 1291105a37caSEmmanuel Vadot unsigned int bus, unsigned int devfn); 1292105a37caSEmmanuel Vadot #define pci_get_domain_bus_and_slot(domain, bus, devfn) \ 1293105a37caSEmmanuel Vadot lkpi_pci_get_domain_bus_and_slot(domain, bus, devfn) 1294105a37caSEmmanuel Vadot 1295105a37caSEmmanuel Vadot static inline int 1296105a37caSEmmanuel Vadot pci_domain_nr(struct pci_bus *pbus) 1297105a37caSEmmanuel Vadot { 1298105a37caSEmmanuel Vadot 12991fac2cb4SBjoern A. Zeeb return (pbus->domain); 1300105a37caSEmmanuel Vadot } 1301105a37caSEmmanuel Vadot 1302105a37caSEmmanuel Vadot static inline int 1303105a37caSEmmanuel Vadot pci_bus_read_config(struct pci_bus *bus, unsigned int devfn, 1304105a37caSEmmanuel Vadot int pos, uint32_t *val, int len) 1305105a37caSEmmanuel Vadot { 1306105a37caSEmmanuel Vadot 1307105a37caSEmmanuel Vadot *val = pci_read_config(bus->self->dev.bsddev, pos, len); 1308105a37caSEmmanuel Vadot return (0); 1309105a37caSEmmanuel Vadot } 1310105a37caSEmmanuel Vadot 1311105a37caSEmmanuel Vadot static inline int 1312105a37caSEmmanuel Vadot pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, int pos, u16 *val) 1313105a37caSEmmanuel Vadot { 1314105a37caSEmmanuel Vadot uint32_t tmp; 1315105a37caSEmmanuel Vadot int ret; 1316105a37caSEmmanuel Vadot 1317105a37caSEmmanuel Vadot ret = pci_bus_read_config(bus, devfn, pos, &tmp, 2); 1318105a37caSEmmanuel Vadot *val = (u16)tmp; 1319105a37caSEmmanuel Vadot return (ret); 1320105a37caSEmmanuel Vadot } 1321105a37caSEmmanuel Vadot 1322105a37caSEmmanuel Vadot static inline int 1323105a37caSEmmanuel Vadot pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, int pos, u8 *val) 1324105a37caSEmmanuel Vadot { 1325105a37caSEmmanuel Vadot uint32_t tmp; 1326105a37caSEmmanuel Vadot int ret; 1327105a37caSEmmanuel Vadot 1328105a37caSEmmanuel Vadot ret = pci_bus_read_config(bus, devfn, pos, &tmp, 1); 1329105a37caSEmmanuel Vadot *val = (u8)tmp; 1330105a37caSEmmanuel Vadot return (ret); 1331105a37caSEmmanuel Vadot } 1332105a37caSEmmanuel Vadot 1333105a37caSEmmanuel Vadot static inline int 1334105a37caSEmmanuel Vadot pci_bus_write_config(struct pci_bus *bus, unsigned int devfn, int pos, 1335105a37caSEmmanuel Vadot uint32_t val, int size) 1336105a37caSEmmanuel Vadot { 1337105a37caSEmmanuel Vadot 1338105a37caSEmmanuel Vadot pci_write_config(bus->self->dev.bsddev, pos, val, size); 1339105a37caSEmmanuel Vadot return (0); 1340105a37caSEmmanuel Vadot } 1341105a37caSEmmanuel Vadot 1342105a37caSEmmanuel Vadot static inline int 1343105a37caSEmmanuel Vadot pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int pos, 1344105a37caSEmmanuel Vadot uint8_t val) 1345105a37caSEmmanuel Vadot { 1346105a37caSEmmanuel Vadot return (pci_bus_write_config(bus, devfn, pos, val, 1)); 1347105a37caSEmmanuel Vadot } 1348105a37caSEmmanuel Vadot 1349105a37caSEmmanuel Vadot static inline int 1350105a37caSEmmanuel Vadot pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int pos, 1351105a37caSEmmanuel Vadot uint16_t val) 1352105a37caSEmmanuel Vadot { 1353105a37caSEmmanuel Vadot return (pci_bus_write_config(bus, devfn, pos, val, 2)); 1354105a37caSEmmanuel Vadot } 1355105a37caSEmmanuel Vadot 1356105a37caSEmmanuel Vadot struct pci_dev *lkpi_pci_get_class(unsigned int class, struct pci_dev *from); 1357105a37caSEmmanuel Vadot #define pci_get_class(class, from) lkpi_pci_get_class(class, from) 1358105a37caSEmmanuel Vadot 1359d4a4960cSBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 1360d4a4960cSBjoern A. Zeeb 136196ab16ebSVladimir Kondratyev #define pcim_enable_device(pdev) linuxkpi_pcim_enable_device(pdev) 136296ab16ebSVladimir Kondratyev #define pcim_iomap_table(pdev) linuxkpi_pcim_iomap_table(pdev) 136396ab16ebSVladimir Kondratyev #define pcim_iomap_regions(pdev, mask, name) \ 136496ab16ebSVladimir Kondratyev linuxkpi_pcim_iomap_regions(pdev, mask, name) 1365d4a4960cSBjoern A. Zeeb 136630048f61SBjoern A. Zeeb static inline int 136730048f61SBjoern A. Zeeb pcim_iomap_regions_request_all(struct pci_dev *pdev, uint32_t mask, char *name) 136830048f61SBjoern A. Zeeb { 136930048f61SBjoern A. Zeeb uint32_t requests, req_mask; 137030048f61SBjoern A. Zeeb int bar, error; 137130048f61SBjoern A. Zeeb 137230048f61SBjoern A. Zeeb /* Request all the BARs ("regions") we do not iomap. */ 137330048f61SBjoern A. Zeeb req_mask = ((1 << (PCIR_MAX_BAR_0 + 1)) - 1) & ~mask; 137430048f61SBjoern A. Zeeb for (bar = requests = 0; requests != req_mask; bar++) { 137530048f61SBjoern A. Zeeb if ((req_mask & (1 << bar)) == 0) 137630048f61SBjoern A. Zeeb continue; 137730048f61SBjoern A. Zeeb error = pci_request_region(pdev, bar, name); 137830048f61SBjoern A. Zeeb if (error != 0 && error != -ENODEV) 137930048f61SBjoern A. Zeeb goto err; 138030048f61SBjoern A. Zeeb requests |= (1 << bar); 138130048f61SBjoern A. Zeeb } 138230048f61SBjoern A. Zeeb 138330048f61SBjoern A. Zeeb error = pcim_iomap_regions(pdev, mask, name); 138430048f61SBjoern A. Zeeb if (error != 0) 138530048f61SBjoern A. Zeeb goto err; 138630048f61SBjoern A. Zeeb 138730048f61SBjoern A. Zeeb return (0); 138830048f61SBjoern A. Zeeb 138930048f61SBjoern A. Zeeb err: 139030048f61SBjoern A. Zeeb for (bar = PCIR_MAX_BAR_0; bar >= 0; bar--) { 139130048f61SBjoern A. Zeeb if ((requests & (1 << bar)) != 0) 139230048f61SBjoern A. Zeeb pci_release_region(pdev, bar); 139330048f61SBjoern A. Zeeb } 139430048f61SBjoern A. Zeeb 139530048f61SBjoern A. Zeeb return (-EINVAL); 139630048f61SBjoern A. Zeeb } 139730048f61SBjoern A. Zeeb 13988f61992dSBjoern A. Zeeb /* 13998f61992dSBjoern A. Zeeb * We cannot simply re-define pci_get_device() as we would normally do 14008f61992dSBjoern A. Zeeb * and then hide it in linux_pci.c as too many semi-native drivers still 1401b15491b4SBjoern A. Zeeb * include linux/pci.h and run into the conflict with native PCI. Linux drivers 14028f61992dSBjoern A. Zeeb * using pci_get_device() need to be changed to call linuxkpi_pci_get_device(). 14038f61992dSBjoern A. Zeeb */ 14048f61992dSBjoern A. Zeeb static inline struct pci_dev * 14058f61992dSBjoern A. Zeeb linuxkpi_pci_get_device(uint16_t vendor, uint16_t device, struct pci_dev *odev) 14068f61992dSBjoern A. Zeeb { 14078f61992dSBjoern A. Zeeb 14088f61992dSBjoern A. Zeeb return (lkpi_pci_get_device(vendor, device, odev)); 14098f61992dSBjoern A. Zeeb } 14108f61992dSBjoern A. Zeeb 1411d4a4960cSBjoern A. Zeeb /* This is a FreeBSD extension so we can use bus_*(). */ 1412d4a4960cSBjoern A. Zeeb static inline void 1413d4a4960cSBjoern A. Zeeb linuxkpi_pcim_want_to_use_bus_functions(struct pci_dev *pdev) 1414d4a4960cSBjoern A. Zeeb { 1415d4a4960cSBjoern A. Zeeb pdev->want_iomap_res = true; 1416d4a4960cSBjoern A. Zeeb } 1417d4a4960cSBjoern A. Zeeb 14186890e327SEmmanuel Vadot static inline bool 14196890e327SEmmanuel Vadot pci_is_thunderbolt_attached(struct pci_dev *pdev) 14206890e327SEmmanuel Vadot { 14216890e327SEmmanuel Vadot 14226890e327SEmmanuel Vadot return (false); 14236890e327SEmmanuel Vadot } 14246890e327SEmmanuel Vadot 14256890e327SEmmanuel Vadot static inline void * 14266890e327SEmmanuel Vadot pci_platform_rom(struct pci_dev *pdev, size_t *size) 14276890e327SEmmanuel Vadot { 14286890e327SEmmanuel Vadot 14296890e327SEmmanuel Vadot return (NULL); 14306890e327SEmmanuel Vadot } 14316890e327SEmmanuel Vadot 14326890e327SEmmanuel Vadot static inline void 14336890e327SEmmanuel Vadot pci_ignore_hotplug(struct pci_dev *pdev) 14346890e327SEmmanuel Vadot { 14356890e327SEmmanuel Vadot } 14366890e327SEmmanuel Vadot 14374cb3cb2dSJake Freeland static inline const char * 14384cb3cb2dSJake Freeland pci_power_name(pci_power_t state) 14394cb3cb2dSJake Freeland { 14404cb3cb2dSJake Freeland int pstate = state + 1; 14414cb3cb2dSJake Freeland 14424cb3cb2dSJake Freeland if (pstate >= 0 && pstate < nitems(pci_power_names)) 14434cb3cb2dSJake Freeland return (pci_power_names[pstate]); 14444cb3cb2dSJake Freeland else 14454cb3cb2dSJake Freeland return (pci_power_names[0]); 14464cb3cb2dSJake Freeland } 14474cb3cb2dSJake Freeland 14486890e327SEmmanuel Vadot static inline int 14496890e327SEmmanuel Vadot pcie_get_readrq(struct pci_dev *dev) 14506890e327SEmmanuel Vadot { 14516890e327SEmmanuel Vadot u16 ctl; 14526890e327SEmmanuel Vadot 14536890e327SEmmanuel Vadot if (pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl)) 14546890e327SEmmanuel Vadot return (-EINVAL); 14556890e327SEmmanuel Vadot 14566890e327SEmmanuel Vadot return (128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12)); 14576890e327SEmmanuel Vadot } 14586890e327SEmmanuel Vadot 14595f2f582cSBjoern A. Zeeb static inline bool 14605f2f582cSBjoern A. Zeeb pci_is_enabled(struct pci_dev *pdev) 14615f2f582cSBjoern A. Zeeb { 14625f2f582cSBjoern A. Zeeb 14635f2f582cSBjoern A. Zeeb return ((pci_read_config(pdev->dev.bsddev, PCIR_COMMAND, 2) & 14645f2f582cSBjoern A. Zeeb PCIM_CMD_BUSMASTEREN) != 0); 14655f2f582cSBjoern A. Zeeb } 14665f2f582cSBjoern A. Zeeb 146749b6d5edSJean-Sébastien Pédron static inline int 146849b6d5edSJean-Sébastien Pédron pci_wait_for_pending_transaction(struct pci_dev *pdev) 146949b6d5edSJean-Sébastien Pédron { 147049b6d5edSJean-Sébastien Pédron 147149b6d5edSJean-Sébastien Pédron return (0); 147249b6d5edSJean-Sébastien Pédron } 147349b6d5edSJean-Sébastien Pédron 1474fd1a2f3dSBjoern A. Zeeb static inline int 1475fd1a2f3dSBjoern A. Zeeb pci_assign_resource(struct pci_dev *pdev, int bar) 1476fd1a2f3dSBjoern A. Zeeb { 1477fd1a2f3dSBjoern A. Zeeb 1478fd1a2f3dSBjoern A. Zeeb return (0); 1479fd1a2f3dSBjoern A. Zeeb } 1480fd1a2f3dSBjoern A. Zeeb 1481fd1a2f3dSBjoern A. Zeeb static inline int 1482fd1a2f3dSBjoern A. Zeeb pci_irq_vector(struct pci_dev *pdev, unsigned int vector) 1483fd1a2f3dSBjoern A. Zeeb { 1484fd1a2f3dSBjoern A. Zeeb 1485fd1a2f3dSBjoern A. Zeeb if (!pdev->msix_enabled && !pdev->msi_enabled) { 1486fd1a2f3dSBjoern A. Zeeb if (vector != 0) 1487fd1a2f3dSBjoern A. Zeeb return (-EINVAL); 1488fd1a2f3dSBjoern A. Zeeb return (pdev->irq); 1489fd1a2f3dSBjoern A. Zeeb } 1490fd1a2f3dSBjoern A. Zeeb 1491fd1a2f3dSBjoern A. Zeeb if (pdev->msix_enabled || pdev->msi_enabled) { 1492fd1a2f3dSBjoern A. Zeeb if ((pdev->dev.irq_start + vector) >= pdev->dev.irq_end) 1493fd1a2f3dSBjoern A. Zeeb return (-EINVAL); 1494fd1a2f3dSBjoern A. Zeeb return (pdev->dev.irq_start + vector); 1495fd1a2f3dSBjoern A. Zeeb } 1496fd1a2f3dSBjoern A. Zeeb 1497fd1a2f3dSBjoern A. Zeeb return (-ENXIO); 1498fd1a2f3dSBjoern A. Zeeb } 1499fd1a2f3dSBjoern A. Zeeb 1500307f78f3SVladimir Kondratyev #endif /* _LINUXKPI_LINUX_PCI_H_ */ 1501