Page MenuHomeFreeBSD

D5242.id13415.diff
No OneTemporary

D5242.id13415.diff

Index: sys/dev/pci/pci.c
===================================================================
--- sys/dev/pci/pci.c
+++ sys/dev/pci/pci.c
@@ -63,6 +63,11 @@
#include <dev/pci/pcivar.h>
#include <dev/pci/pci_private.h>
+#ifdef PCI_IOV
+#include <sys/nv.h>
+#include <dev/pci/pci_iov_private.h>
+#endif
+
#include <dev/usb/controller/xhcireg.h>
#include <dev/usb/controller/ehcireg.h>
#include <dev/usb/controller/ohcireg.h>
@@ -694,6 +699,78 @@
#undef REG
static void
+pci_ea_fill_info(device_t pcib, pcicfgregs *cfg)
+{
+#define REG(n, w) PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, \
+ cfg->ea.ea_location + (n), w)
+ int num_ent;
+ int ptr;
+ int a, b;
+ uint32_t val;
+ int ent_size;
+ uint32_t dw[4];
+ uint64_t base, max_offset;
+ struct pci_ea_entry *eae;
+
+ if (cfg->ea.ea_location == 0)
+ return;
+
+ STAILQ_INIT(&cfg->ea.ea_entries);
+
+ /* Determine the number of entries */
+ num_ent = REG(PCIR_EA_NUM_ENT, 2);
+ num_ent &= PCIM_EA_NUM_ENT_MASK;
+
+ /* Find the first entry to care of */
+ ptr = PCIR_EA_FIRST_ENT;
+
+ /* Skip DWORD 2 for type 1 functions */
+ if ((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 = REG(ptr, 4);
+ ptr += 4;
+ ent_size = (val & PCIM_EA_ES);
+
+ for (b = 0; b < ent_size; b++) {
+ dw[b] = REG(ptr, 4);
+ ptr += 4;
+ }
+
+ eae = malloc(sizeof(*eae), M_DEVBUF, M_WAITOK | M_ZERO);
+ eae->eae_flags = val;
+ eae->eae_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++;
+ }
+
+ eae->eae_base = base;
+ eae->eae_max_offset = max_offset;
+
+ STAILQ_INSERT_TAIL(&cfg->ea.ea_entries, eae, eae_link);
+
+ if (bootverbose) {
+ printf("PCI(EA) dev %04x:%04x, bei %d, flags #%x, base #%lx, max_offset #%lx\n",
+ cfg->vendor, cfg->device, eae->eae_bei, eae->eae_flags,
+ eae->eae_base, eae->eae_max_offset);
+ }
+ }
+}
+#undef REG
+
+static void
pci_read_cap(device_t pcib, pcicfgregs *cfg)
{
#define REG(n, w) PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
@@ -830,6 +907,10 @@
val = REG(ptr + PCIER_FLAGS, 2);
cfg->pcie.pcie_type = val & PCIEM_FLAGS_TYPE;
break;
+ case PCIY_EA: /* Enhanced Allocation */
+ cfg->ea.ea_location = ptr;
+ pci_ea_fill_info(pcib, cfg);
+ break;
default:
break;
}
@@ -3504,6 +3585,135 @@
}
#endif
+static int
+pci_ea_bei_to_rid(device_t bus, device_t dev, uint8_t bei)
+{
+#ifdef PCI_IOV
+ struct pci_devinfo *dinfo;
+ int iov_pos;
+ struct pcicfg_iov *iov;
+
+ dinfo = device_get_ivars(dev);
+ iov = dinfo->cfg.iov;
+ if (iov != NULL)
+ iov_pos = iov->iov_pos;
+ else
+ iov_pos = 0;
+#endif
+
+ /* Check if matches BAR */
+ if ((bei >= PCIM_EA_BEI_BAR_0) &&
+ (bei <= PCIM_EA_BEI_BAR_5))
+ return (PCIR_BAR(bei));
+
+ /* Check ROM */
+ if (bei == PCIM_EA_BEI_ROM)
+ return (PCIR_BIOS);
+
+#ifdef PCI_IOV
+ /* Check if matches VF_BAR */
+ if ((iov != NULL) && (bei >= PCIM_EA_BEI_VF_BAR_0) &&
+ (bei <= PCIM_EA_BEI_VF_BAR_5))
+ return (PCIR_SRIOV_BAR(bei - PCIM_EA_BEI_VF_BAR_0) +
+ iov_pos);
+#endif
+
+ return (-1);
+}
+
+void
+pci_add_resources_ea(device_t bus, device_t dev, int alloc_iov)
+{
+ struct pci_ea_entry *ea;
+ struct pci_devinfo *dinfo;
+ pci_addr_t start, end, count;
+ struct resource_list *rl;
+ int type, flags, rid;
+ struct resource *res;
+#ifdef PCI_IOV
+ struct pcicfg_iov *iov;
+#endif
+
+ dinfo = device_get_ivars(dev);
+ rl = &dinfo->resources;
+ flags = 0;
+
+#ifdef PCI_IOV
+ iov = dinfo->cfg.iov;
+#endif
+
+ if (dinfo->cfg.ea.ea_location == 0)
+ return;
+
+ STAILQ_FOREACH(ea, &dinfo->cfg.ea.ea_entries, eae_link) {
+
+ if ((ea->eae_flags & PCIM_EA_ENABLE) == 0)
+ continue;
+
+ switch ((ea->eae_flags & PCIM_EA_PP) >> PCIM_EA_PP_OFFSET) {
+ case PCIM_EA_P_MEM_PREFETCH:
+ case PCIM_EA_P_VF_MEM_PREFETCH:
+ flags = RF_PREFETCHABLE;
+ case PCIM_EA_P_VF_MEM:
+ case PCIM_EA_P_MEM:
+ type = SYS_RES_MEMORY;
+ break;
+ case PCIM_EA_P_IO:
+ type = SYS_RES_IOPORT;
+ break;
+ default:
+ continue;
+ }
+
+ if (alloc_iov != 0) {
+#ifdef PCI_IOV
+ /* Allocating IOV, confirm BEI matches */
+ if ((ea->eae_bei < PCIM_EA_BEI_VF_BAR_0) ||
+ (ea->eae_bei > PCIM_EA_BEI_VF_BAR_5))
+ continue;
+#else
+ continue;
+#endif
+ } else {
+ /* Allocating BAR, confirm BEI matches */
+ if (((ea->eae_bei < PCIM_EA_BEI_BAR_0) ||
+ (ea->eae_bei > PCIM_EA_BEI_BAR_5)) &&
+ (ea->eae_bei != PCIM_EA_BEI_ROM))
+ continue;
+ }
+
+ rid = pci_ea_bei_to_rid(bus, dev, ea->eae_bei);
+ if (rid < 0)
+ continue;
+
+ /* Skip resources already allocated by EA */
+ if ((resource_list_find(rl, SYS_RES_MEMORY, rid) != NULL) ||
+ (resource_list_find(rl, SYS_RES_IOPORT, rid) != NULL))
+ continue;
+
+ start = ea->eae_base;
+ count = ea->eae_max_offset + 1;
+#ifdef PCI_IOV
+ if (iov != NULL)
+ count = count * iov->iov_num_vfs;
+#endif
+ end = start + count - 1;
+ if (count == 0)
+ continue;
+
+ resource_list_add(rl, type, rid, start, end, count);
+ res = resource_list_reserve(rl, bus, dev, type, &rid, start, end, count,
+ flags);
+ if (res == NULL) {
+ resource_list_delete(rl, type, rid);
+ continue;
+ }
+
+ /* As per specification, fill BAR with zeros */
+ pci_write_config(dev, rid, 0, 4);
+ }
+}
+
void
pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask)
{
@@ -3519,6 +3729,9 @@
rl = &dinfo->resources;
devid = (cfg->device << 16) | cfg->vendor;
+ /* Allocate resources using Enhanced Allocation */
+ pci_add_resources_ea(bus, dev, 0);
+
/* ATA devices needs special map treatment */
if ((pci_get_class(dev) == PCIC_STORAGE) &&
(pci_get_subclass(dev) == PCIS_STORAGE_IDE) &&
@@ -3528,6 +3741,13 @@
pci_ata_maps(bus, dev, rl, force, prefetchmask);
else
for (i = 0; i < cfg->nummaps;) {
+ /* Skip resources already allocated by EA */
+ if ((resource_list_find(rl, SYS_RES_MEMORY, PCIR_BAR(i)) != NULL) ||
+ (resource_list_find(rl, SYS_RES_IOPORT, PCIR_BAR(i)) != NULL)) {
+ i++;
+ continue;
+ }
+
/*
* Skip quirked resources.
*/
Index: sys/dev/pci/pci_iov.c
===================================================================
--- sys/dev/pci/pci_iov.c
+++ sys/dev/pci/pci_iov.c
@@ -513,6 +513,37 @@
}
static int
+pci_iov_alloc_bar_ea(struct pci_devinfo *dinfo, int bar)
+{
+ struct pcicfg_iov *iov;
+ rman_res_t start, end;
+ struct resource *res;
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+
+ rl = &dinfo->resources;
+ iov = dinfo->cfg.iov;
+
+ rle = resource_list_find(rl, SYS_RES_MEMORY,
+ iov->iov_pos + PCIR_SRIOV_BAR(bar));
+ if (rle == NULL)
+ rle = resource_list_find(rl, SYS_RES_IOPORT,
+ iov->iov_pos + PCIR_SRIOV_BAR(bar));
+ if (rle == NULL)
+ return (ENXIO);
+ res = rle->res;
+
+ iov->iov_bar[bar].res = res;
+ iov->iov_bar[bar].bar_size = rman_get_size(res) / iov->iov_num_vfs;
+ iov->iov_bar[bar].bar_shift = pci_mapsize(iov->iov_bar[bar].bar_size);
+
+ start = rman_get_start(res);
+ end = rman_get_end(res);
+
+ return (rman_manage_region(&iov->rman, start, end));
+}
+
+static int
pci_iov_setup_bars(struct pci_devinfo *dinfo)
{
device_t dev;
@@ -524,7 +555,14 @@
dev = dinfo->cfg.dev;
last_64 = 0;
+ pci_add_resources_ea(device_get_parent(dev), dev, 1);
+
for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
+ /* First, try to use BARs allocated with EA */
+ error = pci_iov_alloc_bar_ea(dinfo, i);
+ if (error == 0)
+ continue;
+
/*
* If a PCI BAR is a 64-bit wide BAR, then it spans two
* consecutive registers. Therefore if the last BAR that
Index: sys/dev/pci/pci_private.h
===================================================================
--- sys/dev/pci/pci_private.h
+++ sys/dev/pci/pci_private.h
@@ -55,6 +55,7 @@
uint16_t rid, uint16_t vid, uint16_t did);
void pci_add_resources(device_t bus, device_t dev, int force,
uint32_t prefetchmask);
+void pci_add_resources_ea(device_t bus, device_t dev, int alloc_iov);
int pci_attach_common(device_t dev);
void pci_delete_child(device_t dev, device_t child);
void pci_driver_added(device_t dev, driver_t *driver);
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,49 @@
#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 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 */
Index: sys/dev/pci/pcivar.h
===================================================================
--- sys/dev/pci/pcivar.h
+++ sys/dev/pci/pcivar.h
@@ -156,6 +156,19 @@
int index;
};
+struct pci_ea_entry {
+ uint32_t eae_bei;
+ uint32_t eae_flags;
+ uint64_t eae_base;
+ uint64_t eae_max_offset;
+ STAILQ_ENTRY(pci_ea_entry) eae_link;
+};
+
+struct pcicfg_ea {
+ int ea_location; /* Structure offset in Configuration Header */
+ STAILQ_HEAD(, pci_ea_entry) ea_entries; /* EA entries */
+};
+
#define PCICFG_VF 0x0001 /* Device is an SR-IOV Virtual Function */
/* config header information common to all header types */
@@ -207,6 +220,7 @@
struct pcicfg_pcix pcix; /* PCI-X */
struct pcicfg_iov *iov; /* SR-IOV */
struct pcicfg_vf vf; /* SR-IOV Virtual Function */
+ struct pcicfg_ea ea; /* Enhanced Allocation */
} pcicfgregs;
/* additional type 1 device config header information (PCI to PCI bridge) */

File Metadata

Mime Type
text/plain
Expires
Mon, Apr 13, 2:28 PM (19 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31413540
Default Alt Text
D5242.id13415.diff (11 KB)

Event Timeline