diff options
Diffstat (limited to 'arch/mips/mips-boards')
-rw-r--r-- | arch/mips/mips-boards/atlas/atlas_int.c | 105 | ||||
-rw-r--r-- | arch/mips/mips-boards/atlas/atlas_setup.c | 2 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 64 |
3 files changed, 128 insertions, 43 deletions
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c index fb25e0377f1..a020a3cb4f4 100644 --- a/arch/mips/mips-boards/atlas/atlas_int.c +++ b/arch/mips/mips-boards/atlas/atlas_int.c @@ -1,6 +1,8 @@ /* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 1999, 2000, 2006 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard <carstenl@mips.com> + * Maciej W. Rozycki <macro@mips.com> * * ######################################################################## * @@ -25,17 +27,20 @@ */ #include <linux/compiler.h> #include <linux/init.h> +#include <linux/irq.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> -#include <asm/irq.h> +#include <asm/gdb-stub.h> #include <asm/io.h> +#include <asm/irq_cpu.h> +#include <asm/msc01_ic.h> + #include <asm/mips-boards/atlas.h> #include <asm/mips-boards/atlasint.h> -#include <asm/gdb-stub.h> - +#include <asm/mips-boards/generic.h> static struct atlas_ictrl_regs *atlas_hw0_icregs; @@ -47,13 +52,13 @@ static struct atlas_ictrl_regs *atlas_hw0_icregs; void disable_atlas_irq(unsigned int irq_nr) { - atlas_hw0_icregs->intrsten = (1 << (irq_nr-ATLASINT_BASE)); + atlas_hw0_icregs->intrsten = 1 << (irq_nr - ATLAS_INT_BASE); iob(); } void enable_atlas_irq(unsigned int irq_nr) { - atlas_hw0_icregs->intseten = (1 << (irq_nr-ATLASINT_BASE)); + atlas_hw0_icregs->intseten = 1 << (irq_nr - ATLAS_INT_BASE); iob(); } @@ -107,7 +112,7 @@ static inline void atlas_hw0_irqdispatch(struct pt_regs *regs) if (unlikely(int_status == 0)) return; - irq = ATLASINT_BASE + ls1bit32(int_status); + irq = ATLAS_INT_BASE + ls1bit32(int_status); DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq); @@ -161,15 +166,14 @@ static inline unsigned int irq_ffs(unsigned int pending) } /* - * IRQs on the Atlas board look basically (barring software IRQs which we - * don't use at all and all external interrupt sources are combined together - * on hardware interrupt 0 (MIPS IRQ 2)) like: + * IRQs on the Atlas board look basically like (all external interrupt + * sources are combined together on hardware interrupt 0 (MIPS IRQ 2)): * - * MIPS IRQ Source + * MIPS IRQ Source * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Combined hardware interrupt (hw0) + * 0 Software 0 (reschedule IPI on MT) + * 1 Software 1 (remote call IPI on MT) + * 2 Combined Atlas hardware interrupt (hw0) * 3 Hardware (ignored) * 4 Hardware (ignored) * 5 Hardware (ignored) @@ -179,7 +183,7 @@ static inline unsigned int irq_ffs(unsigned int pending) * We handle the IRQ according to _our_ priority which is: * * Highest ---- R4k Timer - * Lowest ---- Combined hardware interrupt + * Lowest ---- Software 0 * * then we just return, if multiple IRQs are pending then we will just take * another exception, big deal. @@ -193,17 +197,19 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) if (irq == MIPSCPU_INT_ATLAS) atlas_hw0_irqdispatch(regs); - else if (irq > 0) + else if (irq >= 0) do_IRQ(MIPSCPU_INT_BASE + irq, regs); else spurious_interrupt(regs); } -void __init arch_init_irq(void) +static inline void init_atlas_irqs (int base) { int i; - atlas_hw0_icregs = (struct atlas_ictrl_regs *)ioremap (ATLAS_ICTRL_REGS_BASE, sizeof(struct atlas_ictrl_regs *)); + atlas_hw0_icregs = (struct atlas_ictrl_regs *) + ioremap(ATLAS_ICTRL_REGS_BASE, + sizeof(struct atlas_ictrl_regs *)); /* * Mask out all interrupt by writing "1" to all bit position in @@ -211,7 +217,7 @@ void __init arch_init_irq(void) */ atlas_hw0_icregs->intrsten = 0xffffffff; - for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) { + for (i = ATLAS_INT_BASE; i <= ATLAS_INT_END; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = 0; irq_desc[i].depth = 1; @@ -219,3 +225,62 @@ void __init arch_init_irq(void) spin_lock_init(&irq_desc[i].lock); } } + +static struct irqaction atlasirq = { + .handler = no_action, + .name = "Atlas cascade" +}; + +msc_irqmap_t __initdata msc_irqmap[] = { + {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, + {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, +}; +int __initdata msc_nr_irqs = sizeof(msc_irqmap) / sizeof(*msc_irqmap); + +msc_irqmap_t __initdata msc_eicirqmap[] = { + {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_ATLAS, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0}, + {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} +}; +int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap) / sizeof(*msc_eicirqmap); + +void __init arch_init_irq(void) +{ + init_atlas_irqs(ATLAS_INT_BASE); + + if (!cpu_has_veic) + mips_cpu_irq_init(MIPSCPU_INT_BASE); + + switch(mips_revision_corid) { + case MIPS_REVISION_CORID_CORE_MSC: + case MIPS_REVISION_CORID_CORE_FPGA2: + case MIPS_REVISION_CORID_CORE_FPGA3: + case MIPS_REVISION_CORID_CORE_24K: + case MIPS_REVISION_CORID_CORE_EMUL_MSC: + if (cpu_has_veic) + init_msc_irqs (MSC01E_INT_BASE, + msc_eicirqmap, msc_nr_eicirqs); + else + init_msc_irqs (MSC01C_INT_BASE, + msc_irqmap, msc_nr_irqs); + } + + + if (cpu_has_veic) { + set_vi_handler (MSC01E_INT_ATLAS, atlas_hw0_irqdispatch); + setup_irq (MSC01E_INT_BASE + MSC01E_INT_ATLAS, &atlasirq); + } else if (cpu_has_vint) { + set_vi_handler (MIPSCPU_INT_ATLAS, atlas_hw0_irqdispatch); +#ifdef CONFIG_MIPS_MT_SMTC + setup_irq_smtc (MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, + &atlasirq, (0x100 << MIPSCPU_INT_ATLAS)); +#else /* Not SMTC */ + setup_irq(MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, &atlasirq); +#endif /* CONFIG_MIPS_MT_SMTC */ + } else + setup_irq(MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, &atlasirq); +} diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c index 9871a91fdb0..0c6b0ce1502 100644 --- a/arch/mips/mips-boards/atlas/atlas_setup.c +++ b/arch/mips/mips-boards/atlas/atlas_setup.c @@ -77,7 +77,7 @@ static void __init serial_init(void) #else s.iobase = ATLAS_UART_REGS_BASE+3; #endif - s.irq = ATLASINT_UART; + s.irq = ATLAS_INT_UART; s.uartclk = ATLAS_BASE_BAUD * 16; s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ; s.iotype = UPIO_PORT; diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 557bf961f36..8d15861fce6 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -41,8 +41,13 @@ #include <asm/mips-boards/generic.h> #include <asm/mips-boards/prom.h> + +#ifdef CONFIG_MIPS_ATLAS +#include <asm/mips-boards/atlasint.h> +#endif +#ifdef CONFIG_MIPS_MALTA #include <asm/mips-boards/maltaint.h> -#include <asm/mc146818-time.h> +#endif unsigned long cpu_khz; @@ -92,10 +97,9 @@ extern int (*perf_irq)(struct pt_regs *regs); irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int cpu = smp_processor_id(); - int r2 = cpu_has_mips_r2; #ifdef CONFIG_MIPS_MT_SMTC - /* + /* * In an SMTC system, one Count/Compare set exists per VPE. * Which TC within a VPE gets the interrupt is essentially * random - we only know that it shouldn't be one with @@ -108,29 +112,46 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * the general MIPS timer_interrupt routine. */ + int vpflags; + /* - * DVPE is necessary so long as cross-VPE interrupts - * are done via read-modify-write of Cause register. + * We could be here due to timer interrupt, + * perf counter overflow, or both. */ - int vpflags = dvpe(); - write_c0_compare (read_c0_count() - 1); - clear_c0_cause(CPUCTR_IMASKBIT); - evpe(vpflags); + if (read_c0_cause() & (1 << 26)) + perf_irq(regs); - if (cpu_data[cpu].vpe_id == 0) { - timer_interrupt(irq, dev_id, regs); - scroll_display_message(); - } else - write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ)); - smtc_timer_broadcast(cpu_data[cpu].vpe_id); - - if (cpu != 0) + if (read_c0_cause() & (1 << 30)) { + /* If timer interrupt, make it de-assert */ + write_c0_compare (read_c0_count() - 1); /* - * Other CPUs should do profiling and process accounting + * DVPE is necessary so long as cross-VPE interrupts + * are done via read-modify-write of Cause register. */ - local_timer_interrupt(irq, dev_id, regs); - + vpflags = dvpe(); + clear_c0_cause(CPUCTR_IMASKBIT); + evpe(vpflags); + /* + * There are things we only want to do once per tick + * in an "MP" system. One TC of each VPE will take + * the actual timer interrupt. The others will get + * timer broadcast IPIs. We use whoever it is that takes + * the tick on VPE 0 to run the full timer_interrupt(). + */ + if (cpu_data[cpu].vpe_id == 0) { + timer_interrupt(irq, NULL, regs); + smtc_timer_broadcast(cpu_data[cpu].vpe_id); + scroll_display_message(); + } else { + write_c0_compare(read_c0_count() + + (mips_hpt_frequency/HZ)); + local_timer_interrupt(irq, dev_id, regs); + smtc_timer_broadcast(cpu_data[cpu].vpe_id); + } + } #else /* CONFIG_MIPS_MT_SMTC */ + int r2 = cpu_has_mips_r2; + if (cpu == 0) { /* * CPU 0 handles the global timer interrupt job and process @@ -161,9 +182,8 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ local_timer_interrupt(irq, dev_id, regs); } -#endif /* CONFIG_MIPS_MT_SMTC */ - out: +#endif /* CONFIG_MIPS_MT_SMTC */ return IRQ_HANDLED; } |