diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2007-06-17 14:51:22 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2007-06-17 14:51:22 +0000 |
commit | 5015da80f9284319f48f2a784262f2ccbb5dc4d9 (patch) | |
tree | 1e15cc88682ac6b7220ca897e3b792fc5e800d99 /sys | |
parent | fcc9c413fbd826a46db7f895e5d99e46836078f6 (diff) |
Get interrupt information from PDC and use it to program the IO SAPIC.
Needed to make edge triggered interrupts work.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/hppa/dev/apic.c | 120 | ||||
-rw-r--r-- | sys/arch/hppa/dev/elroy.c | 3 | ||||
-rw-r--r-- | sys/arch/hppa/dev/elroyvar.h | 8 |
3 files changed, 123 insertions, 8 deletions
diff --git a/sys/arch/hppa/dev/apic.c b/sys/arch/hppa/dev/apic.c index a52307c4033..fffd0c529eb 100644 --- a/sys/arch/hppa/dev/apic.c +++ b/sys/arch/hppa/dev/apic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: apic.c,v 1.2 2007/05/27 16:36:07 kettenis Exp $ */ +/* $OpenBSD: apic.c,v 1.3 2007/06/17 14:51:21 kettenis Exp $ */ /* * Copyright (c) 2005 Michael Shalayeff @@ -39,6 +39,26 @@ #define APIC_INT_LINE(x) (((x) & APIC_INT_LINE_MASK) >> APIC_INT_LINE_SHIFT) #define APIC_INT_IRQ(x) ((x) & APIC_INT_IRQ_MASK) +/* + * Interrupt types match the Intel MP Specification. + */ + +#define MPS_INTPO_DEF 0 +#define MPS_INTPO_ACTHI 1 +#define MPS_INTPO_ACTLO 3 +#define MPS_INTPO_SHIFT 0 +#define MPS_INTPO_MASK 3 + +#define MPS_INTTR_DEF 0 +#define MPS_INTTR_EDGE 1 +#define MPS_INTTR_LEVEL 3 +#define MPS_INTTR_SHIFT 2 +#define MPS_INTTR_MASK 3 + +#define MPS_INT(p,t) \ + ((((p) & MPS_INTPO_MASK) << MPS_INTPO_SHIFT) | \ + (((t) & MPS_INTTR_MASK) << MPS_INTTR_SHIFT)) + struct apic_iv { struct elroy_softc *sc; pci_intr_handle_t ih; @@ -49,6 +69,8 @@ struct apic_iv { struct apic_iv *apic_intr_list[CPU_NINTS]; +void apic_get_int_tbl(struct elroy_softc *); +u_int32_t apic_get_int_ent0(struct elroy_softc *, int); #ifdef DEBUG void apic_dump(struct elroy_softc *); #endif @@ -84,6 +106,8 @@ apic_attach(struct elroy_softc *sc) panic("apic_attach: cannot allocate irq table\n"); memset(sc->sc_irq, 0, sc->sc_nints * sizeof(int)); + apic_get_int_tbl(sc); + #ifdef DEBUG apic_dump(sc); #endif @@ -157,8 +181,7 @@ apic_intr_establish(void *v, pci_intr_handle_t ih, if ((iv = cpu_intr_establish(pri, irq, apic_intr, aiv, name))) { ent0 = (31 - irq) & APIC_ENT0_VEC; - ent0 |= APIC_ENT0_LOW; - ent0 |= APIC_ENT0_LEV; + ent0 |= apic_get_int_ent0(sc, line); #if 0 if (cold) { sc->sc_imr |= (1 << irq); @@ -205,12 +228,94 @@ apic_intr(void *v) return (claimed); } +/* Maximum number of supported interrupt routing entries. */ +#define MAX_INT_TBL_SZ 8 + +void +apic_get_int_tbl(struct elroy_softc *sc) +{ + struct pdc_pat_io_num int_tbl_sz PDC_ALIGNMENT; + struct pdc_pat_pci_rt int_tbl[MAX_INT_TBL_SZ] PDC_ALIGNMENT; + size_t size; + + /* + * XXX int_tbl should not be allocated on the stack, but we need a + * 1:1 mapping, and malloc doesn't provide that. + */ + + if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SZ, + &int_tbl_sz, 0, 0, 0, 0, 0)) + return; + + if (int_tbl_sz.num > MAX_INT_TBL_SZ) + panic("interrupt routing table too big (%d entries)", + int_tbl_sz.num); + + size = int_tbl_sz.num * sizeof(struct pdc_pat_pci_rt); + sc->sc_int_tbl_sz = int_tbl_sz.num; + sc->sc_int_tbl = malloc(size, M_DEVBUF, M_NOWAIT); + if (sc->sc_int_tbl == NULL) + return; + + if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, + &int_tbl_sz, 0, &int_tbl, 0, 0, 0)) + return; + + memcpy(sc->sc_int_tbl, int_tbl, size); +} + +u_int32_t +apic_get_int_ent0(struct elroy_softc *sc, int line) +{ + int trigger = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF); + u_int32_t ent0 = APIC_ENT0_LOW | APIC_ENT0_LEV; + int mpspo, mpstr; + int i; + + for (i = 0; i < sc->sc_int_tbl_sz; i++) { + if (line == sc->sc_int_tbl[i].line && + sc->sc_hpa == sc->sc_int_tbl[i].addr) + trigger = sc->sc_int_tbl[i].trigger; + } + + mpspo = (trigger >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK; + mpstr = (trigger >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK; + + switch (mpspo) { + case MPS_INTPO_DEF: + break; + case MPS_INTPO_ACTHI: + ent0 &= ~APIC_ENT0_LOW; + break; + case MPS_INTPO_ACTLO: + ent0 |= APIC_ENT0_LOW; + break; + default: + panic("unknown MPS interrupt polarity %d", mpspo); + } + + switch(mpstr) { + case MPS_INTTR_DEF: + break; + case MPS_INTTR_LEVEL: + ent0 |= APIC_ENT0_LEV; + break; + case MPS_INTTR_EDGE: + ent0 &= ~APIC_ENT0_LEV; + break; + default: + panic("unknown MPS interrupt trigger %d", mpstr); + } + + return ent0; +} + #ifdef DEBUG void apic_dump(struct elroy_softc *sc) { struct pdc_pat_io_num int_tbl_sz PDC_ALIGNMENT; - struct pdc_pat_pci_rt int_tbl[5] PDC_ALIGNMENT; + struct pdc_pat_pci_rt int_tbl[MAX_INT_TBL_SZ] PDC_ALIGNMENT; int i; for (i = 0; i < sc->sc_nints; i++) @@ -221,11 +326,14 @@ apic_dump(struct elroy_softc *sc) &int_tbl_sz, 0, 0, 0, 0, 0)) printf("pdc_call failed\n"); printf("int_tbl_sz=%d\n", int_tbl_sz.num); - + + if (int_tbl_sz.num > MAX_INT_TBL_SZ) + int_tbl_sz.num = MAX_INT_TBL_SZ; + if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, &int_tbl_sz, 0, &int_tbl, 0, 0, 0)) printf("pdc_call failed\n"); - for (i = 0; i < 5; i++) { + for (i = 0; i < int_tbl_sz.num; i++) { printf("type=%x, len=%d ", int_tbl[i].type, int_tbl[i].len); printf("itype=%d, trigger=%x ", int_tbl[i].itype, int_tbl[i].trigger); printf("pin=%x, bus=%d ", int_tbl[i].pin, int_tbl[i].bus); diff --git a/sys/arch/hppa/dev/elroy.c b/sys/arch/hppa/dev/elroy.c index 2004b85c629..df499df1e3d 100644 --- a/sys/arch/hppa/dev/elroy.c +++ b/sys/arch/hppa/dev/elroy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: elroy.c,v 1.2 2007/05/23 18:07:19 kettenis Exp $ */ +/* $OpenBSD: elroy.c,v 1.3 2007/06/17 14:51:21 kettenis Exp $ */ /* * Copyright (c) 2005 Michael Shalayeff @@ -1081,6 +1081,7 @@ elroy_attach(struct device *parent, struct device *self, void *aux) const char *p = NULL, *q; int i; + sc->sc_hpa = ca->ca_hpa; sc->sc_bt = ca->ca_iot; sc->sc_dmat = ca->ca_dmatag; if (bus_space_map(sc->sc_bt, ca->ca_hpa, ca->ca_hpasz, 0, &sc->sc_bh)) { diff --git a/sys/arch/hppa/dev/elroyvar.h b/sys/arch/hppa/dev/elroyvar.h index 20c2ed86d70..157ad204a7d 100644 --- a/sys/arch/hppa/dev/elroyvar.h +++ b/sys/arch/hppa/dev/elroyvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: elroyvar.h,v 1.2 2007/05/27 16:36:07 kettenis Exp $ */ +/* $OpenBSD: elroyvar.h,v 1.3 2007/06/17 14:51:21 kettenis Exp $ */ /* * Copyright (c) 2005 Michael Shalayeff @@ -17,10 +17,13 @@ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <machine/pdc.h> + struct elroy_softc { struct device sc_dv; int sc_ver; + hppa_hpa_t sc_hpa; bus_space_tag_t sc_bt; bus_space_handle_t sc_bh; bus_dma_tag_t sc_dmat; @@ -31,6 +34,9 @@ struct elroy_softc { int sc_nints; int *sc_irq; + struct pdc_pat_pci_rt *sc_int_tbl; + int sc_int_tbl_sz; + struct hppa_pci_chipset_tag sc_pc; struct hppa_bus_space_tag sc_iot; struct hppa_bus_space_tag sc_memt; |