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:
parent
1e82631893
commit
7c320e5bfb
@ -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--;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 **);
|
||||
|
Loading…
Reference in New Issue
Block a user