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:
parent
8a979a066f
commit
35228f775a
|
@ -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)
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue