Check in work-in-progress of generic ISA interrupt support. The

goal here is to get the P-5064 PCMCIA slots working, and serve as
the basis for P-6032 interrupt support.

PCMCIA interrupt auto-detection not working -- more work to be
done here.
This commit is contained in:
thorpej 2001-06-10 09:13:06 +00:00
parent 82418a77b0
commit 7c074dc806
5 changed files with 470 additions and 79 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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 *);

View File

@ -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]); \

View File

@ -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 <sys/cdefs.h> /* 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 <machine/intr.h>
#include <machine/bus.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/pci/pcireg.h>
@ -66,9 +67,52 @@ __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.2 2001/06/01 15:20:06 thorpej Exp $");
#include <algor/algor/algor_p6032var.h>
#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);
}