Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F101972257
D42828.id130716.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D42828.id130716.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D42828: x86: Support multiple PCI MCFG regions
Attached
Detach File
Event Timeline
Log In to Comment