summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2007-05-21 22:10:46 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2007-05-21 22:10:46 +0000
commit39b73c48db0b5f8169f56b2d9f66f105f7330089 (patch)
treec0517bc9c60ca58c893ac6ec7b5b233782c7d1e5 /sys/arch/i386
parent9d903cf258c7152aeb91ccb923233df9c9017c86 (diff)
Implement deep interrupt swizzling by mapping all four PCI interrupt pins
for PCI-PCI bridges and passing the mapping to the attached bus device. MD code can use these when mapping PCI device interrupts. This diff adds such code for amd64 and i386. This fixes interrupt mapping for devices that sit behind two PCI-PCI bridges where the firmware only provides a mapping for the first PCI-PCI bridge. tested by sturm@, krw@, and a few others, ok deraadt@
Diffstat (limited to 'sys/arch/i386')
-rw-r--r--sys/arch/i386/pci/pci_machdep.c48
1 files changed, 22 insertions, 26 deletions
diff --git a/sys/arch/i386/pci/pci_machdep.c b/sys/arch/i386/pci/pci_machdep.c
index 6353b135729..4627e6bb880 100644
--- a/sys/arch/i386/pci/pci_machdep.c
+++ b/sys/arch/i386/pci/pci_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.c,v 1.38 2007/02/20 21:15:01 tom Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.39 2007/05/21 22:10:45 kettenis Exp $ */
/* $NetBSD: pci_machdep.c,v 1.28 1997/06/06 23:29:17 thorpej Exp $ */
/*-
@@ -104,6 +104,7 @@ extern bios_pciinfo_t *bios_pciinfo;
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
+#include <dev/pci/ppbreg.h>
#include "ioapic.h"
@@ -409,7 +410,10 @@ not2:
int
pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
+ int pin = pa->pa_intrpin;
+ int line = pa->pa_intrline;
#if NIOAPIC > 0
+ int rawpin = pa->pa_rawintrpin;
struct mp_intr_map *mip;
int bus, dev, func;
#endif
@@ -418,15 +422,13 @@ pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
pci_chipset_tag_t pc = pa->pa_pc;
pcitag_t intrtag = pa->pa_intrtag;
#endif
- int pin = pa->pa_intrpin;
- int line = pa->pa_intrline;
if (pin == 0) {
/* No IRQ used. */
goto bad;
}
- if (pin > 4) {
+ if (pin > PCI_INTERRUPT_PIN_MAX) {
printf("pci_intr_map: bad interrupt pin %d\n", pin);
goto bad;
}
@@ -451,18 +453,13 @@ pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
return 0;
}
}
- if (mip == NULL && pa->pa_bridgetag) {
- int bridgebus, bridgedev;
- pci_decompose_tag(pc, *pa->pa_bridgetag,
- &bridgebus, &bridgedev, NULL);
- mpspec_pin = (bridgedev << 2)|((pin + dev - 1) & 0x3);
- for (mip = mp_busses[bridgebus].mb_intrs; mip != NULL;
- mip = mip->next) {
- if (mip->bus_pin == mpspec_pin) {
- ihp->line = mip->ioapic_ih | line;
- return 0;
- }
+ if (pa->pa_bridgetag) {
+ int pin = PPB_INTERRUPT_SWIZZLE(rawpin, dev);
+ if (pa->pa_bridgeih[pin - 1].line != -1) {
+ ihp->line = pa->pa_bridgeih[pin - 1].line;
+ ihp->line |= line;
+ return 0;
}
}
/*
@@ -491,19 +488,18 @@ pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
* that the BIOS did its job, we also recognize that as meaning that
* the BIOS has not configured the device.
*/
- if (line == 0 || line == 255) {
- printf("pci_intr_map: no mapping for pin %c\n", '@' + pin);
+ if (line == 0 || line == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
goto bad;
- } else {
- if (line >= ICU_LEN) {
- printf("pci_intr_map: bad interrupt line %d\n", line);
- goto bad;
- }
- if (line == 2) {
- printf("pci_intr_map: changed line 2 to line 9\n");
- line = 9;
- }
+
+ if (line >= ICU_LEN) {
+ printf("pci_intr_map: bad interrupt line %d\n", line);
+ goto bad;
+ }
+ if (line == 2) {
+ printf("pci_intr_map: changed line 2 to line 9\n");
+ line = 9;
}
+
#if NIOAPIC > 0
if (!(ihp->line & PCI_INT_VIA_ISA) && mp_busses != NULL) {
if (mip == NULL && mp_isa_bus) {