/*
|
/*
|
* linux/arch/i960/kernel/ints.c
|
* linux/arch/i960/kernel/ints.c
|
*
|
*
|
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu>
|
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu>
|
* Oregon Graduate Institute
|
* Oregon Graduate Institute
|
*
|
*
|
* Based on:
|
* Based on:
|
*
|
*
|
* linux/arch/i386/kernel/irq.c
|
* linux/arch/i386/kernel/irq.c
|
*
|
*
|
* Copyright (C) 1992 Linux Torvalds
|
* Copyright (C) 1992 Linux Torvalds
|
*
|
*
|
* This file is subject to the terms and conditions of the GNU General Public
|
* This file is subject to the terms and conditions of the GNU General Public
|
* License. See the file COPYING in the main directory of this archive
|
* License. See the file COPYING in the main directory of this archive
|
* for more details.
|
* for more details.
|
*
|
*
|
* N.B. that we treat "irq" as meaning, the high order four bits of the vector
|
* N.B. that we treat "irq" as meaning, the high order four bits of the vector
|
* number. Since there seems to be no way to set the low bits to something other
|
* number. Since there seems to be no way to set the low bits to something other
|
* than 0010, this is good enough for us.
|
* than 0010, this is good enough for us.
|
*/
|
*/
|
|
|
#include <linux/types.h>
|
#include <linux/types.h>
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/kernel_stat.h>
|
#include <linux/kernel_stat.h>
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
#include <linux/config.h>
|
#include <linux/config.h>
|
#include <linux/ip.h>
|
#include <linux/ip.h>
|
#include <linux/tcp.h>
|
#include <linux/tcp.h>
|
|
|
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
#include <asm/system.h>
|
#include <asm/system.h>
|
#include <asm/irq.h>
|
#include <asm/irq.h>
|
#include <asm/traps.h>
|
#include <asm/traps.h>
|
#include <asm/page.h>
|
#include <asm/page.h>
|
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
#include <asm/machdep.h>
|
#include <asm/machdep.h>
|
#include <asm/i960.h>
|
#include <asm/i960.h>
|
#include <asm/unistd.h>
|
#include <asm/unistd.h>
|
|
|
#if defined(CONFIG_I960JX) || defined(CONFIG_I960VH)
|
#if defined(CONFIG_I960JX) || defined(CONFIG_I960VH)
|
#include <asm/i960jx.h>
|
#include <asm/i960jx.h>
|
#endif
|
#endif
|
|
|
/*
|
/*
|
* device vectors; the *_HO macros are the corresponding indices into the
|
* device vectors; the *_HO macros are the corresponding indices into the
|
* low-mem isr table
|
* low-mem isr table
|
*/
|
*/
|
#define NMI_VEC 248
|
#define NMI_VEC 248
|
|
|
#define LED ((unsigned char*)0xe0040000)
|
#define LED ((unsigned char*)0xe0040000)
|
#define LED_THRESHOLD (HZ/2)
|
#define LED_THRESHOLD (HZ/2)
|
|
|
#define TMR0_VEC_HO 0xd
|
#define TMR0_VEC_HO 0xd
|
#define TMR1_VEC_HO 0xe
|
#define TMR1_VEC_HO 0xe
|
#define XINT0_VEC_HO 1
|
#define XINT0_VEC_HO 1
|
#define XINT1_VEC_HO 2
|
#define XINT1_VEC_HO 2
|
#define XINT2_VEC_HO 3
|
#define XINT2_VEC_HO 3
|
#define XINT3_VEC_HO 4
|
#define XINT3_VEC_HO 4
|
#define XINT4_VEC_HO 5
|
#define XINT4_VEC_HO 5
|
#define XINT5_VEC_HO 6
|
#define XINT5_VEC_HO 6
|
#define XINT6_VEC_HO 7
|
#define XINT6_VEC_HO 7
|
#define XINT7_VEC_HO 8
|
#define XINT7_VEC_HO 8
|
|
|
static char* irq_names[] = {
|
static char* irq_names[] = {
|
0, /* 0 */
|
0, /* 0 */
|
"xint0",
|
"xint0",
|
"xint1",
|
"xint1",
|
"xint2",
|
"xint2",
|
"xint3",
|
"xint3",
|
"serial",
|
"serial",
|
"xint5",
|
"xint5",
|
"xint6",
|
"xint6",
|
"xint7",
|
"xint7",
|
0, 0, 0, 0,
|
0, 0, 0, 0,
|
"timer0",
|
"timer0",
|
"timer1",
|
"timer1",
|
0,
|
0,
|
};
|
};
|
|
|
#ifdef CONFIG_PROF_IRQ
|
#ifdef CONFIG_PROF_IRQ
|
static struct irqstat {
|
static struct irqstat {
|
unsigned long min;
|
unsigned long min;
|
unsigned long avg;
|
unsigned long avg;
|
unsigned long max;
|
unsigned long max;
|
} irqstat[16];
|
} irqstat[16];
|
#endif
|
#endif
|
|
|
static void* pci_dev;
|
static void* pci_dev;
|
static const char* pci_name;
|
static const char* pci_name;
|
static void (*pci_isr)(int, void *, struct pt_regs *);
|
static void (*pci_isr)(int, void *, struct pt_regs *);
|
|
|
#define __VEC(ho) (((ho) << 4) | 2)
|
#define __VEC(ho) (((ho) << 4) | 2)
|
#define TMR0_VEC __VEC(TMR0_VEC_HO)
|
#define TMR0_VEC __VEC(TMR0_VEC_HO)
|
#define TMR1_VEC __VEC(TMR1_VEC_HO)
|
#define TMR1_VEC __VEC(TMR1_VEC_HO)
|
#define XINT0_VEC __VEC(XINT0_VEC_HO)
|
#define XINT0_VEC __VEC(XINT0_VEC_HO)
|
#define XINT1_VEC __VEC(XINT1_VEC_HO)
|
#define XINT1_VEC __VEC(XINT1_VEC_HO)
|
#define XINT2_VEC __VEC(XINT2_VEC_HO)
|
#define XINT2_VEC __VEC(XINT2_VEC_HO)
|
#define XINT3_VEC __VEC(XINT3_VEC_HO)
|
#define XINT3_VEC __VEC(XINT3_VEC_HO)
|
#define XINT4_VEC __VEC(XINT4_VEC_HO)
|
#define XINT4_VEC __VEC(XINT4_VEC_HO)
|
#define SERIAL_VEC XINT4_VEC
|
#define SERIAL_VEC XINT4_VEC
|
#define PCI_VEC XINT1_VEC
|
#define PCI_VEC XINT1_VEC
|
#define XINT5_VEC __VEC(XINT5_VEC_HO)
|
#define XINT5_VEC __VEC(XINT5_VEC_HO)
|
#define XINT6_VEC __VEC(XINT6_VEC_HO)
|
#define XINT6_VEC __VEC(XINT6_VEC_HO)
|
#define XINT7_VEC __VEC(XINT7_VEC_HO)
|
#define XINT7_VEC __VEC(XINT7_VEC_HO)
|
|
|
|
|
void leave_kernel(struct pt_regs* regs);
|
void leave_kernel(struct pt_regs* regs);
|
static void nmi_intr(void);
|
static void nmi_intr(void);
|
static void bad_intr(unsigned char vec, struct pt_regs* regs);
|
static void bad_intr(unsigned char vec, struct pt_regs* regs);
|
static void xint(unsigned char ho, struct pt_regs* regs);
|
static void xint(unsigned char ho, struct pt_regs* regs);
|
void stack_trace(void);
|
void stack_trace(void);
|
|
|
extern void intr(void);
|
extern void intr(void);
|
static void program_clock(void);
|
static void program_clock(void);
|
|
|
#ifdef CONFIG_MON960
|
#ifdef CONFIG_MON960
|
#include <asm/i960jx.h>
|
#include <asm/i960jx.h>
|
#include <asm/mon960.h>
|
#include <asm/mon960.h>
|
|
|
static unsigned long get_mon960_serial_isr(void)
|
static unsigned long get_mon960_serial_isr(void)
|
{
|
{
|
prcb_t* prcb = (prcb_t*)get_prcbptr();
|
prcb_t* prcb = (prcb_t*)get_prcbptr();
|
unsigned long vec = (*(unsigned long*)IMAP1 & 0x0f00) >> 8;
|
unsigned long vec = (*(unsigned long*)IMAP1 & 0x0f00) >> 8;
|
|
|
/* on cyclone, serial isr is XINT5 */
|
/* on cyclone, serial isr is XINT5 */
|
return (unsigned long) prcb->pr_intr_tab->i_vectors[vec];
|
return (unsigned long) prcb->pr_intr_tab->i_vectors[vec];
|
}
|
}
|
|
|
#endif
|
#endif
|
|
|
static void init_syscalls(void)
|
static void init_syscalls(void)
|
{
|
{
|
unsigned long** prcb = (unsigned long**)get_prcbptr();
|
unsigned long** prcb = (unsigned long**)get_prcbptr();
|
unsigned long* syscall_tab = prcb[5];
|
unsigned long* syscall_tab = prcb[5];
|
extern void syscall(void);
|
extern void syscall(void);
|
/* we only use syscall 0, which is 12 words from the start of
|
/* we only use syscall 0, which is 12 words from the start of
|
* the syscall table. The entry type field of 0x2 indicates a call
|
* the syscall table. The entry type field of 0x2 indicates a call
|
* to supervisor mode. */
|
* to supervisor mode. */
|
syscall_tab[12] = ((unsigned long) syscall) | 0x2;
|
syscall_tab[12] = ((unsigned long) syscall) | 0x2;
|
return;
|
return;
|
}
|
}
|
|
|
/*
|
/*
|
* At entry here, we have a high ipl. We need to establish
|
* At entry here, we have a high ipl. We need to establish
|
* our isr's, and enable the clock.
|
* our isr's, and enable the clock.
|
*/
|
*/
|
void init_IRQ(void)
|
void init_IRQ(void)
|
{
|
{
|
unsigned long *dram = 0;
|
unsigned long *dram = 0;
|
int ii;
|
int ii;
|
|
|
/* set up the following layout in low RAM for our 15 vectors:
|
/* set up the following layout in low RAM for our 15 vectors:
|
* 0: NMI (we have no choice about this)
|
* 0: NMI (we have no choice about this)
|
* 1-8: XINT0-7
|
* 1-8: XINT0-7
|
* 9-12: Invalid
|
* 9-12: Invalid
|
* 13: Timer0. Note that Timer1 is disabled.
|
* 13: Timer0. Note that Timer1 is disabled.
|
* 14-15: Invalid.
|
* 14-15: Invalid.
|
*
|
*
|
* This works out nicely, since the vector number-1 is the
|
* This works out nicely, since the vector number-1 is the
|
* corresponding bit in IMSK; see disable_irq below.
|
* corresponding bit in IMSK; see disable_irq below.
|
*/
|
*/
|
atmod((void*)IMAP0, 0xffff, 0x4321); /* xint 0-3 */
|
atmod((void*)IMAP0, 0xffff, 0x4321); /* xint 0-3 */
|
atmod((void*)IMAP1, 0xffff, 0x8756); /* xint 4-7 */
|
atmod((void*)IMAP1, 0xffff, 0x8756); /* xint 4-7 */
|
atmod((void*)IMAP2, 0xff<<16, 0xed << 16); /* Timer 0, Timer 1 */
|
atmod((void*)IMAP2, 0xff<<16, 0xed << 16); /* Timer 0, Timer 1 */
|
|
|
/* we vector all interrupts through intr */
|
/* we vector all interrupts through intr */
|
for (ii=0; ii < 16; ii++)
|
for (ii=0; ii < 16; ii++)
|
dram[ii] = (unsigned long)intr;
|
dram[ii] = (unsigned long)intr;
|
|
|
#ifdef CONFIG_MON960
|
#ifdef CONFIG_MON960
|
/* reset the XINT5 interrupt handler from software */
|
/* reset the XINT5 interrupt handler from software */
|
dram[XINT5_VEC_HO] = get_mon960_serial_isr();
|
dram[XINT5_VEC_HO] = get_mon960_serial_isr();
|
#endif
|
#endif
|
|
|
program_clock();
|
program_clock();
|
/* set 13th bit of ICON; enable vector caching */
|
/* set 13th bit of ICON; enable vector caching */
|
atmod((void*)ICON, 1<<13, 1<<13);
|
atmod((void*)ICON, 1<<13, 1<<13);
|
/*
|
/*
|
* XXX: what to mask is somewhat board dependent; we leave XINT4
|
* XXX: what to mask is somewhat board dependent; we leave XINT4
|
* masked because Cyclone needs it to always be masked.
|
* masked because Cyclone needs it to always be masked.
|
*/
|
*/
|
atmod((void*)IPND, ~0, 0);
|
atmod((void*)IPND, ~0, 0);
|
atmod((void*)IMSK, 0x30ef, 0x30ef);
|
atmod((void*)IMSK, 0x30ef, 0x30ef);
|
|
|
/* Now set up syscalls */
|
/* Now set up syscalls */
|
init_syscalls();
|
init_syscalls();
|
}
|
}
|
|
|
#define TRR0 (volatile unsigned long*)0xff000300
|
#define TRR0 (volatile unsigned long*)0xff000300
|
#define TCR0 (volatile unsigned long*)0xff000304
|
#define TCR0 (volatile unsigned long*)0xff000304
|
#define TMR0 (volatile unsigned long*)0xff000308
|
#define TMR0 (volatile unsigned long*)0xff000308
|
|
|
#define TRR1 (volatile unsigned long*)0xff000310
|
#define TRR1 (volatile unsigned long*)0xff000310
|
#define TCR1 (volatile unsigned long*)0xff000314
|
#define TCR1 (volatile unsigned long*)0xff000314
|
#define TMR1 (volatile unsigned long*)0xff000318
|
#define TMR1 (volatile unsigned long*)0xff000318
|
/* some helper macros for programming the mode register, TMR0 */
|
/* some helper macros for programming the mode register, TMR0 */
|
|
|
/* the clock may decrement once per cpu cycle, once every two cycles, ...
|
/* the clock may decrement once per cpu cycle, once every two cycles, ...
|
* up to eight; set the appropriate bits in TMR0
|
* up to eight; set the appropriate bits in TMR0
|
*/
|
*/
|
#define CLOCKSHIFT 4
|
#define CLOCKSHIFT 4
|
#define CLOCKDIV(x) (x << CLOCKSHIFT)
|
#define CLOCKDIV(x) (x << CLOCKSHIFT)
|
#define CLOCKDIV1 CLOCKDIV(0)
|
#define CLOCKDIV1 CLOCKDIV(0)
|
#define CLOCKDIV2 CLOCKDIV(1)
|
#define CLOCKDIV2 CLOCKDIV(1)
|
#define CLOCKDIV4 CLOCKDIV(2)
|
#define CLOCKDIV4 CLOCKDIV(2)
|
#define CLOCKDIV8 CLOCKDIV(3)
|
#define CLOCKDIV8 CLOCKDIV(3)
|
|
|
#define CLOCK_ENABLE 2 /* set for clock to work */
|
#define CLOCK_ENABLE 2 /* set for clock to work */
|
#define CLOCK_AUTO_RELOAD 4 /* reload from TRR0 when we reach 0 */
|
#define CLOCK_AUTO_RELOAD 4 /* reload from TRR0 when we reach 0 */
|
#define CLOCK_SUPER_ONLY 8 /* don't let users reprogram clocks */
|
#define CLOCK_SUPER_ONLY 8 /* don't let users reprogram clocks */
|
|
|
/*
|
/*
|
* Set up timer 0 to interrupt us every so many clocks. Assumes
|
* Set up timer 0 to interrupt us every so many clocks. Assumes
|
* interrupts are disabled.
|
* interrupts are disabled.
|
*/
|
*/
|
static void
|
static void
|
program_clock(void)
|
program_clock(void)
|
{
|
{
|
/* 33Mhz PCI Bus assumed */
|
/* 33Mhz PCI Bus assumed */
|
#define CYCLES_PER_HZ (33 * 1000* 1000) / HZ
|
#define CYCLES_PER_HZ (33 * 1000* 1000) / HZ
|
*TRR0 = *TCR0 = CYCLES_PER_HZ;
|
*TRR0 = *TCR0 = CYCLES_PER_HZ;
|
*TMR0 = CLOCKDIV1 | CLOCK_ENABLE | CLOCK_AUTO_RELOAD | CLOCK_SUPER_ONLY;
|
*TMR0 = CLOCKDIV1 | CLOCK_ENABLE | CLOCK_AUTO_RELOAD | CLOCK_SUPER_ONLY;
|
|
|
#ifdef CONFIG_PROF_IRQ
|
#ifdef CONFIG_PROF_IRQ
|
disable_irq(TMR1_VEC_HO);
|
disable_irq(TMR1_VEC_HO);
|
#endif
|
#endif
|
}
|
}
|
|
|
irq_node_t *new_irq_node(void)
|
irq_node_t *new_irq_node(void)
|
{
|
{
|
/* XXX: write me */
|
/* XXX: write me */
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
int request_irq(unsigned int irq,
|
int request_irq(unsigned int irq,
|
void (*handler)(int, void *, struct pt_regs *),
|
void (*handler)(int, void *, struct pt_regs *),
|
unsigned long flags, const char *devname, void *dev_id)
|
unsigned long flags, const char *devname, void *dev_id)
|
{
|
{
|
/* XXX: this is a stopgap; we only can handle one pci device */
|
/* XXX: this is a stopgap; we only can handle one pci device */
|
if (pci_dev)
|
if (pci_dev)
|
return -1;
|
return -1;
|
|
|
pci_dev = dev_id;
|
pci_dev = dev_id;
|
pci_name = devname;
|
pci_name = devname;
|
pci_isr = handler;
|
pci_isr = handler;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void free_irq(unsigned int irq, void *dev_id)
|
void free_irq(unsigned int irq, void *dev_id)
|
{
|
{
|
pci_dev = 0;
|
pci_dev = 0;
|
}
|
}
|
|
|
/*
|
/*
|
* Do we need these probe functions on the i960?
|
* Do we need these probe functions on the i960?
|
*/
|
*/
|
unsigned long probe_irq_on (void)
|
unsigned long probe_irq_on (void)
|
{
|
{
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int probe_irq_off (unsigned long irqs)
|
int probe_irq_off (unsigned long irqs)
|
{
|
{
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void disable_irq(unsigned int irq)
|
void disable_irq(unsigned int irq)
|
{
|
{
|
if (irq && irq < SYS_IRQS)
|
if (irq && irq < SYS_IRQS)
|
atmod((void*)IMSK, 1<<(irq-1), 0);
|
atmod((void*)IMSK, 1<<(irq-1), 0);
|
}
|
}
|
|
|
void enable_irq(unsigned int irq)
|
void enable_irq(unsigned int irq)
|
{
|
{
|
if (irq && irq < SYS_IRQS)
|
if (irq && irq < SYS_IRQS)
|
atmod((void*)IMSK, 1<<(irq-1), 1<<(irq-1));
|
atmod((void*)IMSK, 1<<(irq-1), 1<<(irq-1));
|
}
|
}
|
|
|
#ifdef CONFIG_PROF_IRQ
|
#ifdef CONFIG_PROF_IRQ
|
#define SAMPLE_BITS 7
|
#define SAMPLE_BITS 7
|
static inline void
|
static inline void
|
update_prof_timers(int vec, unsigned long ticks)
|
update_prof_timers(int vec, unsigned long ticks)
|
{
|
{
|
struct irqstat* irq;
|
struct irqstat* irq;
|
vec = vec >> 4;
|
vec = vec >> 4;
|
irq = irqstat + vec;
|
irq = irqstat + vec;
|
|
|
if (!irq->avg) {
|
if (!irq->avg) {
|
irq->max = ticks;
|
irq->max = ticks;
|
irq->min = ticks;
|
irq->min = ticks;
|
irq->avg = ticks;
|
irq->avg = ticks;
|
return;
|
return;
|
}
|
}
|
|
|
if (ticks < irq->min)
|
if (ticks < irq->min)
|
irq->min = ticks;
|
irq->min = ticks;
|
if (ticks > irq->max)
|
if (ticks > irq->max)
|
irq->max = ticks;
|
irq->max = ticks;
|
irq->avg -= irq->avg >> SAMPLE_BITS;
|
irq->avg -= irq->avg >> SAMPLE_BITS;
|
irq->avg += ticks >> SAMPLE_BITS;
|
irq->avg += ticks >> SAMPLE_BITS;
|
}
|
}
|
#endif
|
#endif
|
|
|
/*
|
/*
|
* Interrupt service routine. N.B. that XINT0, which is really a system call,
|
* Interrupt service routine. N.B. that XINT0, which is really a system call,
|
* is never routed to cintr; it ends up in syscall instead.
|
* is never routed to cintr; it ends up in syscall instead.
|
*/
|
*/
|
extern void do_signal(void);
|
extern void do_signal(void);
|
asmlinkage void cintr(unsigned char vec, struct pt_regs* regs)
|
asmlinkage void cintr(unsigned char vec, struct pt_regs* regs)
|
{
|
{
|
extern void timer_interrupt(struct pt_regs* regs);
|
extern void timer_interrupt(struct pt_regs* regs);
|
static int ticks;
|
static int ticks;
|
#ifdef CONFIG_PROF_IRQ
|
#ifdef CONFIG_PROF_IRQ
|
unsigned long clocks;
|
unsigned long clocks;
|
*TCR1 = CYCLES_PER_HZ * HZ;
|
*TCR1 = CYCLES_PER_HZ * HZ;
|
*TMR1 = CLOCKDIV1 | CLOCK_ENABLE;
|
*TMR1 = CLOCKDIV1 | CLOCK_ENABLE;
|
#endif
|
#endif
|
atomic_inc(&intr_count);
|
atomic_inc(&intr_count);
|
|
|
kstat.interrupts[vec >> 4]++;
|
kstat.interrupts[vec >> 4]++;
|
switch(vec) {
|
switch(vec) {
|
case NMI_VEC:
|
case NMI_VEC:
|
nmi_intr();
|
nmi_intr();
|
break;
|
break;
|
|
|
case XINT1_VEC:
|
case XINT1_VEC:
|
case XINT0_VEC:
|
case XINT0_VEC:
|
case XINT2_VEC:
|
case XINT2_VEC:
|
case XINT3_VEC:
|
case XINT3_VEC:
|
case XINT4_VEC:
|
case XINT4_VEC:
|
case XINT5_VEC:
|
case XINT5_VEC:
|
case XINT6_VEC:
|
case XINT6_VEC:
|
case XINT7_VEC:
|
case XINT7_VEC:
|
xint(vec, regs);
|
xint(vec, regs);
|
break;
|
break;
|
|
|
case TMR0_VEC:
|
case TMR0_VEC:
|
if ((++ticks) >= LED_THRESHOLD) {
|
if ((++ticks) >= LED_THRESHOLD) {
|
static char nm = 0;
|
static char nm = 0;
|
*LED = ~ (1 << (nm++ % 8));
|
*LED = ~ (1 << (nm++ % 8));
|
ticks = 0;
|
ticks = 0;
|
}
|
}
|
timer_interrupt(regs);
|
timer_interrupt(regs);
|
break;
|
break;
|
|
|
default:
|
default:
|
bad_intr(vec, regs);
|
bad_intr(vec, regs);
|
break;
|
break;
|
}
|
}
|
atomic_dec(&intr_count);
|
atomic_dec(&intr_count);
|
|
|
if (!intr_count)
|
if (!intr_count)
|
leave_kernel(regs);
|
leave_kernel(regs);
|
|
|
#ifdef CONFIG_PROF_IRQ
|
#ifdef CONFIG_PROF_IRQ
|
clocks = CYCLES_PER_HZ*HZ - *TCR1;
|
clocks = CYCLES_PER_HZ*HZ - *TCR1;
|
update_prof_timers(vec, clocks);
|
update_prof_timers(vec, clocks);
|
#endif
|
#endif
|
return;
|
return;
|
}
|
}
|
|
|
/*
|
/*
|
* Common code to interrupt and syscall paths. When leaving the kernel, and not
|
* Common code to interrupt and syscall paths. When leaving the kernel, and not
|
* returning to an interrupt context, do a whole bunch of processing.
|
* returning to an interrupt context, do a whole bunch of processing.
|
*
|
*
|
* Note that if we're called from cintr, we're running at high ipl.
|
* Note that if we're called from cintr, we're running at high ipl.
|
*
|
*
|
* Run the bottom half, check if scheduling is needed, and deliver signals to
|
* Run the bottom half, check if scheduling is needed, and deliver signals to
|
* the current process, just as in every other architecture.
|
* the current process, just as in every other architecture.
|
*/
|
*/
|
void leave_kernel(struct pt_regs* regs)
|
void leave_kernel(struct pt_regs* regs)
|
{
|
{
|
bh:
|
bh:
|
if (bh_mask & bh_active) {
|
if (bh_mask & bh_active) {
|
atomic_inc(&intr_count);
|
atomic_inc(&intr_count);
|
do_bottom_half();
|
do_bottom_half();
|
atomic_dec(&intr_count);
|
atomic_dec(&intr_count);
|
}
|
}
|
sti();
|
sti();
|
|
|
if (user_mode(regs)) {
|
if (user_mode(regs)) {
|
if (need_resched) {
|
if (need_resched) {
|
schedule();
|
schedule();
|
goto bh;
|
goto bh;
|
}
|
}
|
|
|
|
|
if (current->signal & ~current->blocked) {
|
if (current->signal & ~current->blocked) {
|
do_signal();
|
do_signal();
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
static void nmi_intr(void)
|
static void nmi_intr(void)
|
{
|
{
|
/* XXX: write me */
|
/* XXX: write me */
|
}
|
}
|
|
|
static void bad_intr(unsigned char vec, struct pt_regs* regs)
|
static void bad_intr(unsigned char vec, struct pt_regs* regs)
|
{
|
{
|
/* XXX: write me */
|
/* XXX: write me */
|
printk("whoah! bad intr: %x\n", vec);
|
printk("whoah! bad intr: %x\n", vec);
|
}
|
}
|
|
|
static void xint(unsigned char vec, struct pt_regs* regs)
|
static void xint(unsigned char vec, struct pt_regs* regs)
|
{
|
{
|
/*
|
/*
|
* This basically shouldn't happen
|
* This basically shouldn't happen
|
*/
|
*/
|
#ifdef CONFIG_MON960_CONSOLE
|
#ifdef CONFIG_MON960_CONSOLE
|
if (vec == SERIAL_VEC) {
|
if (vec == SERIAL_VEC) {
|
extern void do_16552_intr(void);
|
extern void do_16552_intr(void);
|
do_16552_intr();
|
do_16552_intr();
|
return;
|
return;
|
}
|
}
|
#endif
|
#endif
|
|
|
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
if (vec == PCI_VEC && pci_dev) {
|
if (vec == PCI_VEC && pci_dev) {
|
pci_isr(0, pci_dev, regs);
|
pci_isr(0, pci_dev, regs);
|
return;
|
return;
|
}
|
}
|
#endif
|
#endif
|
printk("EEP: xint %x\n", vec);
|
printk("EEP: xint %x\n", vec);
|
stack_trace();
|
stack_trace();
|
}
|
}
|
|
|
int get_irq_list(char *buf)
|
int get_irq_list(char *buf)
|
{
|
{
|
int len = 0;
|
int len = 0;
|
int ii;
|
int ii;
|
|
|
for (ii=0; ii < 16; ii++) {
|
for (ii=0; ii < 16; ii++) {
|
if (irq_names[ii]) {
|
if (irq_names[ii]) {
|
#ifdef CONFIG_PROF_IRQ
|
#ifdef CONFIG_PROF_IRQ
|
len += sprintf(buf+len, "%d\t%s\t(%08x, %08x, %08x)\n",
|
len += sprintf(buf+len, "%d\t%s\t(%08x, %08x, %08x)\n",
|
kstat.interrupts[ii],
|
kstat.interrupts[ii],
|
(ii==2 && pci_dev)
|
(ii==2 && pci_dev)
|
? pci_name
|
? pci_name
|
: irq_names[ii],
|
: irq_names[ii],
|
irqstat[ii].min, irqstat[ii].avg,
|
irqstat[ii].min, irqstat[ii].avg,
|
irqstat[ii].max);
|
irqstat[ii].max);
|
#else
|
#else
|
len += sprintf(buf+len, "%d\t%s\n",
|
len += sprintf(buf+len, "%d\t%s\n",
|
kstat.interrupts[ii],
|
kstat.interrupts[ii],
|
(ii==2 && pci_dev)
|
(ii==2 && pci_dev)
|
? pci_name
|
? pci_name
|
: irq_names[ii]);
|
: irq_names[ii]);
|
#endif
|
#endif
|
}
|
}
|
}
|
}
|
return len;
|
return len;
|
}
|
}
|
|
|
|
|