Allow multiple event handlers to be installed to an IRL.

The IRL is specified as IPL (2nd arg of sysasic_intr_establish()).
Current mapping:
	IRL9	IPL_BIO
	IRL11	IPL_NET
	IRL13	IPL_TTY
This commit is contained in:
itohy 2002-11-15 13:29:26 +00:00
parent 5c25ee8090
commit 7710d527c5
5 changed files with 248 additions and 61 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: gapspci_pci.c,v 1.4 2002/05/15 17:09:04 thorpej Exp $ */
/* $NetBSD: gapspci_pci.c,v 1.5 2002/11/15 13:29:27 itohy Exp $ */
/*-
* Copyright (c) 2001 Marcus Comstedt.
@ -199,7 +199,7 @@ const char *
gaps_intr_string(void *v, pci_intr_handle_t ih)
{
return ("SH4 IRL 11");
return sysasic_intr_string(IPL_NET);
}
void *
@ -207,12 +207,12 @@ gaps_intr_establish(void *v, pci_intr_handle_t ih, int level,
int (*func)(void *), void *arg)
{
return (sysasic_intr_establish(ih, func, arg));
return (sysasic_intr_establish(ih, IPL_NET, func, arg));
}
void
gaps_intr_disestablish(void *v, void *ih)
{
panic("gaps_intr_disestablish: not implemented");
return (sysasic_intr_disestablish(ih));
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: gdrom.c,v 1.14 2002/10/23 09:10:59 jdolecek Exp $ */
/* $NetBSD: gdrom.c,v 1.15 2002/11/15 13:29:26 itohy Exp $ */
/*-
* Copyright (c) 2001 Marcus Comstedt
@ -196,7 +196,7 @@ gdrom_intr(void *arg)
}
splx(s);
return (0);
return (1);
}
@ -381,8 +381,6 @@ gdromattach(struct device *parent, struct device *self, void *aux)
sc = (struct gdrom_softc *)self;
printf(": SH4 IRL 9\n");
/*
* Initialize and attach the disk structure.
*/
@ -397,7 +395,8 @@ gdromattach(struct device *parent, struct device *self, void *aux)
for (p = 0; p < 0x200000 / 4; p++)
x = ((__volatile u_int32_t *)0xa0000000)[p];
sysasic_intr_establish(SYSASIC_EVENT_GDROM, gdrom_intr, sc);
printf(": %s\n", sysasic_intr_string(IPL_BIO));
sysasic_intr_establish(SYSASIC_EVENT_GDROM, IPL_BIO, gdrom_intr, sc);
}
int

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysasic.c,v 1.3 2002/09/27 15:35:58 provos Exp $ */
/* $NetBSD: sysasic.c,v 1.4 2002/11/15 13:29:27 itohy Exp $ */
/*-
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@ -36,66 +36,131 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/syslog.h>
#include <sh3/exception.h>
#include <machine/intr.h>
#include <machine/sysasicvar.h>
#define SYSASIC_INTR_ST 0xa05f6900
#define SYSASIC_INTR_EN(level) (0xa05f6910 + ((level) << 4))
#define SYSASIC_IRQ_LEVEL_13 0
#define SYSASIC_IRQ_LEVEL_11 1
#define SYSASIC_IRQ_LEVEL_9 2
#define SYSASIC_IRQ_LEVEL_MAX 2
#define SYSASIC_IRQ_INDEX_TO_IRQ(i) (13 - 2 * (i))
#define IPL_IRL9 IPL_BIO
#define IPL_IRL11 IPL_NET
#define IPL_IRL13 IPL_TTY
/* per-irq */
struct sysasic_intrhand {
/* for quick check on interrupt */
unsigned syh_events[(SYSASIC_EVENT_MAX + 1 + (32 - 1)) / 32];
#define SYSASIC_EVENT_NMAP ((SYSASIC_EVENT_MAX + 1 + (32 - 1)) / 32)
#define SYSASIC_EVENT_INTR_MAP(ev) ((ev) >> 5)
#define SYSASIC_EVENT_INTR_BIT(ev) ((unsigned) 1 << ((ev) & 31))
void *syh_intc;
int syh_event;
int syh_idx;
} sysasic_intrhand[SYSASIC_IRQ_LEVEL_MAX + 1];
void sysasic_intr_enable(struct sysasic_intrhand *, int);
/* per-event */
struct syh_eventhand {
int (*hnd_fn)(void *); /* sub handler */
void *hnd_arg;
struct sysasic_intrhand *hnd_syh;
} sysasic_eventhand[SYSASIC_EVENT_MAX + 1];
int sysasic_intr(void *);
const char * __pure
sysasic_intr_string(int ipl)
{
switch (ipl) {
default:
#ifdef DEBUG
panic("sysasic_intr_string: unknown ipl %d", ipl);
#endif
case IPL_IRL9:
return "SH4 IRL 9";
case IPL_IRL11:
return "SH4 IRL 11";
case IPL_IRL13:
return "SH4 IRL 13";
}
/* NOTREACHED */
}
/*
* Set up an interrupt handler to start being called.
*/
void *
sysasic_intr_establish(int event, int (*ih_fun)(void *), void *ih_arg)
sysasic_intr_establish(int event, int ipl, int (*ih_fun)(void *), void *ih_arg)
{
struct sysasic_intrhand *syh;
int evtcode, ipl, idx;
struct syh_eventhand *hnd;
int idx;
static const int idx2evt[3] = {
SH_INTEVT_IRL13, SH_INTEVT_IRL11, SH_INTEVT_IRL9
};
#ifdef DEBUG
int i;
#endif
if (event < 0 || event > SYSASIC_EVENT_MAX)
panic("invalid sysasic event %d", event);
KDASSERT(event >= 0 && event <= SYSASIC_EVENT_MAX);
KDASSERT(ih_fun);
/*
* Dreamcast use SH4 INTC as IRL mode. if INTEVT code is specified,
* Dreamcast use SH4 INTC as IRL mode. If IRQ is specified,
* its priority level is fixed.
*
* We use IPL to specify the IRQ to trap programming errors. :D
*/
switch (event) {
case SYSASIC_EVENT_EXT:
idx = SYSASIC_IRQ_LEVEL_11;
ipl = IPL_NET;
evtcode = SH_INTEVT_IRL11;
break;
case SYSASIC_EVENT_GDROM:
idx = SYSASIC_IRQ_LEVEL_9;
ipl = IPL_BIO;
evtcode = SH_INTEVT_IRL9;
break;
switch (ipl) {
default:
panic("vaild but unknown event %d", event);
#ifdef DEBUG
panic("sysasic_intr_establish: unknown ipl %d", ipl);
#endif
case IPL_IRL9:
idx = SYSASIC_IRQ_LEVEL_9;
break;
case IPL_IRL11:
idx = SYSASIC_IRQ_LEVEL_11;
break;
case IPL_IRL13:
idx = SYSASIC_IRQ_LEVEL_13;
break;
}
syh = &sysasic_intrhand[idx];
syh->syh_event = event;
syh->syh_idx = idx;
syh->syh_intc = intc_intr_establish(evtcode, IST_LEVEL, ipl,
ih_fun, ih_arg);
if (syh->syh_intc == NULL) {
syh->syh_idx = idx;
syh->syh_intc = intc_intr_establish(idx2evt[idx], IST_LEVEL,
ipl, sysasic_intr, syh);
}
sysasic_intr_enable(syh, 1);
#ifdef DEBUG
/* check if the event handler is already installed */
for (i = 0; i <= SYSASIC_IRQ_LEVEL_MAX; i++)
if ((sysasic_intrhand[i].syh_events[SYSASIC_EVENT_INTR_MAP(event)] &
SYSASIC_EVENT_INTR_BIT(event)) != 0)
panic("sysasic_intr_establish: event %d already insatlled irq %d",
event, SYSASIC_IRQ_INDEX_TO_IRQ(i));
#endif
return (void *)syh;
hnd = &sysasic_eventhand[event];
hnd->hnd_fn = ih_fun;
hnd->hnd_arg = ih_arg;
hnd->hnd_syh = syh;
sysasic_intr_enable(hnd, 1);
return (void *)hnd;
}
/*
@ -104,27 +169,146 @@ sysasic_intr_establish(int event, int (*ih_fun)(void *), void *ih_arg)
void
sysasic_intr_disestablish(void *arg)
{
struct sysasic_intrhand *syh = arg;
struct syh_eventhand *hnd = arg;
struct sysasic_intrhand *syh;
int event;
int i;
event = syh->syh_event;
event = hnd - sysasic_eventhand;
KDASSERT(event >= 0 && event <= SYSASIC_EVENT_MAX);
syh = hnd->hnd_syh;
if (event < 0 || event > SYSASIC_EVENT_MAX)
panic("invalid sysasic event %d", event);
#ifdef DISAGNOSTIC
if (syh->syh_events[SYSASIC_EVENT_INTR_MAP(event)] &
SYSASIC_EVENT_INTR_BIT(event)) == 0)
panic("sysasic_intr_disestablish: event %d not installed for irq %d",
event, SYSASIC_IRQ_INDEX_TO_IRQ(syh->syh_idx));
#endif
sysasic_intr_enable(syh, 0);
sysasic_intr_enable(hnd, 0);
hnd->hnd_fn = 0;
hnd->hnd_arg = 0;
hnd->hnd_syh = 0;
/* deinstall intrc if no event exists */
for (i = 0; i < SYSASIC_EVENT_NMAP; i++)
if (syh->syh_events[i])
return;
intc_intr_disestablish(syh->syh_intc);
syh->syh_intc = 0;
}
void
sysasic_intr_enable(struct sysasic_intrhand *syh, int on)
sysasic_intr_enable(void *arg, int on)
{
int event = syh->syh_event;
__volatile u_int32_t *masks =
(__volatile u_int32_t *)(0xa05f6910 + (syh->syh_idx << 4));
struct syh_eventhand *hnd = arg;
struct sysasic_intrhand *syh;
int event;
__volatile u_int32_t *masks, *stats;
int evmap;
unsigned evbit;
masks[0] = 0;
masks[1] = 0;
if (on)
masks[event >> 5] = 1 << (event & 31);
event = hnd - sysasic_eventhand;
KDASSERT(event >= 0 && event <= SYSASIC_EVENT_MAX);
syh = hnd->hnd_syh;
#ifdef DISAGNOSTIC
if (syh->syh_events[SYSASIC_EVENT_INTR_MAP(event)] &
SYSASIC_EVENT_INTR_BIT(event)) == 0)
panic("sysasic_intr_enable: event %d not installed for irq %d",
event, SYSASIC_IRQ_INDEX_TO_IRQ(syh->syh_idx));
#endif
masks = (__volatile u_int32_t *) SYSASIC_INTR_EN(syh->syh_idx);
stats = (__volatile u_int32_t *) SYSASIC_INTR_ST;
evmap = SYSASIC_EVENT_INTR_MAP(event);
evbit = SYSASIC_EVENT_INTR_BIT(event);
if (on) {
/* clear pending event if any */
stats[evmap] = evbit;
/* set event map */
syh->syh_events[evmap] |= evbit;
/* enable interrupt */
masks[evmap] = syh->syh_events[evmap];
} else {
/* disable interrupt */
masks[evmap] = syh->syh_events[evmap] & ~evbit;
/* clear pending event if any */
stats[evmap] = evbit;
/* clear event map */
syh->syh_events[evmap] &= ~evbit;
}
}
int
sysasic_intr(void *arg)
{
struct sysasic_intrhand *syh = arg;
unsigned ev;
int n, pos;
u_int32_t *evwatched;
__volatile u_int32_t *evmap;
struct syh_eventhand *evh;
#ifdef DEBUG
int handled = 0;
static int reportcnt = 10;
#endif
/* bitmap of watched events */
evwatched = syh->syh_events;
/* status / clear */
evmap = (__volatile u_int32_t *) SYSASIC_INTR_ST;
for (n = 0; n < (SYSASIC_EVENT_NMAP << 5); n |= 31, n++, evmap++) {
if ((ev = *evwatched++) && (ev &= *evmap)) {
/* clear interrupts */
*evmap = ev;
n--; /* to point at current bit after n += pos */
/* call handlers */
do {
pos = ffs(ev);
n += pos;
#ifdef __OPTIMIZE__
/* optimized, assuming 1 <= pos <= 32 */
asm("shld %2,%0"
: "=r" (ev) : "0" (ev), "r" (-pos));
#else
/* ``shift count >= bit width'' is undefined */
if (pos >= 32)
ev = 0;
else
ev >>= pos;
#endif
evh = &sysasic_eventhand[n];
#ifdef DEBUG
KDASSERT(evh->hnd_fn);
if ((*evh->hnd_fn)(evh->hnd_arg))
handled = 1;
#else
(*evh->hnd_fn)(evh->hnd_arg);
#endif
} while (ev);
}
}
#ifdef DEBUG
if (!handled && reportcnt > 0) {
reportcnt--;
log(LOG_ERR, "sysasic_intr: stray irq%d interrupt%s\n",
SYSASIC_IRQ_INDEX_TO_IRQ(syh->syh_idx),
reportcnt == 0 ? "; stopped logging" : "");
}
#endif
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.3 2002/03/24 18:21:08 uch Exp $ */
/* $NetBSD: intr.h,v 1.4 2002/11/15 13:29:27 itohy Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@ -39,12 +39,12 @@
#include <sh3/intr.h>
/* Number of interrupt source */
#define _INTR_N 9 /* TMU0, TMU1, TMU2, SCIF * 4, GDROM, GAPSPCI */
#define _INTR_N 10 /* TMU0, TMU1, TMU2, SCIF * 4, IRL * 3 */
/* Interrupt priority levels */
#define IPL_BIO 9 /* block I/O (GD-ROM) */
#define IPL_NET 11 /* network (GAPS PCI) */
#define IPL_TTY 12 /* terminal */
#define IPL_BIO 9 /* block I/O (IRL9) */
#define IPL_NET 11 /* network (IRL11) */
#define IPL_TTY 12 /* terminal (IRL13) */
#define IPL_SERIAL 12 /* serial */
#define IPL_CLOCK 14 /* clock */
#define IPL_HIGH 15 /* everything */

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysasicvar.h,v 1.2 2002/03/24 18:21:09 uch Exp $ */
/* $NetBSD: sysasicvar.h,v 1.3 2002/11/15 13:29:27 itohy Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -39,13 +39,17 @@
#ifndef _DREAMCAST_SYSASICVAR_H_
#define _DREAMCAST_SYSASICVAR_H_
#define SYSASIC_EVENT_GDROM 32
#define SYSASIC_EVENT_AICA 33
#define SYSASIC_EVENT_EXT 35
#define SYSASIC_EVENT_MAX 63
#define SYSASIC_EVENT_MAPLE_DMADONE 12
#define SYSASIC_EVENT_MAPLE_ERROR 13
#define SYSASIC_EVENT_GDROM 32
#define SYSASIC_EVENT_AICA 33
#define SYSASIC_EVENT_EXT 35
#define SYSASIC_EVENT_MAX 65
void *sysasic_intr_establish(int, int (*ih_fun)(void *), void *);
void sysasic_intr_disestablish(void *);
const char *__pure sysasic_intr_string(int /*ipl*/) __attribute__((__const__));
void *sysasic_intr_establish(int /*event*/, int /*ipl*/,
int (*ih_fun)(void *), void *);
void sysasic_intr_disestablish(void *);
void sysasic_intr_enable(void *, int /*on*/);
#endif /* !_DREAMCAST_SYSASICVAR_H_ */