diff --git a/sys/arch/algor/algor/algor_p4032_intr.c b/sys/arch/algor/algor/algor_p4032_intr.c index 84b3a47fb633..9bda5fd8e549 100644 --- a/sys/arch/algor/algor/algor_p4032_intr.c +++ b/sys/arch/algor/algor/algor_p4032_intr.c @@ -1,4 +1,4 @@ -/* $NetBSD: algor_p4032_intr.c,v 1.2 2001/06/10 05:26:58 thorpej Exp $ */ +/* $NetBSD: algor_p4032_intr.c,v 1.3 2001/06/10 09:13:06 thorpej Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -186,13 +186,6 @@ const struct p4032_irqmap p4032_irqmap[NIRQMAPS] = { 1, 6 }, }; -struct p4032_intrhand { - LIST_ENTRY(p4032_intrhand) ih_q; - int (*ih_func)(void *); - void *ih_arg; - const struct p4032_irqmap *ih_irqmap; -}; - struct p4032_intrhead { struct evcnt intr_count; int intr_refcnt; @@ -202,7 +195,7 @@ struct p4032_intrhead p4032_intrtab[NIRQMAPS]; #define NINTRS 2 /* MIPS INT0 - INT1 */ struct p4032_cpuintr { - LIST_HEAD(, p4032_intrhand) cintr_list; + LIST_HEAD(, algor_intrhand) cintr_list; struct evcnt cintr_count; }; @@ -338,7 +331,7 @@ void * algor_p4032_intr_establish(const struct p4032_irqmap *irqmap, int (*func)(void *), void *arg) { - struct p4032_intrhand *ih; + struct algor_intrhand *ih; int s; ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); @@ -347,6 +340,7 @@ algor_p4032_intr_establish(const struct p4032_irqmap *irqmap, ih->ih_func = func; ih->ih_arg = arg; + ih->ih_irq = 0; ih->ih_irqmap = irqmap; s = splhigh(); @@ -375,7 +369,7 @@ void algor_p4032_intr_disestablish(void *v, void *cookie) { const struct p4032_irqmap *irqmap; - struct p4032_intrhand *ih = v; + struct algor_intrhand *ih = v; int s; s = splhigh(); @@ -404,7 +398,8 @@ void algor_p4032_iointr(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending) { - struct p4032_intrhand *ih; + const struct p4032_irqmap *irqmap; + struct algor_intrhand *ih; int level, i; u_int32_t irr[NIRQREG]; @@ -460,10 +455,10 @@ algor_p4032_iointr(u_int32_t status, u_int32_t cause, u_int32_t pc, p4032_cpuintrs[level].cintr_count.ev_count++; for (ih = LIST_FIRST(&p4032_cpuintrs[level].cintr_list); ih != NULL; ih = LIST_NEXT(ih, ih_q)) { - if (irr[ih->ih_irqmap->irqreg] & - ih->ih_irqmap->irqbit) { + irqmap = ih->ih_irqmap; + if (irr[irqmap->irqreg] & irqmap->irqbit) { p4032_intrtab[ - ih->ih_irqmap->irqidx].intr_count.ev_count++; + irqmap->irqidx].intr_count.ev_count++; (*ih->ih_func)(ih->ih_arg); } } diff --git a/sys/arch/algor/algor/algor_p5064_intr.c b/sys/arch/algor/algor/algor_p5064_intr.c index a641fa0a9af7..118ffbd9aeb6 100644 --- a/sys/arch/algor/algor/algor_p5064_intr.c +++ b/sys/arch/algor/algor/algor_p5064_intr.c @@ -1,4 +1,4 @@ -/* $NetBSD: algor_p5064_intr.c,v 1.2 2001/06/10 05:26:58 thorpej Exp $ */ +/* $NetBSD: algor_p5064_intr.c,v 1.3 2001/06/10 09:13:07 thorpej Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -80,15 +80,6 @@ struct p5064_irqreg { u_int32_t val; }; -struct p5064_irqmap { - int irqidx; - int cpuintr; - int irqreg; - int irqbit; - int xbarreg; - int xbarshift; -}; - #define IRQREG_LOCINT 0 #define IRQREG_PANIC 1 #define IRQREG_PCIINT 2 @@ -114,22 +105,10 @@ struct p5064_irqreg p5064_irqsteer[NSTEERREG] = { { P5064_XBAR4, 0 }, }; -#define IRQ_ETHERNET 4 -#define IRQ_SCSI 5 -#define IRQ_USB 6 #define NPCIIRQS 7 -#define IRQ_MKBD 7 -#define IRQ_COM1 8 -#define IRQ_COM2 9 -#define IRQ_FLOPPY 10 -#define IRQ_CENTRONICS 11 -#define IRQ_RTC 12 #define NLOCIRQS 6 -#define IRQ_ISABRIDGE 13 -#define IRQ_IDE0 14 -#define IRQ_IDE1 15 #define NISAIRQS 3 #define IRQMAP_PCIBASE 0 @@ -260,28 +239,21 @@ const struct p5064_irqmap p5064_irqmap[NIRQMAPS] = { const int p5064_isa_to_irqmap[16] = { -1, /* 0 */ - IRQ_MKBD, /* 1 */ + P5064_IRQ_MKBD, /* 1 */ -1, /* 2 */ - IRQ_COM2, /* 3 */ - IRQ_COM1, /* 4 */ + P5064_IRQ_COM2, /* 3 */ + P5064_IRQ_COM1, /* 4 */ -1, /* 5 */ - IRQ_FLOPPY, /* 6 */ - IRQ_CENTRONICS, /* 7 */ - IRQ_RTC, /* 8 */ + P5064_IRQ_FLOPPY, /* 6 */ + P5064_IRQ_CENTRONICS, /* 7 */ + P5064_IRQ_RTC, /* 8 */ -1, /* 9 */ -1, /* 10 */ -1, /* 11 */ - IRQ_MKBD, /* 12 */ + P5064_IRQ_MKBD, /* 12 */ -1, /* 13 */ - IRQ_IDE0, /* 14 */ - IRQ_IDE1, /* 15 */ -}; - -struct p5064_intrhand { - LIST_ENTRY(p5064_intrhand) ih_q; - int (*ih_func)(void *); - void *ih_arg; - const struct p5064_irqmap *ih_irqmap; + P5064_IRQ_IDE0, /* 14 */ + P5064_IRQ_IDE1, /* 15 */ }; struct p5064_intrhead { @@ -293,7 +265,7 @@ struct p5064_intrhead p5064_intrtab[NIRQMAPS]; #define NINTRS 3 /* MIPS INT0 - INT2 */ struct p5064_cpuintr { - LIST_HEAD(, p5064_intrhand) cintr_list; + LIST_HEAD(, algor_intrhand) cintr_list; struct evcnt cintr_count; }; @@ -310,10 +282,6 @@ const char *p5064_intrgroups[NINTRS] = { "local", }; -void algor_p5064_intr_disestablish(void *, void *); -void *algor_p5064_intr_establish(const struct p5064_irqmap *, - int (*)(void *), void *); - int algor_p5064_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *); const char *algor_p5064_pci_intr_string(void *, pci_intr_handle_t); const struct evcnt *algor_p5064_pci_intr_evcnt(void *, pci_intr_handle_t); @@ -448,7 +416,7 @@ void * algor_p5064_intr_establish(const struct p5064_irqmap *irqmap, int (*func)(void *), void *arg) { - struct p5064_intrhand *ih; + struct algor_intrhand *ih; int s; ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); @@ -457,6 +425,7 @@ algor_p5064_intr_establish(const struct p5064_irqmap *irqmap, ih->ih_func = func; ih->ih_arg = arg; + ih->ih_irq = 0; ih->ih_irqmap = irqmap; s = splhigh(); @@ -485,7 +454,7 @@ void algor_p5064_intr_disestablish(void *v, void *cookie) { const struct p5064_irqmap *irqmap; - struct p5064_intrhand *ih = v; + struct algor_intrhand *ih = v; int s; s = splhigh(); @@ -514,7 +483,8 @@ void algor_p5064_iointr(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending) { - struct p5064_intrhand *ih; + const struct p5064_irqmap *irqmap; + struct algor_intrhand *ih; int level, i; u_int32_t irr[NIRQREG]; @@ -562,10 +532,10 @@ algor_p5064_iointr(u_int32_t status, u_int32_t cause, u_int32_t pc, p5064_cpuintrs[level].cintr_count.ev_count++; for (ih = LIST_FIRST(&p5064_cpuintrs[level].cintr_list); ih != NULL; ih = LIST_NEXT(ih, ih_q)) { - if (irr[ih->ih_irqmap->irqreg] & - ih->ih_irqmap->irqbit) { + irqmap = ih->ih_irqmap; + if (irr[irqmap->irqreg] & irqmap->irqbit) { p5064_intrtab[ - ih->ih_irqmap->irqidx].intr_count.ev_count++; + irqmap->irqidx].intr_count.ev_count++; (*ih->ih_func)(ih->ih_arg); } } @@ -585,12 +555,12 @@ algor_p5064_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) { static const int pciirqmap[6/*device*/][4/*pin*/] = { - { IRQ_ETHERNET, -1, -1, -1 }, /* 0: Ethernet */ - { IRQ_SCSI, -1, -1, -1 }, /* 1: SCSI */ - { -1, -1, -1, IRQ_USB }, /* 2: PCI-ISA bridge */ - { 0, 1, 2, 3 }, /* 3: PCI slot 3 */ - { 3, 0, 1, 2 }, /* 4: PCI slot 2 */ - { 2, 3, 0, 1 }, /* 5: PCI slot 1 */ + { P5064_IRQ_ETHERNET, -1, -1, -1 }, /* 0: Ethernet */ + { P5064_IRQ_SCSI, -1, -1, -1 }, /* 1: SCSI */ + { -1, -1, -1, P5064_IRQ_USB }, /* 2: PCI-ISA bridge */ + { 0, 1, 2, 3 }, /* 3: PCI slot 3 */ + { 3, 0, 1, 2 }, /* 4: PCI slot 2 */ + { 2, 3, 0, 1 }, /* 5: PCI slot 1 */ }; pcitag_t bustag = pa->pa_intrtag; int buspin = pa->pa_intrpin; @@ -683,7 +653,7 @@ algor_p5064_pciide_compat_intr_establish(void *v, struct device *dev, if (bus != 0) return (NULL); - irqmap = &p5064_irqmap[IRQ_IDE0 + chan]; + irqmap = &p5064_irqmap[P5064_IRQ_IDE0 + chan]; cookie = algor_p5064_intr_establish(irqmap, func, arg); if (cookie == NULL) @@ -715,10 +685,6 @@ algor_p5064_isa_intr_establish(void *v, int iirq, int type, int level, if (iirq > 15 || type == IST_NONE) panic("algor_p5064_isa_intr_establish: bad irq or type"); - /* - * XXX WE CURRENTLY DO NOT DO ANYTHING USEFUL AT ALL WITH - * XXX REGULAR ISA INTERRUPTS. - */ if ((irqidx = p5064_isa_to_irqmap[iirq]) == -1) return (NULL); diff --git a/sys/arch/algor/algor/algor_p5064var.h b/sys/arch/algor/algor/algor_p5064var.h index 64d54c6ab3af..232ad0cb8b53 100644 --- a/sys/arch/algor/algor/algor_p5064var.h +++ b/sys/arch/algor/algor/algor_p5064var.h @@ -1,4 +1,4 @@ -/* $NetBSD: algor_p5064var.h,v 1.2 2001/06/10 05:26:58 thorpej Exp $ */ +/* $NetBSD: algor_p5064var.h,v 1.3 2001/06/10 09:13:07 thorpej Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -57,7 +57,36 @@ struct p5064_config { }; #ifdef _KERNEL +#define P5064_IRQ_ETHERNET 4 +#define P5064_IRQ_SCSI 5 +#define P5064_IRQ_USB 6 + +#define P5064_IRQ_MKBD 7 +#define P5064_IRQ_COM1 8 +#define P5064_IRQ_COM2 9 +#define P5064_IRQ_FLOPPY 10 +#define P5064_IRQ_CENTRONICS 11 +#define P5064_IRQ_RTC 12 + +#define P5064_IRQ_ISABRIDGE 13 +#define P5064_IRQ_IDE0 14 +#define P5064_IRQ_IDE1 15 + +struct p5064_irqmap { + int irqidx; + int cpuintr; + int irqreg; + int irqbit; + int xbarreg; + int xbarshift; +}; + +void algor_p5064_intr_disestablish(void *, void *); +void *algor_p5064_intr_establish(const struct p5064_irqmap *, + int (*)(void *), void *); + extern struct p5064_config p5064_configuration; +extern const struct p5064_irqmap p5064_irqmap[]; void algor_p5064_bus_io_init(bus_space_tag_t, void *); void algor_p5064_bus_mem_init(bus_space_tag_t, void *); diff --git a/sys/arch/algor/include/intr.h b/sys/arch/algor/include/intr.h index 7496bae40997..83de7a37b8de 100644 --- a/sys/arch/algor/include/intr.h +++ b/sys/arch/algor/include/intr.h @@ -1,4 +1,4 @@ -/* $NetBSD: intr.h,v 1.2 2001/06/10 05:26:59 thorpej Exp $ */ +/* $NetBSD: intr.h,v 1.3 2001/06/10 09:13:07 thorpej Exp $ */ /*- * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. @@ -114,6 +114,14 @@ extern int _clrsoftintr(int); #define spllowersoftclock() _spllower(ipl_sr_bits[IPL_SOFTCLOCK]) +struct algor_intrhand { + LIST_ENTRY(algor_intrhand) ih_q; + int (*ih_func)(void *); + void *ih_arg; + int ih_irq; /* mostly for ISA */ + const void *ih_irqmap; +}; + #define setsoft(x) \ do { \ _setsoftintr(ipl_si_to_sr[(x) - IPL_SOFT]); \ diff --git a/sys/arch/algor/pci/pcib.c b/sys/arch/algor/pci/pcib.c index 5054318dcfac..702058ff8390 100644 --- a/sys/arch/algor/pci/pcib.c +++ b/sys/arch/algor/pci/pcib.c @@ -1,4 +1,4 @@ -/* $NetBSD: pcib.c,v 1.2 2001/06/01 15:20:06 thorpej Exp $ */ +/* $NetBSD: pcib.c,v 1.3 2001/06/10 09:13:07 thorpej Exp $ */ /*- * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ #include /* RCS ID & Copyright macro defns */ -__KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.2 2001/06/01 15:20:06 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.3 2001/06/10 09:13:07 thorpej Exp $"); #include "opt_algor_p5064.h" #include "opt_algor_p6032.h" @@ -52,6 +52,7 @@ __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.2 2001/06/01 15:20:06 thorpej Exp $"); #include #include +#include #include #include @@ -66,9 +67,52 @@ __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.2 2001/06/01 15:20:06 thorpej Exp $"); #include #endif +const char *pcib_intrnames[16] = { + "irq 0", + "irq 1", + "irq 2", + "irq 3", + "irq 4", + "irq 5", + "irq 6", + "irq 7", + "irq 8", + "irq 9", + "irq 10", + "irq 11", + "irq 12", + "irq 13", + "irq 14", + "irq 15", +}; + +struct pcib_intrhead { + LIST_HEAD(, algor_intrhand) intr_q; + struct evcnt intr_count; + int intr_type; +}; struct pcib_softc { struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh_icu1; + bus_space_handle_t sc_ioh_icu2; + bus_space_handle_t sc_ioh_elcr; + + struct algor_isa_chipset sc_ic; + + struct pcib_intrhead sc_intrtab[16]; + + u_int16_t sc_inten; + u_int16_t sc_elcr; + +#if defined(ALGOR_P5064) + isa_chipset_tag_t sc_parent_ic; + u_int16_t sc_reserved; +#endif + + void *sc_ih; }; int pcib_match(struct device *, struct cfdata *, void *); @@ -82,8 +126,18 @@ int pcib_print(void *, const char *pnp); void pcib_isa_attach_hook(struct device *, struct device *, struct isabus_attach_args *); +int pcib_intr(void *); + void pcib_bridge_callback(struct device *); +const struct evcnt *pcib_isa_intr_evcnt(void *, int); +void *pcib_isa_intr_establish(void *, int, int, int, + int (*)(void *), void *); +void pcib_isa_intr_disestablish(void *, void *); +int pcib_isa_intr_alloc(void *, int, int, int *); + +void pcib_set_icus(struct pcib_softc *); + int pcib_match(struct device *parent, struct cfdata *match, void *aux) { @@ -99,13 +153,133 @@ pcib_match(struct device *parent, struct cfdata *match, void *aux) void pcib_attach(struct device *parent, struct device *self, void *aux) { + struct pcib_softc *sc = (void *) self; struct pci_attach_args *pa = aux; char devinfo[256]; + int i; pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo); printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class)); + sc->sc_iot = pa->pa_iot; + + /* + * Map the PIC/ELCR registers. + */ + if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0) + printf("%s: unable to map ELCR registers\n", + sc->sc_dev.dv_xname); + if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0) + printf("%s: unable to map ICU1 registers\n", + sc->sc_dev.dv_xname); + if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0) + printf("%s: unable to map ICU2 registers\n", + sc->sc_dev.dv_xname); + + /* + * Initialize the 8259s. + */ + + /* ICW1: reset; program device, 4 bytes */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x11); + + /* ICW2: vector base address */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 32/*XXX*/); + + /* ICW3: cascade mode */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 0x04); + + /* ICW4: 8086 mode */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 0x01); + + /* OCW1: mask all interrupts */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, + ~sc->sc_inten & 0xff); + + /* OCW3: enable special mask mode */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x68); + + /* OCW3: read IRR by default */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x0a); + + + /* ICW1: reset; program device, 4 bytes */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x11); + + /* ICW2: vector base address */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 32+8/*XXX*/); + + /* ICW3: slave ID code */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 0x02); + + /* ICW4: 8086 mode */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 0x01); + + /* OCW1: mask all interrupts */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, + (~sc->sc_inten >> 8) & 0xff); + + /* OCW3: enable special mask mode */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x68); + + /* OCW3: read IRR by default */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x0a); + + /* + * Default all interrupts to edge-triggered. + */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, + sc->sc_elcr & 0xff); + bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, + (sc->sc_elcr >> 8) & 0xff); + +#if defined(ALGOR_P5064) + /* + * Some "ISA" interrupts are a little wacky, wired up directly + * to the P-5064 interrupt controller. + */ + sc->sc_reserved = + (1 << 1) | + (1 << 3) | + (1 << 4) | + (1 << 6) | + (1 << 7) | + (1 << 8) | + (1 << 12) | + (1 << 14) | + (1 << 15); + + sc->sc_parent_ic = &p5064_configuration.ac_ic; +#endif /* ALGOR_P5064 */ + + /* Set up our ISA chipset. */ + sc->sc_ic.ic_v = sc; + sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt; + sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish; + sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish; + sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc; + + /* Initialize our interrupt table. */ + for (i = 0; i < 16; i++) { + LIST_INIT(&sc->sc_intrtab[i].intr_q); + evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count, + EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]); + sc->sc_intrtab[i].intr_type = IST_NONE; + } + + /* Hook up our interrupt handler. */ +#if defined(ALGOR_P5064) + sc->sc_ih = algor_p5064_intr_establish(&p5064_irqmap[ + P5064_IRQ_ISABRIDGE], pcib_intr, sc); +#elif defined(ALGOR_P6032) + sc->sc_ih = algor_p6032_intr_establish(&p6032_irqmap[XXX], + pcib_intr, sc); +#endif + if (sc->sc_ih == NULL) + printf("%s: WARNING: unable to register interrupt handler\n", + sc->sc_dev.dv_xname); + config_defer(self, pcib_bridge_callback); } @@ -156,3 +330,222 @@ pcib_isa_attach_hook(struct device *parent, struct device *self, /* Nothing to do. */ } + +void +pcib_set_icus(struct pcib_softc *sc) +{ + + /* Enable the cascade IRQ (2) if 8-15 is enabled. */ + if (sc->sc_inten & 0xff00) + sc->sc_inten |= (1 << 2); + else + sc->sc_inten &= ~(1 << 2); + + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, + ~sc->sc_inten & 0xff); + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, + (~sc->sc_inten >> 8) & 0xff); + + bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, + sc->sc_elcr & 0xff); + bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, + (sc->sc_elcr >> 8) & 0xff); +} + +int +pcib_intr(void *v) +{ + struct pcib_softc *sc = v; + struct algor_intrhand *ih; + u_int16_t ipending; + int i; + + ipending = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, 0) | + (bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2, 0) << 8); + ipending &= (sc->sc_inten & ~0x02); + if (ipending == 0) + return (0); + + for (i = 0; i < 16; i++) { + if ((ipending & (1 << i)) == 0) + continue; + sc->sc_intrtab[i].intr_count.ev_count++; + for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q); + ih != NULL; ih = LIST_NEXT(ih, ih_q)) { + (*ih->ih_func)(ih->ih_arg); + } + + /* Send a specific EOI to the 8259. */ + if (i > 7) + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, + 0, 0x20 | (i & 0x07)); + bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, + 0x20 | (i > 7 ? 2 : i)); + } + + return (1); +} + +const struct evcnt * +pcib_isa_intr_evcnt(void *v, int irq) +{ + struct pcib_softc *sc = v; + + return (&sc->sc_intrtab[irq].intr_count); +} + +void * +pcib_isa_intr_establish(void *v, int irq, int type, int level, + int (*func)(void *), void *arg) +{ + struct pcib_softc *sc = v; + struct algor_intrhand *ih; + int s; + + if (irq > 15 || irq == 2 || type == IST_NONE) + panic("pcib_isa_intr_establish: bad irq or type"); + +#if defined(ALGOR_P5064) + if (sc->sc_reserved & (1 << irq)) { + ih = isa_intr_establish(sc->sc_parent_ic, irq, type, + level, func, arg); + if (ih != NULL) + ih->ih_irq = irq; + } +#endif + + switch (sc->sc_intrtab[irq].intr_type) { + case IST_NONE: + sc->sc_intrtab[irq].intr_type = type; + break; + + case IST_EDGE: + case IST_LEVEL: + if (type == sc->sc_intrtab[irq].intr_type) + break; + /* FALLTHROUGH */ + case IST_PULSE: + /* + * We can't share interrupts in this case. + */ + return (NULL); + } + + ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); + if (ih == NULL) + return (NULL); + + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_irq = irq; + ih->ih_irqmap = NULL; + + s = splhigh(); + + /* Insert the handler into the table. */ + LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q); + sc->sc_intrtab[irq].intr_type = type; + + /* Enable it, set trigger mode. */ + sc->sc_inten |= (1 << irq); + if (sc->sc_intrtab[irq].intr_type == IST_LEVEL) + sc->sc_elcr |= (1 << irq); + else + sc->sc_elcr &= ~(1 << irq); + + pcib_set_icus(sc); + + splx(s); + + return (ih); +} + +void +pcib_isa_intr_disestablish(void *v, void *arg) +{ + struct pcib_softc *sc = v; + struct algor_intrhand *ih = arg; + int s; + +#if defined(ALGOR_P5064) + if (sc->sc_reserved & (1 << ih->ih_irq)) { + isa_intr_disestablish(sc->sc_parent_ic, ih); + return; + } +#endif + + s = splhigh(); + + LIST_REMOVE(ih, ih_q); + + /* If there are no more handlers on this IRQ, disable it. */ + if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) { + sc->sc_inten &= ~(1 << ih->ih_irq); + pcib_set_icus(sc); + } + + splx(s); + + free(ih, M_DEVBUF); +} + +int +pcib_isa_intr_alloc(void *v, int mask, int type, int *irq) +{ + struct pcib_softc *sc = v; + int i, tmp, bestirq, count; + struct algor_intrhand *ih; + + if (type == IST_NONE) + panic("pcib_intr_alloc: bogus type"); + + bestirq = -1; + count = -1; + +#if defined(ALGOR_P5064) + mask &= ~sc->sc_reserved; +#endif + + for (i = 0; i < 16; i++) { + if (i == 2 || (mask & (1 << i)) == 0) + continue; + + switch (sc->sc_intrtab[i].intr_type) { + case IST_NONE: + /* + * If nothing's using the IRQ, just return it. + */ + *irq = i; + return (0); + + case IST_EDGE: + case IST_LEVEL: + if (type != sc->sc_intrtab[i].intr_type) + continue; + /* + * If the IRQ is sharable, count the number of + * other handlers, and if it's smaller than the + * last IRQ like this, remember it. + */ + tmp = 0; + for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q); + ih != NULL; ih = LIST_NEXT(ih, ih_q)) + tmp++; + if (bestirq == -1 || count > tmp) { + bestirq = i; + count = tmp; + } + break; + + case IST_PULSE: + /* This just isn't sharable. */ + continue; + } + } + + if (bestirq == -1) + return (1); + + *irq = bestirq; + return (0); +}