Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152080623
D5242.id13415.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D5242.id13415.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D5242: Support for Extended Allocation in PCI
Attached
Detach File
Event Timeline
Log In to Comment