Add new functions to know which irqs are pending, and to mask and unmask

interrupts, as these are CPU specific.
If the interrupt handler is not marked as INTR_FAST, don't unmask the
interrupt until it as been serviced.
This commit is contained in:
Olivier Houchard 2004-09-23 22:09:57 +00:00
parent 1e82631893
commit 7c320e5bfb
3 changed files with 69 additions and 140 deletions

View File

@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/bus.h>
#include <sys/interrupt.h>
#include <sys/conf.h>
@ -49,56 +50,36 @@ __FBSDID("$FreeBSD$");
#include <machine/intr.h>
#include <machine/cpu.h>
int current_spl_level = _SPL_SERIAL;
u_int spl_masks[_SPL_LEVELS + 1];
u_int spl_smasks[_SPL_LEVELS];
extern u_int irqmasks[];
#define NIRQ 0x20 /* XXX */
struct ithd *ithreads[NIRQ];
void
set_splmasks()
{
int loop;
struct arm_intr {
driver_intr_t *handler;
void *arg;
void *cookiep;
int irq;
};
for (loop = 0; loop < _SPL_LEVELS; ++loop) {
spl_masks[loop] = 0xffffffff;
spl_smasks[loop] = 1;
}
static void
arm_intr_handler(void *arg)
{
struct arm_intr *intr = (struct arm_intr *)arg;
spl_masks[_SPL_NET] = irqmasks[IPL_NET];
spl_masks[_SPL_SOFTSERIAL] = irqmasks[IPL_TTY];
spl_masks[_SPL_TTY] = irqmasks[IPL_TTY];
spl_masks[_SPL_VM] = irqmasks[IPL_VM];
spl_masks[_SPL_AUDIO] = irqmasks[IPL_AUDIO];
spl_masks[_SPL_CLOCK] = irqmasks[IPL_CLOCK];
#ifdef IPL_STATCLOCK
spl_masks[_SPL_STATCLOCK] = irqmasks[IPL_STATCLOCK];
#else
spl_masks[_SPL_STATCLOCK] = irqmasks[IPL_CLOCK];
#endif
spl_masks[_SPL_HIGH] = irqmasks[IPL_HIGH];
spl_masks[_SPL_SERIAL] = irqmasks[IPL_SERIAL];
spl_masks[_SPL_LEVELS] = 0;
spl_smasks[_SPL_0] = 0xffffffff;
for (loop = 0; loop < _SPL_SOFTSERIAL; ++loop)
spl_smasks[loop] |= SOFTIRQ_BIT(SOFTIRQ_SERIAL);
for (loop = 0; loop < _SPL_SOFTNET; ++loop)
spl_smasks[loop] |= SOFTIRQ_BIT(SOFTIRQ_NET);
for (loop = 0; loop < _SPL_SOFTCLOCK; ++loop)
spl_smasks[loop] |= SOFTIRQ_BIT(SOFTIRQ_CLOCK);
intr->handler(intr->arg);
arm_unmask_irqs(1 << intr->irq);
}
void arm_handler_execute(void *, int);
void arm_setup_irqhandler(const char *name, void (*hand)(void*), void *arg,
int irq, int flags, void **cookiep)
{
struct ithd *cur_ith;
struct arm_intr *intr = NULL;
int error;
if (irq < 0 || irq >= NIRQ)
return;
if (!(flags & INTR_FAST))
intr = malloc(sizeof(*intr), M_DEVBUF, M_WAITOK);
cur_ith = ithreads[irq];
if (cur_ith == NULL) {
error = ithread_create(&cur_ith, irq, 0, NULL, NULL, "intr%d:",
@ -107,8 +88,16 @@ void arm_setup_irqhandler(const char *name, void (*hand)(void*), void *arg,
return;
ithreads[irq] = cur_ith;
}
ithread_add_handler(cur_ith, name, hand, arg, ithread_priority(flags),
flags, cookiep);
if (!(flags & INTR_FAST)) {
intr->handler = hand;
intr->arg = arg;
intr->irq = irq;
intr->cookiep = *cookiep;
ithread_add_handler(cur_ith, name, arm_intr_handler, intr,
ithread_priority(flags), flags, cookiep);
} else
ithread_add_handler(cur_ith, name, hand, arg,
ithread_priority(flags), flags, cookiep);
}
void dosoftints(void);
@ -118,33 +107,37 @@ dosoftints(void)
}
void
arm_handler_execute(void *);
void
arm_handler_execute(void *irq)
arm_handler_execute(void *frame, int irqnb)
{
struct ithd *ithd;
int i;
int irqnb = (int)irq;
int i, oldirqstate;
struct intrhand *ih;
struct thread *td = curthread;
for (i = 0; i < NIRQ; i++) {
if (1 << i & irqnb) {
ithd = ithreads[i];
if (!ithd) /* FUCK */
return;
ih = TAILQ_FIRST(&ithd->it_handlers);
if (ih && ih->ih_flags & IH_FAST) {
TAILQ_FOREACH(ih, &ithd->it_handlers,
ih_next) {
ih->ih_handler(ih->ih_argument);
/*
* XXX: what about the irq frame if
* the arg is NULL ?
*/
}
} else if (ih) {
ithread_schedule(ithd);
td->td_intr_nesting_level++;
if (irqnb == 0)
irqnb = arm_get_irqnb(frame);
arm_mask_irqs(irqnb);
while (irqnb != 0) {
i = ffs(irqnb) - 1;
irqnb &= ~(1U << i);
ithd = ithreads[i];
if (!ithd)
continue;
ih = TAILQ_FIRST(&ithd->it_handlers);
if (ih && ih->ih_flags & IH_FAST) {
TAILQ_FOREACH(ih, &ithd->it_handlers,
ih_next) {
ih->ih_handler(ih->ih_argument ?
ih->ih_argument : frame);
}
arm_unmask_irqs(1 << i);
} else if (ih) {
oldirqstate = enable_interrupts(I32_bit);
ithread_schedule(ithd);
restore_interrupts(oldirqstate);
}
}
irqnb |= arm_get_irqnb(frame);
}
td->td_intr_nesting_level--;
}

View File

@ -73,17 +73,7 @@
#include <machine/asmacros.h>
#include <machine/armreg.h>
__FBSDID("$FreeBSD$");
#if 0
#ifdef ARM_INTR_IMPL
#include ARM_INTR_IMPL
#else
#error ARM_INTR_IMPL not defined
#endif
#ifndef ARM_IRQ_HANDLER
#error ARM_IRQ_HANDLER not defined
#endif
#endif
/*
* irq_entry:
* Main entry point for the IRQ vector. This is a generic version
@ -91,54 +81,26 @@ __FBSDID("$FreeBSD$");
*/
.text
.align 0
.Lcurrent_intr_depth:
.word _C_LABEL(current_intr_depth)
AST_ALIGNMENT_FAULT_LOCALS
AST_LOCALS
ASENTRY_NP(irq_entry)
sub lr, lr, #0x00000004 /* Adjust the lr */
PUSHFRAMEINSVC /* Push an interrupt frame */
ENABLE_ALIGNMENT_FAULTS
ldr r1, .Laflt_curpcb
/*
* Increment the interrupt nesting depth and call the interrupt
* dispatch routine. We've pushed a frame, so we can safely use
* callee-saved regs here. We use the following registers, which
* we expect to presist:
*
* r5 address of `current_intr_depth' variable
* r6 old value of `current_intr_depth'
*/
ldr r5, .Lcurrent_intr_depth
mov r0, sp /* arg for dispatcher */
ldr r6, [r5]
add r1, r6, #1
str r1, [r5]
#if 0
bl ARM_IRQ_HANDLER
#endif
mov r1, #0
bl _C_LABEL(arm_handler_execute)
/*
* Restore the old interrupt depth value (which should be the
* same as decrementing it at this point).
*/
str r6, [r5]
DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
DO_AST
PULLFRAMEFROMSVCANDEXIT
movs pc, lr /* Exit */
.bss
.align 0
.global _C_LABEL(current_intr_depth)
_C_LABEL(current_intr_depth):
.word 0
/*
* XXX Provide intrnames/intrcnt for legacy code, but
@ -153,3 +115,8 @@ _C_LABEL(eintrnames):
.global _C_LABEL(intrcnt), _C_LABEL(sintrcnt), _C_LABEL(eintrcnt)
_C_LABEL(intrcnt):
_C_LABEL(eintrcnt):
.global _C_LABEL(current_intr_depth)
_C_LABEL(current_intr_depth):
.word 0

View File

@ -39,44 +39,13 @@
#ifndef _MACHINE_INTR_H_
#define _MACHINE_INTR_H_
/* Define the various Interrupt Priority Levels */
/* Hardware Interrupt Priority Levels are not mutually exclusive. */
#ifdef CPU_SA1110
#define IPL_SOFTCLOCK 0
#define IPL_SOFTNET 1
#define IPL_BIO 2 /* block I/O */
#define IPL_NET 3 /* network */
#define IPL_SOFTSERIAL 4
#define IPL_TTY 5 /* terminal */
#define IPL_VM 6 /* memory allocation */
#define IPL_AUDIO 7 /* audio */
#define IPL_CLOCK 8 /* clock */
#define IPL_HIGH 9 /* */
#define IPL_SERIAL 10 /* serial */
#define IPL_NONE 11
#define NIPL 12
#endif
#define IST_UNUSABLE -1 /* interrupt cannot be used */
#define IST_NONE 0 /* none (dummy) */
#define IST_PULSE 1 /* pulsed */
#define IST_EDGE 2 /* edge-triggered */
#define IST_LEVEL 3 /* level-triggered */
/* Software interrupt priority levels */
#define SOFTIRQ_CLOCK 0
#define SOFTIRQ_NET 1
#define SOFTIRQ_SERIAL 2
#define SOFTIRQ_BIT(x) (1 << x)
#define NIRQ 32
#include <machine/psl.h>
int arm_get_irqnb(void *);
void arm_mask_irqs(int);
void arm_unmask_irqs(int);
void set_splmasks(void);
void arm_setup_irqhandler(const char *, void (*)(void*), void *, int, int,
void **);