diff options
author | jhb <jhb@FreeBSD.org> | 2008-08-22 02:14:23 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-08-22 02:14:23 +0000 |
commit | 2a48176eba96caaa3a31b0d353942f75bb2fbd49 (patch) | |
tree | 9c22e90efaf7573077c0a35e96706beaaa9411fa /sys/amd64/pci | |
parent | 6ab64e14fc373a159372cb6b7df2bf63d117b6f2 (diff) | |
download | FreeBSD-src-2a48176eba96caaa3a31b0d353942f75bb2fbd49.zip FreeBSD-src-2a48176eba96caaa3a31b0d353942f75bb2fbd49.tar.gz |
Extend the support for PCI-e memory mapped configuration space access:
- Rename pciereg_cfgopen() to pcie_cfgregopen() and expose it to the
rest of the kernel. It now also accepts parameters via function
arguments rather than global variables.
- Add a notion of minimum and maximum bus numbers and reject requests for
an out of range bus.
- Add more range checks on slot/func/reg/bytes parameters to the cfg reg
read/write routines. Don't panic on any invalid parameters, just fail
the request (writes do nothing, reads return -1). This matches the
behavior of the other cfg mechanisms.
- Port the memory mapped configuration space access to amd64. On amd64
we simply use the direct map (via pmap_mapdev()) for the memory mapped
window.
- During acpi_attach() just after loading the ACPI tables, check for a
MCFG table. If it exists, call pciereg_cfgopen() on each subtable
(memory mapped window). For now we only support windows for domain 0
that start with bus 0. This removes the need for more chipset-specific
quirks in the MD code.
- Remove the chipset-specific quirks for the Intel 5000P/V/Z chipsets
since these machines should all have MCFG tables via ACPI.
- Updated pci_cfgregopen() to DTRT if ACPI had invoked pcie_cfgregopen()
earlier.
MFC after: 2 weeks
Diffstat (limited to 'sys/amd64/pci')
-rw-r--r-- | sys/amd64/pci/pci_cfgreg.c | 140 |
1 files changed, 137 insertions, 3 deletions
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; + } +} |