Index: sys/dev/pci/pci.c =================================================================== --- sys/dev/pci/pci.c +++ sys/dev/pci/pci.c @@ -63,6 +63,11 @@ #include #include +#ifdef PCI_IOV +#include +#include +#endif + #include #include #include @@ -2729,6 +2734,14 @@ int ln2range; uint16_t cmd; + if (pci_ea_read_bar(dev, reg, &map, &testval, bar64) == 0) { + *mapp = map; + *testvalp = testval; + if (bar64 != NULL) + *bar64 = 1; + return; + } + /* * The device ROM BAR is special. It is always a 32-bit * memory BAR. Bit 0 is special and should not be set when @@ -4616,6 +4629,119 @@ } #endif /* DDB */ +int +pci_ea_read_bar(device_t dev, int reg, pci_addr_t *map, pci_addr_t *testval, + int *bar64) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); +#ifdef PCI_IOV + struct pcicfg_iov *iov; +#endif + int ret; + int cap; + int num_ent, ent_size; + int ptr, a, b, bar, ea_flags, found; + uint32_t val; + uint32_t dw[4]; + uint64_t base, max_offset; + +#ifdef PCI_IOV + iov = dinfo->cfg.iov; +#endif + + ret = pci_find_cap(dev, PCIY_EA, &cap); + if (ret != 0) + return (EINVAL); + + /* Determine the number of entries */ + num_ent = pci_read_config(dev, cap + PCIR_EA_NUM_ENT, 2); + num_ent &= PCIM_EA_NUM_ENT_MASK; + + /* Find the first entry to care of */ + ptr = cap + PCIR_EA_FIRST_ENT; + + /* Skip DWORD 2 for type 1 functions */ + if ((dinfo->cfg.hdrtype & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) + ptr += 4; + + for (a = 0; a < num_ent; a++) { + /* Read a number of dwords in the entry */ + val = pci_read_config(dev, ptr, 4); + ptr += 4; + ent_size = (val & PCIM_EA_ES); + + for (b = 0; b < ent_size; b++) { + dw[b] = pci_read_config(dev, ptr, 4); + ptr += 4; + } + + /* Entry not enabled */ + if ((val & PCIM_EA_ENABLE) == 0) + continue; + + /* Confirm if it is a BAR we're asked for */ + found = 0; + for (bar = 0; bar < PCIR_MAX_BAR_0; bar++) { + if (((val & PCIM_EA_BEI) == PCIM_EA_BEI_BAR(bar)) && + (PCIR_BAR(bar) == reg)) + found = 1; +#ifdef PCI_IOV + if ((iov != NULL) && ((val & PCIM_EA_BEI) == PCIM_EA_BEI_VF_BAR(bar)) && + (iov->iov_pos + PCIR_SRIOV_BAR(bar) == reg)) + found = 1; +#endif + + } + if ((reg == PCIR_BIOS) && + ((val & PCIM_EA_BEI) == PCIM_EA_BEI_ROM)) + found = 1; + + if (found != 0) { + /* 32-bit base&max_offset are mandatory */ + 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 (bar64 != NULL) + *bar64 = 1; + } + if (((dw[1] & PCIM_EA_IS_64) != 0) + && (b < ent_size)) { + max_offset |= (uint64_t)dw[b] << 32UL; + b++; + if (bar64 != NULL) + *bar64 = 1; + } + + /* Check flags */ + ea_flags = (dw[0] & PCIM_EA_PP) >> PCIM_EA_PP_OFFSET; + switch (ea_flags) { + case PCIM_EA_P_MEM: + *testval = PCIM_BAR_MEM_SPACE; + break; + case PCIM_EA_P_MEM_PREFETCH: + *testval = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_PREFETCH; + break; + case PCIM_EA_P_IO: + *testval = PCIM_BAR_IO_SPACE; + break; + default: + *testval = 0; + break; + } + + *testval |= ~((int)max_offset); + *map = base; + + return (0); + } + } + return (EINVAL); +} + static struct resource * pci_reserve_map(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int num, Index: sys/dev/pci/pci_private.h =================================================================== --- sys/dev/pci/pci_private.h +++ sys/dev/pci/pci_private.h @@ -147,6 +147,8 @@ int pci_mapsize(uint64_t testval); void pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp, int *bar64); +int pci_ea_read_bar(device_t dev, int reg, pci_addr_t *map, + pci_addr_t *testval, int *bar64); struct pci_map *pci_add_bar(device_t dev, int reg, pci_addr_t value, pci_addr_t size); Index: sys/dev/pci/pcireg.h =================================================================== --- sys/dev/pci/pcireg.h +++ sys/dev/pci/pcireg.h @@ -146,6 +146,7 @@ #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 */ @@ -586,6 +587,45 @@ #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 */ +/* 0-5 map to BARs 0-5 respectively */ +#define PCIM_EA_BEI_BAR(x) ((x) << 4) +#define PCIM_EA_BEI_BRIDGE 0x60 /* Resource behind bridge */ +#define PCIM_EA_BEI_ENI 0x70 /* Equivalent Not Indicated */ +#define PCIM_EA_BEI_ROM 0x80 /* Expansion ROM */ +/* 9-14 map to VF BARs 0-5 respectively */ +#define PCIM_EA_BEI_VF_BAR(x) (((x) + 9) << 4) +#define PCIM_EA_BEI_RESERVED 0xf0 /* 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 */ + /* PCI-X definitions */ /* For header type 0 devices */