From: Alexander Polakov Date: Sun, 1 Nov 2009 20:16:28 +0000 (+0300) Subject: Expand the support for PCI-e memory mapped configuration space access. X-Git-Tag: v2.7.1~380^2~13^2~2 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/4ea06a727073466f2954853daf292ec27bcfa836 Expand the support for PCI-e memory mapped configuration space access. This defaults to off and must be explicitly enabled by setting the loader tunable hw.pci.mcfg=1. - Add support for the Intel 915GM chipsets by reading the BAR. - Add parsing of the ACPI MCFG table to discover memory mapped configuration access on modern machines. - For config requests to busses not listed in ACPI's min/max valid buses, fall back to using type #1 configuration access instead. - Add a workaround for some K8 chipsets that do not expose all devices on bus 0 via MCFG and fall back to type #1 for those devices instead. Obtained-from: FreeBSD --- diff --git a/sys/bus/pci/i386/pci_cfgreg.c b/sys/bus/pci/i386/pci_cfgreg.c index 209955380c..9eb9da1ebe 100644 --- a/sys/bus/pci/i386/pci_cfgreg.c +++ b/sys/bus/pci/i386/pci_cfgreg.c @@ -26,12 +26,13 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.124.2.2.6.1 2009/04/15 03:14:26 kensmith Exp $ + * $FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.124.2.3 2009/05/04 21:04:29 jhb */ #include #include #include +#include #include #include #include @@ -76,7 +77,9 @@ enum { }; static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU]; -static uint32_t pciebar; +static uint64_t pcie_base; +static int pcie_minbus, pcie_maxbus; +static uint32_t pcie_badslots; static int cfgmech; static int devmax; #if defined(__DragonFly__) @@ -84,16 +87,21 @@ static struct spinlock pcicfg_mtx; #else static struct mtx pcicfg_mtx; #endif +static int mcfg_enable = 0; +TUNABLE_INT("hw.pci.mcfg", &mcfg_enable); + +static uint32_t pci_docfgregread(int bus, int slot, int func, int reg, int 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); static int pcireg_cfgopen(void); -static int pciereg_cfgopen(void); -static int pciereg_cfgread(int bus, int slot, int func, int reg, - int bytes); -static void pciereg_cfgwrite(int bus, int slot, int func, int reg, - int data, int bytes); +static int pciereg_cfgread(int bus, unsigned slot, unsigned func, + unsigned reg, unsigned bytes); +static void pciereg_cfgwrite(int bus, unsigned slot, unsigned func, + unsigned reg, int data, unsigned bytes); + + /* * Some BIOS writers seem to want to ignore the spec and put @@ -138,13 +146,14 @@ int pci_cfgregopen(void) { static int opened = 0; + uint64_t pciebar; u_int16_t vid, did; u_int16_t v; if (opened) - return(1); + return (1); - if (pcireg_cfgopen() == 0) - return(0); + if (cfgmech == CFGMECH_NONE && pcireg_cfgopen() == 0) + return (0); v = pcibios_get_version(); if (v > 0) @@ -157,6 +166,9 @@ pci_cfgregopen(void) if (v >= 0x0210) pci_pir_open(); + if (cfgmech == CFGMECH_PCIE) + return (1); + /* * Grope around in the PCI config space to see if this is a * chipset that is capable of doing memory-mapped config cycles. @@ -166,21 +178,40 @@ pci_cfgregopen(void) /* Check for supported chipsets */ vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2); did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2); - if (vid == 0x8086) { - if (did == 0x3590 || did == 0x3592) { + switch (vid) { + case 0x8086: + switch (did) { + case 0x3590: + case 0x3592: /* Intel 7520 or 7320 */ pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; - pciereg_cfgopen(); - } else if (did == 0x2580 || did == 0x2584) { - /* Intel 915 or 925 */ + pcie_cfgregopen(pciebar, 0, 255); + break; + case 0x2580: + case 0x2584: + case 0x2590: + /* Intel 915, 925, or 915GM */ pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); - pciereg_cfgopen(); + pcie_cfgregopen(pciebar, 0, 255); + break; } } return(1); } +static uint32_t +pci_docfgregread(int bus, int slot, int func, int reg, int bytes) +{ + + if (cfgmech == CFGMECH_PCIE && + (bus >= pcie_minbus && bus <= pcie_maxbus) && + (bus != 0 || !(1 << slot & pcie_badslots))) + return (pciereg_cfgread(bus, slot, func, reg, bytes)); + else + return (pcireg_cfgread(bus, slot, func, reg, bytes)); +} + /* * Read configuration space register */ @@ -195,10 +226,10 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) * the code uses 255 as an invalid IRQ. */ if (reg == PCIR_INTLINE && bytes == 1) { - line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); + line = pci_docfgregread(bus, slot, func, PCIR_INTLINE, 1); return (pci_i386_map_intline(line)); } - return (pcireg_cfgread(bus, slot, func, reg, bytes)); + return (pci_docfgregread(bus, slot, func, reg, bytes)); } /* @@ -208,7 +239,12 @@ void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) { - pcireg_cfgwrite(bus, slot, func, reg, data, bytes); + if (cfgmech == CFGMECH_PCIE && + (bus >= pcie_minbus && bus <= pcie_maxbus) && + (bus != 0 || !(1 << slot & pcie_badslots))) + pciereg_cfgwrite(bus, slot, func, reg, data, bytes); + else + pcireg_cfgwrite(bus, slot, func, reg, data, bytes); } /* @@ -262,6 +298,7 @@ pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) && (unsigned) bytes <= 4 && (reg & (bytes - 1)) == 0) { switch (cfgmech) { + case CFGMECH_PCIE: case CFGMECH_1: outl(CONF1_ADDR_PORT, (1 << 31) | (bus << 16) | (slot << 11) @@ -283,6 +320,7 @@ static void pci_cfgdisable(void) { switch (cfgmech) { + case CFGMECH_PCIE: case CFGMECH_1: /* * Do nothing for the config mechanism 1 case. @@ -303,11 +341,6 @@ pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) int data = -1; int port; - if (cfgmech == CFGMECH_PCIE) { - data = pciereg_cfgread(bus, slot, func, reg, bytes); - return (data); - } - mtx_lock_spin(&pcicfg_mtx); port = pci_cfgenable(bus, slot, func, reg, bytes); if (port != 0) { @@ -333,11 +366,6 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) { int port; - if (cfgmech == CFGMECH_PCIE) { - pciereg_cfgwrite(bus, slot, func, reg, data, bytes); - return; - } - mtx_lock_spin(&pcicfg_mtx); port = pci_cfgenable(bus, slot, func, reg, bytes); if (port != 0) { @@ -485,8 +513,8 @@ pcireg_cfgopen(void) return (cfgmech); } -static int -pciereg_cfgopen(void) +int +pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus) { #ifdef PCIE_CFG_MECH struct pcie_cfg_list *pcielist; @@ -495,10 +523,26 @@ pciereg_cfgopen(void) struct pcpu *pc; #endif vm_offset_t va; - int i; + uint32_t val1, val2; + int i, slot; + + if (!mcfg_enable) + return (0); + + if (minbus != 0) + return (0); + + if (base >= 0x100000000) { + if (bootverbose) + kprintf( + "PCI: Memory Mapped PCI configuration area base 0x%jx too high\n", + (uintmax_t)base); + return (0); + } if (bootverbose) - kprintf("Setting up PCIe mappings for BAR 0x%x\n", pciebar); + kprintf("PCIe: Memory Mapped configuration base @ 0x%jx\n", + (uintmax_t)base); #ifdef SMP SLIST_FOREACH(pc, &cpuhead, pc_allcpu) @@ -530,9 +574,30 @@ pciereg_cfgopen(void) } } - + pcie_base = base; + pcie_minbus = minbus; + pcie_maxbus = maxbus; cfgmech = CFGMECH_PCIE; devmax = 32; + + /* + * On some AMD systems, some of the devices on bus 0 are + * inaccessible using memory-mapped PCI config access. Walk + * bus 0 looking for such devices. For these devices, we will + * fall back to using type 1 config access instead. + */ + if (pci_cfgregopen() != 0) { + for (slot = 0; slot < 32; slot++) { + val1 = pcireg_cfgread(0, slot, 0, 0, 4); + if (val1 == 0xffffffff) + continue; + + val2 = pciereg_cfgread(0, slot, 0, 0, 4); + if (val2 != val1) + pcie_badslots |= (1 << slot); + } + } + return (1); #else /* !PCIE_CFG_MECH */ return (0); @@ -581,15 +646,20 @@ pciereg_findelem(vm_paddr_t papage) } static int -pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) +pciereg_cfgread(int bus, unsigned slot, unsigned func, unsigned reg, + unsigned bytes) { struct pcie_cfg_elem *elem; volatile vm_offset_t va; vm_paddr_t pa, papage; - int data; + int data = -1; + + if (bus < pcie_minbus || bus > pcie_maxbus || slot >= 32 || + func > PCI_FUNCMAX || reg >= 0x1000 || bytes > 4 || bytes == 3) + return (-1); crit_enter(); - pa = PCIE_PADDR(pciebar, reg, bus, slot, func); + pa = PCIE_PADDR(pcie_base, reg, bus, slot, func); papage = pa & ~PAGE_MASK; elem = pciereg_findelem(papage); va = elem->vapage | (pa & PAGE_MASK); @@ -604,8 +674,6 @@ pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) case 1: data = *(volatile uint8_t *)(va); break; - default: - panic("pciereg_cfgread: invalid width"); } crit_exit(); @@ -613,14 +681,14 @@ pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) } static void -pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) +pciereg_cfgwrite(int bus, unsigned slot, unsigned func, unsigned reg, int data, unsigned bytes) { struct pcie_cfg_elem *elem; volatile vm_offset_t va; vm_paddr_t pa, papage; crit_enter(); - pa = PCIE_PADDR(pciebar, reg, bus, slot, func); + pa = PCIE_PADDR(pcie_base, reg, bus, slot, func); papage = pa & ~PAGE_MASK; elem = pciereg_findelem(papage); va = elem->vapage | (pa & PAGE_MASK); @@ -635,8 +703,6 @@ pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) case 1: *(volatile uint8_t *)(va) = data; break; - default: - panic("pciereg_cfgwrite: invalid width"); } crit_exit(); diff --git a/sys/bus/pci/i386/pci_cfgreg.h b/sys/bus/pci/i386/pci_cfgreg.h index 87bf5cfa6e..7f58e96a60 100644 --- a/sys/bus/pci/i386/pci_cfgreg.h +++ b/sys/bus/pci/i386/pci_cfgreg.h @@ -43,6 +43,7 @@ #define CONF2_ENABLE_CHK 0x0e #define CONF2_ENABLE_RES 0x0e +int pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus); int pci_cfgregopen(void); u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes); void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes); diff --git a/sys/bus/pci/x86_64/pci_cfgreg.c b/sys/bus/pci/x86_64/pci_cfgreg.c index 21f0b515a9..cdc0419f81 100644 --- a/sys/bus/pci/x86_64/pci_cfgreg.c +++ b/sys/bus/pci/x86_64/pci_cfgreg.c @@ -26,12 +26,13 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.124.2.2.6.1 2009/04/15 03:14:26 kensmith Exp $ + * $FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.124.2.3 2009/05/04 21:04:29 jhb */ #include #include #include +#include #include #include #include @@ -76,7 +77,9 @@ enum { }; static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU]; -static uint32_t pciebar; +static uint64_t pcie_base; +static int pcie_minbus, pcie_maxbus; +static uint32_t pcie_badslots; static int cfgmech; static int devmax; #if defined(__DragonFly__) @@ -84,16 +87,21 @@ static struct spinlock pcicfg_mtx; #else static struct mtx pcicfg_mtx; #endif +static int mcfg_enable = 0; +TUNABLE_INT("hw.pci.mcfg", &mcfg_enable); + +static uint32_t pci_docfgregread(int bus, int slot, int func, int reg, int 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); static int pcireg_cfgopen(void); -static int pciereg_cfgopen(void); -static int pciereg_cfgread(int bus, int slot, int func, int reg, - int bytes); -static void pciereg_cfgwrite(int bus, int slot, int func, int reg, - int data, int bytes); +static int pciereg_cfgread(int bus, unsigned slot, unsigned func, + unsigned reg, unsigned bytes); +static void pciereg_cfgwrite(int bus, unsigned slot, unsigned func, + unsigned reg, int data, unsigned bytes); + + /* * Some BIOS writers seem to want to ignore the spec and put @@ -165,6 +173,9 @@ pci_cfgregopen(void) if (v >= 0x0210) pci_pir_open(); + if (cfgmech == CFGMECH_PCIE) + return (1); + /* * Grope around in the PCI config space to see if this is a * chipset that is capable of doing memory-mapped config cycles. @@ -172,25 +183,45 @@ pci_cfgregopen(void) */ /* Check for supported chipsets */ - vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2); - did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2); - if (vid == 0x8086) { - if (did == 0x3590 || did == 0x3592) { - /* Intel 7520 or 7320 */ - pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; - pciereg_cfgopen(); - } else if (did == 0x2580 || did == 0x2584) { - /* Intel 915 or 925 */ - pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); - pciereg_cfgopen(); - } - } + vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2); + did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2); + switch (vid) { + case 0x8086: + switch (did) { + case 0x3590: + case 0x3592: + /* Intel 7520 or 7320 */ + pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; + pcie_cfgregopen(pciebar, 0, 255); + break; + case 0x2580: + case 0x2584: + case 0x2590: + /* Intel 915, 925, or 915GM */ + pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); + pcie_cfgregopen(pciebar, 0, 255); + break; + } + } + #else opened = 1; #endif return(1); } +static uint32_t +pci_docfgregread(int bus, int slot, int func, int reg, int bytes) +{ + + if (cfgmech == CFGMECH_PCIE && + (bus >= pcie_minbus && bus <= pcie_maxbus) && + (bus != 0 || !(1 << slot & pcie_badslots))) + return (pciereg_cfgread(bus, slot, func, reg, bytes)); + else + return (pcireg_cfgread(bus, slot, func, reg, bytes)); +} + /* * Read configuration space register */ @@ -205,10 +236,10 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) * the code uses 255 as an invalid IRQ. */ if (reg == PCIR_INTLINE && bytes == 1) { - line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); + line = pci_docfgregread(bus, slot, func, PCIR_INTLINE, 1); return (pci_i386_map_intline(line)); } - return (pcireg_cfgread(bus, slot, func, reg, bytes)); + return (pci_docfgregread(bus, slot, func, reg, bytes)); } /* @@ -218,7 +249,12 @@ void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) { - pcireg_cfgwrite(bus, slot, func, reg, data, bytes); + if (cfgmech == CFGMECH_PCIE && + (bus >= pcie_minbus && bus <= pcie_maxbus) && + (bus != 0 || !(1 << slot & pcie_badslots))) + pciereg_cfgwrite(bus, slot, func, reg, data, bytes); + else + pcireg_cfgwrite(bus, slot, func, reg, data, bytes); } /* @@ -272,6 +308,7 @@ pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) && (unsigned) bytes <= 4 && (reg & (bytes - 1)) == 0) { switch (cfgmech) { + case CFGMECH_PCIE: case CFGMECH_1: outl(CONF1_ADDR_PORT, (1 << 31) | (bus << 16) | (slot << 11) @@ -293,6 +330,7 @@ static void pci_cfgdisable(void) { switch (cfgmech) { + case CFGMECH_PCIE: case CFGMECH_1: /* * Do nothing for the config mechanism 1 case. @@ -313,11 +351,6 @@ pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) int data = -1; int port; - if (cfgmech == CFGMECH_PCIE) { - data = pciereg_cfgread(bus, slot, func, reg, bytes); - return (data); - } - mtx_lock_spin(&pcicfg_mtx); port = pci_cfgenable(bus, slot, func, reg, bytes); if (port != 0) { @@ -343,11 +376,6 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) { int port; - if (cfgmech == CFGMECH_PCIE) { - pciereg_cfgwrite(bus, slot, func, reg, data, bytes); - return; - } - mtx_lock_spin(&pcicfg_mtx); port = pci_cfgenable(bus, slot, func, reg, bytes); if (port != 0) { @@ -495,8 +523,8 @@ pcireg_cfgopen(void) return (cfgmech); } -static int -pciereg_cfgopen(void) +int +pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus) { #ifdef PCIE_CFG_MECH struct pcie_cfg_list *pcielist; @@ -505,10 +533,26 @@ pciereg_cfgopen(void) struct pcpu *pc; #endif vm_offset_t va; - int i; + uint32_t val1, val2; + int i, slot; + + if (!mcfg_enable) + return (0); + + if (minbus != 0) + return (0); + + if (base >= 0x100000000) { + if (bootverbose) + kprintf( + "PCI: Memory Mapped PCI configuration area base 0x%jx too high\n", + (uintmax_t)base); + return (0); + } if (bootverbose) - kprintf("Setting up PCIe mappings for BAR 0x%x\n", pciebar); + kprintf("PCIe: Memory Mapped configuration base @ 0x%jx\n", + (uintmax_t)base); #ifdef SMP SLIST_FOREACH(pc, &cpuhead, pc_allcpu) @@ -540,9 +584,30 @@ pciereg_cfgopen(void) } } - + pcie_base = base; + pcie_minbus = minbus; + pcie_maxbus = maxbus; cfgmech = CFGMECH_PCIE; devmax = 32; + + /* + * On some AMD systems, some of the devices on bus 0 are + * inaccessible using memory-mapped PCI config access. Walk + * bus 0 looking for such devices. For these devices, we will + * fall back to using type 1 config access instead. + */ + if (pci_cfgregopen() != 0) { + for (slot = 0; slot < 32; slot++) { + val1 = pcireg_cfgread(0, slot, 0, 0, 4); + if (val1 == 0xffffffff) + continue; + + val2 = pciereg_cfgread(0, slot, 0, 0, 4); + if (val2 != val1) + pcie_badslots |= (1 << slot); + } + } + return (1); #else /* !PCIE_CFG_MECH */ return (0); @@ -591,15 +656,20 @@ pciereg_findelem(vm_paddr_t papage) } static int -pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) +pciereg_cfgread(int bus, unsigned slot, unsigned func, unsigned reg, + unsigned bytes) { struct pcie_cfg_elem *elem; volatile vm_offset_t va; vm_paddr_t pa, papage; - int data; + int data = -1; + + if (bus < pcie_minbus || bus > pcie_maxbus || slot >= 32 || + func > PCI_FUNCMAX || reg >= 0x1000 || bytes > 4 || bytes == 3) + return (-1); crit_enter(); - pa = PCIE_PADDR(pciebar, reg, bus, slot, func); + pa = PCIE_PADDR(pcie_base, reg, bus, slot, func); papage = pa & ~PAGE_MASK; elem = pciereg_findelem(papage); va = elem->vapage | (pa & PAGE_MASK); @@ -614,8 +684,6 @@ pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) case 1: data = *(volatile uint8_t *)(va); break; - default: - panic("pciereg_cfgread: invalid width"); } crit_exit(); @@ -623,14 +691,14 @@ pciereg_cfgread(int bus, int slot, int func, int reg, int bytes) } static void -pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) +pciereg_cfgwrite(int bus, unsigned slot, unsigned func, unsigned reg, int data, unsigned bytes) { struct pcie_cfg_elem *elem; volatile vm_offset_t va; vm_paddr_t pa, papage; crit_enter(); - pa = PCIE_PADDR(pciebar, reg, bus, slot, func); + pa = PCIE_PADDR(pcie_base, reg, bus, slot, func); papage = pa & ~PAGE_MASK; elem = pciereg_findelem(papage); va = elem->vapage | (pa & PAGE_MASK); @@ -645,8 +713,6 @@ pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) case 1: *(volatile uint8_t *)(va) = data; break; - default: - panic("pciereg_cfgwrite: invalid width"); } crit_exit(); diff --git a/sys/bus/pci/x86_64/pci_cfgreg.h b/sys/bus/pci/x86_64/pci_cfgreg.h index cb49ebe2d7..1834d1380d 100644 --- a/sys/bus/pci/x86_64/pci_cfgreg.h +++ b/sys/bus/pci/x86_64/pci_cfgreg.h @@ -43,6 +43,7 @@ #define CONF2_ENABLE_CHK 0x0e #define CONF2_ENABLE_RES 0x0e +int pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus); int pci_cfgregopen(void); u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes); void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes); diff --git a/sys/dev/acpica5/acpi.c b/sys/dev/acpica5/acpi.c index d5786f92e1..e0e031540c 100644 --- a/sys/dev/acpica5/acpi.c +++ b/sys/dev/acpica5/acpi.c @@ -62,6 +62,7 @@ #include "acglobal.h" #include "pci_if.h" +#include #include #include @@ -156,6 +157,7 @@ static int acpi_child_location_str_method(device_t acdev, device_t child, char *buf, size_t buflen); static int acpi_child_pnpinfo_str_method(device_t acdev, device_t child, char *buf, size_t buflen); +static void acpi_enable_pcie(void); static device_method_t acpi_methods[] = { /* Device interface */ @@ -466,6 +468,9 @@ acpi_attach(device_t dev) goto out; } + /* Handle MCFG table if present. */ + acpi_enable_pcie(); + /* Install the default address space handlers. */ status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL); @@ -1487,6 +1492,34 @@ acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids) return_VALUE (result); } +/* + * Look for a MCFG table. If it is present, use the settings for + * domain (segment) 0 to setup PCI config space access via the memory + * map. + */ +static void +acpi_enable_pcie(void) +{ + ACPI_TABLE_HEADER *hdr; + ACPI_MCFG_ALLOCATION *alloc, *end; + ACPI_STATUS status; + + status = AcpiGetTable(ACPI_SIG_MCFG, 1, &hdr); + if (ACPI_FAILURE(status)) + return; + + 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; + } + alloc++; + } +} + /* * Scan all of the ACPI namespace and attach child devices. *