Index: head/sys/dev/pci/pcireg.h =================================================================== --- head/sys/dev/pci/pcireg.h (revision 355740) +++ head/sys/dev/pci/pcireg.h (revision 355741) @@ -1,1067 +1,1074 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 1997, Stefan Esser * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ /* * PCIM_xxx: mask to locate subfield in register * PCIR_xxx: config register offset * PCIC_xxx: device class * PCIS_xxx: device subclass * PCIP_xxx: device programming interface * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) * PCID_xxx: device ID * PCIY_xxx: capability identification number * PCIZ_xxx: extended capability identification number */ /* some PCI bus constants */ #define PCI_DOMAINMAX 65535 /* highest supported domain number */ #define PCI_BUSMAX 255 /* highest supported bus number */ #define PCI_SLOTMAX 31 /* highest supported slot number */ #define PCI_FUNCMAX 7 /* highest supported function number */ #define PCI_REGMAX 255 /* highest supported config register addr. */ #define PCIE_REGMAX 4095 /* highest supported config register addr. */ #define PCI_MAXHDRTYPE 2 #define PCIE_ARI_SLOTMAX 0 #define PCIE_ARI_FUNCMAX 255 #define PCI_RID_DOMAIN_SHIFT 16 #define PCI_RID_BUS_SHIFT 8 #define PCI_RID_SLOT_SHIFT 3 #define PCI_RID_FUNC_SHIFT 0 #define PCI_RID(bus, slot, func) \ ((((bus) & PCI_BUSMAX) << PCI_RID_BUS_SHIFT) | \ (((slot) & PCI_SLOTMAX) << PCI_RID_SLOT_SHIFT) | \ (((func) & PCI_FUNCMAX) << PCI_RID_FUNC_SHIFT)) #define PCI_ARI_RID(bus, func) \ ((((bus) & PCI_BUSMAX) << PCI_RID_BUS_SHIFT) | \ (((func) & PCIE_ARI_FUNCMAX) << PCI_RID_FUNC_SHIFT)) #define PCI_RID2BUS(rid) (((rid) >> PCI_RID_BUS_SHIFT) & PCI_BUSMAX) #define PCI_RID2SLOT(rid) (((rid) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX) #define PCI_RID2FUNC(rid) (((rid) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX) #define PCIE_ARI_RID2SLOT(rid) (0) #define PCIE_ARI_RID2FUNC(rid) \ (((rid) >> PCI_RID_FUNC_SHIFT) & PCIE_ARI_FUNCMAX) #define PCIE_ARI_SLOT(func) (((func) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX) #define PCIE_ARI_FUNC(func) (((func) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX) /* PCI config header registers for all devices */ #define PCIR_DEVVENDOR 0x00 #define PCIR_VENDOR 0x00 #define PCIR_DEVICE 0x02 #define PCIR_COMMAND 0x04 #define PCIM_CMD_PORTEN 0x0001 #define PCIM_CMD_MEMEN 0x0002 #define PCIM_CMD_BUSMASTEREN 0x0004 #define PCIM_CMD_SPECIALEN 0x0008 #define PCIM_CMD_MWRICEN 0x0010 #define PCIM_CMD_PERRESPEN 0x0040 #define PCIM_CMD_SERRESPEN 0x0100 #define PCIM_CMD_BACKTOBACK 0x0200 #define PCIM_CMD_INTxDIS 0x0400 #define PCIR_STATUS 0x06 #define PCIM_STATUS_INTxSTATE 0x0008 #define PCIM_STATUS_CAPPRESENT 0x0010 #define PCIM_STATUS_66CAPABLE 0x0020 #define PCIM_STATUS_BACKTOBACK 0x0080 #define PCIM_STATUS_MDPERR 0x0100 #define PCIM_STATUS_SEL_FAST 0x0000 #define PCIM_STATUS_SEL_MEDIMUM 0x0200 #define PCIM_STATUS_SEL_SLOW 0x0400 #define PCIM_STATUS_SEL_MASK 0x0600 #define PCIM_STATUS_STABORT 0x0800 #define PCIM_STATUS_RTABORT 0x1000 #define PCIM_STATUS_RMABORT 0x2000 #define PCIM_STATUS_SERR 0x4000 #define PCIM_STATUS_PERR 0x8000 #define PCIR_REVID 0x08 #define PCIR_PROGIF 0x09 #define PCIR_SUBCLASS 0x0a #define PCIR_CLASS 0x0b #define PCIR_CACHELNSZ 0x0c #define PCIR_LATTIMER 0x0d #define PCIR_HDRTYPE 0x0e #define PCIM_HDRTYPE 0x7f #define PCIM_HDRTYPE_NORMAL 0x00 #define PCIM_HDRTYPE_BRIDGE 0x01 #define PCIM_HDRTYPE_CARDBUS 0x02 #define PCIM_MFDEV 0x80 #define PCIR_BIST 0x0f /* PCI Spec rev 2.2: 0FFFFh is an invalid value for Vendor ID. */ #define PCIV_INVALID 0xffff /* Capability Register Offsets */ #define PCICAP_ID 0x0 #define PCICAP_NEXTPTR 0x1 /* Capability Identification Numbers */ #define PCIY_PMG 0x01 /* PCI Power Management */ #define PCIY_AGP 0x02 /* AGP */ #define PCIY_VPD 0x03 /* Vital Product Data */ #define PCIY_SLOTID 0x04 /* Slot Identification */ #define PCIY_MSI 0x05 /* Message Signaled Interrupts */ #define PCIY_CHSWP 0x06 /* CompactPCI Hot Swap */ #define PCIY_PCIX 0x07 /* PCI-X */ #define PCIY_HT 0x08 /* HyperTransport */ #define PCIY_VENDOR 0x09 /* Vendor Unique */ #define PCIY_DEBUG 0x0a /* Debug port */ #define PCIY_CRES 0x0b /* CompactPCI central resource control */ #define PCIY_HOTPLUG 0x0c /* PCI Hot-Plug */ #define PCIY_SUBVENDOR 0x0d /* PCI-PCI bridge subvendor ID */ #define PCIY_AGP8X 0x0e /* AGP 8x */ #define PCIY_SECDEV 0x0f /* Secure Device */ #define PCIY_EXPRESS 0x10 /* PCI Express */ #define PCIY_MSIX 0x11 /* MSI-X */ #define PCIY_SATA 0x12 /* SATA */ #define PCIY_PCIAF 0x13 /* PCI Advanced Features */ #define PCIY_EA 0x14 /* PCI Extended Allocation */ /* Extended Capability Register Fields */ #define PCIR_EXTCAP 0x100 #define PCIM_EXTCAP_ID 0x0000ffff #define PCIM_EXTCAP_VER 0x000f0000 #define PCIM_EXTCAP_NEXTPTR 0xfff00000 #define PCI_EXTCAP_ID(ecap) ((ecap) & PCIM_EXTCAP_ID) #define PCI_EXTCAP_VER(ecap) (((ecap) & PCIM_EXTCAP_VER) >> 16) #define PCI_EXTCAP_NEXTPTR(ecap) (((ecap) & PCIM_EXTCAP_NEXTPTR) >> 20) /* Extended Capability Identification Numbers */ #define PCIZ_AER 0x0001 /* Advanced Error Reporting */ #define PCIZ_VC 0x0002 /* Virtual Channel if MFVC Ext Cap not set */ #define PCIZ_SERNUM 0x0003 /* Device Serial Number */ #define PCIZ_PWRBDGT 0x0004 /* Power Budgeting */ #define PCIZ_RCLINK_DCL 0x0005 /* Root Complex Link Declaration */ #define PCIZ_RCLINK_CTL 0x0006 /* Root Complex Internal Link Control */ #define PCIZ_RCEC_ASSOC 0x0007 /* Root Complex Event Collector Association */ #define PCIZ_MFVC 0x0008 /* Multi-Function Virtual Channel */ #define PCIZ_VC2 0x0009 /* Virtual Channel if MFVC Ext Cap set */ #define PCIZ_RCRB 0x000a /* RCRB Header */ #define PCIZ_VENDOR 0x000b /* Vendor Unique */ #define PCIZ_CAC 0x000c /* Configuration Access Correction -- obsolete */ #define PCIZ_ACS 0x000d /* Access Control Services */ #define PCIZ_ARI 0x000e /* Alternative Routing-ID Interpretation */ #define PCIZ_ATS 0x000f /* Address Translation Services */ #define PCIZ_SRIOV 0x0010 /* Single Root IO Virtualization */ #define PCIZ_MRIOV 0x0011 /* Multiple Root IO Virtualization */ #define PCIZ_MULTICAST 0x0012 /* Multicast */ #define PCIZ_PAGE_REQ 0x0013 /* Page Request */ #define PCIZ_AMD 0x0014 /* Reserved for AMD */ #define PCIZ_RESIZE_BAR 0x0015 /* Resizable BAR */ #define PCIZ_DPA 0x0016 /* Dynamic Power Allocation */ #define PCIZ_TPH_REQ 0x0017 /* TPH Requester */ #define PCIZ_LTR 0x0018 /* Latency Tolerance Reporting */ #define PCIZ_SEC_PCIE 0x0019 /* Secondary PCI Express */ #define PCIZ_PMUX 0x001a /* Protocol Multiplexing */ #define PCIZ_PASID 0x001b /* Process Address Space ID */ #define PCIZ_LN_REQ 0x001c /* LN Requester */ #define PCIZ_DPC 0x001d /* Downstream Porto Containment */ #define PCIZ_L1PM 0x001e /* L1 PM Substates */ /* config registers for header type 0 devices */ #define PCIR_BARS 0x10 #define PCIR_BAR(x) (PCIR_BARS + (x) * 4) #define PCIR_MAX_BAR_0 5 #define PCI_RID2BAR(rid) (((rid) - PCIR_BARS) / 4) #define PCI_BAR_IO(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE) #define PCI_BAR_MEM(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE) #define PCIM_BAR_SPACE 0x00000001 #define PCIM_BAR_MEM_SPACE 0 #define PCIM_BAR_IO_SPACE 1 #define PCIM_BAR_MEM_TYPE 0x00000006 #define PCIM_BAR_MEM_32 0 #define PCIM_BAR_MEM_1MB 2 /* Locate below 1MB in PCI <= 2.1 */ #define PCIM_BAR_MEM_64 4 #define PCIM_BAR_MEM_PREFETCH 0x00000008 #define PCIM_BAR_MEM_BASE 0xfffffffffffffff0ULL #define PCIM_BAR_IO_RESERVED 0x00000002 #define PCIM_BAR_IO_BASE 0xfffffffc #define PCIR_CIS 0x28 #define PCIM_CIS_ASI_MASK 0x00000007 #define PCIM_CIS_ASI_CONFIG 0 #define PCIM_CIS_ASI_BAR0 1 #define PCIM_CIS_ASI_BAR1 2 #define PCIM_CIS_ASI_BAR2 3 #define PCIM_CIS_ASI_BAR3 4 #define PCIM_CIS_ASI_BAR4 5 #define PCIM_CIS_ASI_BAR5 6 #define PCIM_CIS_ASI_ROM 7 #define PCIM_CIS_ADDR_MASK 0x0ffffff8 #define PCIM_CIS_ROM_MASK 0xf0000000 #define PCIM_CIS_CONFIG_MASK 0xff #define PCIR_SUBVEND_0 0x2c #define PCIR_SUBDEV_0 0x2e #define PCIR_BIOS 0x30 #define PCIM_BIOS_ENABLE 0x01 #define PCIM_BIOS_ADDR_MASK 0xfffff800 #define PCIR_CAP_PTR 0x34 #define PCIR_INTLINE 0x3c #define PCIR_INTPIN 0x3d #define PCIR_MINGNT 0x3e #define PCIR_MAXLAT 0x3f /* config registers for header type 1 (PCI-to-PCI bridge) devices */ #define PCIR_MAX_BAR_1 1 #define PCIR_SECSTAT_1 0x1e #define PCIR_PRIBUS_1 0x18 #define PCIR_SECBUS_1 0x19 #define PCIR_SUBBUS_1 0x1a #define PCIR_SECLAT_1 0x1b #define PCIR_IOBASEL_1 0x1c #define PCIR_IOLIMITL_1 0x1d #define PCIR_IOBASEH_1 0x30 #define PCIR_IOLIMITH_1 0x32 #define PCIM_BRIO_16 0x0 #define PCIM_BRIO_32 0x1 #define PCIM_BRIO_MASK 0xf #define PCIR_MEMBASE_1 0x20 #define PCIR_MEMLIMIT_1 0x22 #define PCIR_PMBASEL_1 0x24 #define PCIR_PMLIMITL_1 0x26 #define PCIR_PMBASEH_1 0x28 #define PCIR_PMLIMITH_1 0x2c #define PCIM_BRPM_32 0x0 #define PCIM_BRPM_64 0x1 #define PCIM_BRPM_MASK 0xf #define PCIR_BIOS_1 0x38 #define PCIR_BRIDGECTL_1 0x3e #define PCI_PPBMEMBASE(h,l) ((((uint64_t)(h) << 32) + ((l)<<16)) & ~0xfffff) #define PCI_PPBMEMLIMIT(h,l) ((((uint64_t)(h) << 32) + ((l)<<16)) | 0xfffff) #define PCI_PPBIOBASE(h,l) ((((h)<<16) + ((l)<<8)) & ~0xfff) #define PCI_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff) /* config registers for header type 2 (CardBus) devices */ #define PCIR_MAX_BAR_2 0 #define PCIR_CAP_PTR_2 0x14 #define PCIR_SECSTAT_2 0x16 #define PCIR_PRIBUS_2 0x18 #define PCIR_SECBUS_2 0x19 #define PCIR_SUBBUS_2 0x1a #define PCIR_SECLAT_2 0x1b #define PCIR_MEMBASE0_2 0x1c #define PCIR_MEMLIMIT0_2 0x20 #define PCIR_MEMBASE1_2 0x24 #define PCIR_MEMLIMIT1_2 0x28 #define PCIR_IOBASE0_2 0x2c #define PCIR_IOLIMIT0_2 0x30 #define PCIR_IOBASE1_2 0x34 #define PCIR_IOLIMIT1_2 0x38 #define PCIM_CBBIO_16 0x0 #define PCIM_CBBIO_32 0x1 #define PCIM_CBBIO_MASK 0x3 #define PCIR_BRIDGECTL_2 0x3e #define PCIR_SUBVEND_2 0x40 #define PCIR_SUBDEV_2 0x42 #define PCIR_PCCARDIF_2 0x44 #define PCI_CBBMEMBASE(l) ((l) & ~0xfffff) #define PCI_CBBMEMLIMIT(l) ((l) | 0xfffff) #define PCI_CBBIOBASE(l) ((l) & ~0x3) #define PCI_CBBIOLIMIT(l) ((l) | 0x3) /* PCI device class, subclass and programming interface definitions */ #define PCIC_OLD 0x00 #define PCIS_OLD_NONVGA 0x00 #define PCIS_OLD_VGA 0x01 #define PCIC_STORAGE 0x01 #define PCIS_STORAGE_SCSI 0x00 #define PCIS_STORAGE_IDE 0x01 #define PCIP_STORAGE_IDE_MODEPRIM 0x01 #define PCIP_STORAGE_IDE_PROGINDPRIM 0x02 #define PCIP_STORAGE_IDE_MODESEC 0x04 #define PCIP_STORAGE_IDE_PROGINDSEC 0x08 #define PCIP_STORAGE_IDE_MASTERDEV 0x80 #define PCIS_STORAGE_FLOPPY 0x02 #define PCIS_STORAGE_IPI 0x03 #define PCIS_STORAGE_RAID 0x04 #define PCIS_STORAGE_ATA_ADMA 0x05 #define PCIS_STORAGE_SATA 0x06 #define PCIP_STORAGE_SATA_AHCI_1_0 0x01 #define PCIS_STORAGE_SAS 0x07 #define PCIS_STORAGE_NVM 0x08 #define PCIP_STORAGE_NVM_NVMHCI_1_0 0x01 #define PCIP_STORAGE_NVM_ENTERPRISE_NVMHCI_1_0 0x02 #define PCIS_STORAGE_OTHER 0x80 #define PCIC_NETWORK 0x02 #define PCIS_NETWORK_ETHERNET 0x00 #define PCIS_NETWORK_TOKENRING 0x01 #define PCIS_NETWORK_FDDI 0x02 #define PCIS_NETWORK_ATM 0x03 #define PCIS_NETWORK_ISDN 0x04 #define PCIS_NETWORK_WORLDFIP 0x05 #define PCIS_NETWORK_PICMG 0x06 #define PCIS_NETWORK_OTHER 0x80 #define PCIC_DISPLAY 0x03 #define PCIS_DISPLAY_VGA 0x00 #define PCIS_DISPLAY_XGA 0x01 #define PCIS_DISPLAY_3D 0x02 #define PCIS_DISPLAY_OTHER 0x80 #define PCIC_MULTIMEDIA 0x04 #define PCIS_MULTIMEDIA_VIDEO 0x00 #define PCIS_MULTIMEDIA_AUDIO 0x01 #define PCIS_MULTIMEDIA_TELE 0x02 #define PCIS_MULTIMEDIA_HDA 0x03 #define PCIS_MULTIMEDIA_OTHER 0x80 #define PCIC_MEMORY 0x05 #define PCIS_MEMORY_RAM 0x00 #define PCIS_MEMORY_FLASH 0x01 #define PCIS_MEMORY_OTHER 0x80 #define PCIC_BRIDGE 0x06 #define PCIS_BRIDGE_HOST 0x00 #define PCIS_BRIDGE_ISA 0x01 #define PCIS_BRIDGE_EISA 0x02 #define PCIS_BRIDGE_MCA 0x03 #define PCIS_BRIDGE_PCI 0x04 #define PCIP_BRIDGE_PCI_SUBTRACTIVE 0x01 #define PCIS_BRIDGE_PCMCIA 0x05 #define PCIS_BRIDGE_NUBUS 0x06 #define PCIS_BRIDGE_CARDBUS 0x07 #define PCIS_BRIDGE_RACEWAY 0x08 #define PCIS_BRIDGE_PCI_TRANSPARENT 0x09 #define PCIS_BRIDGE_INFINIBAND 0x0a #define PCIS_BRIDGE_OTHER 0x80 #define PCIC_SIMPLECOMM 0x07 #define PCIS_SIMPLECOMM_UART 0x00 #define PCIP_SIMPLECOMM_UART_8250 0x00 #define PCIP_SIMPLECOMM_UART_16450A 0x01 #define PCIP_SIMPLECOMM_UART_16550A 0x02 #define PCIP_SIMPLECOMM_UART_16650A 0x03 #define PCIP_SIMPLECOMM_UART_16750A 0x04 #define PCIP_SIMPLECOMM_UART_16850A 0x05 #define PCIP_SIMPLECOMM_UART_16950A 0x06 #define PCIS_SIMPLECOMM_PAR 0x01 #define PCIS_SIMPLECOMM_MULSER 0x02 #define PCIS_SIMPLECOMM_MODEM 0x03 #define PCIS_SIMPLECOMM_GPIB 0x04 #define PCIS_SIMPLECOMM_SMART_CARD 0x05 #define PCIS_SIMPLECOMM_OTHER 0x80 #define PCIC_BASEPERIPH 0x08 #define PCIS_BASEPERIPH_PIC 0x00 #define PCIP_BASEPERIPH_PIC_8259A 0x00 #define PCIP_BASEPERIPH_PIC_ISA 0x01 #define PCIP_BASEPERIPH_PIC_EISA 0x02 #define PCIP_BASEPERIPH_PIC_IO_APIC 0x10 #define PCIP_BASEPERIPH_PIC_IOX_APIC 0x20 #define PCIS_BASEPERIPH_DMA 0x01 #define PCIS_BASEPERIPH_TIMER 0x02 #define PCIS_BASEPERIPH_RTC 0x03 #define PCIS_BASEPERIPH_PCIHOT 0x04 #define PCIS_BASEPERIPH_SDHC 0x05 #define PCIS_BASEPERIPH_IOMMU 0x06 #define PCIS_BASEPERIPH_OTHER 0x80 #define PCIC_INPUTDEV 0x09 #define PCIS_INPUTDEV_KEYBOARD 0x00 #define PCIS_INPUTDEV_DIGITIZER 0x01 #define PCIS_INPUTDEV_MOUSE 0x02 #define PCIS_INPUTDEV_SCANNER 0x03 #define PCIS_INPUTDEV_GAMEPORT 0x04 #define PCIS_INPUTDEV_OTHER 0x80 #define PCIC_DOCKING 0x0a #define PCIS_DOCKING_GENERIC 0x00 #define PCIS_DOCKING_OTHER 0x80 #define PCIC_PROCESSOR 0x0b #define PCIS_PROCESSOR_386 0x00 #define PCIS_PROCESSOR_486 0x01 #define PCIS_PROCESSOR_PENTIUM 0x02 #define PCIS_PROCESSOR_ALPHA 0x10 #define PCIS_PROCESSOR_POWERPC 0x20 #define PCIS_PROCESSOR_MIPS 0x30 #define PCIS_PROCESSOR_COPROC 0x40 #define PCIC_SERIALBUS 0x0c #define PCIS_SERIALBUS_FW 0x00 #define PCIS_SERIALBUS_ACCESS 0x01 #define PCIS_SERIALBUS_SSA 0x02 #define PCIS_SERIALBUS_USB 0x03 #define PCIP_SERIALBUS_USB_UHCI 0x00 #define PCIP_SERIALBUS_USB_OHCI 0x10 #define PCIP_SERIALBUS_USB_EHCI 0x20 #define PCIP_SERIALBUS_USB_XHCI 0x30 #define PCIP_SERIALBUS_USB_DEVICE 0xfe #define PCIS_SERIALBUS_FC 0x04 #define PCIS_SERIALBUS_SMBUS 0x05 #define PCIS_SERIALBUS_INFINIBAND 0x06 #define PCIS_SERIALBUS_IPMI 0x07 #define PCIP_SERIALBUS_IPMI_SMIC 0x00 #define PCIP_SERIALBUS_IPMI_KCS 0x01 #define PCIP_SERIALBUS_IPMI_BT 0x02 #define PCIS_SERIALBUS_SERCOS 0x08 #define PCIS_SERIALBUS_CANBUS 0x09 #define PCIC_WIRELESS 0x0d #define PCIS_WIRELESS_IRDA 0x00 #define PCIS_WIRELESS_IR 0x01 #define PCIS_WIRELESS_RF 0x10 #define PCIS_WIRELESS_BLUETOOTH 0x11 #define PCIS_WIRELESS_BROADBAND 0x12 #define PCIS_WIRELESS_80211A 0x20 #define PCIS_WIRELESS_80211B 0x21 #define PCIS_WIRELESS_OTHER 0x80 #define PCIC_INTELLIIO 0x0e #define PCIS_INTELLIIO_I2O 0x00 #define PCIC_SATCOM 0x0f #define PCIS_SATCOM_TV 0x01 #define PCIS_SATCOM_AUDIO 0x02 #define PCIS_SATCOM_VOICE 0x03 #define PCIS_SATCOM_DATA 0x04 #define PCIC_CRYPTO 0x10 #define PCIS_CRYPTO_NETCOMP 0x00 #define PCIS_CRYPTO_ENTERTAIN 0x10 #define PCIS_CRYPTO_OTHER 0x80 #define PCIC_DASP 0x11 #define PCIS_DASP_DPIO 0x00 #define PCIS_DASP_PERFCNTRS 0x01 #define PCIS_DASP_COMM_SYNC 0x10 #define PCIS_DASP_MGMT_CARD 0x20 #define PCIS_DASP_OTHER 0x80 #define PCIC_ACCEL 0x12 #define PCIS_ACCEL_PROCESSING 0x00 #define PCIC_INSTRUMENT 0x13 #define PCIC_OTHER 0xff /* Bridge Control Values. */ #define PCIB_BCR_PERR_ENABLE 0x0001 #define PCIB_BCR_SERR_ENABLE 0x0002 #define PCIB_BCR_ISA_ENABLE 0x0004 #define PCIB_BCR_VGA_ENABLE 0x0008 #define PCIB_BCR_MASTER_ABORT_MODE 0x0020 #define PCIB_BCR_SECBUS_RESET 0x0040 #define PCIB_BCR_SECBUS_BACKTOBACK 0x0080 #define PCIB_BCR_PRI_DISCARD_TIMEOUT 0x0100 #define PCIB_BCR_SEC_DISCARD_TIMEOUT 0x0200 #define PCIB_BCR_DISCARD_TIMER_STATUS 0x0400 #define PCIB_BCR_DISCARD_TIMER_SERREN 0x0800 #define CBB_BCR_PERR_ENABLE 0x0001 #define CBB_BCR_SERR_ENABLE 0x0002 #define CBB_BCR_ISA_ENABLE 0x0004 #define CBB_BCR_VGA_ENABLE 0x0008 #define CBB_BCR_MASTER_ABORT_MODE 0x0020 #define CBB_BCR_CARDBUS_RESET 0x0040 #define CBB_BCR_IREQ_INT_ENABLE 0x0080 #define CBB_BCR_PREFETCH_0_ENABLE 0x0100 #define CBB_BCR_PREFETCH_1_ENABLE 0x0200 #define CBB_BCR_WRITE_POSTING_ENABLE 0x0400 /* PCI power manangement */ #define PCIR_POWER_CAP 0x2 #define PCIM_PCAP_SPEC 0x0007 #define PCIM_PCAP_PMEREQCLK 0x0008 #define PCIM_PCAP_DEVSPECINIT 0x0020 #define PCIM_PCAP_AUXPWR_0 0x0000 #define PCIM_PCAP_AUXPWR_55 0x0040 #define PCIM_PCAP_AUXPWR_100 0x0080 #define PCIM_PCAP_AUXPWR_160 0x00c0 #define PCIM_PCAP_AUXPWR_220 0x0100 #define PCIM_PCAP_AUXPWR_270 0x0140 #define PCIM_PCAP_AUXPWR_320 0x0180 #define PCIM_PCAP_AUXPWR_375 0x01c0 #define PCIM_PCAP_AUXPWRMASK 0x01c0 #define PCIM_PCAP_D1SUPP 0x0200 #define PCIM_PCAP_D2SUPP 0x0400 #define PCIM_PCAP_D0PME 0x0800 #define PCIM_PCAP_D1PME 0x1000 #define PCIM_PCAP_D2PME 0x2000 #define PCIM_PCAP_D3PME_HOT 0x4000 #define PCIM_PCAP_D3PME_COLD 0x8000 #define PCIR_POWER_STATUS 0x4 #define PCIM_PSTAT_D0 0x0000 #define PCIM_PSTAT_D1 0x0001 #define PCIM_PSTAT_D2 0x0002 #define PCIM_PSTAT_D3 0x0003 #define PCIM_PSTAT_DMASK 0x0003 #define PCIM_PSTAT_NOSOFTRESET 0x0008 #define PCIM_PSTAT_PMEENABLE 0x0100 #define PCIM_PSTAT_D0POWER 0x0000 #define PCIM_PSTAT_D1POWER 0x0200 #define PCIM_PSTAT_D2POWER 0x0400 #define PCIM_PSTAT_D3POWER 0x0600 #define PCIM_PSTAT_D0HEAT 0x0800 #define PCIM_PSTAT_D1HEAT 0x0a00 #define PCIM_PSTAT_D2HEAT 0x0c00 #define PCIM_PSTAT_D3HEAT 0x0e00 #define PCIM_PSTAT_DATASELMASK 0x1e00 #define PCIM_PSTAT_DATAUNKN 0x0000 #define PCIM_PSTAT_DATADIV10 0x2000 #define PCIM_PSTAT_DATADIV100 0x4000 #define PCIM_PSTAT_DATADIV1000 0x6000 #define PCIM_PSTAT_DATADIVMASK 0x6000 #define PCIM_PSTAT_PME 0x8000 #define PCIR_POWER_BSE 0x6 #define PCIM_PMCSR_BSE_D3B3 0x00 #define PCIM_PMCSR_BSE_D3B2 0x40 #define PCIM_PMCSR_BSE_BPCCE 0x80 #define PCIR_POWER_DATA 0x7 /* VPD capability registers */ #define PCIR_VPD_ADDR 0x2 #define PCIR_VPD_DATA 0x4 /* PCI Message Signalled Interrupts (MSI) */ #define PCIR_MSI_CTRL 0x2 #define PCIM_MSICTRL_VECTOR 0x0100 #define PCIM_MSICTRL_64BIT 0x0080 #define PCIM_MSICTRL_MME_MASK 0x0070 #define PCIM_MSICTRL_MME_1 0x0000 #define PCIM_MSICTRL_MME_2 0x0010 #define PCIM_MSICTRL_MME_4 0x0020 #define PCIM_MSICTRL_MME_8 0x0030 #define PCIM_MSICTRL_MME_16 0x0040 #define PCIM_MSICTRL_MME_32 0x0050 #define PCIM_MSICTRL_MMC_MASK 0x000E #define PCIM_MSICTRL_MMC_1 0x0000 #define PCIM_MSICTRL_MMC_2 0x0002 #define PCIM_MSICTRL_MMC_4 0x0004 #define PCIM_MSICTRL_MMC_8 0x0006 #define PCIM_MSICTRL_MMC_16 0x0008 #define PCIM_MSICTRL_MMC_32 0x000A #define PCIM_MSICTRL_MSI_ENABLE 0x0001 #define PCIR_MSI_ADDR 0x4 #define PCIR_MSI_ADDR_HIGH 0x8 #define PCIR_MSI_DATA 0x8 #define PCIR_MSI_DATA_64BIT 0xc #define PCIR_MSI_MASK 0x10 #define PCIR_MSI_PENDING 0x14 /* PCI Enhanced Allocation registers */ #define PCIR_EA_NUM_ENT 2 /* Number of Capability Entries */ #define PCIM_EA_NUM_ENT_MASK 0x3f /* Num Entries Mask */ #define PCIR_EA_FIRST_ENT 4 /* First EA Entry in List */ #define PCIR_EA_FIRST_ENT_BRIDGE 8 /* First EA Entry for Bridges */ #define PCIM_EA_ES 0x00000007 /* Entry Size */ #define PCIM_EA_BEI 0x000000f0 /* BAR Equivalent Indicator */ #define PCIM_EA_BEI_OFFSET 4 /* 0-5 map to BARs 0-5 respectively */ #define PCIM_EA_BEI_BAR_0 0 #define PCIM_EA_BEI_BAR_5 5 #define PCIM_EA_BEI_BAR(x) (((x) >> PCIM_EA_BEI_OFFSET) & 0xf) #define PCIM_EA_BEI_BRIDGE 0x6 /* Resource behind bridge */ #define PCIM_EA_BEI_ENI 0x7 /* Equivalent Not Indicated */ #define PCIM_EA_BEI_ROM 0x8 /* Expansion ROM */ /* 9-14 map to VF BARs 0-5 respectively */ #define PCIM_EA_BEI_VF_BAR_0 9 #define PCIM_EA_BEI_VF_BAR_5 14 #define PCIM_EA_BEI_RESERVED 0xf /* Reserved - Treat like ENI */ #define PCIM_EA_PP 0x0000ff00 /* Primary Properties */ #define PCIM_EA_PP_OFFSET 8 #define PCIM_EA_SP_OFFSET 16 #define PCIM_EA_SP 0x00ff0000 /* Secondary Properties */ #define PCIM_EA_P_MEM 0x00 /* Non-Prefetch Memory */ #define PCIM_EA_P_MEM_PREFETCH 0x01 /* Prefetchable Memory */ #define PCIM_EA_P_IO 0x02 /* I/O Space */ #define PCIM_EA_P_VF_MEM_PREFETCH 0x03 /* VF Prefetchable Memory */ #define PCIM_EA_P_VF_MEM 0x04 /* VF Non-Prefetch Memory */ #define PCIM_EA_P_BRIDGE_MEM 0x05 /* Bridge Non-Prefetch Memory */ #define PCIM_EA_P_BRIDGE_MEM_PREFETCH 0x06 /* Bridge Prefetchable Memory */ #define PCIM_EA_P_BRIDGE_IO 0x07 /* Bridge I/O Space */ /* 0x08-0xfc reserved */ #define PCIM_EA_P_MEM_RESERVED 0xfd /* Reserved Memory */ #define PCIM_EA_P_IO_RESERVED 0xfe /* Reserved I/O Space */ #define PCIM_EA_P_UNAVAILABLE 0xff /* Entry Unavailable */ #define PCIM_EA_WRITABLE 0x40000000 /* Writable: 1 = RW, 0 = HwInit */ #define PCIM_EA_ENABLE 0x80000000 /* Enable for this entry */ #define PCIM_EA_BASE 4 /* Base Address Offset */ #define PCIM_EA_MAX_OFFSET 8 /* MaxOffset (resource length) */ /* bit 0 is reserved */ #define PCIM_EA_IS_64 0x00000002 /* 64-bit field flag */ #define PCIM_EA_FIELD_MASK 0xfffffffc /* For Base & Max Offset */ /* Bridge config register */ #define PCIM_EA_SEC_NR(reg) ((reg) & 0xff) #define PCIM_EA_SUB_NR(reg) (((reg) >> 8) & 0xff) /* PCI-X definitions */ /* For header type 0 devices */ #define PCIXR_COMMAND 0x2 #define PCIXM_COMMAND_DPERR_E 0x0001 /* Data Parity Error Recovery */ #define PCIXM_COMMAND_ERO 0x0002 /* Enable Relaxed Ordering */ #define PCIXM_COMMAND_MAX_READ 0x000c /* Maximum Burst Read Count */ #define PCIXM_COMMAND_MAX_READ_512 0x0000 #define PCIXM_COMMAND_MAX_READ_1024 0x0004 #define PCIXM_COMMAND_MAX_READ_2048 0x0008 #define PCIXM_COMMAND_MAX_READ_4096 0x000c #define PCIXM_COMMAND_MAX_SPLITS 0x0070 /* Maximum Split Transactions */ #define PCIXM_COMMAND_MAX_SPLITS_1 0x0000 #define PCIXM_COMMAND_MAX_SPLITS_2 0x0010 #define PCIXM_COMMAND_MAX_SPLITS_3 0x0020 #define PCIXM_COMMAND_MAX_SPLITS_4 0x0030 #define PCIXM_COMMAND_MAX_SPLITS_8 0x0040 #define PCIXM_COMMAND_MAX_SPLITS_12 0x0050 #define PCIXM_COMMAND_MAX_SPLITS_16 0x0060 #define PCIXM_COMMAND_MAX_SPLITS_32 0x0070 #define PCIXM_COMMAND_VERSION 0x3000 #define PCIXR_STATUS 0x4 #define PCIXM_STATUS_DEVFN 0x000000FF #define PCIXM_STATUS_BUS 0x0000FF00 #define PCIXM_STATUS_64BIT 0x00010000 #define PCIXM_STATUS_133CAP 0x00020000 #define PCIXM_STATUS_SC_DISCARDED 0x00040000 #define PCIXM_STATUS_UNEXP_SC 0x00080000 #define PCIXM_STATUS_COMPLEX_DEV 0x00100000 #define PCIXM_STATUS_MAX_READ 0x00600000 #define PCIXM_STATUS_MAX_READ_512 0x00000000 #define PCIXM_STATUS_MAX_READ_1024 0x00200000 #define PCIXM_STATUS_MAX_READ_2048 0x00400000 #define PCIXM_STATUS_MAX_READ_4096 0x00600000 #define PCIXM_STATUS_MAX_SPLITS 0x03800000 #define PCIXM_STATUS_MAX_SPLITS_1 0x00000000 #define PCIXM_STATUS_MAX_SPLITS_2 0x00800000 #define PCIXM_STATUS_MAX_SPLITS_3 0x01000000 #define PCIXM_STATUS_MAX_SPLITS_4 0x01800000 #define PCIXM_STATUS_MAX_SPLITS_8 0x02000000 #define PCIXM_STATUS_MAX_SPLITS_12 0x02800000 #define PCIXM_STATUS_MAX_SPLITS_16 0x03000000 #define PCIXM_STATUS_MAX_SPLITS_32 0x03800000 #define PCIXM_STATUS_MAX_CUM_READ 0x1C000000 #define PCIXM_STATUS_RCVD_SC_ERR 0x20000000 #define PCIXM_STATUS_266CAP 0x40000000 #define PCIXM_STATUS_533CAP 0x80000000 /* For header type 1 devices (PCI-X bridges) */ #define PCIXR_SEC_STATUS 0x2 #define PCIXM_SEC_STATUS_64BIT 0x0001 #define PCIXM_SEC_STATUS_133CAP 0x0002 #define PCIXM_SEC_STATUS_SC_DISC 0x0004 #define PCIXM_SEC_STATUS_UNEXP_SC 0x0008 #define PCIXM_SEC_STATUS_SC_OVERRUN 0x0010 #define PCIXM_SEC_STATUS_SR_DELAYED 0x0020 #define PCIXM_SEC_STATUS_BUS_MODE 0x03c0 #define PCIXM_SEC_STATUS_VERSION 0x3000 #define PCIXM_SEC_STATUS_266CAP 0x4000 #define PCIXM_SEC_STATUS_533CAP 0x8000 #define PCIXR_BRIDGE_STATUS 0x4 #define PCIXM_BRIDGE_STATUS_DEVFN 0x000000FF #define PCIXM_BRIDGE_STATUS_BUS 0x0000FF00 #define PCIXM_BRIDGE_STATUS_64BIT 0x00010000 #define PCIXM_BRIDGE_STATUS_133CAP 0x00020000 #define PCIXM_BRIDGE_STATUS_SC_DISCARDED 0x00040000 #define PCIXM_BRIDGE_STATUS_UNEXP_SC 0x00080000 #define PCIXM_BRIDGE_STATUS_SC_OVERRUN 0x00100000 #define PCIXM_BRIDGE_STATUS_SR_DELAYED 0x00200000 #define PCIXM_BRIDGE_STATUS_DEVID_MSGCAP 0x20000000 #define PCIXM_BRIDGE_STATUS_266CAP 0x40000000 #define PCIXM_BRIDGE_STATUS_533CAP 0x80000000 /* HT (HyperTransport) Capability definitions */ #define PCIR_HT_COMMAND 0x2 #define PCIM_HTCMD_CAP_MASK 0xf800 /* Capability type. */ #define PCIM_HTCAP_SLAVE 0x0000 /* 000xx */ #define PCIM_HTCAP_HOST 0x2000 /* 001xx */ #define PCIM_HTCAP_SWITCH 0x4000 /* 01000 */ #define PCIM_HTCAP_INTERRUPT 0x8000 /* 10000 */ #define PCIM_HTCAP_REVISION_ID 0x8800 /* 10001 */ #define PCIM_HTCAP_UNITID_CLUMPING 0x9000 /* 10010 */ #define PCIM_HTCAP_EXT_CONFIG_SPACE 0x9800 /* 10011 */ #define PCIM_HTCAP_ADDRESS_MAPPING 0xa000 /* 10100 */ #define PCIM_HTCAP_MSI_MAPPING 0xa800 /* 10101 */ #define PCIM_HTCAP_DIRECT_ROUTE 0xb000 /* 10110 */ #define PCIM_HTCAP_VCSET 0xb800 /* 10111 */ #define PCIM_HTCAP_RETRY_MODE 0xc000 /* 11000 */ #define PCIM_HTCAP_X86_ENCODING 0xc800 /* 11001 */ #define PCIM_HTCAP_GEN3 0xd000 /* 11010 */ #define PCIM_HTCAP_FLE 0xd800 /* 11011 */ #define PCIM_HTCAP_PM 0xe000 /* 11100 */ #define PCIM_HTCAP_HIGH_NODE_COUNT 0xe800 /* 11101 */ /* HT MSI Mapping Capability definitions. */ #define PCIM_HTCMD_MSI_ENABLE 0x0001 #define PCIM_HTCMD_MSI_FIXED 0x0002 #define PCIR_HTMSI_ADDRESS_LO 0x4 #define PCIR_HTMSI_ADDRESS_HI 0x8 /* PCI Vendor capability definitions */ #define PCIR_VENDOR_LENGTH 0x2 #define PCIR_VENDOR_DATA 0x3 /* PCI Device capability definitions */ #define PCIR_DEVICE_LENGTH 0x2 /* PCI EHCI Debug Port definitions */ #define PCIR_DEBUG_PORT 0x2 #define PCIM_DEBUG_PORT_OFFSET 0x1FFF #define PCIM_DEBUG_PORT_BAR 0xe000 /* PCI-PCI Bridge Subvendor definitions */ #define PCIR_SUBVENDCAP_ID 0x4 /* PCI Express definitions */ #define PCIER_FLAGS 0x2 #define PCIEM_FLAGS_VERSION 0x000F #define PCIEM_FLAGS_TYPE 0x00F0 #define PCIEM_TYPE_ENDPOINT 0x0000 #define PCIEM_TYPE_LEGACY_ENDPOINT 0x0010 #define PCIEM_TYPE_ROOT_PORT 0x0040 #define PCIEM_TYPE_UPSTREAM_PORT 0x0050 #define PCIEM_TYPE_DOWNSTREAM_PORT 0x0060 #define PCIEM_TYPE_PCI_BRIDGE 0x0070 #define PCIEM_TYPE_PCIE_BRIDGE 0x0080 #define PCIEM_TYPE_ROOT_INT_EP 0x0090 #define PCIEM_TYPE_ROOT_EC 0x00a0 #define PCIEM_FLAGS_SLOT 0x0100 #define PCIEM_FLAGS_IRQ 0x3e00 #define PCIER_DEVICE_CAP 0x4 #define PCIEM_CAP_MAX_PAYLOAD 0x00000007 #define PCIEM_CAP_PHANTHOM_FUNCS 0x00000018 #define PCIEM_CAP_EXT_TAG_FIELD 0x00000020 #define PCIEM_CAP_L0S_LATENCY 0x000001c0 #define PCIEM_CAP_L1_LATENCY 0x00000e00 #define PCIEM_CAP_ROLE_ERR_RPT 0x00008000 #define PCIEM_CAP_SLOT_PWR_LIM_VAL 0x03fc0000 #define PCIEM_CAP_SLOT_PWR_LIM_SCALE 0x0c000000 #define PCIEM_CAP_FLR 0x10000000 #define PCIER_DEVICE_CTL 0x8 #define PCIEM_CTL_COR_ENABLE 0x0001 #define PCIEM_CTL_NFER_ENABLE 0x0002 #define PCIEM_CTL_FER_ENABLE 0x0004 #define PCIEM_CTL_URR_ENABLE 0x0008 #define PCIEM_CTL_RELAXED_ORD_ENABLE 0x0010 #define PCIEM_CTL_MAX_PAYLOAD 0x00e0 #define PCIEM_CTL_EXT_TAG_FIELD 0x0100 #define PCIEM_CTL_PHANTHOM_FUNCS 0x0200 #define PCIEM_CTL_AUX_POWER_PM 0x0400 #define PCIEM_CTL_NOSNOOP_ENABLE 0x0800 #define PCIEM_CTL_MAX_READ_REQUEST 0x7000 #define PCIEM_CTL_BRDG_CFG_RETRY 0x8000 /* PCI-E - PCI/PCI-X bridges */ #define PCIEM_CTL_INITIATE_FLR 0x8000 /* FLR capable endpoints */ #define PCIER_DEVICE_STA 0xa #define PCIEM_STA_CORRECTABLE_ERROR 0x0001 #define PCIEM_STA_NON_FATAL_ERROR 0x0002 #define PCIEM_STA_FATAL_ERROR 0x0004 #define PCIEM_STA_UNSUPPORTED_REQ 0x0008 #define PCIEM_STA_AUX_POWER 0x0010 #define PCIEM_STA_TRANSACTION_PND 0x0020 #define PCIER_LINK_CAP 0xc #define PCIEM_LINK_CAP_MAX_SPEED 0x0000000f #define PCIEM_LINK_CAP_MAX_WIDTH 0x000003f0 #define PCIEM_LINK_CAP_ASPM 0x00000c00 #define PCIEM_LINK_CAP_L0S_EXIT 0x00007000 #define PCIEM_LINK_CAP_L1_EXIT 0x00038000 #define PCIEM_LINK_CAP_CLOCK_PM 0x00040000 #define PCIEM_LINK_CAP_SURPRISE_DOWN 0x00080000 #define PCIEM_LINK_CAP_DL_ACTIVE 0x00100000 #define PCIEM_LINK_CAP_LINK_BW_NOTIFY 0x00200000 #define PCIEM_LINK_CAP_ASPM_COMPLIANCE 0x00400000 #define PCIEM_LINK_CAP_PORT 0xff000000 #define PCIER_LINK_CTL 0x10 #define PCIEM_LINK_CTL_ASPMC_DIS 0x0000 #define PCIEM_LINK_CTL_ASPMC_L0S 0x0001 #define PCIEM_LINK_CTL_ASPMC_L1 0x0002 #define PCIEM_LINK_CTL_ASPMC 0x0003 #define PCIEM_LINK_CTL_RCB 0x0008 #define PCIEM_LINK_CTL_LINK_DIS 0x0010 #define PCIEM_LINK_CTL_RETRAIN_LINK 0x0020 #define PCIEM_LINK_CTL_COMMON_CLOCK 0x0040 #define PCIEM_LINK_CTL_EXTENDED_SYNC 0x0080 #define PCIEM_LINK_CTL_ECPM 0x0100 #define PCIEM_LINK_CTL_HAWD 0x0200 #define PCIEM_LINK_CTL_LBMIE 0x0400 #define PCIEM_LINK_CTL_LABIE 0x0800 #define PCIER_LINK_STA 0x12 #define PCIEM_LINK_STA_SPEED 0x000f #define PCIEM_LINK_STA_WIDTH 0x03f0 #define PCIEM_LINK_STA_TRAINING_ERROR 0x0400 #define PCIEM_LINK_STA_TRAINING 0x0800 #define PCIEM_LINK_STA_SLOT_CLOCK 0x1000 #define PCIEM_LINK_STA_DL_ACTIVE 0x2000 #define PCIEM_LINK_STA_LINK_BW_MGMT 0x4000 #define PCIEM_LINK_STA_LINK_AUTO_BW 0x8000 #define PCIER_SLOT_CAP 0x14 #define PCIEM_SLOT_CAP_APB 0x00000001 #define PCIEM_SLOT_CAP_PCP 0x00000002 #define PCIEM_SLOT_CAP_MRLSP 0x00000004 #define PCIEM_SLOT_CAP_AIP 0x00000008 #define PCIEM_SLOT_CAP_PIP 0x00000010 #define PCIEM_SLOT_CAP_HPS 0x00000020 #define PCIEM_SLOT_CAP_HPC 0x00000040 #define PCIEM_SLOT_CAP_SPLV 0x00007f80 #define PCIEM_SLOT_CAP_SPLS 0x00018000 #define PCIEM_SLOT_CAP_EIP 0x00020000 #define PCIEM_SLOT_CAP_NCCS 0x00040000 #define PCIEM_SLOT_CAP_PSN 0xfff80000 #define PCIER_SLOT_CTL 0x18 #define PCIEM_SLOT_CTL_ABPE 0x0001 #define PCIEM_SLOT_CTL_PFDE 0x0002 #define PCIEM_SLOT_CTL_MRLSCE 0x0004 #define PCIEM_SLOT_CTL_PDCE 0x0008 #define PCIEM_SLOT_CTL_CCIE 0x0010 #define PCIEM_SLOT_CTL_HPIE 0x0020 #define PCIEM_SLOT_CTL_AIC 0x00c0 #define PCIEM_SLOT_CTL_AI_ON 0x0040 #define PCIEM_SLOT_CTL_AI_BLINK 0x0080 #define PCIEM_SLOT_CTL_AI_OFF 0x00c0 #define PCIEM_SLOT_CTL_PIC 0x0300 #define PCIEM_SLOT_CTL_PI_ON 0x0100 #define PCIEM_SLOT_CTL_PI_BLINK 0x0200 #define PCIEM_SLOT_CTL_PI_OFF 0x0300 #define PCIEM_SLOT_CTL_PCC 0x0400 #define PCIEM_SLOT_CTL_PC_ON 0x0000 #define PCIEM_SLOT_CTL_PC_OFF 0x0400 #define PCIEM_SLOT_CTL_EIC 0x0800 #define PCIEM_SLOT_CTL_DLLSCE 0x1000 #define PCIER_SLOT_STA 0x1a #define PCIEM_SLOT_STA_ABP 0x0001 #define PCIEM_SLOT_STA_PFD 0x0002 #define PCIEM_SLOT_STA_MRLSC 0x0004 #define PCIEM_SLOT_STA_PDC 0x0008 #define PCIEM_SLOT_STA_CC 0x0010 #define PCIEM_SLOT_STA_MRLSS 0x0020 #define PCIEM_SLOT_STA_PDS 0x0040 #define PCIEM_SLOT_STA_EIS 0x0080 #define PCIEM_SLOT_STA_DLLSC 0x0100 #define PCIER_ROOT_CTL 0x1c #define PCIEM_ROOT_CTL_SERR_CORR 0x0001 #define PCIEM_ROOT_CTL_SERR_NONFATAL 0x0002 #define PCIEM_ROOT_CTL_SERR_FATAL 0x0004 #define PCIEM_ROOT_CTL_PME 0x0008 #define PCIEM_ROOT_CTL_CRS_VIS 0x0010 #define PCIER_ROOT_CAP 0x1e #define PCIEM_ROOT_CAP_CRS_VIS 0x0001 #define PCIER_ROOT_STA 0x20 #define PCIEM_ROOT_STA_PME_REQID_MASK 0x0000ffff #define PCIEM_ROOT_STA_PME_STATUS 0x00010000 #define PCIEM_ROOT_STA_PME_PEND 0x00020000 #define PCIER_DEVICE_CAP2 0x24 #define PCIEM_CAP2_COMP_TIMO_RANGES 0x0000000f #define PCIEM_CAP2_COMP_TIMO_RANGE_A 0x00000001 #define PCIEM_CAP2_COMP_TIMO_RANGE_B 0x00000002 #define PCIEM_CAP2_COMP_TIMO_RANGE_C 0x00000004 #define PCIEM_CAP2_COMP_TIMO_RANGE_D 0x00000008 #define PCIEM_CAP2_COMP_TIMO_DISABLE 0x00000010 #define PCIEM_CAP2_ARI 0x00000020 #define PCIER_DEVICE_CTL2 0x28 #define PCIEM_CTL2_COMP_TIMO_VAL 0x000f #define PCIEM_CTL2_COMP_TIMO_50MS 0x0000 #define PCIEM_CTL2_COMP_TIMO_100US 0x0001 #define PCIEM_CTL2_COMP_TIMO_10MS 0x0002 #define PCIEM_CTL2_COMP_TIMO_55MS 0x0005 #define PCIEM_CTL2_COMP_TIMO_210MS 0x0006 #define PCIEM_CTL2_COMP_TIMO_900MS 0x0009 #define PCIEM_CTL2_COMP_TIMO_3500MS 0x000a #define PCIEM_CTL2_COMP_TIMO_13S 0x000d #define PCIEM_CTL2_COMP_TIMO_64S 0x000e #define PCIEM_CTL2_COMP_TIMO_DISABLE 0x0010 #define PCIEM_CTL2_ARI 0x0020 #define PCIEM_CTL2_ATOMIC_REQ_ENABLE 0x0040 #define PCIEM_CTL2_ATOMIC_EGR_BLOCK 0x0080 #define PCIEM_CTL2_ID_ORDERED_REQ_EN 0x0100 #define PCIEM_CTL2_ID_ORDERED_CMP_EN 0x0200 #define PCIEM_CTL2_LTR_ENABLE 0x0400 #define PCIEM_CTL2_OBFF 0x6000 #define PCIEM_OBFF_DISABLE 0x0000 #define PCIEM_OBFF_MSGA_ENABLE 0x2000 #define PCIEM_OBFF_MSGB_ENABLE 0x4000 #define PCIEM_OBFF_WAKE_ENABLE 0x6000 #define PCIEM_CTL2_END2END_TLP 0x8000 #define PCIER_DEVICE_STA2 0x2a #define PCIER_LINK_CAP2 0x2c #define PCIER_LINK_CTL2 0x30 #define PCIER_LINK_STA2 0x32 #define PCIER_SLOT_CAP2 0x34 #define PCIER_SLOT_CTL2 0x38 #define PCIER_SLOT_STA2 0x3a /* MSI-X definitions */ #define PCIR_MSIX_CTRL 0x2 #define PCIM_MSIXCTRL_MSIX_ENABLE 0x8000 #define PCIM_MSIXCTRL_FUNCTION_MASK 0x4000 #define PCIM_MSIXCTRL_TABLE_SIZE 0x07FF #define PCIR_MSIX_TABLE 0x4 #define PCIR_MSIX_PBA 0x8 #define PCIM_MSIX_BIR_MASK 0x7 #define PCIM_MSIX_BIR_BAR_10 0 #define PCIM_MSIX_BIR_BAR_14 1 #define PCIM_MSIX_BIR_BAR_18 2 #define PCIM_MSIX_BIR_BAR_1C 3 #define PCIM_MSIX_BIR_BAR_20 4 #define PCIM_MSIX_BIR_BAR_24 5 #define PCIM_MSIX_VCTRL_MASK 0x1 /* PCI Advanced Features definitions */ #define PCIR_PCIAF_CAP 0x3 #define PCIM_PCIAFCAP_TP 0x01 #define PCIM_PCIAFCAP_FLR 0x02 #define PCIR_PCIAF_CTRL 0x4 #define PCIR_PCIAFCTRL_FLR 0x01 #define PCIR_PCIAF_STATUS 0x5 #define PCIR_PCIAFSTATUS_TP 0x01 /* Advanced Error Reporting */ #define PCIR_AER_UC_STATUS 0x04 #define PCIM_AER_UC_TRAINING_ERROR 0x00000001 #define PCIM_AER_UC_DL_PROTOCOL_ERROR 0x00000010 #define PCIM_AER_UC_SURPRISE_LINK_DOWN 0x00000020 #define PCIM_AER_UC_POISONED_TLP 0x00001000 #define PCIM_AER_UC_FC_PROTOCOL_ERROR 0x00002000 #define PCIM_AER_UC_COMPLETION_TIMEOUT 0x00004000 #define PCIM_AER_UC_COMPLETER_ABORT 0x00008000 #define PCIM_AER_UC_UNEXPECTED_COMPLETION 0x00010000 #define PCIM_AER_UC_RECEIVER_OVERFLOW 0x00020000 #define PCIM_AER_UC_MALFORMED_TLP 0x00040000 #define PCIM_AER_UC_ECRC_ERROR 0x00080000 #define PCIM_AER_UC_UNSUPPORTED_REQUEST 0x00100000 #define PCIM_AER_UC_ACS_VIOLATION 0x00200000 #define PCIM_AER_UC_INTERNAL_ERROR 0x00400000 #define PCIM_AER_UC_MC_BLOCKED_TLP 0x00800000 #define PCIM_AER_UC_ATOMIC_EGRESS_BLK 0x01000000 #define PCIM_AER_UC_TLP_PREFIX_BLOCKED 0x02000000 #define PCIR_AER_UC_MASK 0x08 /* Shares bits with UC_STATUS */ #define PCIR_AER_UC_SEVERITY 0x0c /* Shares bits with UC_STATUS */ #define PCIR_AER_COR_STATUS 0x10 #define PCIM_AER_COR_RECEIVER_ERROR 0x00000001 #define PCIM_AER_COR_BAD_TLP 0x00000040 #define PCIM_AER_COR_BAD_DLLP 0x00000080 #define PCIM_AER_COR_REPLAY_ROLLOVER 0x00000100 #define PCIM_AER_COR_REPLAY_TIMEOUT 0x00001000 #define PCIM_AER_COR_ADVISORY_NF_ERROR 0x00002000 #define PCIM_AER_COR_INTERNAL_ERROR 0x00004000 #define PCIM_AER_COR_HEADER_LOG_OVFLOW 0x00008000 #define PCIR_AER_COR_MASK 0x14 /* Shares bits with COR_STATUS */ #define PCIR_AER_CAP_CONTROL 0x18 #define PCIM_AER_FIRST_ERROR_PTR 0x0000001f #define PCIM_AER_ECRC_GEN_CAPABLE 0x00000020 #define PCIM_AER_ECRC_GEN_ENABLE 0x00000040 #define PCIM_AER_ECRC_CHECK_CAPABLE 0x00000080 #define PCIM_AER_ECRC_CHECK_ENABLE 0x00000100 #define PCIM_AER_MULT_HDR_CAPABLE 0x00000200 #define PCIM_AER_MULT_HDR_ENABLE 0x00000400 #define PCIM_AER_TLP_PREFIX_LOG_PRESENT 0x00000800 #define PCIR_AER_HEADER_LOG 0x1c #define PCIR_AER_ROOTERR_CMD 0x2c /* Only for root complex ports */ #define PCIM_AER_ROOTERR_COR_ENABLE 0x00000001 #define PCIM_AER_ROOTERR_NF_ENABLE 0x00000002 #define PCIM_AER_ROOTERR_F_ENABLE 0x00000004 #define PCIR_AER_ROOTERR_STATUS 0x30 /* Only for root complex ports */ #define PCIM_AER_ROOTERR_COR_ERR 0x00000001 #define PCIM_AER_ROOTERR_MULTI_COR_ERR 0x00000002 #define PCIM_AER_ROOTERR_UC_ERR 0x00000004 #define PCIM_AER_ROOTERR_MULTI_UC_ERR 0x00000008 #define PCIM_AER_ROOTERR_FIRST_UC_FATAL 0x00000010 #define PCIM_AER_ROOTERR_NF_ERR 0x00000020 #define PCIM_AER_ROOTERR_F_ERR 0x00000040 #define PCIM_AER_ROOTERR_INT_MESSAGE 0xf8000000 #define PCIR_AER_COR_SOURCE_ID 0x34 /* Only for root complex ports */ #define PCIR_AER_ERR_SOURCE_ID 0x36 /* Only for root complex ports */ #define PCIR_AER_TLP_PREFIX_LOG 0x38 /* Only for TLP prefix functions */ /* Virtual Channel definitions */ #define PCIR_VC_CAP1 0x04 #define PCIM_VC_CAP1_EXT_COUNT 0x00000007 #define PCIM_VC_CAP1_LOWPRI_EXT_COUNT 0x00000070 #define PCIR_VC_CAP2 0x08 #define PCIR_VC_CONTROL 0x0C #define PCIR_VC_STATUS 0x0E #define PCIR_VC_RESOURCE_CAP(n) (0x10 + (n) * 0x0C) #define PCIR_VC_RESOURCE_CTL(n) (0x14 + (n) * 0x0C) #define PCIR_VC_RESOURCE_STA(n) (0x18 + (n) * 0x0C) /* Serial Number definitions */ #define PCIR_SERIAL_LOW 0x04 #define PCIR_SERIAL_HIGH 0x08 /* SR-IOV definitions */ #define PCIR_SRIOV_CTL 0x08 #define PCIM_SRIOV_VF_EN 0x01 #define PCIM_SRIOV_VF_MSE 0x08 /* Memory space enable. */ #define PCIM_SRIOV_ARI_EN 0x10 #define PCIR_SRIOV_TOTAL_VFS 0x0E #define PCIR_SRIOV_NUM_VFS 0x10 #define PCIR_SRIOV_VF_OFF 0x14 #define PCIR_SRIOV_VF_STRIDE 0x16 #define PCIR_SRIOV_VF_DID 0x1A #define PCIR_SRIOV_PAGE_CAP 0x1C #define PCIR_SRIOV_PAGE_SIZE 0x20 #define PCI_SRIOV_BASE_PAGE_SHIFT 12 #define PCIR_SRIOV_BARS 0x24 #define PCIR_SRIOV_BAR(x) (PCIR_SRIOV_BARS + (x) * 4) +/* Extended Capability Vendor-Specific definitions */ +#define PCIR_VSEC_HEADER 0x04 +#define PCIR_VSEC_ID(hdr) ((hdr) & 0xffff) +#define PCIR_VSEC_REV(hdr) (((hdr) & 0xf0000) >> 16) +#define PCIR_VSEC_LENGTH(hdr) (((hdr) & 0xfff00000) >> 20) +#define PCIR_VSEC_DATA 0x08 + /* * PCI Express Firmware Interface definitions */ #define PCI_OSC_STATUS 0 #define PCI_OSC_SUPPORT 1 #define PCIM_OSC_SUPPORT_EXT_PCI_CONF 0x01 /* Extended PCI Config Space */ #define PCIM_OSC_SUPPORT_ASPM 0x02 /* Active State Power Management */ #define PCIM_OSC_SUPPORT_CPMC 0x04 /* Clock Power Management Cap */ #define PCIM_OSC_SUPPORT_SEG_GROUP 0x08 /* PCI Segment Groups supported */ #define PCIM_OSC_SUPPORT_MSI 0x10 /* MSI signalling supported */ #define PCI_OSC_CTL 2 #define PCIM_OSC_CTL_PCIE_HP 0x01 /* PCIe Native Hot Plug */ #define PCIM_OSC_CTL_SHPC_HP 0x02 /* SHPC Native Hot Plug */ #define PCIM_OSC_CTL_PCIE_PME 0x04 /* PCIe Native Power Mgt Events */ #define PCIM_OSC_CTL_PCIE_AER 0x08 /* PCIe Advanced Error Reporting */ #define PCIM_OSC_CTL_PCIE_CAP_STRUCT 0x10 /* Various Capability Structures */ Index: head/usr.sbin/pciconf/cap.c =================================================================== --- head/usr.sbin/pciconf/cap.c (revision 355740) +++ head/usr.sbin/pciconf/cap.c (revision 355741) @@ -1,1086 +1,1110 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2007 Yahoo!, Inc. * All rights reserved. * Written by: John Baldwin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include "pciconf.h" static void list_ecaps(int fd, struct pci_conf *p); +static int cap_level; + static void cap_power(int fd, struct pci_conf *p, uint8_t ptr) { uint16_t cap, status; cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); printf("powerspec %d supports D0%s%s D3 current D%d", cap & PCIM_PCAP_SPEC, cap & PCIM_PCAP_D1SUPP ? " D1" : "", cap & PCIM_PCAP_D2SUPP ? " D2" : "", status & PCIM_PSTAT_DMASK); } static void cap_agp(int fd, struct pci_conf *p, uint8_t ptr) { uint32_t status, command; status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); printf("AGP "); if (AGP_MODE_GET_MODE_3(status)) { printf("v3 "); if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) printf("8x "); if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) printf("4x "); } else { if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) printf("4x "); if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) printf("2x "); if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) printf("1x "); } if (AGP_MODE_GET_SBA(status)) printf("SBA "); if (AGP_MODE_GET_AGP(command)) { printf("enabled at "); if (AGP_MODE_GET_MODE_3(command)) { printf("v3 "); switch (AGP_MODE_GET_RATE(command)) { case AGP_MODE_V3_RATE_8x: printf("8x "); break; case AGP_MODE_V3_RATE_4x: printf("4x "); break; } } else switch (AGP_MODE_GET_RATE(command)) { case AGP_MODE_V2_RATE_4x: printf("4x "); break; case AGP_MODE_V2_RATE_2x: printf("2x "); break; case AGP_MODE_V2_RATE_1x: printf("1x "); break; } if (AGP_MODE_GET_SBA(command)) printf("SBA "); } else printf("disabled"); } static void cap_vpd(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused) { printf("VPD"); } static void cap_msi(int fd, struct pci_conf *p, uint8_t ptr) { uint16_t ctrl; int msgnum; ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); printf("MSI supports %d message%s%s%s ", msgnum, (msgnum == 1) ? "" : "s", (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); printf("enabled with %d message%s", msgnum, (msgnum == 1) ? "" : "s"); } } static void cap_pcix(int fd, struct pci_conf *p, uint8_t ptr) { uint32_t status; int comma, max_splits, max_burst_read; status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); printf("PCI-X "); if (status & PCIXM_STATUS_64BIT) printf("64-bit "); if ((p->pc_hdr & PCIM_HDRTYPE) == 1) printf("bridge "); if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP | PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0) printf("supports"); comma = 0; if (status & PCIXM_STATUS_133CAP) { printf(" 133MHz"); comma = 1; } if (status & PCIXM_STATUS_266CAP) { printf("%s 266MHz", comma ? "," : ""); comma = 1; } if (status & PCIXM_STATUS_533CAP) { printf("%s 533MHz", comma ? "," : ""); comma = 1; } if ((p->pc_hdr & PCIM_HDRTYPE) == 1) return; max_burst_read = 0; switch (status & PCIXM_STATUS_MAX_READ) { case PCIXM_STATUS_MAX_READ_512: max_burst_read = 512; break; case PCIXM_STATUS_MAX_READ_1024: max_burst_read = 1024; break; case PCIXM_STATUS_MAX_READ_2048: max_burst_read = 2048; break; case PCIXM_STATUS_MAX_READ_4096: max_burst_read = 4096; break; } max_splits = 0; switch (status & PCIXM_STATUS_MAX_SPLITS) { case PCIXM_STATUS_MAX_SPLITS_1: max_splits = 1; break; case PCIXM_STATUS_MAX_SPLITS_2: max_splits = 2; break; case PCIXM_STATUS_MAX_SPLITS_3: max_splits = 3; break; case PCIXM_STATUS_MAX_SPLITS_4: max_splits = 4; break; case PCIXM_STATUS_MAX_SPLITS_8: max_splits = 8; break; case PCIXM_STATUS_MAX_SPLITS_12: max_splits = 12; break; case PCIXM_STATUS_MAX_SPLITS_16: max_splits = 16; break; case PCIXM_STATUS_MAX_SPLITS_32: max_splits = 32; break; } printf("%s %d burst read, %d split transaction%s", comma ? "," : "", max_burst_read, max_splits, max_splits == 1 ? "" : "s"); } static void cap_ht(int fd, struct pci_conf *p, uint8_t ptr) { uint32_t reg; uint16_t command; command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); printf("HT "); if ((command & 0xe000) == PCIM_HTCAP_SLAVE) printf("slave"); else if ((command & 0xe000) == PCIM_HTCAP_HOST) printf("host"); else switch (command & PCIM_HTCMD_CAP_MASK) { case PCIM_HTCAP_SWITCH: printf("switch"); break; case PCIM_HTCAP_INTERRUPT: printf("interrupt"); break; case PCIM_HTCAP_REVISION_ID: printf("revision ID"); break; case PCIM_HTCAP_UNITID_CLUMPING: printf("unit ID clumping"); break; case PCIM_HTCAP_EXT_CONFIG_SPACE: printf("extended config space"); break; case PCIM_HTCAP_ADDRESS_MAPPING: printf("address mapping"); break; case PCIM_HTCAP_MSI_MAPPING: printf("MSI %saddress window %s at 0x", command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : "disabled"); if (command & PCIM_HTCMD_MSI_FIXED) printf("fee00000"); else { reg = read_config(fd, &p->pc_sel, ptr + PCIR_HTMSI_ADDRESS_HI, 4); if (reg != 0) printf("%08x", reg); reg = read_config(fd, &p->pc_sel, ptr + PCIR_HTMSI_ADDRESS_LO, 4); printf("%08x", reg); } break; case PCIM_HTCAP_DIRECT_ROUTE: printf("direct route"); break; case PCIM_HTCAP_VCSET: printf("VC set"); break; case PCIM_HTCAP_RETRY_MODE: printf("retry mode"); break; case PCIM_HTCAP_X86_ENCODING: printf("X86 encoding"); break; case PCIM_HTCAP_GEN3: printf("Gen3"); break; case PCIM_HTCAP_FLE: printf("function-level extension"); break; case PCIM_HTCAP_PM: printf("power management"); break; case PCIM_HTCAP_HIGH_NODE_COUNT: printf("high node count"); break; default: printf("unknown %02x", command); break; } } static void cap_vendor(int fd, struct pci_conf *p, uint8_t ptr) { uint8_t length; length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); printf("vendor (length %d)", length); if (p->pc_vendor == 0x8086) { /* Intel */ uint8_t version; version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 1); printf(" Intel cap %d version %d", version >> 4, version & 0xf); if (version >> 4 == 1 && length == 12) { /* Feature Detection */ uint32_t fvec; int comma; comma = 0; fvec = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA + 5, 4); printf("\n\t\t features:"); if (fvec & (1 << 0)) { printf(" AMT"); comma = 1; } fvec = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA + 1, 4); if (fvec & (1 << 21)) { printf("%s Quick Resume", comma ? "," : ""); comma = 1; } if (fvec & (1 << 18)) { printf("%s SATA RAID-5", comma ? "," : ""); comma = 1; } if (fvec & (1 << 9)) { printf("%s Mobile", comma ? "," : ""); comma = 1; } if (fvec & (1 << 7)) { printf("%s 6 PCI-e x1 slots", comma ? "," : ""); comma = 1; } else { printf("%s 4 PCI-e x1 slots", comma ? "," : ""); comma = 1; } if (fvec & (1 << 5)) { printf("%s SATA RAID-0/1/10", comma ? "," : ""); comma = 1; } if (fvec & (1 << 3)) printf(", SATA AHCI"); } } } static void cap_debug(int fd, struct pci_conf *p, uint8_t ptr) { uint16_t debug_port; debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); } static void cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) { uint32_t id; uint16_t ssid, ssvid; id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); ssid = id >> 16; ssvid = id & 0xffff; printf("PCI Bridge subvendor=0x%04x subdevice=0x%04x", ssvid, ssid); } #define MAX_PAYLOAD(field) (128 << (field)) static const char * link_speed_string(uint8_t speed) { switch (speed) { case 1: return ("2.5"); case 2: return ("5.0"); case 3: return ("8.0"); case 4: return ("16.0"); default: return ("undef"); } } static const char * aspm_string(uint8_t aspm) { switch (aspm) { case 1: return ("L0s"); case 2: return ("L1"); case 3: return ("L0s/L1"); default: return ("disabled"); } } static int slot_power(uint32_t cap) { int mwatts; mwatts = (cap & PCIEM_SLOT_CAP_SPLV) >> 7; switch (cap & PCIEM_SLOT_CAP_SPLS) { case 0x0: mwatts *= 1000; break; case 0x1: mwatts *= 100; break; case 0x2: mwatts *= 10; break; default: break; } return (mwatts); } static void cap_express(int fd, struct pci_conf *p, uint8_t ptr) { uint32_t cap; uint16_t ctl, flags, sta; unsigned int version; flags = read_config(fd, &p->pc_sel, ptr + PCIER_FLAGS, 2); version = flags & PCIEM_FLAGS_VERSION; printf("PCI-Express %u ", version); switch (flags & PCIEM_FLAGS_TYPE) { case PCIEM_TYPE_ENDPOINT: printf("endpoint"); break; case PCIEM_TYPE_LEGACY_ENDPOINT: printf("legacy endpoint"); break; case PCIEM_TYPE_ROOT_PORT: printf("root port"); break; case PCIEM_TYPE_UPSTREAM_PORT: printf("upstream port"); break; case PCIEM_TYPE_DOWNSTREAM_PORT: printf("downstream port"); break; case PCIEM_TYPE_PCI_BRIDGE: printf("PCI bridge"); break; case PCIEM_TYPE_PCIE_BRIDGE: printf("PCI to PCIe bridge"); break; case PCIEM_TYPE_ROOT_INT_EP: printf("root endpoint"); break; case PCIEM_TYPE_ROOT_EC: printf("event collector"); break; default: printf("type %d", (flags & PCIEM_FLAGS_TYPE) >> 4); break; } if (flags & PCIEM_FLAGS_IRQ) printf(" MSI %d", (flags & PCIEM_FLAGS_IRQ) >> 9); cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP, 4); ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2); printf(" max data %d(%d)", MAX_PAYLOAD((ctl & PCIEM_CTL_MAX_PAYLOAD) >> 5), MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD)); if ((cap & PCIEM_CAP_FLR) != 0) printf(" FLR"); if (ctl & PCIEM_CTL_RELAXED_ORD_ENABLE) printf(" RO"); if (ctl & PCIEM_CTL_NOSNOOP_ENABLE) printf(" NS"); if (version >= 2) { cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP2, 4); if ((cap & PCIEM_CAP2_ARI) != 0) { ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL2, 4); printf(" ARI %s", (ctl & PCIEM_CTL2_ARI) ? "enabled" : "disabled"); } } cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4); sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2); if (cap == 0 && sta == 0) return; printf("\n "); printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4, (cap & PCIEM_LINK_CAP_MAX_WIDTH) >> 4); if ((cap & PCIEM_LINK_CAP_MAX_WIDTH) != 0) { printf(" speed %s(%s)", (sta & PCIEM_LINK_STA_WIDTH) == 0 ? "0.0" : link_speed_string(sta & PCIEM_LINK_STA_SPEED), link_speed_string(cap & PCIEM_LINK_CAP_MAX_SPEED)); } if ((cap & PCIEM_LINK_CAP_ASPM) != 0) { ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2); printf(" ASPM %s(%s)", aspm_string(ctl & PCIEM_LINK_CTL_ASPMC), aspm_string((cap & PCIEM_LINK_CAP_ASPM) >> 10)); } if ((cap & PCIEM_LINK_CAP_CLOCK_PM) != 0) { ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2); printf(" ClockPM %s", (ctl & PCIEM_LINK_CTL_ECPM) ? "enabled" : "disabled"); } if (!(flags & PCIEM_FLAGS_SLOT)) return; cap = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CAP, 4); sta = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_STA, 2); ctl = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CTL, 2); printf("\n "); printf(" slot %d", (cap & PCIEM_SLOT_CAP_PSN) >> 19); printf(" power limit %d mW", slot_power(cap)); if (cap & PCIEM_SLOT_CAP_HPC) printf(" HotPlug(%s)", sta & PCIEM_SLOT_STA_PDS ? "present" : "empty"); if (cap & PCIEM_SLOT_CAP_HPS) printf(" surprise"); if (cap & PCIEM_SLOT_CAP_APB) printf(" Attn Button"); if (cap & PCIEM_SLOT_CAP_PCP) printf(" PC(%s)", ctl & PCIEM_SLOT_CTL_PCC ? "off" : "on"); if (cap & PCIEM_SLOT_CAP_MRLSP) printf(" MRL(%s)", sta & PCIEM_SLOT_STA_MRLSS ? "open" : "closed"); if (cap & PCIEM_SLOT_CAP_EIP) printf(" EI(%s)", sta & PCIEM_SLOT_STA_EIS ? "engaged" : "disengaged"); } static void cap_msix(int fd, struct pci_conf *p, uint8_t ptr) { uint32_t pba_offset, table_offset, val; int msgnum, pba_bar, table_bar; uint16_t ctrl; ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); table_offset = val & ~PCIM_MSIX_BIR_MASK; val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); pba_offset = val & ~PCIM_MSIX_BIR_MASK; printf("MSI-X supports %d message%s%s\n", msgnum, (msgnum == 1) ? "" : "s", (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) ? ", enabled" : ""); printf(" "); printf("Table in map 0x%x[0x%x], PBA in map 0x%x[0x%x]", table_bar, table_offset, pba_bar, pba_offset); } static void cap_sata(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused) { printf("SATA Index-Data Pair"); } static void cap_pciaf(int fd, struct pci_conf *p, uint8_t ptr) { uint8_t cap; cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1); printf("PCI Advanced Features:%s%s", cap & PCIM_PCIAFCAP_FLR ? " FLR" : "", cap & PCIM_PCIAFCAP_TP ? " TP" : ""); } static const char * ea_bei_to_name(int bei) { static const char *barstr[] = { "BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5" }; static const char *vfbarstr[] = { "VFBAR0", "VFBAR1", "VFBAR2", "VFBAR3", "VFBAR4", "VFBAR5" }; if ((bei >= PCIM_EA_BEI_BAR_0) && (bei <= PCIM_EA_BEI_BAR_5)) return (barstr[bei - PCIM_EA_BEI_BAR_0]); if ((bei >= PCIM_EA_BEI_VF_BAR_0) && (bei <= PCIM_EA_BEI_VF_BAR_5)) return (vfbarstr[bei - PCIM_EA_BEI_VF_BAR_0]); switch (bei) { case PCIM_EA_BEI_BRIDGE: return "BRIDGE"; case PCIM_EA_BEI_ENI: return "ENI"; case PCIM_EA_BEI_ROM: return "ROM"; case PCIM_EA_BEI_RESERVED: default: return "RSVD"; } } static const char * ea_prop_to_name(uint8_t prop) { switch (prop) { case PCIM_EA_P_MEM: return "Non-Prefetchable Memory"; case PCIM_EA_P_MEM_PREFETCH: return "Prefetchable Memory"; case PCIM_EA_P_IO: return "I/O Space"; case PCIM_EA_P_VF_MEM_PREFETCH: return "VF Prefetchable Memory"; case PCIM_EA_P_VF_MEM: return "VF Non-Prefetchable Memory"; case PCIM_EA_P_BRIDGE_MEM: return "Bridge Non-Prefetchable Memory"; case PCIM_EA_P_BRIDGE_MEM_PREFETCH: return "Bridge Prefetchable Memory"; case PCIM_EA_P_BRIDGE_IO: return "Bridge I/O Space"; case PCIM_EA_P_MEM_RESERVED: return "Reserved Memory"; case PCIM_EA_P_IO_RESERVED: return "Reserved I/O Space"; case PCIM_EA_P_UNAVAILABLE: return "Unavailable"; default: return "Reserved"; } } static void cap_ea(int fd, struct pci_conf *p, uint8_t ptr) { int num_ent; int a, b; uint32_t bei; uint32_t val; int ent_size; uint32_t dw[4]; uint32_t flags, flags_pp, flags_sp; uint64_t base, max_offset; uint8_t fixed_sub_bus_nr, fixed_sec_bus_nr; /* Determine the number of entries */ num_ent = read_config(fd, &p->pc_sel, ptr + PCIR_EA_NUM_ENT, 2); num_ent &= PCIM_EA_NUM_ENT_MASK; printf("PCI Enhanced Allocation (%d entries)", num_ent); /* Find the first entry to care of */ ptr += PCIR_EA_FIRST_ENT; /* Print BUS numbers for bridges */ if ((p->pc_hdr & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) { val = read_config(fd, &p->pc_sel, ptr, 4); fixed_sec_bus_nr = PCIM_EA_SEC_NR(val); fixed_sub_bus_nr = PCIM_EA_SUB_NR(val); printf("\n\t\t BRIDGE, sec bus [%d], sub bus [%d]", fixed_sec_bus_nr, fixed_sub_bus_nr); ptr += 4; } for (a = 0; a < num_ent; a++) { /* Read a number of dwords in the entry */ val = read_config(fd, &p->pc_sel, ptr, 4); ptr += 4; ent_size = (val & PCIM_EA_ES); for (b = 0; b < ent_size; b++) { dw[b] = read_config(fd, &p->pc_sel, ptr, 4); ptr += 4; } flags = val; flags_pp = (flags & PCIM_EA_PP) >> PCIM_EA_PP_OFFSET; flags_sp = (flags & PCIM_EA_SP) >> PCIM_EA_SP_OFFSET; bei = (PCIM_EA_BEI & val) >> PCIM_EA_BEI_OFFSET; base = dw[0] & PCIM_EA_FIELD_MASK; max_offset = dw[1] | ~PCIM_EA_FIELD_MASK; b = 2; if (((dw[0] & PCIM_EA_IS_64) != 0) && (b < ent_size)) { base |= (uint64_t)dw[b] << 32UL; b++; } if (((dw[1] & PCIM_EA_IS_64) != 0) && (b < ent_size)) { max_offset |= (uint64_t)dw[b] << 32UL; b++; } printf("\n\t\t [%d] %s, %s, %s, base [0x%jx], size [0x%jx]" "\n\t\t\tPrimary properties [0x%x] (%s)" "\n\t\t\tSecondary properties [0x%x] (%s)", bei, ea_bei_to_name(bei), (flags & PCIM_EA_ENABLE ? "Enabled" : "Disabled"), (flags & PCIM_EA_WRITABLE ? "Writable" : "Read-only"), (uintmax_t)base, (uintmax_t)(max_offset + 1), flags_pp, ea_prop_to_name(flags_pp), flags_sp, ea_prop_to_name(flags_sp)); } } void -list_caps(int fd, struct pci_conf *p) +list_caps(int fd, struct pci_conf *p, int level) { int express; uint16_t sta; uint8_t ptr, cap; /* Are capabilities present for this device? */ sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); if (!(sta & PCIM_STATUS_CAPPRESENT)) return; + cap_level = level; + switch (p->pc_hdr & PCIM_HDRTYPE) { case PCIM_HDRTYPE_NORMAL: case PCIM_HDRTYPE_BRIDGE: ptr = PCIR_CAP_PTR; break; case PCIM_HDRTYPE_CARDBUS: ptr = PCIR_CAP_PTR_2; break; default: errx(1, "list_caps: bad header type"); } /* Walk the capability list. */ express = 0; ptr = read_config(fd, &p->pc_sel, ptr, 1); while (ptr != 0 && ptr != 0xff) { cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); printf(" cap %02x[%02x] = ", cap, ptr); switch (cap) { case PCIY_PMG: cap_power(fd, p, ptr); break; case PCIY_AGP: cap_agp(fd, p, ptr); break; case PCIY_VPD: cap_vpd(fd, p, ptr); break; case PCIY_MSI: cap_msi(fd, p, ptr); break; case PCIY_PCIX: cap_pcix(fd, p, ptr); break; case PCIY_HT: cap_ht(fd, p, ptr); break; case PCIY_VENDOR: cap_vendor(fd, p, ptr); break; case PCIY_DEBUG: cap_debug(fd, p, ptr); break; case PCIY_SUBVENDOR: cap_subvendor(fd, p, ptr); break; case PCIY_EXPRESS: express = 1; cap_express(fd, p, ptr); break; case PCIY_MSIX: cap_msix(fd, p, ptr); break; case PCIY_SATA: cap_sata(fd, p, ptr); break; case PCIY_PCIAF: cap_pciaf(fd, p, ptr); break; case PCIY_EA: cap_ea(fd, p, ptr); break; default: printf("unknown"); break; } printf("\n"); ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); } if (express) list_ecaps(fd, p); } /* From . */ static __inline uint32_t bitcount32(uint32_t x) { x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); x = (x + (x >> 4)) & 0x0f0f0f0f; x = (x + (x >> 8)); x = (x + (x >> 16)) & 0x000000ff; return (x); } static void ecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) { uint32_t sta, mask; printf("AER %d", ver); if (ver < 1) return; sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4); mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4); printf(" %d fatal", bitcount32(sta & mask)); printf(" %d non-fatal", bitcount32(sta & ~mask)); sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4); printf(" %d corrected\n", bitcount32(sta)); } static void ecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) { uint32_t cap1; printf("VC %d", ver); if (ver < 1) return; cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4); printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT); if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0) printf(" lowpri VC0-VC%d", (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4); printf("\n"); } static void ecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) { uint32_t high, low; printf("Serial %d", ver); if (ver < 1) return; low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4); high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4); printf(" %08x%08x\n", high, low); } static void ecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) { - uint32_t val; + uint32_t val, hdr; + uint16_t nextptr, len; + int i; - printf("Vendor %d", ver); - if (ver < 1) + val = read_config(fd, &p->pc_sel, ptr, 4); + nextptr = PCI_EXTCAP_NEXTPTR(val); + hdr = read_config(fd, &p->pc_sel, ptr + PCIR_VSEC_HEADER, 4); + len = PCIR_VSEC_LENGTH(hdr); + if (len == 0) { + if (nextptr == 0) + nextptr = 0x1000; + len = nextptr - ptr; + } + + printf("Vendor [%d] ID %04x Rev %d Length %d\n", ver, + PCIR_VSEC_ID(hdr), PCIR_VSEC_REV(hdr), len); + if ((ver < 1) || (cap_level <= 1)) return; - val = read_config(fd, &p->pc_sel, ptr + 4, 4); - printf(" ID %d\n", val & 0xffff); + for (i = 0; i < len; i += 4) { + val = read_config(fd, &p->pc_sel, ptr + PCIR_VSEC_DATA + i, 4); + if ((i % 16) == 0) + printf(" "); + printf("%02x %02x %02x %02x ", val & 0xff, (val >> 8) & 0xff, + (val >> 16) & 0xff, (val >> 24) & 0xff); + if ((((i + 4) % 16) == 0 ) || ((i + 4) >= len)) + printf("\n"); + } } static void ecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) { uint32_t val; printf("PCIe Sec %d", ver); if (ver < 1) return; val = read_config(fd, &p->pc_sel, ptr + 8, 4); printf(" lane errors %#x\n", val); } static const char * check_enabled(int value) { return (value ? "enabled" : "disabled"); } static void ecap_sriov(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) { const char *comma, *enabled; uint16_t iov_ctl, total_vfs, num_vfs, vf_offset, vf_stride, vf_did; uint32_t page_caps, page_size, page_shift, size; int i; printf("SR-IOV %d ", ver); iov_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_CTL, 2); printf("IOV %s, Memory Space %s, ARI %s\n", check_enabled(iov_ctl & PCIM_SRIOV_VF_EN), check_enabled(iov_ctl & PCIM_SRIOV_VF_MSE), check_enabled(iov_ctl & PCIM_SRIOV_ARI_EN)); total_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_TOTAL_VFS, 2); num_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_NUM_VFS, 2); printf(" "); printf("%d VFs configured out of %d supported\n", num_vfs, total_vfs); vf_offset = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_OFF, 2); vf_stride = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_STRIDE, 2); printf(" "); printf("First VF RID Offset 0x%04x, VF RID Stride 0x%04x\n", vf_offset, vf_stride); vf_did = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_DID, 2); printf(" VF Device ID 0x%04x\n", vf_did); page_caps = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_CAP, 4); page_size = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_SIZE, 4); printf(" "); printf("Page Sizes: "); comma = ""; while (page_caps != 0) { page_shift = ffs(page_caps) - 1; if (page_caps & page_size) enabled = " (enabled)"; else enabled = ""; size = (1 << (page_shift + PCI_SRIOV_BASE_PAGE_SHIFT)); printf("%s%d%s", comma, size, enabled); comma = ", "; page_caps &= ~(1 << page_shift); } printf("\n"); for (i = 0; i <= PCIR_MAX_BAR_0; i++) print_bar(fd, p, "iov bar ", ptr + PCIR_SRIOV_BAR(i)); } static struct { uint16_t id; const char *name; } ecap_names[] = { { PCIZ_PWRBDGT, "Power Budgeting" }, { PCIZ_RCLINK_DCL, "Root Complex Link Declaration" }, { PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" }, { PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" }, { PCIZ_MFVC, "MFVC" }, { PCIZ_RCRB, "RCRB" }, { PCIZ_ACS, "ACS" }, { PCIZ_ARI, "ARI" }, { PCIZ_ATS, "ATS" }, { PCIZ_MULTICAST, "Multicast" }, { PCIZ_RESIZE_BAR, "Resizable BAR" }, { PCIZ_DPA, "DPA" }, { PCIZ_TPH_REQ, "TPH Requester" }, { PCIZ_LTR, "LTR" }, { 0, NULL } }; static void list_ecaps(int fd, struct pci_conf *p) { const char *name; uint32_t ecap; uint16_t ptr; int i; ptr = PCIR_EXTCAP; ecap = read_config(fd, &p->pc_sel, ptr, 4); if (ecap == 0xffffffff || ecap == 0) return; for (;;) { printf(" ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr); switch (PCI_EXTCAP_ID(ecap)) { case PCIZ_AER: ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap)); break; case PCIZ_VC: ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap)); break; case PCIZ_SERNUM: ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap)); break; case PCIZ_VENDOR: ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap)); break; case PCIZ_SEC_PCIE: ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap)); break; case PCIZ_SRIOV: ecap_sriov(fd, p, ptr, PCI_EXTCAP_VER(ecap)); break; default: name = "unknown"; for (i = 0; ecap_names[i].name != NULL; i++) if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) { name = ecap_names[i].name; break; } printf("%s %d\n", name, PCI_EXTCAP_VER(ecap)); break; } ptr = PCI_EXTCAP_NEXTPTR(ecap); if (ptr == 0) break; ecap = read_config(fd, &p->pc_sel, ptr, 4); } } /* Find offset of a specific capability. Returns 0 on failure. */ uint8_t pci_find_cap(int fd, struct pci_conf *p, uint8_t id) { uint16_t sta; uint8_t ptr, cap; /* Are capabilities present for this device? */ sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); if (!(sta & PCIM_STATUS_CAPPRESENT)) return (0); switch (p->pc_hdr & PCIM_HDRTYPE) { case PCIM_HDRTYPE_NORMAL: case PCIM_HDRTYPE_BRIDGE: ptr = PCIR_CAP_PTR; break; case PCIM_HDRTYPE_CARDBUS: ptr = PCIR_CAP_PTR_2; break; default: return (0); } ptr = read_config(fd, &p->pc_sel, ptr, 1); while (ptr != 0 && ptr != 0xff) { cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); if (cap == id) return (ptr); ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); } return (0); } /* Find offset of a specific extended capability. Returns 0 on failure. */ uint16_t pcie_find_cap(int fd, struct pci_conf *p, uint16_t id) { uint32_t ecap; uint16_t ptr; ptr = PCIR_EXTCAP; ecap = read_config(fd, &p->pc_sel, ptr, 4); if (ecap == 0xffffffff || ecap == 0) return (0); for (;;) { if (PCI_EXTCAP_ID(ecap) == id) return (ptr); ptr = PCI_EXTCAP_NEXTPTR(ecap); if (ptr == 0) break; ecap = read_config(fd, &p->pc_sel, ptr, 4); } return (0); } Index: head/usr.sbin/pciconf/pciconf.8 =================================================================== --- head/usr.sbin/pciconf/pciconf.8 (revision 355740) +++ head/usr.sbin/pciconf/pciconf.8 (revision 355741) @@ -1,398 +1,401 @@ .\" Copyright (c) 1997 .\" Stefan Esser . All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd June 14, 2018 .Dt PCICONF 8 .Os .Sh NAME .Nm pciconf .Nd diagnostic utility for the PCI bus .Sh SYNOPSIS .Nm .Fl l Oo Fl BbceVv Oc Op Ar device .Nm .Fl a Ar device .Nm .Fl r Oo Fl b | h Oc Ar device addr Ns Op : Ns Ar addr2 .Nm .Fl w Oo Fl b | h Oc Ar device addr value .Nm .Fl D Oo Fl b | h | x Oc Ar device addr Op start Ns Op : Ns Ar count .Sh DESCRIPTION The .Nm utility provides a command line interface to functionality provided by the .Xr pci 4 .Xr ioctl 2 interface. As such, some of the functions are only available to users with write access to .Pa /dev/pci , normally only the super-user. .Pp With the .Fl l option, .Nm lists PCI devices in the following format: .Bd -literal foo0@pci0:0:4:0: class=0x010000 rev=0x01 hdr=0x00 vendor=0x1000 device=0x000f \ subvendor=0x0000 subdevice=0x0000 bar0@pci0:0:5:0: class=0x000100 rev=0x00 hdr=0x00 vendor=0x88c1 device=0x5333 \ subvendor=0x0000 subdevice=0x0000 none0@pci0:0:6:0: class=0x020000 rev=0x00 hdr=0x00 vendor=0x10ec device=0x8029 \ subvendor=0x0000 subdevice=0x0000 .Ed .Pp The first column gives the driver name, unit number, and selector. If there is no driver attached to the .Tn PCI device in question, the driver name will be .Dq none . Unit numbers for detached devices start at zero and are incremented for each detached device that is encountered. The selector is in a form which may directly be used for the other forms of the command. The second column is the class code, with the class byte printed as two hex digits, followed by the sub-class and the interface bytes. The third column prints the device's revision. The fourth column describes the header type. .Pp Currently assigned header types include 0 for standard devices, 1 for .Tn PCI to .Tn PCI bridges, and 2 for .Tn PCI to .Tn CardBus bridges. If the most significant bit of the header type register is set for function 0 of a .Tn PCI device, it is a .Em multi-function device, which contains several (similar or independent) functions on one chip. .Pp The sixth and seventh columns contain the vendor ID and the device ID of the device. The eigth and ninth columns contain subvendor and subdevice IDs, introduced in revision 2.1 of the .Tn PCI standard. Note that they will be 0 for older cards. .Pp If the .Fl B option is supplied, .Nm will list additional information for .Tn PCI to .Tn PCI and .Tn PCI to .Tn CardBus bridges, specifically the resource ranges decoded by the bridge for use by devices behind the bridge. Each bridge lists a range of bus numbers handled by the bridge and its downstream devices. Memory and I/O port decoding windows are enumerated via a line in the following format: .Bd -literal window[1c] = type I/O Port, range 16, addr 0x5000-0x8fff, enabled .Ed .Pp The first value after the .Dq Li window prefix in the square brackets is the offset of the decoding window in config space in hexadecimal. The type of a window is one of .Dq Memory , .Dq Prefetchable Memory , or .Dq I/O Port . The range indicates the binary log of the maximum address the window decodes. The address field indicates the start and end addresses of the decoded range. Finally, the last flag indicates if the window is enabled or disabled. .Pp If the .Fl b option is supplied, .Nm will list any base address registers .Pq BARs that are assigned resources for each device. Each BAR will be enumerated via a line in the following format: .Bd -literal bar [10] = type Memory, range 32, base 0xda060000, size 131072, enabled .Ed .Pp The first value after the .Dq Li bar prefix in the square brackets is the offset of the BAR in config space in hexadecimal. The type of a BAR is one of .Dq Memory , .Dq Prefetchable Memory , or .Dq I/O Port . The range indicates the binary log of the maximum address the BAR decodes. The base and size indicate the start and length of the BAR's address window, respectively. Finally, the last flag indicates if the BAR is enabled or disabled. .Pp If the .Fl c option is supplied, .Nm will list any capabilities supported by each device. +A second invocation of +.Fl c +will print additional data for certain capabilities. Each capability is enumerated via a line in the following format: .Bd -literal cap 10[40] = PCI-Express 1 root port .Ed .Pp The first value after the .Dq Li cap prefix is the capability ID in hexadecimal. The second value in the square brackets is the offset of the capability in config space in hexadecimal. The format of the text after the equals sign is capability-specific. .Pp Each extended capability is enumerated via a line in a similar format: .Bd -literal ecap 0002[100] = VC 1 max VC0 .Ed .Pp The first value after the .Dq Li ecap prefix is the extended capability ID in hexadecimal. The second value in the square brackets is the offset of the extended capability in config space in hexadecimal. The format of the text after the equals sign is capability-specific. .Pp If the .Fl e option is supplied, .Nm will list any errors reported for this device in standard PCI error registers. Errors are checked for in the PCI status register, the PCI-express device status register, and the Advanced Error Reporting status registers. .Pp If the .Fl v option is supplied, .Nm will attempt to load the vendor/device information database, and print vendor, device, class and subclass identification strings for each device. .Pp If the .Fl V option is supplied, .Nm will list any vital product data .Pq VPD provided by each device. Each VPD keyword is enumerated via a line in the following format: .Bd -literal VPD ro PN = '110114640C0 ' .Ed .Pp The first string after the .Dq Li VPD prefix indicates if the keyword is read-only .Dq ro or read-write .Dq rw . The second string provides the keyword name. The text after the equals sign lists the value of the keyword which is usually an ASCII string. .Pp If the optional .Ar device argument is given with the .Fl l flag, .Nm will only list details about a single device instead of all devices. .Pp All invocations of .Nm except for .Fl l require a .Ar device . The device can be identified either by a device name if the device is attached to a driver or by a selector. Selectors identify a PCI device by its address in PCI config space and can take one of the following forms: .Pp .Bl -bullet -offset indent -compact .It .Li pci Ns Va domain Ns \&: Ns Va bus Ns \&: Ns Va device Ns \&: \ Ns Va function Ns .It .Li pci Ns Va bus Ns \&: Ns Va device Ns \&: Ns Va function Ns .It .Li pci Ns Va bus Ns \&: Ns Va device Ns .El .Pp In the case of an abridged form, omitted selector components are assumed to be 0. An optional leading device name followed by @ and an optional final colon will be ignored; this is so that the first column in the output of .Nm .Fl l can be used without modification. All numbers are base 10. .Pp With the .Fl a flag, .Nm determines whether any driver has been assigned to the device identified by .Ar selector . An exit status of zero indicates that the device has a driver; non-zero indicates that it does not. .Pp The .Fl r option reads a configuration space register at byte offset .Ar addr of device .Ar selector and prints out its value in hexadecimal. The optional second address .Ar addr2 specifies a range to read. The .Fl w option writes the .Ar value into a configuration space register at byte offset .Ar addr of device .Ar selector . .Pp The .Fl D option request a dump of the specified BAR. Dump is performed to the standard output, raw register values are written. Use .Xr hexdump 1 to convert them to human-readable dump, or redirect into a file to save the snapshot of the device state. Optionally, the .Ar start and .Ar count of the registers dumped can be specified, in multiple of the operation width, see next paragraph. .Pp For read, write, and dump operations, the flags .Fl b , .Fl h , and .Fl x select the width of the operation; .Fl b indicates a byte operation, and .Fl h indicates a halfword (two-byte) operation. .Fl x indicates a quadword (four-byte) operation. The default is to read or write a longword (four bytes). The quadword mode is only valid for BAR dump. .Sh ENVIRONMENT PCI vendor and device information is read from .Pa /usr/local/share/pciids/pci.ids . If that file is not present, it is read from .Pa /usr/share/misc/pci_vendors . This path can be overridden by setting the environment variable .Ev PCICONF_VENDOR_DATABASE . .Sh SEE ALSO .Xr ioctl 2 , .\" .Xr pci 4 , .Xr devinfo 8 , .Xr kldload 8 .Sh HISTORY The .Nm utility appeared first in .Fx 2.2 . The .Fl a option was added for .Tn PCI KLD support in .Fx 3.0 . .Sh AUTHORS .An -nosplit The .Nm utility was written by .An Stefan Esser and .An Garrett Wollman . .Sh BUGS The .Fl b and .Fl h options are implemented in .Nm , but not in the underlying .Xr ioctl 2 . .Pp It might be useful to give non-root users access to the .Fl a and .Fl r options. But only root will be able to execute a .Nm kldload to provide the device with a driver KLD, and reading of configuration space registers may cause a failure in badly designed .Tn PCI chips. .Pp There is currently no way to specify the caching mode for the mapping established by the .Fl D option, .Nm always uses uncached access. This is fine for control register BARs. Index: head/usr.sbin/pciconf/pciconf.c =================================================================== --- head/usr.sbin/pciconf/pciconf.c (revision 355740) +++ head/usr.sbin/pciconf/pciconf.c (revision 355741) @@ -1,1167 +1,1167 @@ /* * Copyright 1996 Massachusetts Institute of Technology * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby * granted, provided that both the above copyright notice and this * permission notice appear in all copies, that both the above * copyright notice and this permission notice appear in all * supporting documentation, and that the name of M.I.T. not be used * in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. M.I.T. makes * no representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied * warranty. * * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" #include "pciconf.h" struct pci_device_info { TAILQ_ENTRY(pci_device_info) link; int id; char *desc; }; struct pci_vendor_info { TAILQ_ENTRY(pci_vendor_info) link; TAILQ_HEAD(,pci_device_info) devs; int id; char *desc; }; static TAILQ_HEAD(,pci_vendor_info) pci_vendors; static struct pcisel getsel(const char *str); static void list_bridge(int fd, struct pci_conf *p); static void list_bars(int fd, struct pci_conf *p); static void list_devs(const char *name, int verbose, int bars, int bridge, int caps, int errors, int vpd); static void list_verbose(struct pci_conf *p); static void list_vpd(int fd, struct pci_conf *p); static const char *guess_class(struct pci_conf *p); static const char *guess_subclass(struct pci_conf *p); static int load_vendors(void); static void readit(const char *, const char *, int); static void writeit(const char *, const char *, const char *, int); static void chkattached(const char *); static void dump_bar(const char *name, const char *reg, const char *bar_start, const char *bar_count, int width, int verbose); static int exitstatus = 0; static void usage(void) { fprintf(stderr, "%s", "usage: pciconf -l [-BbcevV] [device]\n" " pciconf -a device\n" " pciconf -r [-b | -h] device addr[:addr2]\n" " pciconf -w [-b | -h] device addr value\n" " pciconf -D [-b | -h | -x] device bar [start [count]]" "\n"); exit(1); } int main(int argc, char **argv) { int c, width; int listmode, readmode, writemode, attachedmode, dumpbarmode; int bars, bridge, caps, errors, verbose, vpd; listmode = readmode = writemode = attachedmode = dumpbarmode = 0; bars = bridge = caps = errors = verbose = vpd= 0; width = 4; while ((c = getopt(argc, argv, "aBbcDehlrwVv")) != -1) { switch(c) { case 'a': attachedmode = 1; break; case 'B': bridge = 1; break; case 'b': bars = 1; width = 1; break; case 'c': - caps = 1; + caps++; break; case 'D': dumpbarmode = 1; break; case 'e': errors = 1; break; case 'h': width = 2; break; case 'l': listmode = 1; break; case 'r': readmode = 1; break; case 'w': writemode = 1; break; case 'v': verbose = 1; break; case 'V': vpd = 1; break; case 'x': width = 8; break; default: usage(); } } if ((listmode && optind >= argc + 1) || (writemode && optind + 3 != argc) || (readmode && optind + 2 != argc) || (attachedmode && optind + 1 != argc) || (dumpbarmode && (optind + 2 > argc || optind + 4 < argc)) || (width == 8 && !dumpbarmode)) usage(); if (listmode) { list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose, bars, bridge, caps, errors, vpd); } else if (attachedmode) { chkattached(argv[optind]); } else if (readmode) { readit(argv[optind], argv[optind + 1], width); } else if (writemode) { writeit(argv[optind], argv[optind + 1], argv[optind + 2], width); } else if (dumpbarmode) { dump_bar(argv[optind], argv[optind + 1], optind + 2 < argc ? argv[optind + 2] : NULL, optind + 3 < argc ? argv[optind + 3] : NULL, width, verbose); } else { usage(); } return (exitstatus); } static void list_devs(const char *name, int verbose, int bars, int bridge, int caps, int errors, int vpd) { int fd; struct pci_conf_io pc; struct pci_conf conf[255], *p; struct pci_match_conf patterns[1]; int none_count = 0; if (verbose) load_vendors(); fd = open(_PATH_DEVPCI, (bridge || caps || errors) ? O_RDWR : O_RDONLY, 0); if (fd < 0) err(1, "%s", _PATH_DEVPCI); bzero(&pc, sizeof(struct pci_conf_io)); pc.match_buf_len = sizeof(conf); pc.matches = conf; if (name != NULL) { bzero(&patterns, sizeof(patterns)); patterns[0].pc_sel = getsel(name); patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; pc.num_patterns = 1; pc.pat_buf_len = sizeof(patterns); pc.patterns = patterns; } do { if (ioctl(fd, PCIOCGETCONF, &pc) == -1) err(1, "ioctl(PCIOCGETCONF)"); /* * 255 entries should be more than enough for most people, * but if someone has more devices, and then changes things * around between ioctls, we'll do the cheesy thing and * just bail. The alternative would be to go back to the * beginning of the list, and print things twice, which may * not be desirable. */ if (pc.status == PCI_GETCONF_LIST_CHANGED) { warnx("PCI device list changed, please try again"); exitstatus = 1; close(fd); return; } else if (pc.status == PCI_GETCONF_ERROR) { warnx("error returned from PCIOCGETCONF ioctl"); exitstatus = 1; close(fd); return; } for (p = conf; p < &conf[pc.num_matches]; p++) { printf("%s%d@pci%d:%d:%d:%d:" "\tclass=0x%06x rev=0x%02x hdr=0x%02x " "vendor=0x%04x device=0x%04x " "subvendor=0x%04x subdevice=0x%04x\n", *p->pd_name ? p->pd_name : "none", *p->pd_name ? (int)p->pd_unit : none_count++, p->pc_sel.pc_domain, p->pc_sel.pc_bus, p->pc_sel.pc_dev, p->pc_sel.pc_func, (p->pc_class << 16) | (p->pc_subclass << 8) | p->pc_progif, p->pc_revid, p->pc_hdr, p->pc_vendor, p->pc_device, p->pc_subvendor, p->pc_subdevice); if (verbose) list_verbose(p); if (bars) list_bars(fd, p); if (bridge) list_bridge(fd, p); if (caps) - list_caps(fd, p); + list_caps(fd, p, caps); if (errors) list_errors(fd, p); if (vpd) list_vpd(fd, p); } } while (pc.status == PCI_GETCONF_MORE_DEVS); close(fd); } static void print_bus_range(int fd, struct pci_conf *p, int secreg, int subreg) { uint8_t secbus, subbus; secbus = read_config(fd, &p->pc_sel, secreg, 1); subbus = read_config(fd, &p->pc_sel, subreg, 1); printf(" bus range = %u-%u\n", secbus, subbus); } static void print_window(int reg, const char *type, int range, uint64_t base, uint64_t limit) { printf(" window[%02x] = type %s, range %2d, addr %#jx-%#jx, %s\n", reg, type, range, (uintmax_t)base, (uintmax_t)limit, base < limit ? "enabled" : "disabled"); } static void print_special_decode(bool isa, bool vga, bool subtractive) { bool comma; if (isa || vga || subtractive) { comma = false; printf(" decode = "); if (isa) { printf("ISA"); comma = true; } if (vga) { printf("%sVGA", comma ? ", " : ""); comma = true; } if (subtractive) printf("%ssubtractive", comma ? ", " : ""); printf("\n"); } } static void print_bridge_windows(int fd, struct pci_conf *p) { uint64_t base, limit; uint32_t val; uint16_t bctl; bool subtractive; int range; /* * XXX: This assumes that a window with a base and limit of 0 * is not implemented. In theory a window might be programmed * at the smallest size with a base of 0, but those do not seem * common in practice. */ val = read_config(fd, &p->pc_sel, PCIR_IOBASEL_1, 1); if (val != 0 || read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1) != 0) { if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { base = PCI_PPBIOBASE( read_config(fd, &p->pc_sel, PCIR_IOBASEH_1, 2), val); limit = PCI_PPBIOLIMIT( read_config(fd, &p->pc_sel, PCIR_IOLIMITH_1, 2), read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1)); range = 32; } else { base = PCI_PPBIOBASE(0, val); limit = PCI_PPBIOLIMIT(0, read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1)); range = 16; } print_window(PCIR_IOBASEL_1, "I/O Port", range, base, limit); } base = PCI_PPBMEMBASE(0, read_config(fd, &p->pc_sel, PCIR_MEMBASE_1, 2)); limit = PCI_PPBMEMLIMIT(0, read_config(fd, &p->pc_sel, PCIR_MEMLIMIT_1, 2)); print_window(PCIR_MEMBASE_1, "Memory", 32, base, limit); val = read_config(fd, &p->pc_sel, PCIR_PMBASEL_1, 2); if (val != 0 || read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2) != 0) { if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { base = PCI_PPBMEMBASE( read_config(fd, &p->pc_sel, PCIR_PMBASEH_1, 4), val); limit = PCI_PPBMEMLIMIT( read_config(fd, &p->pc_sel, PCIR_PMLIMITH_1, 4), read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2)); range = 64; } else { base = PCI_PPBMEMBASE(0, val); limit = PCI_PPBMEMLIMIT(0, read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2)); range = 32; } print_window(PCIR_PMBASEL_1, "Prefetchable Memory", range, base, limit); } /* * XXX: This list of bridges that are subtractive but do not set * progif to indicate it is copied from pci_pci.c. */ subtractive = p->pc_progif == PCIP_BRIDGE_PCI_SUBTRACTIVE; switch (p->pc_device << 16 | p->pc_vendor) { case 0xa002177d: /* Cavium ThunderX */ case 0x124b8086: /* Intel 82380FB Mobile */ case 0x060513d7: /* Toshiba ???? */ subtractive = true; } if (p->pc_vendor == 0x8086 && (p->pc_device & 0xff00) == 0x2400) subtractive = true; bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_1, 2); print_special_decode(bctl & PCIB_BCR_ISA_ENABLE, bctl & PCIB_BCR_VGA_ENABLE, subtractive); } static void print_cardbus_mem_window(int fd, struct pci_conf *p, int basereg, int limitreg, bool prefetch) { print_window(basereg, prefetch ? "Prefetchable Memory" : "Memory", 32, PCI_CBBMEMBASE(read_config(fd, &p->pc_sel, basereg, 4)), PCI_CBBMEMLIMIT(read_config(fd, &p->pc_sel, limitreg, 4))); } static void print_cardbus_io_window(int fd, struct pci_conf *p, int basereg, int limitreg) { uint32_t base, limit; uint32_t val; int range; val = read_config(fd, &p->pc_sel, basereg, 2); if ((val & PCIM_CBBIO_MASK) == PCIM_CBBIO_32) { base = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, basereg, 4)); limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 4)); range = 32; } else { base = PCI_CBBIOBASE(val); limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 2)); range = 16; } print_window(basereg, "I/O Port", range, base, limit); } static void print_cardbus_windows(int fd, struct pci_conf *p) { uint16_t bctl; bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_2, 2); print_cardbus_mem_window(fd, p, PCIR_MEMBASE0_2, PCIR_MEMLIMIT0_2, bctl & CBB_BCR_PREFETCH_0_ENABLE); print_cardbus_mem_window(fd, p, PCIR_MEMBASE1_2, PCIR_MEMLIMIT1_2, bctl & CBB_BCR_PREFETCH_1_ENABLE); print_cardbus_io_window(fd, p, PCIR_IOBASE0_2, PCIR_IOLIMIT0_2); print_cardbus_io_window(fd, p, PCIR_IOBASE1_2, PCIR_IOLIMIT1_2); print_special_decode(bctl & CBB_BCR_ISA_ENABLE, bctl & CBB_BCR_VGA_ENABLE, false); } static void list_bridge(int fd, struct pci_conf *p) { switch (p->pc_hdr & PCIM_HDRTYPE) { case PCIM_HDRTYPE_BRIDGE: print_bus_range(fd, p, PCIR_SECBUS_1, PCIR_SUBBUS_1); print_bridge_windows(fd, p); break; case PCIM_HDRTYPE_CARDBUS: print_bus_range(fd, p, PCIR_SECBUS_2, PCIR_SUBBUS_2); print_cardbus_windows(fd, p); break; } } static void list_bars(int fd, struct pci_conf *p) { int i, max; switch (p->pc_hdr & PCIM_HDRTYPE) { case PCIM_HDRTYPE_NORMAL: max = PCIR_MAX_BAR_0; break; case PCIM_HDRTYPE_BRIDGE: max = PCIR_MAX_BAR_1; break; case PCIM_HDRTYPE_CARDBUS: max = PCIR_MAX_BAR_2; break; default: return; } for (i = 0; i <= max; i++) print_bar(fd, p, "bar ", PCIR_BAR(i)); } void print_bar(int fd, struct pci_conf *p, const char *label, uint16_t bar_offset) { uint64_t base; const char *type; struct pci_bar_io bar; int range; bar.pbi_sel = p->pc_sel; bar.pbi_reg = bar_offset; if (ioctl(fd, PCIOCGETBAR, &bar) < 0) return; if (PCI_BAR_IO(bar.pbi_base)) { type = "I/O Port"; range = 32; base = bar.pbi_base & PCIM_BAR_IO_BASE; } else { if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH) type = "Prefetchable Memory"; else type = "Memory"; switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) { case PCIM_BAR_MEM_32: range = 32; break; case PCIM_BAR_MEM_1MB: range = 20; break; case PCIM_BAR_MEM_64: range = 64; break; default: range = -1; } base = bar.pbi_base & ~((uint64_t)0xf); } printf(" %s[%02x] = type %s, range %2d, base %#jx, ", label, bar_offset, type, range, (uintmax_t)base); printf("size %ju, %s\n", (uintmax_t)bar.pbi_length, bar.pbi_enabled ? "enabled" : "disabled"); } static void list_verbose(struct pci_conf *p) { struct pci_vendor_info *vi; struct pci_device_info *di; const char *dp; TAILQ_FOREACH(vi, &pci_vendors, link) { if (vi->id == p->pc_vendor) { printf(" vendor = '%s'\n", vi->desc); break; } } if (vi == NULL) { di = NULL; } else { TAILQ_FOREACH(di, &vi->devs, link) { if (di->id == p->pc_device) { printf(" device = '%s'\n", di->desc); break; } } } if ((dp = guess_class(p)) != NULL) printf(" class = %s\n", dp); if ((dp = guess_subclass(p)) != NULL) printf(" subclass = %s\n", dp); } static void list_vpd(int fd, struct pci_conf *p) { struct pci_list_vpd_io list; struct pci_vpd_element *vpd, *end; list.plvi_sel = p->pc_sel; list.plvi_len = 0; list.plvi_data = NULL; if (ioctl(fd, PCIOCLISTVPD, &list) < 0 || list.plvi_len == 0) return; list.plvi_data = malloc(list.plvi_len); if (ioctl(fd, PCIOCLISTVPD, &list) < 0) { free(list.plvi_data); return; } vpd = list.plvi_data; end = (struct pci_vpd_element *)((char *)vpd + list.plvi_len); for (; vpd < end; vpd = PVE_NEXT(vpd)) { if (vpd->pve_flags == PVE_FLAG_IDENT) { printf(" VPD ident = '%.*s'\n", (int)vpd->pve_datalen, vpd->pve_data); continue; } /* Ignore the checksum keyword. */ if (!(vpd->pve_flags & PVE_FLAG_RW) && memcmp(vpd->pve_keyword, "RV", 2) == 0) continue; /* Ignore remaining read-write space. */ if (vpd->pve_flags & PVE_FLAG_RW && memcmp(vpd->pve_keyword, "RW", 2) == 0) continue; /* Handle extended capability keyword. */ if (!(vpd->pve_flags & PVE_FLAG_RW) && memcmp(vpd->pve_keyword, "CP", 2) == 0) { printf(" VPD ro CP = ID %02x in map 0x%x[0x%x]\n", (unsigned int)vpd->pve_data[0], PCIR_BAR((unsigned int)vpd->pve_data[1]), (unsigned int)vpd->pve_data[3] << 8 | (unsigned int)vpd->pve_data[2]); continue; } /* Remaining keywords should all have ASCII values. */ printf(" VPD %s %c%c = '%.*s'\n", vpd->pve_flags & PVE_FLAG_RW ? "rw" : "ro", vpd->pve_keyword[0], vpd->pve_keyword[1], (int)vpd->pve_datalen, vpd->pve_data); } free(list.plvi_data); } /* * This is a direct cut-and-paste from the table in sys/dev/pci/pci.c. */ static struct { int class; int subclass; const char *desc; } pci_nomatch_tab[] = { {PCIC_OLD, -1, "old"}, {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, {PCIC_STORAGE, -1, "mass storage"}, {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, {PCIC_STORAGE, PCIS_STORAGE_NVM, "NVM"}, {PCIC_NETWORK, -1, "network"}, {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, {PCIC_DISPLAY, -1, "display"}, {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, {PCIC_MULTIMEDIA, -1, "multimedia"}, {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, {PCIC_MEMORY, -1, "memory"}, {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, {PCIC_BRIDGE, -1, "bridge"}, {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, {PCIC_SIMPLECOMM, -1, "simple comms"}, {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, {PCIC_BASEPERIPH, -1, "base peripheral"}, {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, {PCIC_BASEPERIPH, PCIS_BASEPERIPH_IOMMU, "IOMMU"}, {PCIC_INPUTDEV, -1, "input device"}, {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, {PCIC_DOCKING, -1, "docking station"}, {PCIC_PROCESSOR, -1, "processor"}, {PCIC_SERIALBUS, -1, "serial bus"}, {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, {PCIC_WIRELESS, -1, "wireless controller"}, {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, {PCIC_SATCOM, -1, "satellite communication"}, {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, {PCIC_CRYPTO, -1, "encrypt/decrypt"}, {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "entertainment crypto"}, {PCIC_DASP, -1, "dasp"}, {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, {PCIC_DASP, PCIS_DASP_PERFCNTRS, "performance counters"}, {PCIC_DASP, PCIS_DASP_COMM_SYNC, "communication synchronizer"}, {PCIC_DASP, PCIS_DASP_MGMT_CARD, "signal processing management"}, {PCIC_ACCEL, -1, "processing accelerators"}, {PCIC_ACCEL, PCIS_ACCEL_PROCESSING, "processing accelerators"}, {PCIC_INSTRUMENT, -1, "non-essential instrumentation"}, {0, 0, NULL} }; static const char * guess_class(struct pci_conf *p) { int i; for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { if (pci_nomatch_tab[i].class == p->pc_class) return(pci_nomatch_tab[i].desc); } return(NULL); } static const char * guess_subclass(struct pci_conf *p) { int i; for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { if ((pci_nomatch_tab[i].class == p->pc_class) && (pci_nomatch_tab[i].subclass == p->pc_subclass)) return(pci_nomatch_tab[i].desc); } return(NULL); } static int load_vendors(void) { const char *dbf; FILE *db; struct pci_vendor_info *cv; struct pci_device_info *cd; char buf[1024], str[1024]; char *ch; int id, error; /* * Locate the database and initialise. */ TAILQ_INIT(&pci_vendors); if ((dbf = getenv("PCICONF_VENDOR_DATABASE")) == NULL) dbf = _PATH_LPCIVDB; if ((db = fopen(dbf, "r")) == NULL) { dbf = _PATH_PCIVDB; if ((db = fopen(dbf, "r")) == NULL) return(1); } cv = NULL; cd = NULL; error = 0; /* * Scan input lines from the database */ for (;;) { if (fgets(buf, sizeof(buf), db) == NULL) break; if ((ch = strchr(buf, '#')) != NULL) *ch = '\0'; ch = strchr(buf, '\0') - 1; while (ch > buf && isspace(*ch)) *ch-- = '\0'; if (ch <= buf) continue; /* Can't handle subvendor / subdevice entries yet */ if (buf[0] == '\t' && buf[1] == '\t') continue; /* Check for vendor entry */ if (buf[0] != '\t' && sscanf(buf, "%04x %[^\n]", &id, str) == 2) { if ((id == 0) || (strlen(str) < 1)) continue; if ((cv = malloc(sizeof(struct pci_vendor_info))) == NULL) { warn("allocating vendor entry"); error = 1; break; } if ((cv->desc = strdup(str)) == NULL) { free(cv); warn("allocating vendor description"); error = 1; break; } cv->id = id; TAILQ_INIT(&cv->devs); TAILQ_INSERT_TAIL(&pci_vendors, cv, link); continue; } /* Check for device entry */ if (buf[0] == '\t' && sscanf(buf + 1, "%04x %[^\n]", &id, str) == 2) { if ((id == 0) || (strlen(str) < 1)) continue; if (cv == NULL) { warnx("device entry with no vendor!"); continue; } if ((cd = malloc(sizeof(struct pci_device_info))) == NULL) { warn("allocating device entry"); error = 1; break; } if ((cd->desc = strdup(str)) == NULL) { free(cd); warn("allocating device description"); error = 1; break; } cd->id = id; TAILQ_INSERT_TAIL(&cv->devs, cd, link); continue; } /* It's a comment or junk, ignore it */ } if (ferror(db)) error = 1; fclose(db); return(error); } uint32_t read_config(int fd, struct pcisel *sel, long reg, int width) { struct pci_io pi; pi.pi_sel = *sel; pi.pi_reg = reg; pi.pi_width = width; if (ioctl(fd, PCIOCREAD, &pi) < 0) err(1, "ioctl(PCIOCREAD)"); return (pi.pi_data); } static struct pcisel getdevice(const char *name) { struct pci_conf_io pc; struct pci_conf conf[1]; struct pci_match_conf patterns[1]; char *cp; int fd; fd = open(_PATH_DEVPCI, O_RDONLY, 0); if (fd < 0) err(1, "%s", _PATH_DEVPCI); bzero(&pc, sizeof(struct pci_conf_io)); pc.match_buf_len = sizeof(conf); pc.matches = conf; bzero(&patterns, sizeof(patterns)); /* * The pattern structure requires the unit to be split out from * the driver name. Walk backwards from the end of the name to * find the start of the unit. */ if (name[0] == '\0') errx(1, "Empty device name"); cp = strchr(name, '\0'); assert(cp != NULL && cp != name); cp--; while (cp != name && isdigit(cp[-1])) cp--; if (cp == name || !isdigit(*cp)) errx(1, "Invalid device name"); if ((size_t)(cp - name) + 1 > sizeof(patterns[0].pd_name)) errx(1, "Device name is too long"); memcpy(patterns[0].pd_name, name, cp - name); patterns[0].pd_unit = strtol(cp, &cp, 10); if (*cp != '\0') errx(1, "Invalid device name"); patterns[0].flags = PCI_GETCONF_MATCH_NAME | PCI_GETCONF_MATCH_UNIT; pc.num_patterns = 1; pc.pat_buf_len = sizeof(patterns); pc.patterns = patterns; if (ioctl(fd, PCIOCGETCONF, &pc) == -1) err(1, "ioctl(PCIOCGETCONF)"); if (pc.status != PCI_GETCONF_LAST_DEVICE && pc.status != PCI_GETCONF_MORE_DEVS) errx(1, "error returned from PCIOCGETCONF ioctl"); close(fd); if (pc.num_matches == 0) errx(1, "Device not found"); return (conf[0].pc_sel); } static struct pcisel parsesel(const char *str) { const char *ep; char *eppos; struct pcisel sel; unsigned long selarr[4]; int i; ep = strchr(str, '@'); if (ep != NULL) ep++; else ep = str; if (strncmp(ep, "pci", 3) == 0) { ep += 3; i = 0; while (isdigit(*ep) && i < 4) { selarr[i++] = strtoul(ep, &eppos, 10); ep = eppos; if (*ep == ':') ep++; } if (i > 0 && *ep == '\0') { sel.pc_func = (i > 2) ? selarr[--i] : 0; sel.pc_dev = (i > 0) ? selarr[--i] : 0; sel.pc_bus = (i > 0) ? selarr[--i] : 0; sel.pc_domain = (i > 0) ? selarr[--i] : 0; return (sel); } } errx(1, "cannot parse selector %s", str); } static struct pcisel getsel(const char *str) { /* * No device names contain colons and selectors always contain * at least one colon. */ if (strchr(str, ':') == NULL) return (getdevice(str)); else return (parsesel(str)); } static void readone(int fd, struct pcisel *sel, long reg, int width) { printf("%0*x", width*2, read_config(fd, sel, reg, width)); } static void readit(const char *name, const char *reg, int width) { long rstart; long rend; long r; char *end; int i; int fd; struct pcisel sel; fd = open(_PATH_DEVPCI, O_RDWR, 0); if (fd < 0) err(1, "%s", _PATH_DEVPCI); rend = rstart = strtol(reg, &end, 0); if (end && *end == ':') { end++; rend = strtol(end, (char **) 0, 0); } sel = getsel(name); for (i = 1, r = rstart; r <= rend; i++, r += width) { readone(fd, &sel, r, width); if (i && !(i % 8)) putchar(' '); putchar(i % (16/width) ? ' ' : '\n'); } if (i % (16/width) != 1) putchar('\n'); close(fd); } static void writeit(const char *name, const char *reg, const char *data, int width) { int fd; struct pci_io pi; pi.pi_sel = getsel(name); pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ pi.pi_width = width; pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ fd = open(_PATH_DEVPCI, O_RDWR, 0); if (fd < 0) err(1, "%s", _PATH_DEVPCI); if (ioctl(fd, PCIOCWRITE, &pi) < 0) err(1, "ioctl(PCIOCWRITE)"); close(fd); } static void chkattached(const char *name) { int fd; struct pci_io pi; pi.pi_sel = getsel(name); fd = open(_PATH_DEVPCI, O_RDWR, 0); if (fd < 0) err(1, "%s", _PATH_DEVPCI); if (ioctl(fd, PCIOCATTACHED, &pi) < 0) err(1, "ioctl(PCIOCATTACHED)"); exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); close(fd); } static void dump_bar(const char *name, const char *reg, const char *bar_start, const char *bar_count, int width, int verbose) { struct pci_bar_mmap pbm; uint32_t *dd; uint16_t *dh; uint8_t *db; uint64_t *dx, a, start, count; char *el; size_t res; int fd; start = 0; if (bar_start != NULL) { start = strtoul(bar_start, &el, 0); if (*el != '\0') errx(1, "Invalid bar start specification %s", bar_start); } count = 0; if (bar_count != NULL) { count = strtoul(bar_count, &el, 0); if (*el != '\0') errx(1, "Invalid count specification %s", bar_count); } pbm.pbm_sel = getsel(name); pbm.pbm_reg = strtoul(reg, &el, 0); if (*reg == '\0' || *el != '\0') errx(1, "Invalid bar specification %s", reg); pbm.pbm_flags = 0; pbm.pbm_memattr = VM_MEMATTR_UNCACHEABLE; /* XXX */ fd = open(_PATH_DEVPCI, O_RDWR, 0); if (fd < 0) err(1, "%s", _PATH_DEVPCI); if (ioctl(fd, PCIOCBARMMAP, &pbm) < 0) err(1, "ioctl(PCIOCBARMMAP)"); if (count == 0) count = pbm.pbm_bar_length / width; if (start + count < start || (start + count) * width < (uint64_t)width) errx(1, "(start + count) x width overflow"); if ((start + count) * width > pbm.pbm_bar_length) { if (start * width > pbm.pbm_bar_length) count = 0; else count = (pbm.pbm_bar_length - start * width) / width; } if (verbose) { fprintf(stderr, "Dumping pci%d:%d:%d:%d BAR %x mapped base %p " "off %#x length %#jx from %#jx count %#jx in %d-bytes\n", pbm.pbm_sel.pc_domain, pbm.pbm_sel.pc_bus, pbm.pbm_sel.pc_dev, pbm.pbm_sel.pc_func, pbm.pbm_reg, pbm.pbm_map_base, pbm.pbm_bar_off, pbm.pbm_bar_length, start, count, width); } switch (width) { case 1: db = (uint8_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base + pbm.pbm_bar_off + start * width); for (a = 0; a < count; a += width, db++) { res = fwrite(db, width, 1, stdout); if (res != 1) { errx(1, "error writing to stdout"); break; } } break; case 2: dh = (uint16_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base + pbm.pbm_bar_off + start * width); for (a = 0; a < count; a += width, dh++) { res = fwrite(dh, width, 1, stdout); if (res != 1) { errx(1, "error writing to stdout"); break; } } break; case 4: dd = (uint32_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base + pbm.pbm_bar_off + start * width); for (a = 0; a < count; a += width, dd++) { res = fwrite(dd, width, 1, stdout); if (res != 1) { errx(1, "error writing to stdout"); break; } } break; case 8: dx = (uint64_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base + pbm.pbm_bar_off + start * width); for (a = 0; a < count; a += width, dx++) { res = fwrite(dx, width, 1, stdout); if (res != 1) { errx(1, "error writing to stdout"); break; } } break; default: errx(1, "invalid access width"); } munmap((void *)pbm.pbm_map_base, pbm.pbm_map_length); close(fd); } Index: head/usr.sbin/pciconf/pciconf.h =================================================================== --- head/usr.sbin/pciconf/pciconf.h (revision 355740) +++ head/usr.sbin/pciconf/pciconf.h (revision 355741) @@ -1,45 +1,45 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2007 Yahoo!, Inc. * All rights reserved. * Written by: John Baldwin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __PCICONF_H__ #define __PCICONF_H__ -void list_caps(int fd, struct pci_conf *p); +void list_caps(int fd, struct pci_conf *p, int level); void list_errors(int fd, struct pci_conf *p); uint8_t pci_find_cap(int fd, struct pci_conf *p, uint8_t id); uint16_t pcie_find_cap(int fd, struct pci_conf *p, uint16_t id); void print_bar(int fd, struct pci_conf *p, const char *label, uint16_t bar); uint32_t read_config(int fd, struct pcisel *sel, long reg, int width); #endif