Two related changes:

Make splhigh disable IRQs at the CPU rather than at the IOC.  This has the
potential to be faster, and more importantly ensures that splhigh() blocks
FIQ downgrades.

Have a variable which indicates that a FIQ downgrade is required, and ensure
that the IOC "force IRQ" bit is turned on in this case.  This ensures that
FIQ downgrades don't get lost if something happens to be fiddling with the
interrupt mask at the wrong moment.
This commit is contained in:
bjh21 2001-08-21 22:47:17 +00:00
parent 8a979a066f
commit 35228f775a
4 changed files with 51 additions and 39 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: fiq_util.S,v 1.1 2001/08/20 23:08:10 bjh21 Exp $ */
/* $NetBSD: fiq_util.S,v 1.2 2001/08/21 22:47:17 bjh21 Exp $ */
/*-
* Copyright (c) 2001 Ben Harris
@ -29,7 +29,7 @@
#include <machine/asm.h>
RCSID("$NetBSD: fiq_util.S,v 1.1 2001/08/20 23:08:10 bjh21 Exp $")
RCSID("$NetBSD: fiq_util.S,v 1.2 2001/08/21 22:47:17 bjh21 Exp $")
#include <machine/memcreg.h>
#include <arch/arm26/iobus/iocreg.h>
@ -45,6 +45,11 @@ ENTRY(fiq_downgrade)
strb r13, [r12, #(IOC_IRQMSKA << 2)]
mov r13, #0
strb r13, [r12, #(IOC_FIQMSK << 2)]
ldr r12, Lfiq_want_downgrade
mov r13, #1
str r13, [r12]
subs pc, r14, #4
Lioc_base:
.word 0x03200000
.word 0x03200000
Lfiq_want_downgrade:
.word _C_LABEL(fiq_want_downgrade)

View File

@ -1,4 +1,4 @@
/* $NetBSD: irq.c,v 1.19 2001/08/20 23:08:10 bjh21 Exp $ */
/* $NetBSD: irq.c,v 1.20 2001/08/21 22:47:18 bjh21 Exp $ */
/*-
* Copyright (c) 2000, 2001 Ben Harris
@ -33,7 +33,7 @@
#include <sys/param.h>
__RCSID("$NetBSD: irq.c,v 1.19 2001/08/20 23:08:10 bjh21 Exp $");
__RCSID("$NetBSD: irq.c,v 1.20 2001/08/21 22:47:18 bjh21 Exp $");
#include <sys/device.h>
#include <sys/kernel.h> /* for cold */
@ -76,6 +76,10 @@ extern char *irqnames[];
int current_intr_depth = 0;
#if NFIQ > 0
int fiq_want_downgrade;
#endif
/*
* Interrupt masks are held in 32-bit integers. At present, the
* bottom eight bits are interrupt register A on the IOC, and the next
@ -133,13 +137,8 @@ irq_handler(struct irqframe *irqf)
status |= unixbp_irq_status_full() << IRQ_UNIXBP_BASE;
#endif
/* Get interrupt-disabling back to the IOC */
#if NFIQ > 0
s = hardsplx(IPL_HIGH); /* In case it's a FIQ downgrade. */
#else
/* We're already in splhigh, but make sure the kernel knows that. */
s = splhigh();
#endif
int_on();
#if 0
printf("*");
@ -149,8 +148,9 @@ irq_handler(struct irqframe *irqf)
stray = 1;
#if NFIQ > 0
/* Check for downgraded FIQs. */
if (status & (1 << IOC_IRQ_1)) {
fiq_downgrade_handler();
if (fiq_want_downgrade) {
fiq_want_downgrade = 0;
(fiq_downgrade_handler)();
goto handled;
}
#endif
@ -183,16 +183,17 @@ irq_handler(struct irqframe *irqf)
stray = 0;
}
if (__predict_false(stray))
if (__predict_false(stray)) {
log(LOG_WARNING, "Stray IRQ, status = 0x%x, spl = %d, "
"mask = 0x%x\n", status, s, irqmask[s]);
Debugger();
}
handled:
#if 0
printf(" handled\n");
#endif
dosoftints(s); /* May lower spl to s + 1, but no lower. */
int_off();
hardsplx(s);
current_intr_depth--;
}
@ -308,20 +309,43 @@ __inline int
hardsplx(int s)
{
int was;
u_int32_t mask;
KASSERT(s < IPL_HIGH);
int_off();
was = current_spl;
mask = irqmask[s];
#if NFIQ > 0
if (fiq_want_downgrade)
mask |= IOC_IRQ_1;
#endif
/* Don't try this till we've found the IOC */
if (the_ioc != NULL)
ioc_irq_setmask(irqmask[s]);
ioc_irq_setmask(mask);
#if NUNIXBP > 0
unixbp_irq_setmask(irqmask[s] >> IRQ_UNIXBP_BASE);
unixbp_irq_setmask(mask >> IRQ_UNIXBP_BASE);
#endif
current_spl = s;
int_on();
return was;
}
int
splhigh(void)
{
int was;
int_off();
was = current_spl;
current_spl = IPL_HIGH;
#ifdef DEBUG
/* Make sure that anything that turns off the I flag gets spotted. */
if (the_ioc != NULL)
ioc_irq_setmask(0xffff);
#endif
return was;
}
int
raisespl(int s)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: start.c,v 1.10 2001/05/13 13:48:11 bjh21 Exp $ */
/* $NetBSD: start.c,v 1.11 2001/08/21 22:47:18 bjh21 Exp $ */
/*-
* Copyright (c) 1998, 2000 Ben Harris
* All rights reserved.
@ -32,7 +32,7 @@
#include <sys/param.h>
__KERNEL_RCSID(0, "$NetBSD: start.c,v 1.10 2001/05/13 13:48:11 bjh21 Exp $");
__KERNEL_RCSID(0, "$NetBSD: start.c,v 1.11 2001/08/21 22:47:18 bjh21 Exp $");
#include <sys/msgbuf.h>
#include <sys/user.h>
@ -196,24 +196,7 @@ start(initbootconfig)
/* Set up the undefined instruction handlers. */
undefined_init();
/*
* This is a nasty bit. Because the kernel uses a 26-bit APCS
* variant, the CPU interrupt disable flags get munged on
* every function return. Thus, we need to enable interrupts
* at the CPU now since this is the last function we control
* that won't return. In order to be able to do this, we need
* to ensure we won't get any interrupts before we're ready
* for them. For now, I'll assume we've got an IOC doing all
* this at the usual location, but it should be done more
* elegantly.
*/
#if NIOC > 0
*(volatile u_char *)(0x03200000 + (IOC_IRQMSKA << 2)) = 0;
*(volatile u_char *)(0x03200000 + (IOC_IRQMSKB << 2)) = 0;
*(volatile u_char *)(0x03200000 + (IOC_FIQMSK << 2)) = 0;
#endif
int_on();
splhigh();
/*
* Locate process 0's user structure, in the bottom of its kernel

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.9 2001/05/13 13:47:23 bjh21 Exp $ */
/* $NetBSD: intr.h,v 1.10 2001/08/21 22:47:18 bjh21 Exp $ */
/*-
* Copyright (c) 1998, 2000 Ben Harris
* All rights reserved.
@ -74,7 +74,6 @@
#define splserial() raisespl(IPL_SERIAL)
#define splclock() raisespl(IPL_CLOCK)
#define splstatclock() raisespl(IPL_STATCLOCK)
#define splhigh() raisespl(IPL_HIGH)
#define splsched() splhigh()
#define spllock() splhigh()
@ -85,6 +84,7 @@
extern int current_spl_level; /* XXX tautological name */
extern int splhigh(void);
extern int raisespl(int);
extern void lowerspl(int);
extern int hardsplx(int);