Subject: proposed sysasic changes
To: None <port-dreamcast@netbsd.org>
From: ITOH Yasufumi <itohy@netbsd.org>
List: port-dreamcast
Date: 09/01/2002 01:19:08
------- =_aaaaaaaaaa0
Content-Type: text/plain; charset="us-ascii"
Content-ID: <25650.1030808997.1@fmv.my.domain>
Content-Transfer-Encoding: 7bit
Hello,
I made modification to sysasic-related code.
This is to handle more than three (= number of IRL) events
of peripheral interrupts.
This changes the interface of sysasic_intr_establish() to specify
the IRL (using processor level), and installes master interrupt
handler which calls event specific handlers.
Currently, the changes don't add any function but to make the interrupt
handlers slower, however. :)
Only two (gdrom and gapspci) events are handled for now.
I'm optimizing ffs(3) to minimize the overhead. :)
OK to commit this? / Any thoughts?
--
ITOH Yasufumi
------- =_aaaaaaaaaa0
Content-Type: text/plain; name="sysasic.diff"; charset="us-ascii"
Content-ID: <25650.1030808997.2@fmv.my.domain>
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="sysasic.diff"
Index: dreamcast/sysasic.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dreamcast/sysasic.c,v
retrieving revision 1.2
diff -u -r1.2 sysasic.c
--- dreamcast/sysasic.c 2002/03/24 18:21:10 1.2
+++ dreamcast/sysasic.c 2002/08/31 15:41:39
@@ -36,66 +36,132 @@
#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];
+
+/* 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];
-void sysasic_intr_enable(struct sysasic_intrhand *, int);
+void sysasic_intr_enable(struct sysasic_intrhand *, int /*event*/, int /*on*/);
+int sysasic_intr(void *);
+const char *
+sysasic_intr_string(int ipl)
+{
+
+ switch (ipl) {
+ default:
+#ifdef DIAGNOSTIC
+ panic("sysasic_intr_string: unknown ipl %d\n", 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 DIAGNOSTIC
+ int i;
+#endif
- if (event < 0 || event > SYSASIC_EVENT_MAX)
- panic("invalid sysasic event %d", event);
+ KASSERT(event >= 0 && event <= SYSASIC_EVENT_MAX);
+ KASSERT(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:
+ switch (ipl) {
+ default:
+#ifdef DIAGNOSTIC
+ panic("sysasic_intr_establish: unknown ipl %d\n", ipl);
+#endif
+ case IPL_IRL9:
+ idx = SYSASIC_IRQ_LEVEL_9;
+ break;
+ case IPL_IRL11:
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;
+ case IPL_IRL13:
+ idx = SYSASIC_IRQ_LEVEL_13;
break;
- default:
- panic("vaild but unknown event %d\n", event);
}
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 DIAGNOSTIC
+ /* 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
+
+ hnd = &sysasic_eventhand[event];
+ hnd->hnd_fn = ih_fun;
+ hnd->hnd_arg = ih_arg;
+ hnd->hnd_syh = syh;
+ sysasic_intr_enable(syh, event, 1);
- return (void *)syh;
+ return (void *)hnd;
}
/*
@@ -104,27 +170,123 @@
void
sysasic_intr_disestablish(void *arg)
{
- struct sysasic_intrhand *syh = arg;
+ struct syh_eventhand *hnd = arg;
+ struct sysasic_intrhand *syh = hnd->hnd_syh;
int event;
+ int i;
- event = syh->syh_event;
+ event = hnd - sysasic_eventhand;
+#ifdef DISAGNOSTIC
if (event < 0 || event > SYSASIC_EVENT_MAX)
panic("invalid sysasic event %d", event);
-
- sysasic_intr_enable(syh, 0);
+ 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, event, 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(struct sysasic_intrhand *syh, int event, int on)
{
- int event = syh->syh_event;
__volatile u_int32_t *masks =
- (__volatile u_int32_t *)(0xa05f6910 + (syh->syh_idx << 4));
+ (__volatile u_int32_t *) SYSASIC_INTR_EN(syh->syh_idx);
+ __volatile u_int32_t *stats = (__volatile u_int32_t *) SYSASIC_INTR_ST;
+ int evmap = SYSASIC_EVENT_INTR_MAP(event);
+ unsigned 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 ev0, ev;
+ unsigned m, n;
+ unsigned pos;
+ struct syh_eventhand *evh;
+#ifdef DIAGNOSTIC
+ int handled = 0;
+ static int reportcnt = 10;
+#endif
+
+ for (m = 0; m < SYSASIC_EVENT_NMAP; m++) {
+ if ((ev0 = syh->syh_events[m]) &&
+ (ev = ev0 & ((__volatile u_int32_t *)SYSASIC_INTR_ST)[m])) {
+
+ /* clear interrupts */
+ ((__volatile u_int32_t *)SYSASIC_INTR_ST)[m] = ev;
+
+ /* call handlers */
+ n = (m << 5) - 1; /* -1 to point at current bit */
+ while ((pos = ffs(ev)) != 0) {
+ 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 DIAGNOSTIC
+ KASSERT(evh->hnd_fn);
+ if ((*evh->hnd_fn)(evh->hnd_arg))
+ handled = 1;
+#else
+ (*evh->hnd_fn)(evh->hnd_arg);
+#endif
+ }
+ }
+ }
+
+#ifdef DIAGNOSTIC
+ if (!handled) {
+ if (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
- masks[0] = 0;
- masks[1] = 0;
- if (on)
- masks[event >> 5] = 1 << (event & 31);
+ return 0;
}
Index: include/intr.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/include/intr.h,v
retrieving revision 1.3
diff -u -r1.3 intr.h
--- include/intr.h 2002/03/24 18:21:08 1.3
+++ include/intr.h 2002/08/31 15:41:40
@@ -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_TTY 12 /* terminal (Maple) */
#define IPL_SERIAL 12 /* serial */
#define IPL_CLOCK 14 /* clock */
#define IPL_HIGH 15 /* everything */
Index: include/sysasicvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/include/sysasicvar.h,v
retrieving revision 1.2
diff -u -r1.2 sysasicvar.h
--- include/sysasicvar.h 2002/03/24 18:21:09 1.2
+++ include/sysasicvar.h 2002/08/31 15:41:40
@@ -39,13 +39,15 @@
#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 *);
+const char *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 *);
#endif /* !_DREAMCAST_SYSASICVAR_H_ */
-
Index: dev/gdrom.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/gdrom.c,v
retrieving revision 1.9
diff -u -r1.9 gdrom.c
--- dev/gdrom.c 2002/07/27 11:07:35 1.9
+++ dev/gdrom.c 2002/08/31 15:41:40
@@ -187,7 +187,7 @@
}
splx(s);
- return (0);
+ return (1);
}
@@ -372,8 +372,6 @@
sc = (struct gdrom_softc *)self;
- printf(": SH4 IRL 9\n");
-
/*
* Initialize and attach the disk structure.
*/
@@ -388,7 +386,8 @@
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
Index: dev/g2/gapspci_pci.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/g2/gapspci_pci.c,v
retrieving revision 1.4
diff -u -r1.4 gapspci_pci.c
--- dev/g2/gapspci_pci.c 2002/05/15 17:09:04 1.4
+++ dev/g2/gapspci_pci.c 2002/08/31 15:41:40
@@ -199,7 +199,7 @@
gaps_intr_string(void *v, pci_intr_handle_t ih)
{
- return ("SH4 IRL 11");
+ return sysasic_intr_string(IPL_NET);
}
void *
@@ -207,7 +207,7 @@
int (*func)(void *), void *arg)
{
- return (sysasic_intr_establish(ih, func, arg));
+ return (sysasic_intr_establish(ih, IPL_NET, func, arg));
}
void
------- =_aaaaaaaaaa0--