summaryrefslogtreecommitdiffstats
path: root/sys/amd64/pci/pci_cfgreg.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/pci/pci_cfgreg.c')
-rw-r--r--sys/amd64/pci/pci_cfgreg.c140
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;
+ }
+}
OpenPOWER on IntegriCloud