Page MenuHomeFreeBSD

D42828.id130716.diff
No OneTemporary

D42828.id130716.diff

diff --git a/sys/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c
--- a/sys/amd64/pci/pci_cfgreg.c
+++ b/sys/amd64/pci/pci_cfgreg.c
@@ -34,6 +34,7 @@
#include <sys/bus.h>
#include <sys/lock.h>
#include <sys/kernel.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <dev/pci/pcivar.h>
@@ -42,12 +43,21 @@
#include <vm/pmap.h>
#include <machine/pci_cfgreg.h>
+struct pcie_mcfg_region {
+ char *base;
+ uint16_t domain;
+ uint8_t minbus;
+ uint8_t maxbus;
+};
+
static uint32_t pci_docfgregread(int domain, int bus, int slot, int func,
int reg, int bytes);
-static int pciereg_cfgread(int domain, int bus, unsigned slot,
- unsigned func, unsigned reg, unsigned bytes);
-static void pciereg_cfgwrite(int domain, int bus, unsigned slot,
- unsigned func, unsigned reg, int data, unsigned bytes);
+static struct pcie_mcfg_region *pcie_lookup_region(int domain, int bus);
+static int pciereg_cfgread(struct pcie_mcfg_region *region, int bus,
+ unsigned slot, unsigned func, unsigned reg, unsigned bytes);
+static void pciereg_cfgwrite(struct pcie_mcfg_region *region, int bus,
+ unsigned slot, unsigned func, unsigned reg, int data,
+ unsigned bytes);
static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
@@ -60,11 +70,12 @@
*/
int cfgmech = CFGMECH_1;
-static vm_offset_t pcie_base;
-static int pcie_minbus, pcie_maxbus;
+static struct pcie_mcfg_region *mcfg_regions;
+static int mcfg_numregions;
static uint32_t pcie_badslots;
static struct mtx pcicfg_mtx;
MTX_SYSINIT(pcicfg_mtx, &pcicfg_mtx, "pcicfg_mtx", MTX_SPIN);
+
static int mcfg_enable = 1;
SYSCTL_INT(_hw_pci, OID_AUTO, mcfg, CTLFLAG_RDTUN, &mcfg_enable, 0,
"Enable support for PCI-e memory mapped config access");
@@ -76,16 +87,33 @@
return (1);
}
+static struct pcie_mcfg_region *
+pcie_lookup_region(int domain, int bus)
+{
+ for (int i = 0; i < mcfg_numregions; i++)
+ if (mcfg_regions[i].domain == domain &&
+ bus >= mcfg_regions[i].minbus &&
+ bus <= mcfg_regions[i].maxbus)
+ return (&mcfg_regions[i]);
+ return (NULL);
+}
+
static uint32_t
pci_docfgregread(int domain, int bus, int slot, int func, int reg, int bytes)
{
if (domain == 0 && bus == 0 && (1 << slot & pcie_badslots) != 0)
return (pcireg_cfgread(bus, slot, func, reg, bytes));
- if (cfgmech == CFGMECH_PCIE &&
- (bus >= pcie_minbus && bus <= pcie_maxbus))
- return (pciereg_cfgread(domain, bus, slot, func, reg, bytes));
- else if (domain == 0)
+ if (cfgmech == CFGMECH_PCIE) {
+ struct pcie_mcfg_region *region;
+
+ region = pcie_lookup_region(domain, bus);
+ if (region != NULL)
+ return (pciereg_cfgread(region, bus, slot, func, reg,
+ bytes));
+ }
+
+ if (domain == 0)
return (pcireg_cfgread(bus, slot, func, reg, bytes));
else
return (-1);
@@ -129,10 +157,18 @@
return;
}
- if (cfgmech == CFGMECH_PCIE &&
- (bus >= pcie_minbus && bus <= pcie_maxbus))
- pciereg_cfgwrite(domain, bus, slot, func, reg, data, bytes);
- else if (domain == 0)
+ if (cfgmech == CFGMECH_PCIE) {
+ struct pcie_mcfg_region *region;
+
+ region = pcie_lookup_region(domain, bus);
+ if (region != NULL) {
+ pciereg_cfgwrite(region, bus, slot, func, reg, data,
+ bytes);
+ return;
+ }
+ }
+
+ if (domain == 0)
pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
}
@@ -217,28 +253,12 @@
mtx_unlock_spin(&pcicfg_mtx);
}
-int
-pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus)
+static void
+pcie_init_badslots(struct pcie_mcfg_region *region)
{
uint32_t val1, val2;
int slot;
- if (!mcfg_enable)
- return (0);
-
- if (minbus != 0)
- return (0);
-
- if (bootverbose)
- printf("PCIe: Memory Mapped configuration base @ 0x%lx\n",
- base);
-
- /* XXX: We should make sure this really fits into the direct map. */
- pcie_base = (vm_offset_t)pmap_mapdev_pciecfg(base, (maxbus + 1) << 20);
- pcie_minbus = minbus;
- pcie_maxbus = maxbus;
- cfgmech = CFGMECH_PCIE;
-
/*
* On some AMD systems, some of the devices on bus 0 are
* inaccessible using memory-mapped PCI config access. Walk
@@ -251,11 +271,42 @@
if (val1 == 0xffffffff)
continue;
- val2 = pciereg_cfgread(0, 0, slot, 0, 0, 4);
+ val2 = pciereg_cfgread(region, 0, slot, 0, 0, 4);
if (val2 != val1)
pcie_badslots |= (1 << slot);
}
}
+}
+
+int
+pcie_cfgregopen(uint64_t base, uint16_t domain, uint8_t minbus, uint8_t maxbus)
+{
+ struct pcie_mcfg_region *region;
+
+ if (!mcfg_enable)
+ return (0);
+
+ if (bootverbose)
+ printf("PCI: MCFG domain %u bus %u-%u base @ 0x%lx\n",
+ domain, minbus, maxbus, base);
+
+ /* Resize the array. */
+ mcfg_regions = realloc(mcfg_regions,
+ sizeof(*mcfg_regions) * (mcfg_numregions + 1), M_DEVBUF, M_WAITOK);
+
+ region = &mcfg_regions[mcfg_numregions];
+
+ /* XXX: We should make sure this really fits into the direct map. */
+ region->base = pmap_mapdev_pciecfg(base, (maxbus + 1 - minbus) << 20);
+ region->domain = domain;
+ region->minbus = minbus;
+ region->maxbus = maxbus;
+ mcfg_numregions++;
+
+ cfgmech = CFGMECH_PCIE;
+
+ if (domain == 0 && minbus == 0)
+ pcie_init_badslots(region);
return (1);
}
@@ -276,17 +327,18 @@
*/
static int
-pciereg_cfgread(int domain, int bus, unsigned slot, unsigned func, unsigned reg,
- unsigned bytes)
+pciereg_cfgread(struct pcie_mcfg_region *region, int bus, unsigned slot,
+ unsigned func, unsigned reg, unsigned bytes)
{
- vm_offset_t va;
+ char *va;
int data = -1;
- if (domain != 0 || bus < pcie_minbus || bus > pcie_maxbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
+ MPASS(bus >= region->minbus && bus <= region->maxbus);
+
+ if (slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
return (-1);
- va = PCIE_VADDR(pcie_base, reg, bus, slot, func);
+ va = PCIE_VADDR(region->base, reg, bus - region->minbus, slot, func);
switch (bytes) {
case 4:
@@ -307,16 +359,17 @@
}
static void
-pciereg_cfgwrite(int domain, int bus, unsigned slot, unsigned func,
- unsigned reg, int data, unsigned bytes)
+pciereg_cfgwrite(struct pcie_mcfg_region *region, int bus, unsigned slot,
+ unsigned func, unsigned reg, int data, unsigned bytes)
{
- vm_offset_t va;
+ char *va;
- if (domain != 0 || bus < pcie_minbus || bus > pcie_maxbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
+ MPASS(bus >= region->minbus && bus <= region->maxbus);
+
+ if (slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
return;
- va = PCIE_VADDR(pcie_base, reg, bus, slot, func);
+ va = PCIE_VADDR(region->base, reg, bus - region->minbus, slot, func);
switch (bytes) {
case 4:
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -2226,11 +2226,8 @@
end = (ACPI_MCFG_ALLOCATION *)((char *)hdr + hdr->Length);
alloc = (ACPI_MCFG_ALLOCATION *)((ACPI_TABLE_MCFG *)hdr + 1);
while (alloc < end) {
- if (alloc->PciSegment == 0) {
- pcie_cfgregopen(alloc->Address, alloc->StartBusNumber,
- alloc->EndBusNumber);
- return;
- }
+ pcie_cfgregopen(alloc->Address, alloc->PciSegment,
+ alloc->StartBusNumber, alloc->EndBusNumber);
alloc++;
}
#endif
diff --git a/sys/i386/pci/pci_cfgreg.c b/sys/i386/pci/pci_cfgreg.c
--- a/sys/i386/pci/pci_cfgreg.c
+++ b/sys/i386/pci/pci_cfgreg.c
@@ -55,6 +55,13 @@
printf a ; \
} while(0)
+struct pcie_mcfg_region {
+ uint64_t base;
+ uint16_t domain;
+ uint8_t minbus;
+ uint8_t maxbus;
+};
+
#define PCIE_CACHE 8
struct pcie_cfg_elem {
TAILQ_ENTRY(pcie_cfg_elem) elem;
@@ -64,26 +71,30 @@
SYSCTL_DECL(_hw_pci);
+static struct pcie_mcfg_region *mcfg_regions;
+static int mcfg_numregions;
static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU];
-static uint64_t pcie_base;
-static int pcie_minbus, pcie_maxbus;
+static int pcie_cache_initted;
static uint32_t pcie_badslots;
int cfgmech;
static int devmax;
static struct mtx pcicfg_mtx;
+
static int mcfg_enable = 1;
SYSCTL_INT(_hw_pci, OID_AUTO, mcfg, CTLFLAG_RDTUN, &mcfg_enable, 0,
"Enable support for PCI-e memory mapped config access");
static uint32_t pci_docfgregread(int domain, int bus, int slot, int func,
int reg, int bytes);
+static struct pcie_mcfg_region *pcie_lookup_region(int domain, int bus);
static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
static int pcireg_cfgopen(void);
-static int pciereg_cfgread(int domain, int bus, unsigned slot,
- unsigned func, unsigned reg, unsigned bytes);
-static void pciereg_cfgwrite(int domain, int bus, unsigned slot,
- unsigned func, unsigned reg, int data, unsigned bytes);
+static int pciereg_cfgread(struct pcie_mcfg_region *region, int bus,
+ unsigned slot, unsigned func, unsigned reg, unsigned bytes);
+static void pciereg_cfgwrite(struct pcie_mcfg_region *region, int bus,
+ unsigned slot, unsigned func, unsigned reg, int data,
+ unsigned bytes);
/*
* Some BIOS writers seem to want to ignore the spec and put
@@ -150,16 +161,33 @@
return (1);
}
+static struct pcie_mcfg_region *
+pcie_lookup_region(int domain, int bus)
+{
+ for (int i = 0; i < mcfg_numregions; i++)
+ if (mcfg_regions[i].domain == domain &&
+ bus >= mcfg_regions[i].minbus &&
+ bus <= mcfg_regions[i].maxbus)
+ return (&mcfg_regions[i]);
+ return (NULL);
+}
+
static uint32_t
pci_docfgregread(int domain, int bus, int slot, int func, int reg, int bytes)
{
if (domain == 0 && bus == 0 && (1 << slot & pcie_badslots) != 0)
return (pcireg_cfgread(bus, slot, func, reg, bytes));
- if (cfgmech == CFGMECH_PCIE &&
- (bus >= pcie_minbus && bus <= pcie_maxbus))
- return (pciereg_cfgread(domain, bus, slot, func, reg, bytes));
- else if (domain == 0)
+ if (cfgmech == CFGMECH_PCIE) {
+ struct pcie_mcfg_region *region;
+
+ region = pcie_lookup_region(domain, bus);
+ if (region != NULL)
+ return (pciereg_cfgread(region, bus, slot, func, reg,
+ bytes));
+ }
+
+ if (domain == 0)
return (pcireg_cfgread(bus, slot, func, reg, bytes));
else
return (-1);
@@ -198,10 +226,18 @@
return;
}
- if (cfgmech == CFGMECH_PCIE &&
- (bus >= pcie_minbus && bus <= pcie_maxbus))
- pciereg_cfgwrite(domain, bus, slot, func, reg, data, bytes);
- else if (domain == 0)
+ if (cfgmech == CFGMECH_PCIE) {
+ struct pcie_mcfg_region *region;
+
+ region = pcie_lookup_region(domain, bus);
+ if (region != NULL) {
+ pciereg_cfgwrite(region, bus, slot, func, reg, data,
+ bytes);
+ return;
+ }
+ }
+
+ if (domain == 0)
pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
}
@@ -437,8 +473,8 @@
return (cfgmech);
}
-int
-pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus)
+static bool
+pcie_init_cache(void)
{
struct pcie_cfg_list *pcielist;
struct pcie_cfg_elem *pcie_array, *elem;
@@ -446,26 +482,7 @@
struct pcpu *pc;
#endif
vm_offset_t va;
- uint32_t val1, val2;
- int i, slot;
-
- if (!mcfg_enable)
- return (0);
-
- if (minbus != 0)
- return (0);
-
- if (!pae_mode && base >= 0x100000000) {
- if (bootverbose)
- printf(
- "PCI: Memory Mapped PCI configuration area base 0x%jx too high\n",
- (uintmax_t)base);
- return (0);
- }
-
- if (bootverbose)
- printf("PCIe: Memory Mapped configuration base @ 0x%jx\n",
- (uintmax_t)base);
+ int i;
#ifdef SMP
STAILQ_FOREACH(pc, &cpuhead, pc_allcpu)
@@ -474,12 +491,12 @@
pcie_array = malloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE,
M_DEVBUF, M_NOWAIT);
if (pcie_array == NULL)
- return (0);
+ return (false);
va = kva_alloc(PCIE_CACHE * PAGE_SIZE);
if (va == 0) {
free(pcie_array, M_DEVBUF);
- return (0);
+ return (false);
}
#ifdef SMP
@@ -495,12 +512,14 @@
TAILQ_INSERT_HEAD(pcielist, elem, elem);
}
}
+ return (true);
+}
- pcie_base = base;
- pcie_minbus = minbus;
- pcie_maxbus = maxbus;
- cfgmech = CFGMECH_PCIE;
- devmax = 32;
+static void
+pcie_init_badslots(struct pcie_mcfg_region *region)
+{
+ uint32_t val1, val2;
+ int slot;
/*
* On some AMD systems, some of the devices on bus 0 are
@@ -514,11 +533,59 @@
if (val1 == 0xffffffff)
continue;
- val2 = pciereg_cfgread(0, 0, slot, 0, 0, 4);
+ val2 = pciereg_cfgread(region, 0, slot, 0, 0, 4);
if (val2 != val1)
pcie_badslots |= (1 << slot);
}
}
+}
+
+int
+pcie_cfgregopen(uint64_t base, uint16_t domain, uint8_t minbus, uint8_t maxbus)
+{
+ struct pcie_mcfg_region *region;
+
+ if (!mcfg_enable)
+ return (0);
+
+ if (!pae_mode && base >= 0x100000000) {
+ if (bootverbose)
+ printf(
+ "PCI: MCFG domain %u bus %u-%u base 0x%jx too high\n",
+ domain, minbus, maxbus, (uintmax_t)base);
+ return (0);
+ }
+
+ if (bootverbose)
+ printf("PCI: MCFG domain %u bus %u-%u base @ 0x%jx\n",
+ domain, minbus, maxbus, (uintmax_t)base);
+
+ if (pcie_cache_initted == 0) {
+ if (!pcie_init_cache())
+ pcie_cache_initted = -1;
+ else
+ pcie_cache_initted = 1;
+ }
+
+ if (pcie_cache_initted == -1)
+ return (0);
+
+ /* Resize the array. */
+ mcfg_regions = realloc(mcfg_regions,
+ sizeof(*mcfg_regions) * (mcfg_numregions + 1), M_DEVBUF, M_WAITOK);
+
+ region = &mcfg_regions[mcfg_numregions];
+ region->base = base;
+ region->domain = domain;
+ region->minbus = minbus;
+ region->maxbus = maxbus;
+ mcfg_numregions++;
+
+ cfgmech = CFGMECH_PCIE;
+ devmax = 32;
+
+ if (domain == 0 && minbus == 0)
+ pcie_init_badslots(region);
return (1);
}
@@ -531,13 +598,16 @@
((reg) & 0xfff)))
static __inline vm_offset_t
-pciereg_findaddr(int bus, unsigned slot, unsigned func, unsigned reg)
+pciereg_findaddr(struct pcie_mcfg_region *region, int bus, unsigned slot,
+ unsigned func, unsigned reg)
{
struct pcie_cfg_list *pcielist;
struct pcie_cfg_elem *elem;
vm_paddr_t pa, papage;
- pa = PCIE_PADDR(pcie_base, reg, bus, slot, func);
+ MPASS(bus >= region->minbus && bus <= region->maxbus);
+
+ pa = PCIE_PADDR(region->base, reg, bus - region->minbus, slot, func);
papage = pa & ~PAGE_MASK;
/*
@@ -578,18 +648,17 @@
*/
static int
-pciereg_cfgread(int domain, int bus, unsigned slot, unsigned func, unsigned reg,
- unsigned bytes)
+pciereg_cfgread(struct pcie_mcfg_region *region, int bus, unsigned slot,
+ unsigned func, unsigned reg, unsigned bytes)
{
vm_offset_t va;
int data = -1;
- if (domain != 0 || bus < pcie_minbus || bus > pcie_maxbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
+ if (slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
return (-1);
critical_enter();
- va = pciereg_findaddr(bus, slot, func, reg);
+ va = pciereg_findaddr(region, bus, slot, func, reg);
switch (bytes) {
case 4:
@@ -611,17 +680,16 @@
}
static void
-pciereg_cfgwrite(int domain, int bus, unsigned slot, unsigned func,
- unsigned reg, int data, unsigned bytes)
+pciereg_cfgwrite(struct pcie_mcfg_region *region, int bus, unsigned slot,
+ unsigned func, unsigned reg, int data, unsigned bytes)
{
vm_offset_t va;
- if (domain != 0 || bus < pcie_minbus || bus > pcie_maxbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
+ if (slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
return;
critical_enter();
- va = pciereg_findaddr(bus, slot, func, reg);
+ va = pciereg_findaddr(region, bus, slot, func, reg);
switch (bytes) {
case 4:
diff --git a/sys/x86/include/pci_cfgreg.h b/sys/x86/include/pci_cfgreg.h
--- a/sys/x86/include/pci_cfgreg.h
+++ b/sys/x86/include/pci_cfgreg.h
@@ -56,7 +56,7 @@
extern int cfgmech;
rman_res_t hostb_alloc_start(int type, rman_res_t start, rman_res_t end, rman_res_t count);
-int pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus);
+int pcie_cfgregopen(uint64_t base, uint16_t domain, uint8_t minbus, uint8_t maxbus);
int pci_cfgregopen(void);
u_int32_t pci_cfgregread(int domain, int bus, int slot, int func, int reg, int bytes);
void pci_cfgregwrite(int domain, int bus, int slot, int func, int reg, u_int32_t data, int bytes);
diff --git a/sys/x86/x86/legacy.c b/sys/x86/x86/legacy.c
--- a/sys/x86/x86/legacy.c
+++ b/sys/x86/x86/legacy.c
@@ -133,14 +133,14 @@
case 0x3592:
/* Intel 7520 or 7320 */
pciebar = pci_cfgregread(0, 0, 0, 0, 0xce, 2) << 16;
- pcie_cfgregopen(pciebar, 0, 255);
+ pcie_cfgregopen(pciebar, 0, 0, 255);
break;
case 0x2580:
case 0x2584:
case 0x2590:
/* Intel 915, 925, or 915GM */
pciebar = pci_cfgregread(0, 0, 0, 0, 0x48, 4);
- pcie_cfgregopen(pciebar, 0, 255);
+ pcie_cfgregopen(pciebar, 0, 0, 255);
break;
}
}

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 7, 12:12 AM (10 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14502071
Default Alt Text
D42828.id130716.diff (16 KB)

Event Timeline