Page MenuHomeFreeBSD

D5242.diff
No OneTemporary

D5242.diff

Index: head/sys/dev/pci/pci.c
===================================================================
--- head/sys/dev/pci/pci.c
+++ head/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,81 @@
#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++) {
+
+ eae = malloc(sizeof(*eae), M_DEVBUF, M_WAITOK | M_ZERO);
+ eae->eae_cfg_offset = cfg->ea.ea_location + ptr;
+
+ /* 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->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 #%jx, max_offset #%jx\n",
+ cfg->vendor, cfg->device, eae->eae_bei, eae->eae_flags,
+ (uintmax_t)eae->eae_base, (uintmax_t)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 +910,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 +3588,176 @@
}
#endif
+static int
+pci_ea_bei_to_rid(device_t dev, int 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);
+}
+
+int
+pci_ea_is_enabled(device_t dev, int rid)
+{
+ struct pci_ea_entry *ea;
+ struct pci_devinfo *dinfo;
+
+ dinfo = device_get_ivars(dev);
+
+ STAILQ_FOREACH(ea, &dinfo->cfg.ea.ea_entries, eae_link) {
+ if (pci_ea_bei_to_rid(dev, ea->eae_bei) == rid)
+ return ((ea->eae_flags & PCIM_EA_ENABLE) > 0);
+ }
+
+ return (0);
+}
+
+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;
+ uint32_t tmp;
+#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) {
+
+ /*
+ * TODO: Ignore EA-BAR if is not enabled.
+ * Currently the EA implementation supports
+ * only situation, where EA structure contains
+ * predefined entries. In case they are not enabled
+ * leave them unallocated and proceed with
+ * a legacy-BAR mechanism.
+ */
+ 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(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);
+
+ /*
+ * Failed to allocate using EA, disable entry.
+ * Another attempt to allocation will be performed
+ * further, but this time using legacy BAR registers
+ */
+ tmp = pci_read_config(dev, ea->eae_cfg_offset, 4);
+ tmp &= ~PCIM_EA_ENABLE;
+ pci_write_config(dev, ea->eae_cfg_offset, tmp, 4);
+
+ /*
+ * Disabling entry might fail in case it is hardwired.
+ * Read flags again to match current status.
+ */
+ ea->eae_flags = pci_read_config(dev, ea->eae_cfg_offset, 4);
+
+ 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 +3773,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 +3785,14 @@
pci_ata_maps(bus, dev, rl, force, prefetchmask);
else
for (i = 0; i < cfg->nummaps;) {
+ /* Skip resources already managed 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) ||
+ pci_ea_is_enabled(dev, PCIR_BAR(i))) {
+ i++;
+ continue;
+ }
+
/*
* Skip quirked resources.
*/
@@ -4629,6 +4894,11 @@
int mapsize;
res = NULL;
+
+ /* If rid is managed by EA, ignore it */
+ if (pci_ea_is_enabled(child, *rid))
+ goto out;
+
pm = pci_find_bar(child, *rid);
if (pm != NULL) {
/* This is a BAR that we failed to allocate earlier. */
Index: head/sys/dev/pci/pci_iov.c
===================================================================
--- head/sys/dev/pci/pci_iov.c
+++ head/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,18 @@
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;
+
+ /* Allocate legacy-BAR only if EA is not enabled */
+ if (pci_ea_is_enabled(dev, iov->iov_pos + PCIR_SRIOV_BAR(i)))
+ continue;
+
/*
* If a PCI BAR is a 64-bit wide BAR, then it spans two
* consecutive registers. Therefore if the last BAR that
Index: head/sys/dev/pci/pci_private.h
===================================================================
--- head/sys/dev/pci/pci_private.h
+++ head/sys/dev/pci/pci_private.h
@@ -55,9 +55,11 @@
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);
+int pci_ea_is_enabled(device_t dev, int rid);
int pci_print_child(device_t dev, device_t child);
void pci_probe_nomatch(device_t dev, device_t child);
int pci_read_ivar(device_t dev, device_t child, int which,
Index: head/sys/dev/pci/pcivar.h
===================================================================
--- head/sys/dev/pci/pcivar.h
+++ head/sys/dev/pci/pcivar.h
@@ -156,6 +156,20 @@
int index;
};
+struct pci_ea_entry {
+ int eae_bei;
+ uint32_t eae_flags;
+ uint64_t eae_base;
+ uint64_t eae_max_offset;
+ uint32_t eae_cfg_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 +221,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, 3:32 PM (15 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31415432
Default Alt Text
D5242.diff (11 KB)

Event Timeline