summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2011-05-21 15:14:58 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2011-05-21 15:14:58 +0000
commitb0d2fea50996d8267d0cbc0aa0c2835e25b0a85a (patch)
treefb59c8dd0cef4e73c351ade69887969575f819ee /sys/arch/i386
parentc7f4e256e12129ad2d28cf67dc6351f9ea11244e (diff)
First stab at supporting Message Signaled Interrupts on i386. Still work in
progress. The code is effectively disabled as long as PCI_FLAGS_MSI_ENABLED doesn't get set for the root PCI bus.
Diffstat (limited to 'sys/arch/i386')
-rw-r--r--sys/arch/i386/include/i82093var.h3
-rw-r--r--sys/arch/i386/pci/pci_machdep.c66
-rw-r--r--sys/arch/i386/pci/pci_machdep.h6
3 files changed, 70 insertions, 5 deletions
diff --git a/sys/arch/i386/include/i82093var.h b/sys/arch/i386/include/i82093var.h
index ef7715b6f42..5439da32dc6 100644
--- a/sys/arch/i386/include/i82093var.h
+++ b/sys/arch/i386/include/i82093var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: i82093var.h,v 1.10 2011/03/23 16:54:35 pirofti Exp $ */
+/* $OpenBSD: i82093var.h,v 1.11 2011/05/21 15:14:57 kettenis Exp $ */
/* $NetBSD: i82093var.h,v 1.1 2003/02/26 21:26:10 fvdl Exp $ */
/*-
@@ -71,6 +71,7 @@ struct ioapic_softc {
*/
#define APIC_INT_VIA_APIC 0x10000000
+#define APIC_INT_VIA_MSG 0x20000000
#define APIC_INT_APIC_MASK 0x00ff0000
#define APIC_INT_APIC_SHIFT 16
#define APIC_INT_PIN_MASK 0x0000ff00
diff --git a/sys/arch/i386/pci/pci_machdep.c b/sys/arch/i386/pci/pci_machdep.c
index 74af57f3f86..2b18b445fc9 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.59 2011/04/22 15:02:35 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.60 2011/05/21 15:14:57 kettenis Exp $ */
/* $NetBSD: pci_machdep.c,v 1.28 1997/06/06 23:29:17 thorpej Exp $ */
/*-
@@ -103,6 +103,8 @@ extern bios_pciinfo_t *bios_pciinfo;
#include "ioapic.h"
#include <machine/i82093var.h>
+#include <machine/i82489reg.h>
+#include <machine/i82489var.h>
#if NIOAPIC > 0
#include <machine/mpbiosvar.h>
#endif
@@ -478,6 +480,22 @@ not2:
}
int
+pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
+{
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pcitag_t tag = pa->pa_tag;
+
+ if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 ||
+ pci_get_capability(pc, tag, PCI_CAP_MSI, NULL, NULL) == 0)
+ return 1;
+
+ ihp->tag = tag;
+ ihp->line = APIC_INT_VIA_MSG;
+ ihp->pin = 0;
+ return 0;
+}
+
+int
pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
int pin = pa->pa_rawintrpin;
@@ -607,6 +625,9 @@ pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
static char irqstr[64];
int line = ih.line & APIC_INT_LINE_MASK;
+ if (ih.line & APIC_INT_VIA_MSG)
+ return ("msi");
+
#if NIOAPIC > 0
if (ih.line & APIC_INT_VIA_APIC) {
snprintf(irqstr, sizeof irqstr, "apic %d int %d",
@@ -627,6 +648,9 @@ pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
void acpiprt_route_interrupt(int bus, int dev, int pin);
#endif
+extern struct intrhand *apic_intrhand[256];
+extern int apic_maxlevel[256];
+
void *
pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
int (*func)(void *), void *arg, const char *what)
@@ -634,6 +658,46 @@ pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
void *ret;
int bus, dev;
int l = ih.line & APIC_INT_LINE_MASK;
+ pcitag_t tag = ih.tag;
+
+ if (ih.line & APIC_INT_VIA_MSG) {
+ struct intrhand *ih;
+ pcireg_t reg;
+ int off, vec;
+
+ if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
+ panic("%s: no msi capability", __func__);
+
+ vec = idt_vec_alloc(level, level + 15);
+ if (vec == 0)
+ return (NULL);
+
+ ih = malloc(sizeof(*ih), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
+ if (ih == NULL)
+ panic("%s: can't malloc handler info", __func__);
+
+ ih->ih_fun = func;
+ ih->ih_arg = arg;
+ ih->ih_next = NULL;
+ ih->ih_level = level;
+ ih->ih_irq = vec;
+ evcount_attach(&ih->ih_count, what, &ih->ih_irq);
+
+ apic_maxlevel[vec] = level;
+ apic_intrhand[vec] = ih;
+ idt_vec_set(vec, apichandler[vec & 0xf]);
+
+ if (reg & PCI_MSI_MC_C64) {
+ pci_conf_write(pc, tag, off + PCI_MSI_MA, 0xfee00000);
+ pci_conf_write(pc, tag, off + PCI_MSI_MAU32, 0);
+ pci_conf_write(pc, tag, off + PCI_MSI_MD64, vec);
+ } else {
+ pci_conf_write(pc, tag, off + PCI_MSI_MA, 0xfee00000);
+ pci_conf_write(pc, tag, off + PCI_MSI_MD32, vec);
+ }
+ pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE);
+ return (ih);
+ }
pci_decompose_tag(pc, ih.tag, &bus, &dev, NULL);
#if NACPIPRT > 0
diff --git a/sys/arch/i386/pci/pci_machdep.h b/sys/arch/i386/pci/pci_machdep.h
index 378c684bfb8..13c5f711095 100644
--- a/sys/arch/i386/pci/pci_machdep.h
+++ b/sys/arch/i386/pci/pci_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.h,v 1.21 2011/01/04 21:17:49 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.22 2011/05/21 15:14:57 kettenis Exp $ */
/* $NetBSD: pci_machdep.h,v 1.7 1997/06/06 23:29:18 thorpej Exp $ */
/*
@@ -96,8 +96,8 @@ pcireg_t pci_conf_read(pci_chipset_tag_t, pcitag_t, int);
void pci_conf_write(pci_chipset_tag_t, pcitag_t, int,
pcireg_t);
struct pci_attach_args;
-int pci_intr_map(struct pci_attach_args *,
- pci_intr_handle_t *);
+int pci_intr_map_msi(struct pci_attach_args *, pci_intr_handle_t *);
+int pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
#define pci_intr_line(c, ih) ((ih).line)
const char *pci_intr_string(pci_chipset_tag_t, pci_intr_handle_t);
void *pci_intr_establish(pci_chipset_tag_t, pci_intr_handle_t,