Checkin new interrupt handling code for the footbridge.
This is based upon Jason's work on xscale. Most of the interrupt handling code is now written in C using an asm stub to call into the C code. spl* now only updates a software mask, and does not update the hardware, this should be much faster. The new code works well on cats, it's untested on netwinder, but should work. The code implements generic soft interrupts. More work is still required to bring the isa interrupt handling code upto scratch currently all isa interrupts are handled at IPL_BIO on the footbridge. This may cause isa interrupts to be handled later than they should be. I plan to fix this in the near future.
This commit is contained in:
parent
09f6c6a9cc
commit
61578bc307
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.footbridge,v 1.9 2002/10/18 20:03:02 thorpej Exp $
|
||||
# $NetBSD: files.footbridge,v 1.10 2002/11/03 21:43:29 chris Exp $
|
||||
#
|
||||
# Shared footbridge files information
|
||||
|
||||
|
@ -12,6 +12,7 @@ file arch/arm/footbridge/footbridge_pci.c footbridge
|
|||
file arch/arm/footbridge/footbridge_irq.S footbridge
|
||||
file arch/arm/footbridge/footbridge_irqhandler.c footbridge
|
||||
file arch/arm/footbridge/footbridge_clock.c footbridge
|
||||
file arch/arm/arm/softintr.c footbridge
|
||||
|
||||
# DC21285 "Footbridge" serial port
|
||||
device fcom: tty, bus_space_generic
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: dc21285reg.h,v 1.2 2002/09/28 10:34:02 chris Exp $ */
|
||||
/* $NetBSD: dc21285reg.h,v 1.3 2002/11/03 21:43:30 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997,1998 Mark Brinicombe.
|
||||
|
@ -316,7 +316,7 @@
|
|||
#define IRQ_SERR 0x17
|
||||
#define IRQ_SDRAM_PARITY 0x18
|
||||
#define IRQ_I2O 0x19
|
||||
#define IRQ_RESERVED4 0x1A
|
||||
#define IRQ_RESERVED3 0x1A
|
||||
#define IRQ_DISCARD_TIMER 0x1B
|
||||
#define IRQ_DATA_PARITY 0x1C
|
||||
#define IRQ_MASTER_ABORT 0x1D
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: footbridge.c,v 1.10 2002/10/02 05:02:30 thorpej Exp $ */
|
||||
/* $NetBSD: footbridge.c,v 1.11 2002/11/03 21:43:30 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997,1998 Mark Brinicombe.
|
||||
|
@ -183,19 +183,19 @@ footbridge_attach(parent, self, aux)
|
|||
/* bus_space_write_4(sc->sc_iot, sc->sc_ioh, 0x18, 0x40000000);*/
|
||||
|
||||
/* Install a generic handler to catch a load of system interrupts */
|
||||
sc->sc_serr_ih = intr_claim(IRQ_SERR, IPL_NONE,
|
||||
sc->sc_serr_ih = footbridge_intr_claim(IRQ_SERR, IPL_HIGH,
|
||||
"serr", footbridge_intr, sc);
|
||||
sc->sc_sdram_par_ih = intr_claim(IRQ_SDRAM_PARITY, IPL_NONE,
|
||||
sc->sc_sdram_par_ih = footbridge_intr_claim(IRQ_SDRAM_PARITY, IPL_HIGH,
|
||||
"sdram parity", footbridge_intr, sc);
|
||||
sc->sc_data_par_ih = intr_claim(IRQ_DATA_PARITY, IPL_NONE,
|
||||
sc->sc_data_par_ih = footbridge_intr_claim(IRQ_DATA_PARITY, IPL_HIGH,
|
||||
"data parity", footbridge_intr, sc);
|
||||
sc->sc_master_abt_ih = intr_claim(IRQ_MASTER_ABORT, IPL_NONE,
|
||||
sc->sc_master_abt_ih = footbridge_intr_claim(IRQ_MASTER_ABORT, IPL_HIGH,
|
||||
"mast abt", footbridge_intr, sc);
|
||||
sc->sc_target_abt_ih = intr_claim(IRQ_TARGET_ABORT, IPL_NONE,
|
||||
sc->sc_target_abt_ih = footbridge_intr_claim(IRQ_TARGET_ABORT, IPL_HIGH,
|
||||
"targ abt", footbridge_intr, sc);
|
||||
sc->sc_parity_ih = intr_claim(IRQ_PARITY, IPL_NONE,
|
||||
sc->sc_parity_ih = footbridge_intr_claim(IRQ_PARITY, IPL_HIGH,
|
||||
"parity", footbridge_intr, sc);
|
||||
|
||||
|
||||
/* Set up the PCI bus tags */
|
||||
footbridge_create_io_bs_tag(&footbridge_pci_io_bs_tag,
|
||||
(void *)DC21285_PCI_IO_VBASE);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: footbridge_clock.c,v 1.14 2002/10/29 14:30:03 tsutsui Exp $ */
|
||||
/* $NetBSD: footbridge_clock.c,v 1.15 2002/11/03 21:43:30 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Mark Brinicombe.
|
||||
|
@ -291,7 +291,7 @@ cpu_initclocks()
|
|||
*/
|
||||
clock_sc->sc_clock_ticks_per_256us =
|
||||
((((clock_sc->sc_clock_count * hz) / 1000) * 256) / 1000);
|
||||
clock_sc->sc_clockintr = intr_claim(IRQ_TIMER_1, IPL_CLOCK,
|
||||
clock_sc->sc_clockintr = footbridge_intr_claim(IRQ_TIMER_1, IPL_CLOCK,
|
||||
"tmr1 hard clk", clockhandler, 0);
|
||||
|
||||
if (clock_sc->sc_clockintr == NULL)
|
||||
|
@ -302,7 +302,7 @@ cpu_initclocks()
|
|||
if (stathz) {
|
||||
/* Setup timer 2 and claim interrupt */
|
||||
setstatclockrate(stathz);
|
||||
clock_sc->sc_statclockintr = intr_claim(IRQ_TIMER_2, IPL_STATCLOCK,
|
||||
clock_sc->sc_statclockintr = footbridge_intr_claim(IRQ_TIMER_2, IPL_STATCLOCK,
|
||||
"tmr2 stat clk", statclockhandler, 0);
|
||||
if (clock_sc->sc_statclockintr == NULL)
|
||||
panic("%s: Cannot install timer 2 interrupt handler",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: footbridge_com.c,v 1.9 2002/10/23 09:10:41 jdolecek Exp $ */
|
||||
/* $NetBSD: footbridge_com.c,v 1.10 2002/11/03 21:43:30 chris Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997 Mark Brinicombe
|
||||
|
@ -211,8 +211,8 @@ fcom_attach(parent, self, aux)
|
|||
}
|
||||
printf("\n");
|
||||
|
||||
sc->sc_ih = intr_claim(sc->sc_rx_irq, IPL_SERIAL, "serial rx",
|
||||
fcom_rxintr, sc);
|
||||
sc->sc_ih = footbridge_intr_claim(sc->sc_rx_irq, IPL_SERIAL,
|
||||
"serial rx", fcom_rxintr, sc);
|
||||
if (sc->sc_ih == NULL)
|
||||
panic("%s: Cannot install rx interrupt handler",
|
||||
sc->sc_dev.dv_xname);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: footbridge_intr.h,v 1.1 2002/09/28 15:53:03 chris Exp $ */
|
||||
/* $NetBSD: footbridge_intr.h,v 1.2 2002/11/03 21:43:31 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Mark Brinicombe.
|
||||
|
@ -36,22 +36,28 @@
|
|||
#ifndef _FOOTBRIDGE_INTR_H_
|
||||
#define _FOOTBRIDGE_INTR_H_
|
||||
|
||||
#include <arm/armreg.h>
|
||||
|
||||
/* Define the various Interrupt Priority Levels */
|
||||
|
||||
/* Hardware Interrupt Priority Levels are not mutually exclusive. */
|
||||
|
||||
#define IPL_BIO 0 /* block I/O */
|
||||
#define IPL_NET 1 /* network */
|
||||
#define IPL_TTY 2 /* terminal */
|
||||
#define IPL_IMP 3 /* memory allocation */
|
||||
#define IPL_AUDIO 4 /* audio */
|
||||
#define IPL_CLOCK 5 /* clock */
|
||||
#define IPL_STATCLOCK 6 /* statclock */
|
||||
#define IPL_HIGH 7 /* */
|
||||
#define IPL_SERIAL 8 /* serial */
|
||||
#define IPL_NONE 9
|
||||
#define IPL_NONE 0 /* nothing */
|
||||
#define IPL_SOFT 1 /* generic soft interrupts */
|
||||
#define IPL_SOFTCLOCK 2 /* clock software interrupts */
|
||||
#define IPL_SOFTNET 3 /* network software interrupts */
|
||||
#define IPL_BIO 4 /* block I/O */
|
||||
#define IPL_NET 5 /* network */
|
||||
#define IPL_SOFTSERIAL 6 /* serial software interrupts */
|
||||
#define IPL_TTY 7 /* terminal */
|
||||
#define IPL_IMP 8 /* memory allocation */
|
||||
#define IPL_AUDIO 9 /* audio */
|
||||
#define IPL_CLOCK 10 /* clock */
|
||||
#define IPL_STATCLOCK 11 /* statclock */
|
||||
#define IPL_HIGH 12 /* everything */
|
||||
#define IPL_SERIAL 13 /* serial */
|
||||
|
||||
#define IPL_LEVELS 10
|
||||
#define NIPL 14
|
||||
|
||||
#define IST_UNUSABLE -1 /* interrupt cannot be used */
|
||||
#define IST_NONE 0 /* none (dummy) */
|
||||
|
@ -59,15 +65,145 @@
|
|||
#define IST_EDGE 2 /* edge-triggered */
|
||||
#define IST_LEVEL 3 /* level-triggered */
|
||||
|
||||
/* Software interrupt priority levels */
|
||||
#define __NEWINTR /* enables new hooks in cpu_fork()/cpu_switch() */
|
||||
|
||||
#define SOFTIRQ_CLOCK 0
|
||||
#define SOFTIRQ_NET 1
|
||||
#define SOFTIRQ_SERIAL 2
|
||||
#ifndef _LOCORE
|
||||
#include <arm/cpufunc.h>
|
||||
|
||||
#define SOFTIRQ_BIT(x) (1 << x)
|
||||
#include <arm/footbridge/dc21285mem.h>
|
||||
#include <arm/footbridge/dc21285reg.h>
|
||||
|
||||
#define INT_SWMASK \
|
||||
((1U << IRQ_SOFTINT) | (1U << IRQ_RESERVED0) | \
|
||||
(1U << IRQ_RESERVED1) | (1U << IRQ_RESERVED2))
|
||||
#define ICU_INT_HWMASK (0xffffffff & ~(INT_SWMASK | (1U << IRQ_RESERVED3)))
|
||||
|
||||
/* only call this with interrupts off */
|
||||
static __inline void __attribute__((__unused__))
|
||||
footbridge_set_intrmask(void)
|
||||
{
|
||||
extern __volatile uint32_t intr_enabled;
|
||||
/* fetch once so we write the same number to both registers */
|
||||
uint32_t tmp = intr_enabled & ICU_INT_HWMASK;
|
||||
|
||||
((__volatile uint32_t*)(DC21285_ARMCSR_VBASE))[IRQ_ENABLE_SET>>2] = tmp;
|
||||
((__volatile uint32_t*)(DC21285_ARMCSR_VBASE))[IRQ_ENABLE_CLEAR>>2] = ~tmp;
|
||||
}
|
||||
|
||||
static __inline void __attribute__((__unused__))
|
||||
footbridge_splx(int newspl)
|
||||
{
|
||||
extern __volatile uint32_t intr_enabled;
|
||||
extern __volatile int current_spl_level;
|
||||
extern __volatile int footbridge_ipending;
|
||||
extern void footbridge_do_pending(void);
|
||||
int oldirqstate, hwpend;
|
||||
|
||||
current_spl_level = newspl;
|
||||
|
||||
hwpend = (footbridge_ipending & ICU_INT_HWMASK) & ~newspl;
|
||||
if (hwpend != 0) {
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
intr_enabled |= hwpend;
|
||||
footbridge_set_intrmask();
|
||||
restore_interrupts(oldirqstate);
|
||||
}
|
||||
|
||||
if ((footbridge_ipending & INT_SWMASK) & ~newspl)
|
||||
footbridge_do_pending();
|
||||
}
|
||||
|
||||
static __inline int __attribute__((__unused__))
|
||||
footbridge_splraise(int ipl)
|
||||
{
|
||||
extern __volatile int current_spl_level;
|
||||
extern int footbridge_imask[];
|
||||
int old;
|
||||
|
||||
old = current_spl_level;
|
||||
current_spl_level |= footbridge_imask[ipl];
|
||||
|
||||
return (old);
|
||||
}
|
||||
|
||||
static __inline int __attribute__((__unused__))
|
||||
footbridge_spllower(int ipl)
|
||||
{
|
||||
extern __volatile int current_spl_level;
|
||||
extern int footbridge_imask[];
|
||||
int old = current_spl_level;
|
||||
|
||||
footbridge_splx(footbridge_imask[ipl]);
|
||||
return(old);
|
||||
}
|
||||
|
||||
/* should only be defined in footbridge_intr.c */
|
||||
#if !defined(ARM_SPL_NOINLINE)
|
||||
|
||||
#define splx(newspl) footbridge_splx(newspl)
|
||||
#define _spllower(ipl) footbridge_spllower(ipl)
|
||||
#define _splraise(ipl) footbridge_splraise(ipl)
|
||||
void _setsoftintr(int);
|
||||
|
||||
#else
|
||||
|
||||
int _splraise(int);
|
||||
int _spllower(int);
|
||||
void splx(int);
|
||||
void _setsoftintr(int);
|
||||
|
||||
#endif /* ! ARM_SPL_NOINLINE */
|
||||
|
||||
#include <sys/device.h>
|
||||
#include <sys/queue.h>
|
||||
#include <machine/irqhandler.h>
|
||||
#include <arm/arm32/psl.h>
|
||||
|
||||
#define splsoft() _splraise(IPL_SOFT)
|
||||
#define splsoftclock() _splraise(IPL_SOFTCLOCK)
|
||||
#define splsoftnet() _splraise(IPL_SOFTNET)
|
||||
#define splbio() _splraise(IPL_BIO)
|
||||
#define splnet() _splraise(IPL_NET)
|
||||
#define splsoftserial() _splraise(IPL_SOFTSERIAL)
|
||||
#define spltty() _splraise(IPL_TTY)
|
||||
#define spllpt() spltty()
|
||||
#define splvm() _splraise(IPL_IMP)
|
||||
#define splaudio() _splraise(IPL_AUDIO)
|
||||
#define splclock() _splraise(IPL_CLOCK)
|
||||
#define splstatclock() _splraise(IPL_STATCLOCK)
|
||||
#define splhigh() _splraise(IPL_HIGH)
|
||||
#define splserial() _splraise(IPL_SERIAL)
|
||||
|
||||
#define spl0() (void)_spllower(IPL_NONE)
|
||||
#define spllowersoftclock() (void)_spllower(IPL_SOFTCLOCK)
|
||||
|
||||
#define splsched() splhigh()
|
||||
#define spllock() splhigh()
|
||||
|
||||
/* Use generic software interrupt support. */
|
||||
#include <arm/softintr.h>
|
||||
|
||||
/* footbridge has 32 interrupt lines */
|
||||
#define NIRQ 32
|
||||
|
||||
struct intrhand {
|
||||
TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */
|
||||
int (*ih_func)(void *); /* handler */
|
||||
void *ih_arg; /* arg for handler */
|
||||
int ih_ipl; /* IPL_* */
|
||||
int ih_irq; /* IRQ number */
|
||||
};
|
||||
|
||||
#define IRQNAMESIZE sizeof("footbridge irq 31")
|
||||
|
||||
struct intrq {
|
||||
TAILQ_HEAD(, intrhand) iq_list; /* handler list */
|
||||
struct evcnt iq_ev; /* event counter */
|
||||
int iq_mask; /* IRQs to mask while handling */
|
||||
int iq_levels; /* IPL_*'s this IRQ has */
|
||||
int iq_ist; /* share type */
|
||||
char iq_name[IRQNAMESIZE]; /* interrupt name */
|
||||
};
|
||||
|
||||
#endif /* _LOCORE */
|
||||
|
||||
#endif /* _FOOTBRIDGE_INTR_H */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: footbridge_irq.S,v 1.3 2002/10/14 22:32:51 bjh21 Exp $ */
|
||||
/* $NetBSD: footbridge_irq.S,v 1.4 2002/11/03 21:43:31 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Mark Brinicombe.
|
||||
|
@ -43,67 +43,22 @@
|
|||
#include <arm/footbridge/dc21285mem.h>
|
||||
#include <arm/footbridge/dc21285reg.h>
|
||||
|
||||
/*
|
||||
* irq_entry:
|
||||
*
|
||||
* Main entry point for the IRQ vector on dc21285 CPUs. Calls
|
||||
* external interrupt dispatch routine.
|
||||
*/
|
||||
|
||||
.text
|
||||
.align 0
|
||||
/*
|
||||
* ffs table used for servicing irq's quickly must be here otherwise adr can't
|
||||
* reach it
|
||||
* The algorithm for ffs was devised by D. Seal and posted to
|
||||
* comp.sys.arm on 16 Feb 1994.
|
||||
*/
|
||||
.type Lirq_ffs_table, _ASM_TYPE_OBJECT;
|
||||
Lirq_ffs_table:
|
||||
/* same as ffs table but all nums are -1 from that */
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
.byte 0, 0, 1, 12, 2, 6, 0, 13 /* 0- 7 */
|
||||
.byte 3, 0, 7, 0, 0, 0, 0, 14 /* 8-15 */
|
||||
.byte 10, 4, 0, 0, 8, 0, 0, 25 /* 16-23 */
|
||||
.byte 0, 0, 0, 0, 0, 21, 27, 15 /* 24-31 */
|
||||
.byte 31, 11, 5, 0, 0, 0, 0, 0 /* 32-39 */
|
||||
.byte 9, 0, 0, 24, 0, 0, 20, 26 /* 40-47 */
|
||||
.byte 30, 0, 0, 0, 0, 23, 0, 19 /* 48-55 */
|
||||
.byte 29, 0, 22, 18, 28, 17, 16, 0 /* 56-63 */
|
||||
|
||||
/*
|
||||
*
|
||||
* irq_entry
|
||||
*
|
||||
* Main entry point for the IRQ vector
|
||||
*
|
||||
* This function reads the IRQ request register in the 21285
|
||||
* and then calls the installed handlers for each bit that is set.
|
||||
* The function stray_irqhandler is called if a handler is not defined
|
||||
* for a particular interrupt.
|
||||
* If a interrupt handler is found then it is called with r0 containing
|
||||
* the argument defined in the handler structure. If the field ih_arg
|
||||
* is zero then a pointer to the IRQ frame on the stack is passed instead.
|
||||
*/
|
||||
|
||||
Lintr_disabled_mask:
|
||||
.word _C_LABEL(intr_disabled_mask)
|
||||
|
||||
Lintr_claimed_mask:
|
||||
.word _C_LABEL(intr_claimed_mask)
|
||||
|
||||
Lcurrent_spl_level:
|
||||
.word _C_LABEL(current_spl_level)
|
||||
|
||||
Lcurrent_intr_depth:
|
||||
.Lcurrent_intr_depth:
|
||||
.word _C_LABEL(current_intr_depth)
|
||||
.word _C_LABEL(prev_intr_depth)
|
||||
|
||||
Lspl_masks:
|
||||
.word _C_LABEL(spl_masks)
|
||||
|
||||
/*
|
||||
* Register usage
|
||||
*
|
||||
* r5 - Address of ffs table
|
||||
* r6 - Address of current handler
|
||||
* r7 - Pointer to handler pointer list
|
||||
* r8 - Current IRQ requests.
|
||||
* r10 - Base address of IOMD
|
||||
* r11 - IRQ requests still to service.
|
||||
*/
|
||||
.Lastpending:
|
||||
.word _C_LABEL(astpending)
|
||||
|
||||
ASENTRY_NP(irq_entry)
|
||||
sub lr, lr, #0x00000004 /* Adjust the lr */
|
||||
|
@ -116,408 +71,83 @@ ASENTRY_NP(irq_entry)
|
|||
* to determine if we are in an IRQ. Instead we will count the
|
||||
* each time the interrupt handler is nested.
|
||||
*/
|
||||
ldr r0, Lcurrent_intr_depth
|
||||
ldr r0, .Lcurrent_intr_depth
|
||||
ldr r2, .Lcurrent_intr_depth+4
|
||||
ldr r1, [r0]
|
||||
str r1, [r2]
|
||||
add r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
/* Load r8 with the Footbridge interrupt requests */
|
||||
mov r10, #(DC21285_ARMCSR_VBASE)
|
||||
ldr r8, [r10, #(IRQ_STATUS)]
|
||||
|
||||
/* This condition needs further examination */
|
||||
teq r8, #0
|
||||
beq irq_unknown
|
||||
|
||||
/* Block the current requested interrupts */
|
||||
ldr r1, Lintr_disabled_mask
|
||||
ldr r0, [r1]
|
||||
stmfd sp!, {r0}
|
||||
orr r0, r0, r8
|
||||
|
||||
/* branch off into the external handler */
|
||||
mov r0, sp
|
||||
bl _C_LABEL(footbridge_intr_dispatch)
|
||||
|
||||
/* Decremement the nest count. */
|
||||
ldr r0, .Lcurrent_intr_depth
|
||||
ldr r2, .Lcurrent_intr_depth+4
|
||||
ldr r1, [r0]
|
||||
str r1, [r2]
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
/*
|
||||
* Need to block all interrupts at the IPL or lower for
|
||||
* all asserted interrupts.
|
||||
* This basically emulates hardware interrupt priority levels.
|
||||
* Means we need to go through the interrupt mask and for
|
||||
* every asserted interrupt we need to mask out all other
|
||||
* interrupts at the same or lower IPL.
|
||||
* If only we could wait until the main loop but we need to sort
|
||||
* this out first so interrupts can be re-enabled.
|
||||
*
|
||||
* This would benefit from a special ffs type routine
|
||||
* If we're returning to user mode, check for pending ASTs.
|
||||
*/
|
||||
mov r9, #(_SPL_LEVELS - 1)
|
||||
ldr r7, Lspl_masks
|
||||
|
||||
Lfind_highest_ipl:
|
||||
ldr r2, [r7, r9, lsl #2]
|
||||
tst r8, r2
|
||||
subeq r9, r9, #1
|
||||
beq Lfind_highest_ipl
|
||||
|
||||
/* r9 = SPL level of highest priority interrupt */
|
||||
add r9, r9, #1
|
||||
ldr r2, [r7, r9, lsl #2]
|
||||
mvn r2, r2
|
||||
orr r0, r0, r2
|
||||
|
||||
str r0, [r1] /* store new disabled mask */
|
||||
|
||||
ldr r2, Lcurrent_spl_level
|
||||
ldr r1, [r2]
|
||||
str r9, [r2]
|
||||
stmfd sp!, {r1}
|
||||
|
||||
ldr r7, Lintr_claimed_mask /* get claimed mask */
|
||||
ldr r6, [r7]
|
||||
bic r6, r6, r0 /* mask out disabled */
|
||||
ldr r7, Lintr_current_mask /* get claimed mask */
|
||||
str r6, [r7] /* new current mask */
|
||||
|
||||
/* Update the DC21285 irq masks */
|
||||
bl _C_LABEL(irq_setmasks_nointr)
|
||||
|
||||
mrs r0, cpsr_all /* Enable IRQ's */
|
||||
bic r0, r0, #I32_bit
|
||||
msr cpsr_all, r0
|
||||
|
||||
ldr r7, Lirqhandlers
|
||||
|
||||
/* take a copy of the irq mask so we can alter it */
|
||||
mov r11, r8
|
||||
|
||||
/* ffs routine to find first irq to service */
|
||||
/* standard trick to isolate bottom bit in a0 or 0 if a0 = 0 on entry */
|
||||
rsb r4, r11, #0
|
||||
ands r10, r11, r4
|
||||
|
||||
/*
|
||||
* now r10 has at most 1 set bit, call this X
|
||||
* if X = 0, branch to exit code
|
||||
*/
|
||||
beq exitirq
|
||||
adr r5, Lirq_ffs_table
|
||||
irqloop:
|
||||
/*
|
||||
* at this point:
|
||||
* r5 = address of ffs table
|
||||
* r7 = address of irq handlers table
|
||||
* r8 = irq request
|
||||
* r10 = bit of irq to be serviced
|
||||
* r11 = bitmask of IRQ's to service
|
||||
*/
|
||||
|
||||
/* find the set bit */
|
||||
orr r9, r10, r10, lsl #4 /* X * 0x11 */
|
||||
orr r9, r9, r9, lsl #6 /* X * 0x451 */
|
||||
rsb r9, r9, r9, lsl #16 /* X * 0x0450fbaf */
|
||||
/* fetch the bit number */
|
||||
ldrb r9, [r5, r9, lsr #26 ]
|
||||
|
||||
/*
|
||||
* r9 = irq to service
|
||||
*/
|
||||
|
||||
/* apologies for the dogs dinner of code here, but it's in an attempt
|
||||
* to minimise stalling on SA's, hence lots of things happen here:
|
||||
* - getting address of handler, if it doesn't exist we call
|
||||
* stray_irqhandler this is assumed to be rare so we don't
|
||||
* care about performance for it
|
||||
* - statinfo is updated
|
||||
* - unsetting of the irq bit in r11
|
||||
* - irq stats (if enabled) also get put in the mix
|
||||
*/
|
||||
ldr r4, Lcnt /* Stat info A */
|
||||
ldr r6, [r7, r9, lsl #2] /* Get address of first handler structure */
|
||||
|
||||
ldr r1, [r4, #(V_INTR)] /* Stat info B */
|
||||
|
||||
teq r6, #0x00000000 /* Do we have a handler */
|
||||
moveq r0, r8 /* IRQ requests as arg 0 */
|
||||
adreq lr, nextirq /* return address */
|
||||
bic r11, r11, r10 /* clear the IRQ bit */
|
||||
beq _C_LABEL(stray_irqhandler) /* call special handler */
|
||||
|
||||
#ifdef IRQSTATS
|
||||
ldr r2, Lintrcnt
|
||||
ldr r3, [r6, #(IH_NUM)]
|
||||
#endif
|
||||
/* stat info C */
|
||||
add r1, r1, #0x00000001
|
||||
|
||||
#ifdef IRQSTATS
|
||||
ldr r3, [r2, r3, lsl #2]!
|
||||
#endif
|
||||
/* stat info D */
|
||||
str r1, [r4, #(V_INTR)]
|
||||
|
||||
#ifdef IRQSTATS
|
||||
add r3, r3, #0x00000001
|
||||
str r3, [r2]
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
irqchainloop:
|
||||
ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */
|
||||
teq r0, #0x00000000 /* If arg is zero pass stack frame */
|
||||
addeq r0, sp, #8 /* ... stack frame [XXX needs care] */
|
||||
mov lr, pc /* return address */
|
||||
ldr pc, [r6, #(IH_FUNC)] /* Call handler */
|
||||
|
||||
ldr r6, [r6, #(IH_NEXT)] /* fetch next handler */
|
||||
#if 0
|
||||
teq r0, #0x00000001 /* Was the irq serviced ? */
|
||||
#endif
|
||||
/* if it was it'll just fall through this: */
|
||||
teq r6, #0x00000000
|
||||
bne irqchainloop
|
||||
nextirq:
|
||||
/* Check for next irq */
|
||||
rsb r4, r11, #0
|
||||
ands r10, r11, r4
|
||||
/* check if there are anymore irq's to service */
|
||||
bne irqloop
|
||||
|
||||
exitirq:
|
||||
ldmfd sp!, {r2, r3}
|
||||
ldr r1, Lcurrent_spl_level
|
||||
ldr r9, Lintr_disabled_mask
|
||||
str r2, [r1] /* store current spl level */
|
||||
|
||||
ldr r1, Lintr_claimed_mask /* get claimed mask */
|
||||
|
||||
str r3, [r9] /* store disabled mask */
|
||||
|
||||
ldr r0, [r1]
|
||||
ldr r9, Lintr_current_mask /* get claimed mask */
|
||||
bic r0, r0, r3 /* mask out disabled */
|
||||
str r0, [r9] /* new current mask */
|
||||
bl _C_LABEL(irq_setmasks)
|
||||
|
||||
bl _C_LABEL(dosoftints) /* Handle the soft interrupts */
|
||||
|
||||
/* Manage AST's. Maybe this should be done as a soft interrupt ? */
|
||||
ldr r0, [sp] /* Get the SPSR from stack */
|
||||
|
||||
and r0, r0, #(PSR_MODE) /* Test for USR32 mode before the IRQ */
|
||||
teq r0, #(PSR_USR32_MODE)
|
||||
ldreq r0, Lastpending /* Do we have an AST pending ? */
|
||||
ldreq r1, [r0]
|
||||
teqeq r1, #0x00000001
|
||||
bne .Lirqout /* Nope, get out now */
|
||||
|
||||
beq irqast /* call the AST handler */
|
||||
|
||||
/* Kill IRQ's in preparation for exit */
|
||||
mrs r0, cpsr_all
|
||||
orr r0, r0, #(I32_bit)
|
||||
msr cpsr_all, r0
|
||||
|
||||
irq_unknown:
|
||||
/* Decrement the nest count */
|
||||
ldr r0, Lcurrent_intr_depth
|
||||
.Lastloop:
|
||||
ldr r0, .Lastpending /* Do we have an AST pending? */
|
||||
ldr r1, [r0]
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
teq r1, #0x00000000
|
||||
beq .Lirqout /* Nope, get out now */
|
||||
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
mov r1, #0x00000000
|
||||
str r1, [r0] /* Clear astpending */
|
||||
|
||||
movs pc, lr /* Exit */
|
||||
|
||||
/*
|
||||
* Ok, snag with current intr depth ...
|
||||
* If ast() calls mi_sleep() the current_intr_depth will not be
|
||||
* decremented until the process is woken up. This can result
|
||||
* in the system believing it is still in the interrupt handler.
|
||||
* If we are calling ast() then correct the current_intr_depth
|
||||
* before the call.
|
||||
*/
|
||||
irqast:
|
||||
mov r1, #0x00000000 /* Clear ast_pending */
|
||||
str r1, [r0]
|
||||
|
||||
/* Kill IRQ's so we atomically decrement current_intr_depth */
|
||||
mrs r2, cpsr_all
|
||||
orr r3, r2, #(I32_bit)
|
||||
msr cpsr_all, r3
|
||||
|
||||
/* Decrement the nest count */
|
||||
ldr r0, Lcurrent_intr_depth
|
||||
ldr r1, [r0]
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
/* Restore IRQ's */
|
||||
msr cpsr_all, r2
|
||||
mrs r4, cpsr /* save CPSR */
|
||||
bic r0, r4, #(I32_bit) /* Enable IRQs */
|
||||
msr cpsr_c, r0
|
||||
|
||||
mov r0, sp
|
||||
bl _C_LABEL(ast)
|
||||
bl _C_LABEL(ast) /* ast(frame) */
|
||||
|
||||
/* Kill IRQ's in preparation for exit */
|
||||
|
||||
mrs r0, cpsr_all
|
||||
orr r0, r0, #(I32_bit)
|
||||
msr cpsr_all, r0
|
||||
msr cpsr_c, r4 /* Disable IRQs */
|
||||
b .Lastloop /* Check for more ASTs */
|
||||
|
||||
.Lirqout:
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
|
||||
movs pc, lr /* Exit */
|
||||
|
||||
Lcnt:
|
||||
.word _C_LABEL(uvmexp)
|
||||
|
||||
Lintrcnt:
|
||||
.word _C_LABEL(intrcnt)
|
||||
|
||||
Lirqhandlers:
|
||||
.word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */
|
||||
|
||||
Lastpending:
|
||||
.word _C_LABEL(astpending)
|
||||
|
||||
Lspl_mask:
|
||||
.word _C_LABEL(spl_mask) /* irq's allowed at current spl level */
|
||||
|
||||
Lintr_current_mask:
|
||||
.word _C_LABEL(intr_current_mask)
|
||||
|
||||
ENTRY(irq_setmasks)
|
||||
/* Disable interrupts */
|
||||
mrs r3, cpsr_all
|
||||
orr r1, r3, #(I32_bit)
|
||||
msr cpsr_all, r1
|
||||
|
||||
/* Calculate DC21285 interrupt mask */
|
||||
ldr r1, Lintr_current_mask /* All the enabled interrupts */
|
||||
ldr r2, Lspl_mask /* Block due to current spl level */
|
||||
ldr r1, [r1]
|
||||
ldr r2, [r2]
|
||||
and r1, r1, r2
|
||||
|
||||
mov r0, #(DC21285_ARMCSR_VBASE)
|
||||
str r1, [r0, #(IRQ_ENABLE_SET)]
|
||||
mvn r1, r1
|
||||
str r1, [r0, #(IRQ_ENABLE_CLEAR)]
|
||||
|
||||
/* Restore old cpsr and exit */
|
||||
msr cpsr_all, r3
|
||||
mov pc, lr
|
||||
|
||||
ENTRY(irq_setmasks_nointr)
|
||||
/* Calculate DC21285 interrupt mask */
|
||||
ldr r1, Lintr_current_mask /* All the enabled interrupts */
|
||||
ldr r1, [r1]
|
||||
ldr r2, Lspl_mask /* Block due to current spl level */
|
||||
ldr r2, [r2]
|
||||
and r1, r1, r2
|
||||
|
||||
mov r0, #(DC21285_ARMCSR_VBASE)
|
||||
str r1, [r0, #(IRQ_ENABLE_SET)]
|
||||
mvn r1, r1
|
||||
str r1, [r0, #(IRQ_ENABLE_CLEAR)]
|
||||
|
||||
mov pc, lr
|
||||
|
||||
#ifdef IRQSTATS
|
||||
/* These symbols are used by vmstat */
|
||||
|
||||
.text
|
||||
.global _C_LABEL(_intrnames)
|
||||
_C_LABEL(_intrnames):
|
||||
.word _C_LABEL(intrnames)
|
||||
|
||||
.data
|
||||
.align 0
|
||||
.global _C_LABEL(intrnames), _C_LABEL(sintrnames), _C_LABEL(eintrnames)
|
||||
.global _C_LABEL(intrcnt), _C_LABEL(sintrcnt), _C_LABEL(eintrcnt)
|
||||
_C_LABEL(intrnames):
|
||||
.asciz "interrupt 0 "
|
||||
.asciz "interrupt 1 "
|
||||
.asciz "interrupt 2 "
|
||||
.asciz "interrupt 3 "
|
||||
.asciz "interrupt 4 "
|
||||
.asciz "interrupt 5 "
|
||||
.asciz "interrupt 6 "
|
||||
.asciz "interrupt 7 "
|
||||
.asciz "interrupt 8 "
|
||||
.asciz "interrupt 9 "
|
||||
.asciz "interrupt 10 "
|
||||
.asciz "interrupt 11 "
|
||||
.asciz "interrupt 12 "
|
||||
.asciz "interrupt 13 "
|
||||
.asciz "interrupt 14 "
|
||||
.asciz "interrupt 15 "
|
||||
.asciz "interrupt 16 "
|
||||
.asciz "interrupt 17 "
|
||||
.asciz "interrupt 18 "
|
||||
.asciz "interrupt 19 "
|
||||
.asciz "interrupt 20 "
|
||||
.asciz "interrupt 21 "
|
||||
.asciz "interrupt 22 "
|
||||
.asciz "interrupt 23 "
|
||||
.asciz "interrupt 24 "
|
||||
.asciz "interrupt 25 "
|
||||
.asciz "interrupt 26 "
|
||||
.asciz "interrupt 27 "
|
||||
.asciz "interrupt 28 "
|
||||
.asciz "interrupt 29 "
|
||||
.asciz "interrupt 30 "
|
||||
.asciz "interrupt 31 "
|
||||
_C_LABEL(sintrnames):
|
||||
.asciz "soft int 0 "
|
||||
.asciz "soft int 1 "
|
||||
.asciz "soft int 2 "
|
||||
.asciz "soft int 3 "
|
||||
.asciz "soft int 4 "
|
||||
.asciz "soft int 5 "
|
||||
.asciz "soft int 6 "
|
||||
.asciz "soft int 7 "
|
||||
.asciz "soft int 8 "
|
||||
.asciz "soft int 9 "
|
||||
.asciz "soft int 10 "
|
||||
.asciz "soft int 11 "
|
||||
.asciz "soft int 12 "
|
||||
.asciz "soft int 13 "
|
||||
.asciz "soft int 14 "
|
||||
.asciz "soft int 15 "
|
||||
.asciz "soft int 16 "
|
||||
.asciz "soft int 17 "
|
||||
.asciz "soft int 18 "
|
||||
.asciz "soft int 19 "
|
||||
.asciz "soft int 20 "
|
||||
.asciz "soft int 21 "
|
||||
.asciz "soft int 22 "
|
||||
.asciz "soft int 23 "
|
||||
.asciz "soft int 24 "
|
||||
.asciz "soft int 25 "
|
||||
.asciz "soft int 26 "
|
||||
.asciz "soft int 27 "
|
||||
.asciz "soft int 28 "
|
||||
.asciz "soft int 29 "
|
||||
.asciz "soft int 30 "
|
||||
.asciz "soft int 31 "
|
||||
_C_LABEL(eintrnames):
|
||||
|
||||
.bss
|
||||
.align 0
|
||||
.global _C_LABEL(intrcnt), _C_LABEL(sintrcnt), _C_LABEL(eintrcnt)
|
||||
_C_LABEL(intrcnt):
|
||||
.space 32*4 /* XXX Should be linked to number of interrupts */
|
||||
_C_LABEL(sintrcnt):
|
||||
.space 32*4 /* XXX Should be linked to number of soft ints */
|
||||
_C_LABEL(eintrcnt):
|
||||
|
||||
#else /* IRQSTATS */
|
||||
/* Dummy entries to keep vmstat happy */
|
||||
.global _C_LABEL(astpending)
|
||||
_C_LABEL(astpending):
|
||||
.word 0
|
||||
|
||||
.text
|
||||
.globl _C_LABEL(intrnames), _C_LABEL(eintrnames), _C_LABEL(intrcnt), _C_LABEL(eintrcnt)
|
||||
_C_LABEL(intrnames):
|
||||
.long 0
|
||||
.global _C_LABEL(current_intr_depth)
|
||||
_C_LABEL(current_intr_depth):
|
||||
.word 0
|
||||
|
||||
.global _C_LABEL(prev_intr_depth)
|
||||
_C_LABEL(prev_intr_depth):
|
||||
.word 0
|
||||
|
||||
/*
|
||||
* XXX Provide intrnames/intrcnt for legacy code, but
|
||||
* don't actually use them.
|
||||
*/
|
||||
|
||||
.global _C_LABEL(intrnames), _C_LABEL(eintrnames)
|
||||
.global _C_LABEL(intrcnt), _C_LABEL(eintrcnt)
|
||||
_C_LABEL(intrnames):
|
||||
_C_LABEL(eintrnames):
|
||||
|
||||
.global _C_LABEL(intrcnt), _C_LABEL(sintrcnt), _C_LABEL(eintrcnt)
|
||||
_C_LABEL(intrcnt):
|
||||
.long 0
|
||||
_C_LABEL(eintrcnt):
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
/* End of footbridge_irq.S */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: footbridge_irqhandler.c,v 1.5 2002/09/27 15:35:44 provos Exp $ */
|
||||
/* $NetBSD: footbridge_irqhandler.c,v 1.6 2002/11/03 21:43:31 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1998 Mark Brinicombe.
|
||||
|
@ -37,421 +37,425 @@
|
|||
* from: iomd_irqhandler.c,v 1.16 $
|
||||
*/
|
||||
|
||||
#ifndef ARM_SPL_NOINLINE
|
||||
#define ARM_SPL_NOINLINE
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef __lint
|
||||
__RCSID("$NetBSD: footbridge_irqhandler.c,v 1.6 2002/11/03 21:43:31 chris Exp $");
|
||||
#endif /* !__lint */
|
||||
|
||||
#include "opt_irqstats.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#include <machine/intr.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <arm/arm32/machdep.h>
|
||||
|
||||
irqhandler_t *irqhandlers[NIRQS];
|
||||
#include <arm/footbridge/dc21285mem.h>
|
||||
#include <arm/footbridge/dc21285reg.h>
|
||||
|
||||
int current_intr_depth; /* Depth of interrupt nesting */
|
||||
u_int intr_claimed_mask; /* Interrupts that are claimed */
|
||||
u_int intr_disabled_mask; /* Interrupts that are temporarily disabled */
|
||||
u_int intr_current_mask; /* Interrupts currently allowable */
|
||||
u_int spl_mask;
|
||||
u_int irqmasks[IPL_LEVELS];
|
||||
u_int irqblock[NIRQS];
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
extern u_int soft_interrupts; /* Only so we can initialise it */
|
||||
|
||||
extern char *_intrnames;
|
||||
|
||||
void stray_irqhandler __P((void));
|
||||
|
||||
void
|
||||
irq_init(void)
|
||||
{
|
||||
int loop;
|
||||
|
||||
/* Clear all the IRQ handlers and the irq block masks */
|
||||
for (loop = 0; loop < NIRQS; ++loop) {
|
||||
irqhandlers[loop] = NULL;
|
||||
irqblock[loop] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the irqmasks for the different Interrupt Priority Levels
|
||||
* We will start with no bits set and these will be updated as handlers
|
||||
* are installed at different IPL's.
|
||||
*/
|
||||
for (loop = 0; loop < IPL_LEVELS; ++loop)
|
||||
irqmasks[loop] = 0;
|
||||
|
||||
current_intr_depth = 0;
|
||||
intr_claimed_mask = 0x00000000;
|
||||
intr_disabled_mask = 0x00000000;
|
||||
intr_current_mask = 0x00000000;
|
||||
spl_mask = 0x00000000;
|
||||
soft_interrupts = 0x00000000;
|
||||
|
||||
set_spl_masks();
|
||||
irq_setmasks();
|
||||
|
||||
/* Enable IRQ's and FIQ's */
|
||||
enable_interrupts(I32_bit | F32_bit);
|
||||
}
|
||||
|
||||
void
|
||||
stray_irqhandler()
|
||||
{
|
||||
panic("stray irq");
|
||||
}
|
||||
|
||||
/*
|
||||
* void disable_irq(int irq)
|
||||
*
|
||||
* Disables a specific irq. The irq is removed from the master irq mask
|
||||
*
|
||||
* Use of this function outside this file is deprecated.
|
||||
*/
|
||||
|
||||
void
|
||||
disable_irq(irq)
|
||||
int irq;
|
||||
{
|
||||
int oldirqstate;
|
||||
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
intr_claimed_mask &= ~(1 << irq);
|
||||
intr_current_mask = intr_claimed_mask & ~intr_disabled_mask;
|
||||
irq_setmasks();
|
||||
restore_interrupts(oldirqstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void enable_irq(int irq)
|
||||
*
|
||||
* Enables a specific irq. The irq is added to the master irq mask
|
||||
* This routine should be used with caution. A handler should already
|
||||
* be installed.
|
||||
*
|
||||
* Use of this function outside this file is deprecated.
|
||||
*/
|
||||
|
||||
void
|
||||
enable_irq(irq)
|
||||
int irq;
|
||||
{
|
||||
u_int oldirqstate;
|
||||
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
intr_claimed_mask |= (1 << irq);
|
||||
intr_current_mask = intr_claimed_mask & ~intr_disabled_mask;
|
||||
irq_setmasks();
|
||||
restore_interrupts(oldirqstate);
|
||||
}
|
||||
|
||||
/*
|
||||
* int irq_claim(int irq, irqhandler_t *handler)
|
||||
*
|
||||
* Enable an IRQ and install a handler for it.
|
||||
*/
|
||||
|
||||
int
|
||||
irq_claim(irq, handler)
|
||||
int irq;
|
||||
irqhandler_t *handler;
|
||||
{
|
||||
int level;
|
||||
int loop;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/* Sanity check */
|
||||
if (handler == NULL)
|
||||
panic("NULL interrupt handler");
|
||||
if (handler->ih_func == NULL)
|
||||
panic("Interrupt handler does not have a function");
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
/*
|
||||
* IRQ_INSTRUCT indicates that we should get the irq number
|
||||
* from the irq structure
|
||||
*/
|
||||
if (irq == IRQ_INSTRUCT)
|
||||
irq = handler->ih_num;
|
||||
|
||||
/* Make sure the irq number is valid */
|
||||
if (irq < 0 || irq >= NIRQS)
|
||||
return(-1);
|
||||
|
||||
/* Make sure the level is valid */
|
||||
if (handler->ih_level < 0 || handler->ih_level >= IPL_LEVELS)
|
||||
return(-1);
|
||||
|
||||
/* Attach handler at top of chain */
|
||||
handler->ih_next = irqhandlers[irq];
|
||||
irqhandlers[irq] = handler;
|
||||
|
||||
/*
|
||||
* Reset the flags for this handler.
|
||||
* As the handler is now in the chain mark it as active.
|
||||
*/
|
||||
handler->ih_flags = 0 | IRQ_FLAG_ACTIVE;
|
||||
|
||||
/*
|
||||
* Record the interrupt number for accounting.
|
||||
* Done here as the accounting number may not be the same as the IRQ number
|
||||
* though for the moment they are
|
||||
*/
|
||||
handler->ih_num = irq;
|
||||
|
||||
#ifdef IRQSTATS
|
||||
/* Get the interrupt name from the head of the list */
|
||||
if (handler->ih_name) {
|
||||
char *ptr = _intrnames + (irq * 14);
|
||||
strcpy(ptr, " ");
|
||||
strncpy(ptr, handler->ih_name,
|
||||
min(strlen(handler->ih_name), 13));
|
||||
} else {
|
||||
char *ptr = _intrnames + (irq * 14);
|
||||
sprintf(ptr, "irq %2d ", irq);
|
||||
}
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
/*
|
||||
* Update the irq masks.
|
||||
* If ih_level is out of range then don't bother to update
|
||||
* the masks.
|
||||
*/
|
||||
if (handler->ih_level >= 0 && handler->ih_level < IPL_LEVELS) {
|
||||
irqhandler_t *ptr;
|
||||
|
||||
/*
|
||||
* Find the lowest interrupt priority on the irq chain.
|
||||
* Interrupt is allowable at priorities lower than this.
|
||||
*/
|
||||
ptr = irqhandlers[irq];
|
||||
if (ptr) {
|
||||
level = ptr->ih_level - 1;
|
||||
while (ptr) {
|
||||
if (ptr->ih_level - 1 < level)
|
||||
level = ptr->ih_level - 1;
|
||||
ptr = ptr->ih_next;
|
||||
}
|
||||
for (loop = 0; loop < IPL_LEVELS; ++loop) {
|
||||
if (level >= loop)
|
||||
irqmasks[loop] |= (1 << irq);
|
||||
else
|
||||
irqmasks[loop] &= ~(1 << irq);
|
||||
}
|
||||
}
|
||||
|
||||
#include "sl.h"
|
||||
#include "ppp.h"
|
||||
#if NSL > 0 || NPPP > 0
|
||||
/* In the presence of SLIP or PPP, splimp > spltty. */
|
||||
irqmasks[IPL_NET] &= irqmasks[IPL_TTY];
|
||||
#include "isa.h"
|
||||
#if NISA > 0
|
||||
#include <dev/isa/isavar.h>
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* We now need to update the irqblock array. This array indicates
|
||||
* what other interrupts should be blocked when interrupt is asserted
|
||||
* This basically emulates hardware interrupt priorities e.g. by blocking
|
||||
* all other IPL_BIO interrupts with an IPL_BIO interrupt is asserted.
|
||||
* For each interrupt we find the highest IPL and set the block mask to
|
||||
* the interrupt mask for that level.
|
||||
*/
|
||||
for (loop = 0; loop < NIRQS; ++loop) {
|
||||
irqhandler_t *ptr;
|
||||
/* Interrupt handler queues. */
|
||||
static struct intrq footbridge_intrq[NIRQ];
|
||||
|
||||
ptr = irqhandlers[loop];
|
||||
if (ptr) {
|
||||
/* There is at least 1 handler so scan the chain */
|
||||
level = ptr->ih_level;
|
||||
while (ptr) {
|
||||
if (ptr->ih_level > level)
|
||||
level = ptr->ih_level;
|
||||
ptr = ptr->ih_next;
|
||||
}
|
||||
irqblock[loop] = ~irqmasks[level];
|
||||
} else
|
||||
/* No handlers for this irq so nothing to block */
|
||||
irqblock[loop] = 0;
|
||||
}
|
||||
/* Interrupts to mask at each level. */
|
||||
int footbridge_imask[NIPL];
|
||||
|
||||
enable_irq(irq);
|
||||
set_spl_masks();
|
||||
/* Software copy of the IRQs we have enabled. */
|
||||
__volatile uint32_t intr_enabled;
|
||||
|
||||
return(0);
|
||||
}
|
||||
/* Current interrupt priority level */
|
||||
__volatile int current_spl_level;
|
||||
|
||||
/* Interrupts pending */
|
||||
__volatile int footbridge_ipending;
|
||||
|
||||
void footbridge_intr_dispatch(struct clockframe *frame);
|
||||
|
||||
const struct evcnt *footbridge_pci_intr_evcnt __P((void *, pci_intr_handle_t));
|
||||
|
||||
void footbridge_do_pending(void);
|
||||
|
||||
static const uint32_t si_to_irqbit[SI_NQUEUES] =
|
||||
{ IRQ_SOFTINT,
|
||||
IRQ_RESERVED0,
|
||||
IRQ_RESERVED1,
|
||||
IRQ_RESERVED2 };
|
||||
|
||||
#define SI_TO_IRQBIT(si) (1U << si_to_irqbit[(si)])
|
||||
|
||||
/*
|
||||
* int irq_release(int irq, irqhandler_t *handler)
|
||||
*
|
||||
* Disable an IRQ and remove a handler for it.
|
||||
* Map a software interrupt queue to an interrupt priority level.
|
||||
*/
|
||||
static const int si_to_ipl[SI_NQUEUES] = {
|
||||
IPL_SOFT, /* SI_SOFT */
|
||||
IPL_SOFTCLOCK, /* SI_SOFTCLOCK */
|
||||
IPL_SOFTNET, /* SI_SOFTNET */
|
||||
IPL_SOFTSERIAL, /* SI_SOFTSERIAL */
|
||||
};
|
||||
|
||||
int
|
||||
irq_release(irq, handler)
|
||||
int irq;
|
||||
irqhandler_t *handler;
|
||||
const struct evcnt *
|
||||
footbridge_pci_intr_evcnt(pcv, ih)
|
||||
void *pcv;
|
||||
pci_intr_handle_t ih;
|
||||
{
|
||||
int level;
|
||||
int loop;
|
||||
irqhandler_t *irqhand;
|
||||
irqhandler_t **prehand;
|
||||
#ifdef IRQSTATS
|
||||
extern char *_intrnames;
|
||||
#endif /* IRQSTATS */
|
||||
/*
|
||||
* IRQ_INSTRUCT indicates that we should get the irq number
|
||||
* from the irq structure
|
||||
*/
|
||||
if (irq == IRQ_INSTRUCT)
|
||||
irq = handler->ih_num;
|
||||
|
||||
/* Make sure the irq number is valid */
|
||||
if (irq < 0 || irq >= NIRQS)
|
||||
return(-1);
|
||||
|
||||
/* Locate the handler */
|
||||
irqhand = irqhandlers[irq];
|
||||
prehand = &irqhandlers[irq];
|
||||
|
||||
while (irqhand && handler != irqhand) {
|
||||
prehand = &irqhand->ih_next;
|
||||
irqhand = irqhand->ih_next;
|
||||
/* XXX check range is valid */
|
||||
#if NISA > 0
|
||||
if (ih >= 0x80 && ih <= 0x8f) {
|
||||
return isa_intr_evcnt(NULL, (ih & 0x0f));
|
||||
}
|
||||
|
||||
/* Remove the handler if located */
|
||||
if (irqhand)
|
||||
*prehand = irqhand->ih_next;
|
||||
else
|
||||
return(-1);
|
||||
|
||||
/* Now the handler has been removed from the chain mark is as inactive */
|
||||
irqhand->ih_flags &= ~IRQ_FLAG_ACTIVE;
|
||||
|
||||
/* Make sure the head of the handler list is active */
|
||||
if (irqhandlers[irq])
|
||||
irqhandlers[irq]->ih_flags |= IRQ_FLAG_ACTIVE;
|
||||
|
||||
#ifdef IRQSTATS
|
||||
/* Get the interrupt name from the head of the list */
|
||||
if (irqhandlers[irq] && irqhandlers[irq]->ih_name) {
|
||||
char *ptr = _intrnames + (irq * 14);
|
||||
strcpy(ptr, " ");
|
||||
strncpy(ptr, irqhandlers[irq]->ih_name,
|
||||
min(strlen(irqhandlers[irq]->ih_name), 13));
|
||||
} else {
|
||||
char *ptr = _intrnames + (irq * 14);
|
||||
sprintf(ptr, "irq %2d ", irq);
|
||||
}
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
/*
|
||||
* Update the irq masks.
|
||||
* If ih_level is out of range then don't bother to update
|
||||
* the masks.
|
||||
*/
|
||||
if (handler->ih_level >= 0 && handler->ih_level < IPL_LEVELS) {
|
||||
irqhandler_t *ptr;
|
||||
|
||||
/*
|
||||
* Find the lowest interrupt priority on the irq chain.
|
||||
* Interrupt is allowable at priorities lower than this.
|
||||
*/
|
||||
ptr = irqhandlers[irq];
|
||||
if (ptr) {
|
||||
level = ptr->ih_level - 1;
|
||||
while (ptr) {
|
||||
if (ptr->ih_level - 1 < level)
|
||||
level = ptr->ih_level - 1;
|
||||
ptr = ptr->ih_next;
|
||||
}
|
||||
for (loop = 0; loop < IPL_LEVELS; ++loop) {
|
||||
if (level >= loop)
|
||||
irqmasks[loop] |= (1 << irq);
|
||||
else
|
||||
irqmasks[loop] &= ~(1 << irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We now need to update the irqblock array. This array indicates
|
||||
* what other interrupts should be blocked when interrupt is asserted
|
||||
* This basically emulates hardware interrupt priorities e.g. by
|
||||
* blocking all other IPL_BIO interrupts with an IPL_BIO interrupt
|
||||
* is asserted. For each interrupt we find the highest IPL and set
|
||||
* the block mask to the interrupt mask for that level.
|
||||
*/
|
||||
for (loop = 0; loop < NIRQS; ++loop) {
|
||||
irqhandler_t *ptr;
|
||||
|
||||
ptr = irqhandlers[loop];
|
||||
if (ptr) {
|
||||
/* There is at least 1 handler so scan the chain */
|
||||
level = ptr->ih_level;
|
||||
while (ptr) {
|
||||
if (ptr->ih_level > level)
|
||||
level = ptr->ih_level;
|
||||
ptr = ptr->ih_next;
|
||||
}
|
||||
irqblock[loop] = ~irqmasks[level];
|
||||
} else
|
||||
/* No handlers for this irq so nothing to block */
|
||||
irqblock[loop] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the appropriate mask bit if there are no handlers left for
|
||||
* this IRQ.
|
||||
*/
|
||||
if (irqhandlers[irq] == NULL)
|
||||
disable_irq(irq);
|
||||
|
||||
set_spl_masks();
|
||||
|
||||
return(0);
|
||||
#endif
|
||||
return &footbridge_intrq[ih].iq_ev;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
footbridge_enable_irq(int irq)
|
||||
{
|
||||
intr_enabled |= (1U << irq);
|
||||
|
||||
footbridge_set_intrmask();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
footbridge_disable_irq(int irq)
|
||||
{
|
||||
intr_enabled &= ~(1U << irq);
|
||||
footbridge_set_intrmask();
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: This routine must be called with interrupts disabled in the CPSR.
|
||||
*/
|
||||
static void
|
||||
footbridge_intr_calculate_masks(void)
|
||||
{
|
||||
struct intrq *iq;
|
||||
struct intrhand *ih;
|
||||
int irq, ipl;
|
||||
|
||||
/* First, figure out which IPLs each IRQ has. */
|
||||
for (irq = 0; irq < NIRQ; irq++) {
|
||||
int levels = 0;
|
||||
iq = &footbridge_intrq[irq];
|
||||
footbridge_disable_irq(irq);
|
||||
for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
|
||||
ih = TAILQ_NEXT(ih, ih_list))
|
||||
levels |= (1U << ih->ih_ipl);
|
||||
iq->iq_levels = levels;
|
||||
}
|
||||
|
||||
/* Next, figure out which IRQs are used by each IPL. */
|
||||
for (ipl = 0; ipl < NIPL; ipl++) {
|
||||
int irqs = 0;
|
||||
for (irq = 0; irq < NIRQ; irq++) {
|
||||
if (footbridge_intrq[irq].iq_levels & (1U << ipl))
|
||||
irqs |= (1U << irq);
|
||||
}
|
||||
footbridge_imask[ipl] = irqs;
|
||||
}
|
||||
|
||||
/* IPL_NONE must open up all interrupts */
|
||||
footbridge_imask[IPL_NONE] = 0;
|
||||
|
||||
/*
|
||||
* Initialize the soft interrupt masks to block themselves.
|
||||
*/
|
||||
footbridge_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFT);
|
||||
footbridge_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTCLOCK);
|
||||
footbridge_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTNET);
|
||||
footbridge_imask[IPL_SOFTSERIAL] = SI_TO_IRQBIT(SI_SOFTSERIAL);
|
||||
|
||||
footbridge_imask[IPL_SOFTCLOCK] |= footbridge_imask[IPL_SOFT];
|
||||
footbridge_imask[IPL_SOFTNET] |= footbridge_imask[IPL_SOFTCLOCK];
|
||||
|
||||
/*
|
||||
* Enforce a heirarchy that gives "slow" device (or devices with
|
||||
* limited input buffer space/"real-time" requirements) a better
|
||||
* chance at not dropping data.
|
||||
*/
|
||||
footbridge_imask[IPL_BIO] |= footbridge_imask[IPL_SOFTNET];
|
||||
footbridge_imask[IPL_NET] |= footbridge_imask[IPL_BIO];
|
||||
footbridge_imask[IPL_SOFTSERIAL] |= footbridge_imask[IPL_NET];
|
||||
|
||||
footbridge_imask[IPL_TTY] |= footbridge_imask[IPL_SOFTSERIAL];
|
||||
|
||||
/*
|
||||
* splvm() blocks all interrupts that use the kernel memory
|
||||
* allocation facilities.
|
||||
*/
|
||||
footbridge_imask[IPL_IMP] |= footbridge_imask[IPL_TTY];
|
||||
|
||||
/*
|
||||
* Audio devices are not allowed to perform memory allocation
|
||||
* in their interrupt routines, and they have fairly "real-time"
|
||||
* requirements, so give them a high interrupt priority.
|
||||
*/
|
||||
footbridge_imask[IPL_AUDIO] |= footbridge_imask[IPL_IMP];
|
||||
|
||||
/*
|
||||
* splclock() must block anything that uses the scheduler.
|
||||
*/
|
||||
footbridge_imask[IPL_CLOCK] |= footbridge_imask[IPL_AUDIO];
|
||||
|
||||
/*
|
||||
* footbridge has seperate statclock.
|
||||
*/
|
||||
footbridge_imask[IPL_STATCLOCK] |= footbridge_imask[IPL_CLOCK];
|
||||
|
||||
/*
|
||||
* splhigh() must block "everything".
|
||||
*/
|
||||
footbridge_imask[IPL_HIGH] |= footbridge_imask[IPL_STATCLOCK];
|
||||
|
||||
/*
|
||||
* XXX We need serial drivers to run at the absolute highest priority
|
||||
* in order to avoid overruns, so serial > high.
|
||||
*/
|
||||
footbridge_imask[IPL_SERIAL] |= footbridge_imask[IPL_HIGH];
|
||||
|
||||
/*
|
||||
* Calculate the ipl level to go to when handling this interrupt
|
||||
*/
|
||||
for (irq = 0; irq < NIRQ; irq++) {
|
||||
int irqs = (1U << irq);
|
||||
iq = &footbridge_intrq[irq];
|
||||
if (TAILQ_FIRST(&iq->iq_list) != NULL)
|
||||
footbridge_enable_irq(irq);
|
||||
for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
|
||||
ih = TAILQ_NEXT(ih, ih_list))
|
||||
irqs |= footbridge_imask[ih->ih_ipl];
|
||||
iq->iq_mask = irqs;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
_splraise(int ipl)
|
||||
{
|
||||
return (footbridge_splraise(ipl));
|
||||
}
|
||||
|
||||
/* this will always take us to the ipl passed in */
|
||||
void
|
||||
splx(int new)
|
||||
{
|
||||
footbridge_splx(new);
|
||||
}
|
||||
|
||||
int
|
||||
_spllower(int ipl)
|
||||
{
|
||||
return (footbridge_spllower(ipl));
|
||||
}
|
||||
|
||||
__inline void
|
||||
footbridge_do_pending(void)
|
||||
{
|
||||
static __cpu_simple_lock_t processing = __SIMPLELOCK_UNLOCKED;
|
||||
uint32_t new, oldirqstate;
|
||||
|
||||
if (__cpu_simple_lock_try(&processing) == 0)
|
||||
return;
|
||||
|
||||
new = current_spl_level;
|
||||
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
|
||||
#define DO_SOFTINT(si) \
|
||||
if ((footbridge_ipending & ~new) & SI_TO_IRQBIT(si)) { \
|
||||
footbridge_ipending &= ~SI_TO_IRQBIT(si); \
|
||||
current_spl_level |= footbridge_imask[si_to_ipl[(si)]]; \
|
||||
restore_interrupts(oldirqstate); \
|
||||
softintr_dispatch(si); \
|
||||
oldirqstate = disable_interrupts(I32_bit); \
|
||||
current_spl_level = new; \
|
||||
}
|
||||
DO_SOFTINT(SI_SOFTSERIAL);
|
||||
DO_SOFTINT(SI_SOFTNET);
|
||||
DO_SOFTINT(SI_SOFTCLOCK);
|
||||
DO_SOFTINT(SI_SOFT);
|
||||
|
||||
__cpu_simple_unlock(&processing);
|
||||
|
||||
restore_interrupts(oldirqstate);
|
||||
}
|
||||
|
||||
|
||||
/* called from splhigh, so the matching splx will set the interrupt up.*/
|
||||
void
|
||||
_setsoftintr(int si)
|
||||
{
|
||||
int oldirqstate;
|
||||
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
footbridge_ipending |= SI_TO_IRQBIT(si);
|
||||
restore_interrupts(oldirqstate);
|
||||
|
||||
/* Process unmasked pending soft interrupts. */
|
||||
if ((footbridge_ipending & INT_SWMASK) & ~current_spl_level)
|
||||
footbridge_do_pending();
|
||||
}
|
||||
|
||||
void
|
||||
footbridge_intr_init(void)
|
||||
{
|
||||
struct intrq *iq;
|
||||
int i;
|
||||
|
||||
intr_enabled = 0;
|
||||
current_spl_level = 0xffffffff;
|
||||
footbridge_ipending = 0;
|
||||
footbridge_set_intrmask();
|
||||
|
||||
for (i = 0; i < NIRQ; i++) {
|
||||
iq = &footbridge_intrq[i];
|
||||
TAILQ_INIT(&iq->iq_list);
|
||||
|
||||
sprintf(iq->iq_name, "irq %d", i);
|
||||
evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
|
||||
NULL, "footbridge", iq->iq_name);
|
||||
}
|
||||
|
||||
footbridge_intr_calculate_masks();
|
||||
|
||||
/* Enable IRQ's, we don't have any FIQ's*/
|
||||
enable_interrupts(I32_bit);
|
||||
}
|
||||
|
||||
void *
|
||||
intr_claim(irq, level, name, ih_func, ih_arg)
|
||||
int irq;
|
||||
int level;
|
||||
const char *name;
|
||||
int (*ih_func) __P((void *));
|
||||
void *ih_arg;
|
||||
footbridge_intr_claim(int irq, int ipl, char *name, int (*func)(void *), void *arg)
|
||||
{
|
||||
irqhandler_t *ih;
|
||||
struct intrq *iq;
|
||||
struct intrhand *ih;
|
||||
u_int oldirqstate;
|
||||
|
||||
if (irq < 0 || irq > NIRQ)
|
||||
panic("footbridge_intr_establish: IRQ %d out of range", irq);
|
||||
|
||||
ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
|
||||
if (!ih)
|
||||
panic("intr_claim(): Cannot malloc handler memory");
|
||||
if (ih == NULL)
|
||||
{
|
||||
printf("No memory");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ih->ih_func = func;
|
||||
ih->ih_arg = arg;
|
||||
ih->ih_ipl = ipl;
|
||||
ih->ih_irq = irq;
|
||||
|
||||
ih->ih_level = level;
|
||||
ih->ih_name = name;
|
||||
ih->ih_func = ih_func;
|
||||
ih->ih_arg = ih_arg;
|
||||
ih->ih_flags = 0;
|
||||
iq = &footbridge_intrq[irq];
|
||||
|
||||
if (irq_claim(irq, ih) != 0)
|
||||
return(NULL);
|
||||
iq->iq_ist = IST_LEVEL;
|
||||
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
|
||||
TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
|
||||
|
||||
footbridge_intr_calculate_masks();
|
||||
|
||||
/* detach the existing event counter and add the new name */
|
||||
evcnt_detach(&iq->iq_ev);
|
||||
evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
|
||||
NULL, "footbridge", name);
|
||||
|
||||
restore_interrupts(oldirqstate);
|
||||
|
||||
return(ih);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
intr_release(arg)
|
||||
void *arg;
|
||||
void
|
||||
footbridge_intr_disestablish(void *cookie)
|
||||
{
|
||||
irqhandler_t *ih = (irqhandler_t *)arg;
|
||||
struct intrhand *ih = cookie;
|
||||
struct intrq *iq = &footbridge_intrq[ih->ih_irq];
|
||||
int oldirqstate;
|
||||
|
||||
if (irq_release(ih->ih_num, ih) == 0) {
|
||||
free(ih, M_DEVBUF);
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
/* XXX need to free ih ? */
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
|
||||
TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
|
||||
|
||||
footbridge_intr_calculate_masks();
|
||||
|
||||
restore_interrupts(oldirqstate);
|
||||
}
|
||||
|
||||
static uint32_t footbridge_intstatus(void);
|
||||
|
||||
static inline uint32_t footbridge_intstatus()
|
||||
{
|
||||
return ((__volatile uint32_t*)(DC21285_ARMCSR_VBASE))[IRQ_STATUS>>2];
|
||||
}
|
||||
|
||||
/* called with external interrupts disabled */
|
||||
void
|
||||
footbridge_intr_dispatch(struct clockframe *frame)
|
||||
{
|
||||
struct intrq *iq;
|
||||
struct intrhand *ih;
|
||||
int oldirqstate, pcpl, irq, ibit, hwpend;
|
||||
|
||||
pcpl = current_spl_level;
|
||||
|
||||
hwpend = footbridge_intstatus();
|
||||
|
||||
/*
|
||||
* Disable all the interrupts that are pending. We will
|
||||
* reenable them once they are processed and not masked.
|
||||
*/
|
||||
intr_enabled &= ~hwpend;
|
||||
footbridge_set_intrmask();
|
||||
|
||||
while (hwpend != 0) {
|
||||
int intr_rc = 0;
|
||||
irq = ffs(hwpend) - 1;
|
||||
ibit = (1U << irq);
|
||||
|
||||
hwpend &= ~ibit;
|
||||
|
||||
if (pcpl & ibit) {
|
||||
/*
|
||||
* IRQ is masked; mark it as pending and check
|
||||
* the next one. Note: the IRQ is already disabled.
|
||||
*/
|
||||
footbridge_ipending |= ibit;
|
||||
continue;
|
||||
}
|
||||
|
||||
footbridge_ipending &= ~ibit;
|
||||
|
||||
iq = &footbridge_intrq[irq];
|
||||
iq->iq_ev.ev_count++;
|
||||
uvmexp.intrs++;
|
||||
current_spl_level |= iq->iq_mask;
|
||||
oldirqstate = enable_interrupts(I32_bit);
|
||||
for (ih = TAILQ_FIRST(&iq->iq_list);
|
||||
((ih != NULL) && (intr_rc != 1));
|
||||
ih = TAILQ_NEXT(ih, ih_list)) {
|
||||
intr_rc = (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame);
|
||||
}
|
||||
restore_interrupts(oldirqstate);
|
||||
|
||||
current_spl_level = pcpl;
|
||||
|
||||
/* Re-enable this interrupt now that's it's cleared. */
|
||||
intr_enabled |= ibit;
|
||||
footbridge_set_intrmask();
|
||||
}
|
||||
|
||||
/*
|
||||
* restore interrupts to their state on entry, this will
|
||||
* trigger pending interrupts, and soft and hard
|
||||
*/
|
||||
splx(pcpl);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: footbridge_irqhandler.h,v 1.1 2002/10/22 20:15:25 chris Exp $ */
|
||||
/* $NetBSD: footbridge_irqhandler.h,v 1.2 2002/11/03 21:43:31 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1996 Mark Brinicombe.
|
||||
|
@ -47,40 +47,17 @@
|
|||
#include <sys/types.h>
|
||||
#endif /* _LOCORE */
|
||||
|
||||
#define IRQ_INSTRUCT -1
|
||||
#define NIRQS 0x20
|
||||
|
||||
#include <machine/intr.h>
|
||||
|
||||
#ifndef _LOCORE
|
||||
typedef struct irqhandler {
|
||||
int (*ih_func) __P((void *arg));/* handler function */
|
||||
void *ih_arg; /* Argument to handler */
|
||||
int ih_level; /* Interrupt level */
|
||||
int ih_num; /* Interrupt number (for accounting) */
|
||||
const char *ih_name; /* Name of interrupt (for vmstat -i) */
|
||||
u_int ih_flags; /* Interrupt flags */
|
||||
u_int ih_maskaddr; /* mask address for expansion cards */
|
||||
u_int ih_maskbits; /* interrupt bit for expansion cards */
|
||||
struct irqhandler *ih_next; /* next handler */
|
||||
} irqhandler_t;
|
||||
void footbridge_intr_init(void);
|
||||
void *footbridge_intr_establish(int, int, int (*)(void *), void *);
|
||||
void footbridge_intr_disestablish(void *);
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern u_int irqmasks[IPL_LEVELS];
|
||||
extern irqhandler_t *irqhandlers[NIRQS];
|
||||
|
||||
void irq_init __P((void));
|
||||
int irq_claim __P((int, irqhandler_t *));
|
||||
int irq_release __P((int, irqhandler_t *));
|
||||
void *intr_claim __P((int irq, int level, const char *name, int (*func) __P((void *)), void *arg));
|
||||
int intr_release __P((void *ih));
|
||||
void irq_setmasks __P((void));
|
||||
void disable_irq __P((int));
|
||||
void enable_irq __P((int));
|
||||
void *footbridge_intr_claim(int irq, int ipl, char *name, int (*func)(void *), void *arg);
|
||||
void footbridge_intr_init(void);
|
||||
void footbridge_intr_disestablish(void *cookie);
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _LOCORE */
|
||||
|
||||
#define IRQ_FLAG_ACTIVE 0x00000001 /* This is the active handler in list */
|
||||
|
||||
#endif /* _FOOTBRIDGE_IRQHANDLER_H_ */
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: footbridge_pci.c,v 1.7 2002/10/09 00:33:38 thorpej Exp $ */
|
||||
/* $NetBSD: footbridge_pci.c,v 1.8 2002/11/03 21:43:31 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997,1998 Mark Brinicombe.
|
||||
|
@ -67,11 +67,10 @@ void footbridge_pci_conf_write __P((void *, pcitag_t, int,
|
|||
int footbridge_pci_intr_map __P((struct pci_attach_args *,
|
||||
pci_intr_handle_t *));
|
||||
const char *footbridge_pci_intr_string __P((void *, pci_intr_handle_t));
|
||||
const struct evcnt *footbridge_pci_intr_evcnt __P((void *, pci_intr_handle_t));
|
||||
void *footbridge_pci_intr_establish __P((void *, pci_intr_handle_t,
|
||||
int, int (*)(void *), void *));
|
||||
void footbridge_pci_intr_disestablish __P((void *, void *));
|
||||
|
||||
const struct evcnt *footbridge_pci_intr_evcnt __P((void *, pci_intr_handle_t));
|
||||
|
||||
struct arm32_pci_chipset footbridge_pci_chipset = {
|
||||
NULL, /* conf_v */
|
||||
|
@ -352,16 +351,6 @@ footbridge_pci_intr_string(pcv, ih)
|
|||
return(irqstr);
|
||||
}
|
||||
|
||||
const struct evcnt *
|
||||
footbridge_pci_intr_evcnt(pcv, ih)
|
||||
void *pcv;
|
||||
pci_intr_handle_t ih;
|
||||
{
|
||||
|
||||
/* XXX for now, no evcnt parent reported */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
footbridge_pci_intr_establish(pcv, ih, level, func, arg)
|
||||
void *pcv;
|
||||
|
@ -395,7 +384,7 @@ footbridge_pci_intr_establish(pcv, ih, level, func, arg)
|
|||
level, func, arg);
|
||||
} else
|
||||
#endif
|
||||
intr = intr_claim(ih, level, string, func, arg);
|
||||
intr = footbridge_intr_claim(ih, level, string, func, arg);
|
||||
|
||||
return(intr);
|
||||
}
|
||||
|
@ -410,6 +399,5 @@ footbridge_pci_intr_disestablish(pcv, cookie)
|
|||
pcv, cookie);
|
||||
#endif
|
||||
/* XXXX Need to free the string */
|
||||
|
||||
intr_release(cookie);
|
||||
footbridge_intr_disestablish(cookie);
|
||||
}
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
# $NetBSD: genassym.cf,v 1.2 2001/12/20 01:20:23 thorpej Exp $
|
||||
|
||||
# Copyright (c) 1982, 1990 The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# William Jolitz.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
|
||||
include <machine/intr.h>
|
||||
|
||||
define IH_FUNC offsetof(struct irqhandler, ih_func)
|
||||
define IH_ARG offsetof(struct irqhandler, ih_arg)
|
||||
define IH_FLAGS offsetof(struct irqhandler, ih_flags)
|
||||
define IH_LEVEL offsetof(struct irqhandler, ih_level)
|
||||
define IH_NUM offsetof(struct irqhandler, ih_num)
|
||||
define IH_MASKADDR offsetof(struct irqhandler, ih_maskaddr)
|
||||
define IH_MASKBITS offsetof(struct irqhandler, ih_maskbits)
|
||||
define IH_NEXT offsetof(struct irqhandler, ih_next)
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: isa_machdep.c,v 1.1 2002/10/12 11:53:38 chris Exp $ */
|
||||
/* $NetBSD: isa_machdep.c,v 1.2 2002/11/03 21:43:31 chris Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996-1998 The NetBSD Foundation, Inc.
|
||||
|
@ -116,13 +116,9 @@ int fakeintr __P((void *));
|
|||
|
||||
int isa_irqdispatch __P((void *arg));
|
||||
|
||||
u_int imask[IPL_LEVELS];
|
||||
u_int imask[NIPL];
|
||||
unsigned imen;
|
||||
|
||||
#ifdef IRQSTATS
|
||||
u_int isa_intr_count[ICU_LEN];
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
#define AUTO_EOI_1
|
||||
#define AUTO_EOI_2
|
||||
|
||||
|
@ -182,8 +178,7 @@ isa_strayintr(irq)
|
|||
strays >= 5 ? "; stopped logging" : "");
|
||||
}
|
||||
|
||||
int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
|
||||
struct irqhandler *intrhand[ICU_LEN];
|
||||
static struct intrq isa_intrq[ICU_LEN];
|
||||
|
||||
/*
|
||||
* Recalculate the interrupt masks from scratch.
|
||||
|
@ -195,22 +190,25 @@ void
|
|||
intr_calculatemasks()
|
||||
{
|
||||
int irq, level;
|
||||
struct irqhandler *q;
|
||||
struct intrq *iq;
|
||||
struct intrhand *ih;
|
||||
|
||||
/* First, figure out which levels each IRQ uses. */
|
||||
for (irq = 0; irq < ICU_LEN; irq++) {
|
||||
int levels = 0;
|
||||
for (q = intrhand[irq]; q; q = q->ih_next)
|
||||
levels |= 1 << q->ih_level;
|
||||
intrlevel[irq] = levels;
|
||||
iq = &isa_intrq[irq];
|
||||
for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
|
||||
ih = TAILQ_NEXT(ih, ih_list))
|
||||
levels |= (1U << ih->ih_ipl);
|
||||
iq->iq_levels = levels;
|
||||
}
|
||||
|
||||
/* Then figure out which IRQs use each level. */
|
||||
for (level = 0; level < IPL_LEVELS; level++) {
|
||||
for (level = 0; level < NIPL; level++) {
|
||||
int irqs = 0;
|
||||
for (irq = 0; irq < ICU_LEN; irq++)
|
||||
if (intrlevel[irq] & (1 << level))
|
||||
irqs |= 1 << irq;
|
||||
if (isa_intrq[irq].iq_levels & (1U << level))
|
||||
irqs |= (1U << irq);
|
||||
imask[level] = irqs;
|
||||
}
|
||||
|
||||
|
@ -220,12 +218,17 @@ intr_calculatemasks()
|
|||
*/
|
||||
imask[IPL_NONE] = 0;
|
||||
|
||||
imask[IPL_SOFT] |= imask[IPL_NONE];
|
||||
imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT];
|
||||
imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK];
|
||||
|
||||
/*
|
||||
* Enforce a hierarchy that gives slow devices a better chance at not
|
||||
* dropping data.
|
||||
*/
|
||||
imask[IPL_BIO] |= imask[IPL_NONE];
|
||||
imask[IPL_BIO] |= imask[IPL_SOFTCLOCK];
|
||||
imask[IPL_NET] |= imask[IPL_BIO];
|
||||
imask[IPL_SOFTSERIAL] |= imask[IPL_NET];
|
||||
imask[IPL_TTY] |= imask[IPL_NET];
|
||||
/*
|
||||
* There are tty, network and disk drivers that use free() at interrupt
|
||||
|
@ -238,13 +241,13 @@ intr_calculatemasks()
|
|||
* Since run queues may be manipulated by both the statclock and tty,
|
||||
* network, and disk drivers, clock > imp.
|
||||
*/
|
||||
imask[IPL_CLOCK] |= imask[IPL_AUDIO];
|
||||
imask[IPL_CLOCK] |= imask[IPL_IMP];
|
||||
imask[IPL_STATCLOCK] |= imask[IPL_CLOCK];
|
||||
|
||||
/*
|
||||
* IPL_HIGH must block everything that can manipulate a run queue.
|
||||
*/
|
||||
imask[IPL_HIGH] |= imask[IPL_CLOCK];
|
||||
imask[IPL_HIGH] |= imask[IPL_STATCLOCK];
|
||||
|
||||
/*
|
||||
* We need serial drivers to run at the absolute highest priority to
|
||||
|
@ -255,17 +258,19 @@ intr_calculatemasks()
|
|||
/* And eventually calculate the complete masks. */
|
||||
for (irq = 0; irq < ICU_LEN; irq++) {
|
||||
int irqs = 1 << irq;
|
||||
for (q = intrhand[irq]; q; q = q->ih_next)
|
||||
irqs |= imask[q->ih_level];
|
||||
intrmask[irq] = irqs;
|
||||
iq = &isa_intrq[irq];
|
||||
for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
|
||||
ih = TAILQ_NEXT(ih, ih_list))
|
||||
irqs |= imask[ih->ih_ipl];
|
||||
iq->iq_mask = irqs;
|
||||
}
|
||||
|
||||
/* Lastly, determine which IRQs are actually in use. */
|
||||
{
|
||||
int irqs = 0;
|
||||
for (irq = 0; irq < ICU_LEN; irq++)
|
||||
if (intrhand[irq])
|
||||
irqs |= 1 << irq;
|
||||
if (!TAILQ_EMPTY(&isa_intrq[irq].iq_list))
|
||||
irqs |= (1U << irq);
|
||||
if (irqs >= 0x100) /* any IRQs >= 8 in use */
|
||||
irqs |= 1 << IRQ_SLAVE;
|
||||
imen = ~irqs;
|
||||
|
@ -300,7 +305,8 @@ isa_intr_alloc(ic, mask, type, irq)
|
|||
int *irq;
|
||||
{
|
||||
int i, tmp, bestirq, count;
|
||||
struct irqhandler **p, *q;
|
||||
struct intrq *iq;
|
||||
struct intrhand *ih;
|
||||
|
||||
if (type == IST_NONE)
|
||||
panic("intr_alloc: bogus type");
|
||||
|
@ -320,8 +326,9 @@ isa_intr_alloc(ic, mask, type, irq)
|
|||
for (i = 0; i < ICU_LEN; i++) {
|
||||
if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
|
||||
continue;
|
||||
|
||||
switch(intrtype[i]) {
|
||||
|
||||
iq = &isa_intrq[i];
|
||||
switch(iq->iq_ist) {
|
||||
case IST_NONE:
|
||||
/*
|
||||
* if nothing's using the irq, just return it
|
||||
|
@ -331,7 +338,7 @@ isa_intr_alloc(ic, mask, type, irq)
|
|||
|
||||
case IST_EDGE:
|
||||
case IST_LEVEL:
|
||||
if (type != intrtype[i])
|
||||
if (type != iq->iq_ist)
|
||||
continue;
|
||||
/*
|
||||
* if the irq is shareable, count the number of other
|
||||
|
@ -342,9 +349,9 @@ isa_intr_alloc(ic, mask, type, irq)
|
|||
* interrupt level and stick IPL_TTY with other
|
||||
* IPL_TTY, etc.
|
||||
*/
|
||||
for (p = &intrhand[i], tmp = 0; (q = *p) != NULL;
|
||||
p = &q->ih_next, tmp++)
|
||||
;
|
||||
tmp = 0;
|
||||
TAILQ_FOREACH(ih, &(iq->iq_list), ih_list)
|
||||
tmp++;
|
||||
if ((bestirq == -1) || (count > tmp)) {
|
||||
bestirq = i;
|
||||
count = tmp;
|
||||
|
@ -368,9 +375,7 @@ isa_intr_alloc(ic, mask, type, irq)
|
|||
const struct evcnt *
|
||||
isa_intr_evcnt(isa_chipset_tag_t ic, int irq)
|
||||
{
|
||||
|
||||
/* XXX for now, no evcnt parent reported */
|
||||
return NULL;
|
||||
return &isa_intrq[irq].iq_ev;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -386,23 +391,29 @@ isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
|
|||
int (*ih_fun) __P((void *));
|
||||
void *ih_arg;
|
||||
{
|
||||
struct irqhandler **p, *q, *ih;
|
||||
static struct irqhandler fakehand = {fakeintr};
|
||||
|
||||
/* printf("isa_intr_establish(%d, %d, %d)\n", irq, type, level);*/
|
||||
struct intrq *iq;
|
||||
struct intrhand *ih;
|
||||
u_int oldirqstate;
|
||||
|
||||
#if 0
|
||||
printf("isa_intr_establish(%d, %d, %d)\n", irq, type, level);
|
||||
#endif
|
||||
/* no point in sleeping unless someone can free memory. */
|
||||
ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
|
||||
if (ih == NULL)
|
||||
panic("isa_intr_establish: can't malloc handler info");
|
||||
return (NULL);
|
||||
|
||||
if (!LEGAL_IRQ(irq) || type == IST_NONE)
|
||||
panic("intr_establish: bogus irq or type");
|
||||
|
||||
switch (intrtype[irq]) {
|
||||
iq = &isa_intrq[irq];
|
||||
|
||||
switch (iq->iq_ist) {
|
||||
case IST_NONE:
|
||||
intrtype[irq] = type;
|
||||
/* printf("Setting irq %d to type %d - ", irq, type);*/
|
||||
iq->iq_ist = type;
|
||||
#if 0
|
||||
printf("Setting irq %d to type %d - ", irq, type);
|
||||
#endif
|
||||
if (irq < 8) {
|
||||
outb(0x4d0, (inb(0x4d0) & ~(1 << irq))
|
||||
| ((type == IST_LEVEL) ? (1 << irq) : 0));
|
||||
|
@ -415,45 +426,29 @@ isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
|
|||
break;
|
||||
case IST_EDGE:
|
||||
case IST_LEVEL:
|
||||
if (type == intrtype[irq])
|
||||
if (iq->iq_ist == type)
|
||||
break;
|
||||
case IST_PULSE:
|
||||
if (type != IST_NONE)
|
||||
panic("intr_establish: can't share %s with %s",
|
||||
isa_intr_typename(intrtype[irq]),
|
||||
isa_intr_typename(iq->iq_ist),
|
||||
isa_intr_typename(type));
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out where to put the handler.
|
||||
* This is O(N^2), but we want to preserve the order, and N is
|
||||
* generally small.
|
||||
*/
|
||||
for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
|
||||
;
|
||||
|
||||
/*
|
||||
* Actually install a fake handler momentarily, since we might be doing
|
||||
* this with interrupts enabled and don't want the real routine called
|
||||
* until masking is set up.
|
||||
*/
|
||||
fakehand.ih_level = level;
|
||||
*p = &fakehand;
|
||||
|
||||
intr_calculatemasks();
|
||||
|
||||
/*
|
||||
* Poke the real handler in now.
|
||||
*/
|
||||
ih->ih_func = ih_fun;
|
||||
ih->ih_arg = ih_arg;
|
||||
/* ih->ih_count = 0;*/
|
||||
ih->ih_next = NULL;
|
||||
ih->ih_level = level;
|
||||
ih->ih_num = irq;
|
||||
*p = ih;
|
||||
ih->ih_ipl = level;
|
||||
ih->ih_irq = irq;
|
||||
|
||||
/* do not stop us */
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
|
||||
TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
|
||||
|
||||
intr_calculatemasks();
|
||||
restore_interrupts(oldirqstate);
|
||||
|
||||
return (ih);
|
||||
}
|
||||
|
||||
|
@ -465,29 +460,26 @@ isa_intr_disestablish(ic, arg)
|
|||
isa_chipset_tag_t ic;
|
||||
void *arg;
|
||||
{
|
||||
struct irqhandler *ih = arg;
|
||||
int irq = ih->ih_num;
|
||||
struct irqhandler **p, *q;
|
||||
|
||||
struct intrhand *ih = arg;
|
||||
struct intrq *iq = &isa_intrq[ih->ih_irq];
|
||||
int irq = ih->ih_irq;
|
||||
u_int oldirqstate;
|
||||
|
||||
if (!LEGAL_IRQ(irq))
|
||||
panic("intr_disestablish: bogus irq");
|
||||
|
||||
/*
|
||||
* Remove the handler from the chain.
|
||||
* This is O(n^2), too.
|
||||
*/
|
||||
for (p = &intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
|
||||
;
|
||||
if (q)
|
||||
*p = q->ih_next;
|
||||
else
|
||||
panic("intr_disestablish: handler not registered");
|
||||
free(ih, M_DEVBUF);
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
|
||||
TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
|
||||
|
||||
intr_calculatemasks();
|
||||
|
||||
if (intrhand[irq] == NULL)
|
||||
intrtype[irq] = IST_NONE;
|
||||
restore_interrupts(oldirqstate);
|
||||
|
||||
free(ih, M_DEVBUF);
|
||||
|
||||
if (TAILQ_EMPTY(&(iq->iq_list)))
|
||||
iq->iq_ist = IST_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -500,13 +492,29 @@ void
|
|||
isa_intr_init(void)
|
||||
{
|
||||
static void *isa_ih;
|
||||
|
||||
struct intrq *iq;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* should get the parent here, but initialisation order being so
|
||||
* strange I need to check if it's available
|
||||
*/
|
||||
for (i = 0; i < ICU_LEN; i++) {
|
||||
iq = &isa_intrq[i];
|
||||
TAILQ_INIT(&iq->iq_list);
|
||||
|
||||
sprintf(iq->iq_name, "irq %d", i);
|
||||
evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
|
||||
NULL, "isa", iq->iq_name);
|
||||
}
|
||||
|
||||
isa_icu_init();
|
||||
/* something break the build in an informative way */
|
||||
intr_calculatemasks();
|
||||
/* something to break the build in an informative way */
|
||||
#ifndef ISA_FOOTBRIDGE_IRQ
|
||||
#warning Before using isa with footbridge you must define ISA_FOOTBRIDGE_IRQ
|
||||
#endif
|
||||
isa_ih = intr_claim(ISA_FOOTBRIDGE_IRQ, IPL_BIO, "isabus",
|
||||
isa_ih = footbridge_intr_claim(ISA_FOOTBRIDGE_IRQ, IPL_BIO, "isabus",
|
||||
isa_irqdispatch, NULL);
|
||||
|
||||
}
|
||||
|
@ -555,10 +563,12 @@ int
|
|||
isa_irqdispatch(arg)
|
||||
void *arg;
|
||||
{
|
||||
struct clockframe *frame = arg;
|
||||
int irq;
|
||||
struct irqhandler *p;
|
||||
struct intrq *iq;
|
||||
struct intrhand *ih;
|
||||
u_int iack;
|
||||
int res;
|
||||
int res = 0;
|
||||
|
||||
iack = *((u_int *)(DC21285_PCI_IACK_VBASE));
|
||||
iack &= 0xff;
|
||||
|
@ -568,18 +578,13 @@ isa_irqdispatch(arg)
|
|||
}
|
||||
|
||||
irq = iack & 0x0f;
|
||||
#ifdef IRQSTATS
|
||||
++isa_intr_count[irq];
|
||||
#endif /* IRQSTATS */
|
||||
p = intrhand[irq];
|
||||
while (p) {
|
||||
#ifdef IRQSTATS
|
||||
/* ++p->ih_count;*/
|
||||
#endif /* IRQSTATS */
|
||||
res = p->ih_func(p->ih_arg);
|
||||
p = p->ih_next;
|
||||
iq = &isa_intrq[irq];
|
||||
iq->iq_ev.ev_count++;
|
||||
for (ih = TAILQ_FIRST(&iq->iq_list); res != 1 && ih != NULL;
|
||||
ih = TAILQ_NEXT(ih, ih_list)) {
|
||||
res = (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame);
|
||||
}
|
||||
return(0);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: autoconf.c,v 1.3 2002/09/06 13:18:43 gehenna Exp $ */
|
||||
/* $NetBSD: autoconf.c,v 1.4 2002/11/03 21:43:31 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1998 Mark Brinicombe.
|
||||
|
@ -133,9 +133,12 @@ cpu_rootconf(void)
|
|||
* Configure all the root devices
|
||||
* The root devices are expected to configure their own children
|
||||
*/
|
||||
extern int footbridge_imask[NIPL];
|
||||
|
||||
void
|
||||
cpu_configure(void)
|
||||
{
|
||||
softintr_init();
|
||||
/*
|
||||
* Since various PCI interrupts could be routed via the ICU
|
||||
* (for PCI devices in the bridge) we need to set up the ICU
|
||||
|
@ -144,16 +147,17 @@ cpu_configure(void)
|
|||
*/
|
||||
isa_intr_init();
|
||||
|
||||
|
||||
config_rootfound("mainbus", NULL);
|
||||
|
||||
/* Debugging information */
|
||||
#ifndef TERSE
|
||||
printf("ipl_bio=%08x ipl_net=%08x ipl_tty=%08x ipl_imp=%08x\n",
|
||||
irqmasks[IPL_BIO], irqmasks[IPL_NET], irqmasks[IPL_TTY],
|
||||
irqmasks[IPL_IMP]);
|
||||
footbridge_imask[IPL_BIO], footbridge_imask[IPL_NET],
|
||||
footbridge_imask[IPL_TTY], footbridge_imask[IPL_IMP]);
|
||||
printf("ipl_audio=%08x ipl_imp=%08x ipl_high=%08x ipl_serial=%08x\n",
|
||||
irqmasks[IPL_AUDIO], irqmasks[IPL_CLOCK], irqmasks[IPL_HIGH],
|
||||
irqmasks[IPL_SERIAL]);
|
||||
footbridge_imask[IPL_AUDIO], footbridge_imask[IPL_CLOCK],
|
||||
footbridge_imask[IPL_HIGH], footbridge_imask[IPL_SERIAL]);
|
||||
#endif
|
||||
|
||||
/* Time to start taking interrupts so lets open the flood gates .... */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: cats_machdep.c,v 1.36 2002/10/12 11:53:39 chris Exp $ */
|
||||
/* $NetBSD: cats_machdep.c,v 1.37 2002/11/03 21:43:31 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997,1998 Mark Brinicombe.
|
||||
|
@ -824,7 +824,7 @@ initarm(bootargs)
|
|||
|
||||
/* Setup the IRQ system */
|
||||
printf("irq ");
|
||||
irq_init();
|
||||
footbridge_intr_init();
|
||||
printf("done.\n");
|
||||
|
||||
#ifdef IPKDB
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
# $NetBSD: Makefile.cats.inc,v 1.10 2002/10/29 14:33:32 tsutsui Exp $
|
||||
|
||||
GENASSYM_EXTRAS+= ${ARM}/footbridge/genassym.cf
|
||||
# $NetBSD: Makefile.cats.inc,v 1.11 2002/11/03 21:43:32 chris Exp $
|
||||
|
||||
.if (${OBJECT_FMT} == "ELF")
|
||||
# Need to convert the kernel from ELF to a.out so that OpenFirmware
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.cats,v 1.23 2002/10/26 13:50:24 jdolecek Exp $
|
||||
# $NetBSD: files.cats,v 1.24 2002/11/03 21:43:32 chris Exp $
|
||||
#
|
||||
# CATS-specific configuration info
|
||||
#
|
||||
|
@ -59,9 +59,6 @@ file arch/arm/arm/disksubr.c disk
|
|||
file arch/arm/arm/disksubr_acorn.c disk
|
||||
file arch/arm/arm/disksubr_mbr.c disk
|
||||
|
||||
file arch/arm/arm32/intr.c
|
||||
file arch/arm/arm32/spl.S
|
||||
|
||||
# ISA Plug 'n Play autoconfiguration glue.
|
||||
file arch/arm/footbridge/isa/isapnp_machdep.c isapnp
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* $NetBSD: types.h,v 1.4 2002/02/28 03:17:26 simonb Exp $ */
|
||||
/* $NetBSD: types.h,v 1.5 2002/11/03 21:43:32 chris Exp $ */
|
||||
|
||||
#ifndef _ARM32_TYPES_H_
|
||||
#define _ARM32_TYPES_H_
|
||||
|
||||
#include <arm/arm32/types.h>
|
||||
|
||||
#define __HAVE_DEVICE_REGISTER
|
||||
#define __HAVE_NWSCONS
|
||||
#define __HAVE_GENERIC_SOFT_INTERRUPTS
|
||||
#define __HAVE_DEVICE_REGISTER
|
||||
#define __HAVE_NWSCONS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
# $NetBSD: Makefile.netwinder.inc,v 1.5 2002/04/03 02:06:33 thorpej Exp $
|
||||
# $NetBSD: Makefile.netwinder.inc,v 1.6 2002/11/03 21:43:32 chris Exp $
|
||||
|
||||
SYSTEM_LD_TAIL_EXTRA=; \
|
||||
echo "${DBSYM} $@ || true"; \
|
||||
${DBSYM} $@ || true
|
||||
|
||||
GENASSYM_EXTRAS+= ${ARM}/footbridge/genassym.cf
|
||||
|
||||
SYSTEM_FIRST_OBJ= nwmmu.o
|
||||
SYSTEM_FIRST_SFILE= ${THISARM}/${MACHINE}/nwmmu.S
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.netwinder,v 1.27 2002/10/26 13:50:36 jdolecek Exp $
|
||||
# $NetBSD: files.netwinder,v 1.28 2002/11/03 21:43:32 chris Exp $
|
||||
#
|
||||
# First try for arm-specific configuration info
|
||||
#
|
||||
|
@ -65,9 +65,6 @@ file arch/arm/arm/disksubr.c disk
|
|||
file arch/arm/arm/disksubr_acorn.c disk
|
||||
file arch/arm/arm/disksubr_mbr.c disk
|
||||
|
||||
file arch/arm/arm32/intr.c
|
||||
file arch/arm/arm32/spl.S
|
||||
|
||||
# ISA support.
|
||||
file arch/arm/footbridge/isa/isa_machdep.c isa
|
||||
file arch/arm/footbridge/isa/isa_io.c isa
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/* $NetBSD: types.h,v 1.3 2002/02/28 03:17:29 simonb Exp $ */
|
||||
/* $NetBSD: types.h,v 1.4 2002/11/03 21:43:32 chris Exp $ */
|
||||
|
||||
#ifndef _ARM32_TYPES_H_
|
||||
#define _ARM32_TYPES_H_
|
||||
|
||||
#include <arm/arm32/types.h>
|
||||
|
||||
#define __HAVE_DEVICE_REGISTER
|
||||
#define __HAVE_NWSCONS
|
||||
#define __HAVE_GENERIC_SOFT_INTERRUPTS
|
||||
#define __HAVE_DEVICE_REGISTER
|
||||
#define __HAVE_NWSCONS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: autoconf.c,v 1.2 2001/09/05 16:17:36 matt Exp $ */
|
||||
/* $NetBSD: autoconf.c,v 1.3 2002/11/03 21:43:33 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1998 Mark Brinicombe.
|
||||
|
@ -60,6 +60,8 @@
|
|||
struct device *booted_device;
|
||||
int booted_partition;
|
||||
|
||||
extern int footbridge_imask[NIPL];
|
||||
|
||||
void isa_intr_init (void);
|
||||
|
||||
/*
|
||||
|
@ -83,6 +85,7 @@ cpu_rootconf(void)
|
|||
void
|
||||
cpu_configure(void)
|
||||
{
|
||||
softintr_init();
|
||||
/*
|
||||
* Since various PCI interrupts could be routed via the ICU
|
||||
* (for PCI devices in the bridge) we need to set up the ICU
|
||||
|
@ -96,11 +99,12 @@ cpu_configure(void)
|
|||
/* Debugging information */
|
||||
#ifndef TERSE
|
||||
printf("ipl_bio=%08x ipl_net=%08x ipl_tty=%08x ipl_imp=%08x\n",
|
||||
irqmasks[IPL_BIO], irqmasks[IPL_NET], irqmasks[IPL_TTY],
|
||||
irqmasks[IPL_IMP]);
|
||||
footbridge_imask[IPL_BIO], footbridge_imask[IPL_NET],
|
||||
footbridge_imask[IPL_TTY], footbridge_imask[IPL_IMP]);
|
||||
|
||||
printf("ipl_audio=%08x ipl_imp=%08x ipl_high=%08x ipl_serial=%08x\n",
|
||||
irqmasks[IPL_AUDIO], irqmasks[IPL_CLOCK], irqmasks[IPL_HIGH],
|
||||
irqmasks[IPL_SERIAL]);
|
||||
footbridge_imask[IPL_AUDIO], footbridge_imask[IPL_CLOCK],
|
||||
footbridge_imask[IPL_HIGH], footbridge_imask[IPL_SERIAL]);
|
||||
#endif
|
||||
|
||||
/* Time to start taking interrupts so lets open the flood gates .... */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: netwinder_machdep.c,v 1.40 2002/10/12 11:53:43 chris Exp $ */
|
||||
/* $NetBSD: netwinder_machdep.c,v 1.41 2002/11/03 21:43:33 chris Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997,1998 Mark Brinicombe.
|
||||
|
@ -804,7 +804,7 @@ initarm(void *arg)
|
|||
|
||||
/* Setup the IRQ system */
|
||||
printf("irq ");
|
||||
irq_init();
|
||||
footbridge_intr_init();
|
||||
printf("done.\n");
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue