diff options
author | imp <imp@FreeBSD.org> | 2000-10-16 07:25:08 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2000-10-16 07:25:08 +0000 |
commit | 893736b5514248e7054dca38d2e8d5e67499a202 (patch) | |
tree | bbb633f1952844855238906002b1612247991ddd /sys | |
parent | d81515c140fdaa360121c179d2f5210424c61bc0 (diff) | |
download | FreeBSD-src-893736b5514248e7054dca38d2e8d5e67499a202.zip FreeBSD-src-893736b5514248e7054dca38d2e8d5e67499a202.tar.gz |
Add the ability to use the $PIR table in the BIOS to route interrupts
on demand.
Submitted by: msmith
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/pci/pci_bus.c | 9 | ||||
-rw-r--r-- | sys/amd64/pci/pci_cfgreg.c | 68 | ||||
-rw-r--r-- | sys/i386/pci/pci_bus.c | 9 | ||||
-rw-r--r-- | sys/i386/pci/pci_cfgreg.c | 68 | ||||
-rw-r--r-- | sys/i386/pci/pci_pir.c | 68 |
5 files changed, 213 insertions, 9 deletions
diff --git a/sys/amd64/pci/pci_bus.c b/sys/amd64/pci/pci_bus.c index e2d6bd6..665b46d 100644 --- a/sys/amd64/pci/pci_bus.c +++ b/sys/amd64/pci/pci_bus.c @@ -68,6 +68,14 @@ nexus_pcib_write_config(device_t dev, int bus, int slot, int func, pci_cfgregwrite(bus, slot, func, reg, data, bytes); } +/* route interrupt */ + +static int +nexus_pcib_route_interrupt(device_t bus, int device, int pin) +{ + return(pci_cfgintr(nexus_get_pcibus(bus), device, pin)); +} + static devclass_t pcib_devclass; static const char * @@ -435,6 +443,7 @@ static device_method_t nexus_pcib_methods[] = { DEVMETHOD(pcib_maxslots, nexus_pcib_maxslots), DEVMETHOD(pcib_read_config, nexus_pcib_read_config), DEVMETHOD(pcib_write_config, nexus_pcib_write_config), + DEVMETHOD(pcib_route_interrupt, nexus_pcib_route_interrupt), { 0, 0 } }; diff --git a/sys/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c index 2654859..e0b8d74 100644 --- a/sys/amd64/pci/pci_cfgreg.c +++ b/sys/amd64/pci/pci_cfgreg.c @@ -35,13 +35,14 @@ #include <sys/kernel.h> #include <sys/module.h> #include <sys/malloc.h> - +#include <vm/vm.h> +#include <vm/pmap.h> +#include <machine/md_var.h> #include <pci/pcivar.h> #include <pci/pcireg.h> #include <isa/isavar.h> #include <machine/nexusvar.h> #include <machine/pci_cfgreg.h> - #include <machine/segments.h> #include <machine/pc/bios.h> @@ -58,13 +59,20 @@ 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 struct PIR_entry *pci_route_table; +static int pci_route_count; + /* * Initialise access to PCI configuration space */ int pci_cfgregopen(void) { - static int opened = 0; + static int opened = 0; + u_long sigaddr; + static struct PIR_table *pt; + u_int8_t ck, *cv; + int i; if (opened) return(1); @@ -76,6 +84,24 @@ pci_cfgregopen(void) } else { return(0); } + + /* + * Look for the interrupt routing table. + */ + /* XXX use PCI BIOS if it's available */ + + if ((pt == NULL) && ((sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0)) != 0)) { + pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < (pt->pt_header.ph_length); i++) { + ck += cv[i]; + } + if (ck == 0) { + pci_route_table = &pt->pt_entry[0]; + pci_route_count = (pt->pt_header.ph_length - sizeof(struct PIR_header)) / sizeof(struct PIR_entry); + printf("Using $PIR table, %d entries at %p\n", pci_route_count, pci_route_table); + } + } + opened = 1; return(1); } @@ -103,6 +129,42 @@ pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) } /* + * Route a PCI interrupt + * + * XXX this needs to learn to actually route uninitialised interrupts as well + * as just returning interrupts for stuff that's already initialised. + */ +int +pci_cfgintr(int bus, int device, int pin) +{ + struct PIR_entry *pe; + int i; + + if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || (pin < 1) || (pin > 4)) { + printf("bus %d pin %d device %d, returning 255\n", bus, pin, device); + return(255); + } + + /* + * Scan the entry table for a contender + */ + printf("bus %d device %d\n", bus, device); + for (i = 0, pe = pci_route_table; i < pci_route_count; i++, pe++) { + printf("pe_bus %d pe_device %d\n", pe->pe_bus, pe->pe_device); + if ((bus != pe->pe_bus) || (device != pe->pe_device)) + continue; + if (!powerof2(pe->pe_intpin[pin - 1].irqs)) { + printf("pci_cfgintr: %d:%d:%c is not routed to a unique interrupt\n", bus, device, 'A' + pin - 1); + break; + } + printf("pci_cfgintr: %d:%d:%c routed to irq %d\n", bus, device, 'A' + pin - 1, ffs(pe->pe_intpin[pin - 1].irqs)); + return(ffs(pe->pe_intpin[pin - 1].irqs)); + } + return(255); +} + + +/* * Config space access using BIOS functions */ static int diff --git a/sys/i386/pci/pci_bus.c b/sys/i386/pci/pci_bus.c index e2d6bd6..665b46d 100644 --- a/sys/i386/pci/pci_bus.c +++ b/sys/i386/pci/pci_bus.c @@ -68,6 +68,14 @@ nexus_pcib_write_config(device_t dev, int bus, int slot, int func, pci_cfgregwrite(bus, slot, func, reg, data, bytes); } +/* route interrupt */ + +static int +nexus_pcib_route_interrupt(device_t bus, int device, int pin) +{ + return(pci_cfgintr(nexus_get_pcibus(bus), device, pin)); +} + static devclass_t pcib_devclass; static const char * @@ -435,6 +443,7 @@ static device_method_t nexus_pcib_methods[] = { DEVMETHOD(pcib_maxslots, nexus_pcib_maxslots), DEVMETHOD(pcib_read_config, nexus_pcib_read_config), DEVMETHOD(pcib_write_config, nexus_pcib_write_config), + DEVMETHOD(pcib_route_interrupt, nexus_pcib_route_interrupt), { 0, 0 } }; diff --git a/sys/i386/pci/pci_cfgreg.c b/sys/i386/pci/pci_cfgreg.c index 2654859..e0b8d74 100644 --- a/sys/i386/pci/pci_cfgreg.c +++ b/sys/i386/pci/pci_cfgreg.c @@ -35,13 +35,14 @@ #include <sys/kernel.h> #include <sys/module.h> #include <sys/malloc.h> - +#include <vm/vm.h> +#include <vm/pmap.h> +#include <machine/md_var.h> #include <pci/pcivar.h> #include <pci/pcireg.h> #include <isa/isavar.h> #include <machine/nexusvar.h> #include <machine/pci_cfgreg.h> - #include <machine/segments.h> #include <machine/pc/bios.h> @@ -58,13 +59,20 @@ 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 struct PIR_entry *pci_route_table; +static int pci_route_count; + /* * Initialise access to PCI configuration space */ int pci_cfgregopen(void) { - static int opened = 0; + static int opened = 0; + u_long sigaddr; + static struct PIR_table *pt; + u_int8_t ck, *cv; + int i; if (opened) return(1); @@ -76,6 +84,24 @@ pci_cfgregopen(void) } else { return(0); } + + /* + * Look for the interrupt routing table. + */ + /* XXX use PCI BIOS if it's available */ + + if ((pt == NULL) && ((sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0)) != 0)) { + pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < (pt->pt_header.ph_length); i++) { + ck += cv[i]; + } + if (ck == 0) { + pci_route_table = &pt->pt_entry[0]; + pci_route_count = (pt->pt_header.ph_length - sizeof(struct PIR_header)) / sizeof(struct PIR_entry); + printf("Using $PIR table, %d entries at %p\n", pci_route_count, pci_route_table); + } + } + opened = 1; return(1); } @@ -103,6 +129,42 @@ pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) } /* + * Route a PCI interrupt + * + * XXX this needs to learn to actually route uninitialised interrupts as well + * as just returning interrupts for stuff that's already initialised. + */ +int +pci_cfgintr(int bus, int device, int pin) +{ + struct PIR_entry *pe; + int i; + + if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || (pin < 1) || (pin > 4)) { + printf("bus %d pin %d device %d, returning 255\n", bus, pin, device); + return(255); + } + + /* + * Scan the entry table for a contender + */ + printf("bus %d device %d\n", bus, device); + for (i = 0, pe = pci_route_table; i < pci_route_count; i++, pe++) { + printf("pe_bus %d pe_device %d\n", pe->pe_bus, pe->pe_device); + if ((bus != pe->pe_bus) || (device != pe->pe_device)) + continue; + if (!powerof2(pe->pe_intpin[pin - 1].irqs)) { + printf("pci_cfgintr: %d:%d:%c is not routed to a unique interrupt\n", bus, device, 'A' + pin - 1); + break; + } + printf("pci_cfgintr: %d:%d:%c routed to irq %d\n", bus, device, 'A' + pin - 1, ffs(pe->pe_intpin[pin - 1].irqs)); + return(ffs(pe->pe_intpin[pin - 1].irqs)); + } + return(255); +} + + +/* * Config space access using BIOS functions */ static int diff --git a/sys/i386/pci/pci_pir.c b/sys/i386/pci/pci_pir.c index 2654859..e0b8d74 100644 --- a/sys/i386/pci/pci_pir.c +++ b/sys/i386/pci/pci_pir.c @@ -35,13 +35,14 @@ #include <sys/kernel.h> #include <sys/module.h> #include <sys/malloc.h> - +#include <vm/vm.h> +#include <vm/pmap.h> +#include <machine/md_var.h> #include <pci/pcivar.h> #include <pci/pcireg.h> #include <isa/isavar.h> #include <machine/nexusvar.h> #include <machine/pci_cfgreg.h> - #include <machine/segments.h> #include <machine/pc/bios.h> @@ -58,13 +59,20 @@ 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 struct PIR_entry *pci_route_table; +static int pci_route_count; + /* * Initialise access to PCI configuration space */ int pci_cfgregopen(void) { - static int opened = 0; + static int opened = 0; + u_long sigaddr; + static struct PIR_table *pt; + u_int8_t ck, *cv; + int i; if (opened) return(1); @@ -76,6 +84,24 @@ pci_cfgregopen(void) } else { return(0); } + + /* + * Look for the interrupt routing table. + */ + /* XXX use PCI BIOS if it's available */ + + if ((pt == NULL) && ((sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0)) != 0)) { + pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); + for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < (pt->pt_header.ph_length); i++) { + ck += cv[i]; + } + if (ck == 0) { + pci_route_table = &pt->pt_entry[0]; + pci_route_count = (pt->pt_header.ph_length - sizeof(struct PIR_header)) / sizeof(struct PIR_entry); + printf("Using $PIR table, %d entries at %p\n", pci_route_count, pci_route_table); + } + } + opened = 1; return(1); } @@ -103,6 +129,42 @@ pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) } /* + * Route a PCI interrupt + * + * XXX this needs to learn to actually route uninitialised interrupts as well + * as just returning interrupts for stuff that's already initialised. + */ +int +pci_cfgintr(int bus, int device, int pin) +{ + struct PIR_entry *pe; + int i; + + if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || (pin < 1) || (pin > 4)) { + printf("bus %d pin %d device %d, returning 255\n", bus, pin, device); + return(255); + } + + /* + * Scan the entry table for a contender + */ + printf("bus %d device %d\n", bus, device); + for (i = 0, pe = pci_route_table; i < pci_route_count; i++, pe++) { + printf("pe_bus %d pe_device %d\n", pe->pe_bus, pe->pe_device); + if ((bus != pe->pe_bus) || (device != pe->pe_device)) + continue; + if (!powerof2(pe->pe_intpin[pin - 1].irqs)) { + printf("pci_cfgintr: %d:%d:%c is not routed to a unique interrupt\n", bus, device, 'A' + pin - 1); + break; + } + printf("pci_cfgintr: %d:%d:%c routed to irq %d\n", bus, device, 'A' + pin - 1, ffs(pe->pe_intpin[pin - 1].irqs)); + return(ffs(pe->pe_intpin[pin - 1].irqs)); + } + return(255); +} + + +/* * Config space access using BIOS functions */ static int |