diff options
-rw-r--r-- | sys/amd64/include/pci_cfgreg.h | 1 | ||||
-rw-r--r-- | sys/amd64/pci/pci_cfgreg.c | 140 | ||||
-rw-r--r-- | sys/dev/acpica/acpi.c | 41 | ||||
-rw-r--r-- | sys/i386/include/pci_cfgreg.h | 1 | ||||
-rw-r--r-- | sys/i386/pci/pci_cfgreg.c | 78 |
5 files changed, 222 insertions, 39 deletions
diff --git a/sys/amd64/include/pci_cfgreg.h b/sys/amd64/include/pci_cfgreg.h index e97b367..7588282 100644 --- a/sys/amd64/include/pci_cfgreg.h +++ b/sys/amd64/include/pci_cfgreg.h @@ -37,6 +37,7 @@ #define CONF1_ENABLE_MSK1 0x80000001ul #define CONF1_ENABLE_RES1 0x80000000ul +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/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c index eceaf5e..8d5dde0 100644 --- a/sys/amd64/pci/pci_cfgreg.c +++ b/sys/amd64/pci/pci_cfgreg.c @@ -36,11 +36,26 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> +#include <vm/vm.h> +#include <vm/pmap.h> #include <machine/pci_cfgreg.h> +enum { + CFGMECH_NONE = 0, + CFGMECH_1, + CFGMECH_PCIE, +}; + +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); 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 cfgmech; +static vm_offset_t pcie_base; +static int pcie_minbus, pcie_maxbus; static struct mtx pcicfg_mtx; /* @@ -49,12 +64,42 @@ static struct mtx pcicfg_mtx; int pci_cfgregopen(void) { - static int opened = 0; + uint64_t pciebar; + uint16_t did, vid; - if (opened) + if (cfgmech != CFGMECH_NONE) return (1); mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); - opened = 1; + cfgmech = CFGMECH_1; + + /* + * Grope around in the PCI config space to see if this is a + * chipset that is capable of doing memory-mapped config cycles. + * This also implies that it can do PCIe extended config cycles. + */ + + /* Check for supported chipsets */ + 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; + } + } + return (1); } @@ -130,6 +175,11 @@ 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) { @@ -155,6 +205,11 @@ 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) { @@ -173,3 +228,82 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) } mtx_unlock_spin(&pcicfg_mtx); } + +int +pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus) +{ + + 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(base, (maxbus + 1) << 20); + pcie_minbus = minbus; + pcie_maxbus = maxbus; + cfgmech = CFGMECH_PCIE; + return (1); +} + +#define PCIE_VADDR(base, reg, bus, slot, func) \ + ((base) + \ + ((((bus) & 0xff) << 20) | \ + (((slot) & 0x1f) << 15) | \ + (((func) & 0x7) << 12) | \ + ((reg) & 0xfff))) + +static int +pciereg_cfgread(int bus, unsigned slot, unsigned func, unsigned reg, + unsigned bytes) +{ + volatile vm_offset_t va; + int data = -1; + + if (bus < pcie_minbus || bus > pcie_maxbus || slot >= 32 || + func > PCI_FUNCMAX || reg >= 0x1000) + return (-1); + + va = PCIE_VADDR(pcie_base, reg, bus, slot, func); + + switch (bytes) { + case 4: + data = *(volatile uint32_t *)(va); + break; + case 2: + data = *(volatile uint16_t *)(va); + break; + case 1: + data = *(volatile uint8_t *)(va); + break; + } + + return (data); +} + +static void +pciereg_cfgwrite(int bus, unsigned slot, unsigned func, unsigned reg, int data, + unsigned bytes) +{ + volatile vm_offset_t va; + + if (bus < pcie_minbus || bus > pcie_maxbus || slot >= 32 || + func > PCI_FUNCMAX || reg >= 0x1000) + return; + + va = PCIE_VADDR(pcie_base, reg, bus, slot, func); + + switch (bytes) { + case 4: + *(volatile uint32_t *)(va) = data; + break; + case 2: + *(volatile uint16_t *)(va) = data; + break; + case 1: + *(volatile uint8_t *)(va) = data; + break; + } +} diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index f3e6f16..a291152 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -48,6 +48,9 @@ __FBSDID("$FreeBSD$"); #include <sys/sbuf.h> #include <sys/smp.h> +#if defined(__i386__) || defined(__amd64__) +#include <machine/pci_cfgreg.h> +#endif #include <machine/resource.h> #include <machine/bus.h> #include <sys/rman.h> @@ -152,6 +155,9 @@ 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); +#if defined(__i386__) || defined(__amd64__) +static void acpi_enable_pcie(void); +#endif static device_method_t acpi_methods[] = { /* Device interface */ @@ -448,6 +454,11 @@ acpi_attach(device_t dev) goto out; } +#if defined(__i386__) || defined(__amd64__) + /* Handle MCFG table if present. */ + acpi_enable_pcie(); +#endif + /* Install the default address space handlers. */ status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL); @@ -1466,6 +1477,36 @@ acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids) return_VALUE (result); } +#if defined(__i386__) || defined(__amd64__) +/* + * 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++; + } +} +#endif + /* * Scan all of the ACPI namespace and attach child devices. * diff --git a/sys/i386/include/pci_cfgreg.h b/sys/i386/include/pci_cfgreg.h index b246993..bc72418 100644 --- a/sys/i386/include/pci_cfgreg.h +++ b/sys/i386/include/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/i386/pci/pci_cfgreg.c b/sys/i386/pci/pci_cfgreg.c index 6350990..9157a3c 100644 --- a/sys/i386/pci/pci_cfgreg.c +++ b/sys/i386/pci/pci_cfgreg.c @@ -75,7 +75,8 @@ enum { }; static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU]; -static uint64_t pciebar; +static uint64_t pcie_base; +static int pcie_minbus, pcie_maxbus; static int cfgmech; static int devmax; static struct mtx pcicfg_mtx; @@ -84,13 +85,11 @@ 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); #ifndef XEN static int pcireg_cfgopen(void); - -static int pciereg_cfgopen(void); #endif -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 @@ -140,14 +139,15 @@ pci_cfgregopen(void) return (0); #else 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) @@ -160,6 +160,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. @@ -176,22 +179,15 @@ pci_cfgregopen(void) case 0x3592: /* Intel 7520 or 7320 */ pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; - pciereg_cfgopen(); + 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; - case 0x25d0: - case 0x25d4: - case 0x25d8: - /* Intel 5000Z/V/P */ - pciebar = pci_cfgregread(0, 16, 0, 0x64, 4) << 16; - pciereg_cfgopen(); - break; } } @@ -504,8 +500,8 @@ pcireg_cfgopen(void) return (cfgmech); } -static int -pciereg_cfgopen(void) +int +pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus) { struct pcie_cfg_list *pcielist; struct pcie_cfg_elem *pcie_array, *elem; @@ -515,20 +511,22 @@ pciereg_cfgopen(void) vm_offset_t va; int i; + if (minbus != 0) + return (0); + #ifndef PAE - if (pciebar >= 0x100000000) { + if (base >= 0x100000000) { if (bootverbose) printf( "PCI: Memory Mapped PCI configuration area base 0x%jx too high\n", - (uintmax_t)pciebar); - pciebar = 0; + (uintmax_t)base); return (0); } #endif if (bootverbose) - printf("Setting up PCIe mappings for BAR 0x%jx\n", - (uintmax_t)pciebar); + printf("PCIe: Memory Mapped configuration base @ 0x%jx\n", + (uintmax_t)base); #ifdef SMP SLIST_FOREACH(pc, &cpuhead, pc_allcpu) @@ -560,7 +558,9 @@ pciereg_cfgopen(void) } } - + pcie_base = base; + pcie_minbus = minbus; + pcie_maxbus = maxbus; cfgmech = CFGMECH_PCIE; devmax = 32; return (1); @@ -610,15 +610,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); critical_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); @@ -633,8 +638,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"); } critical_exit(); @@ -642,14 +645,19 @@ 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; + if (bus < pcie_minbus || bus > pcie_maxbus || slot >= 32 || + func > PCI_FUNCMAX || reg >= 0x1000) + return; + critical_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); @@ -664,8 +672,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"); } critical_exit(); |