diff options
-rw-r--r-- | arch/mips/Kconfig | 24 | ||||
-rw-r--r-- | arch/mips/au1000/Kconfig | 1 | ||||
-rw-r--r-- | arch/mips/jazz/irq.c | 6 | ||||
-rw-r--r-- | arch/mips/jazz/setup.c | 8 | ||||
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/setup.c | 66 | ||||
-rw-r--r-- | arch/mips/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/kernel/cevt-r4k.c | 272 | ||||
-rw-r--r-- | arch/mips/kernel/head.S | 16 | ||||
-rw-r--r-- | arch/mips/kernel/time.c | 262 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 11 | ||||
-rw-r--r-- | arch/mips/pmc-sierra/Kconfig | 2 | ||||
-rw-r--r-- | arch/mips/sgi-ip27/ip27-irq.c | 5 | ||||
-rw-r--r-- | arch/mips/sgi-ip27/ip27-timer.c | 155 | ||||
-rw-r--r-- | arch/mips/sgi-ip32/ip32-setup.c | 6 | ||||
-rw-r--r-- | arch/mips/vr41xx/Kconfig | 6 | ||||
-rw-r--r-- | include/asm-mips/mach-ip27/kernel-entry-init.h | 9 | ||||
-rw-r--r-- | include/asm-mips/time.h | 7 |
17 files changed, 483 insertions, 375 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 235d4514e0a9..cb027580cd1d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -21,6 +21,7 @@ config MACH_ALCHEMY config BASLER_EXCITE bool "Basler eXcite smart camera" + select CEVT_R4K select DMA_COHERENT select HW_HAS_PCI select IRQ_CPU @@ -47,6 +48,7 @@ config BASLER_EXCITE_PROTOTYPE config BCM47XX bool "BCM47XX based boards" + select CEVT_R4K select DMA_NONCOHERENT select HW_HAS_PCI select IRQ_CPU @@ -63,6 +65,7 @@ config BCM47XX config MIPS_COBALT bool "Cobalt Server" + select CEVT_R4K select DMA_NONCOHERENT select HW_HAS_PCI select I8253 @@ -80,6 +83,7 @@ config MIPS_COBALT config MACH_DECSTATION bool "DECstations" select BOOT_ELF32 + select CEVT_R4K select DMA_NONCOHERENT select NO_IOPORT select IRQ_CPU @@ -111,6 +115,7 @@ config MACH_JAZZ select ARC select ARC32 select ARCH_MAY_HAVE_PC_FDC + select CEVT_R4K select GENERIC_ISA_DMA select IRQ_CPU select I8253 @@ -130,6 +135,7 @@ config MACH_JAZZ config LASAT bool "LASAT Networks platforms" + select CEVT_R4K select DMA_NONCOHERENT select SYS_HAS_EARLY_PRINTK select HW_HAS_PCI @@ -146,6 +152,7 @@ config LASAT config LEMOTE_FULONG bool "Lemote Fulong mini-PC" select ARCH_SPARSEMEM_ENABLE + select CEVT_R4K select SYS_HAS_CPU_LOONGSON2 select DMA_NONCOHERENT select BOOT_ELF32 @@ -170,6 +177,7 @@ config LEMOTE_FULONG config MIPS_ATLAS bool "MIPS Atlas board" select BOOT_ELF32 + select CEVT_R4K select DMA_NONCOHERENT select SYS_HAS_EARLY_PRINTK select IRQ_CPU @@ -200,6 +208,7 @@ config MIPS_MALTA bool "MIPS Malta board" select ARCH_MAY_HAVE_PC_FDC select BOOT_ELF32 + select CEVT_R4K select DMA_NONCOHERENT select GENERIC_ISA_DMA select IRQ_CPU @@ -230,6 +239,7 @@ config MIPS_MALTA config MIPS_SEAD bool "MIPS SEAD board" + select CEVT_R4K select IRQ_CPU select DMA_NONCOHERENT select SYS_HAS_EARLY_PRINTK @@ -248,6 +258,7 @@ config MIPS_SEAD config MIPS_SIM bool 'MIPS simulator (MIPSsim)' + select CEVT_R4K select DMA_NONCOHERENT select SYS_HAS_EARLY_PRINTK select IRQ_CPU @@ -265,6 +276,7 @@ config MIPS_SIM config MARKEINS bool "NEC EMMA2RH Mark-eins" + select CEVT_R4K select DMA_NONCOHERENT select HW_HAS_PCI select IRQ_CPU @@ -279,6 +291,7 @@ config MARKEINS config MACH_VR41XX bool "NEC VR4100 series based machines" + select CEVT_R4K select SYS_HAS_CPU_VR41XX select GENERIC_HARDIRQS_NO__DO_IRQ @@ -315,6 +328,7 @@ config PMC_MSP config PMC_YOSEMITE bool "PMC-Sierra Yosemite eval board" + select CEVT_R4K select DMA_COHERENT select HW_HAS_PCI select IRQ_CPU @@ -335,6 +349,7 @@ config PMC_YOSEMITE config QEMU bool "Qemu" + select CEVT_R4K select DMA_COHERENT select GENERIC_ISA_DMA select HAVE_STD_PC_SERIAL_PORT @@ -365,6 +380,7 @@ config SGI_IP22 select ARC select ARC32 select BOOT_ELF32 + select CEVT_R4K select DMA_NONCOHERENT select HW_HAS_EISA select I8253 @@ -409,6 +425,7 @@ config SGI_IP32 select ARC select ARC32 select BOOT_ELF32 + select CEVT_R4K select DMA_NONCOHERENT select HW_HAS_PCI select IRQ_CPU @@ -536,6 +553,7 @@ config SNI_RM select ARC32 if CPU_LITTLE_ENDIAN select ARCH_MAY_HAVE_PC_FDC select BOOT_ELF32 + select CEVT_R4K select DMA_NONCOHERENT select GENERIC_ISA_DMA select HW_HAS_EISA @@ -577,6 +595,7 @@ config TOSHIBA_JMR3927 config TOSHIBA_RBTX4927 bool "Toshiba RBTX49[23]7 board" + select CEVT_R4K select DMA_NONCOHERENT select HAS_TXX9_SERIAL select HW_HAS_PCI @@ -597,6 +616,7 @@ config TOSHIBA_RBTX4927 config TOSHIBA_RBTX4938 bool "Toshiba RBTX4938 board" + select CEVT_R4K select DMA_NONCOHERENT select HAS_TXX9_SERIAL select HW_HAS_PCI @@ -616,6 +636,7 @@ config TOSHIBA_RBTX4938 config WR_PPMC bool "Wind River PPMC board" + select CEVT_R4K select IRQ_CPU select BOOT_ELF32 select DMA_NONCOHERENT @@ -708,6 +729,9 @@ config ARCH_MAY_HAVE_PC_FDC config BOOT_RAW bool +config CEVT_R4K + bool + config CFE bool diff --git a/arch/mips/au1000/Kconfig b/arch/mips/au1000/Kconfig index a23d4154da01..b36cec58a9a8 100644 --- a/arch/mips/au1000/Kconfig +++ b/arch/mips/au1000/Kconfig @@ -137,6 +137,7 @@ config SOC_AU1200 config SOC_AU1X00 bool select 64BIT_PHYS_ADDR + select CEVT_R4K select IRQ_CPU select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_32BIT_KERNEL diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index 835b056cea36..ae25b480723e 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -4,7 +4,7 @@ * for more details. * * Copyright (C) 1992 Linus Torvalds - * Copyright (C) 1994 - 2001, 2003 Ralf Baechle + * Copyright (C) 1994 - 2001, 2003, 07 Ralf Baechle */ #include <linux/clockchips.h> #include <linux/init.h> @@ -13,6 +13,7 @@ #include <linux/spinlock.h> #include <asm/irq_cpu.h> +#include <asm/i8253.h> #include <asm/i8259.h> #include <asm/io.h> #include <asm/jazz.h> @@ -136,7 +137,7 @@ static struct irqaction r4030_timer_irqaction = { .name = "timer", }; -void __init plat_timer_setup(struct irqaction *ignored) +void __init plat_time_init(void) { struct irqaction *irq = &r4030_timer_irqaction; @@ -152,4 +153,5 @@ void __init plat_timer_setup(struct irqaction *ignored) setup_irq(JAZZ_TIMER_IRQ, irq); clockevents_register_device(&r4030_clockevent); + setup_pit_timer(); } diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index cfc7dce78dab..a7857973ca03 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1997, 1998, 2001 by Ralf Baechle + * Copyright (C) 1996, 1997, 1998, 2001, 07 by Ralf Baechle * Copyright (C) 2001 MIPS Technologies, Inc. * Copyright (C) 2007 by Thomas Bogendoerfer */ @@ -25,7 +25,6 @@ #include <linux/serial_8250.h> #include <asm/bootinfo.h> -#include <asm/i8253.h> #include <asm/irq.h> #include <asm/jazz.h> #include <asm/jazzdma.h> @@ -64,11 +63,6 @@ static struct resource jazz_io_resources[] = { } }; -void __init plat_time_init(void) -{ - setup_pit_timer(); -} - void __init plat_mem_setup(void) { int i; diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index 0c7aee1682cd..edb9e59248ec 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c @@ -1,15 +1,4 @@ -/*********************************************************************** - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ahennessy@mvista.com - * - * Based on arch/mips/ddb5xxx/ddb5477/setup.c - * - * Setup file for JMR3927. - * - * Copyright (C) 2000-2001 Toshiba Corporation - * +/* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -30,9 +19,15 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. * - *********************************************************************** + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Copyright (C) 2000-2001 Toshiba Corporation + * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) */ +#include <linux/clockchips.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/kdev_t.h> @@ -104,27 +99,60 @@ static cycle_t jmr3927_hpt_read(void) return jiffies * (JMR3927_TIMER_CLK / HZ) + jmr3927_tmrptr->trr; } -static void jmr3927_timer_ack(void) +static void jmr3927_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + /* Nothing to do here */ +} + +struct clock_event_device jmr3927_clock_event_device = { + .name = "MIPS", + .features = CLOCK_EVT_FEAT_PERIODIC, + .shift = 32, + .rating = 300, + .cpumask = CPU_MASK_CPU0, + .irq = JMR3927_IRQ_TICK, + .set_mode = jmr3927_set_mode, +}; + +static irqreturn_t jmr3927_timer_interrupt(int irq, void *dev_id) { + struct clock_event_device *cd = &jmr3927_clock_event_device; + jmr3927_tmrptr->tisr = 0; /* ack interrupt */ + + cd->event_handler(cd); + + return IRQ_HANDLED; } +static struct irqaction jmr3927_timer_irqaction = { + .handler = jmr3927_timer_interrupt, + .flags = IRQF_DISABLED | IRQF_PERCPU, + .name = "jmr3927-timer", +}; + void __init plat_time_init(void) { + struct clock_event_device *cd; + clocksource_mips.read = jmr3927_hpt_read; - mips_timer_ack = jmr3927_timer_ack; mips_hpt_frequency = JMR3927_TIMER_CLK; -} -void __init plat_timer_setup(struct irqaction *irq) -{ jmr3927_tmrptr->cpra = JMR3927_TIMER_CLK / HZ; jmr3927_tmrptr->itmr = TXx927_TMTITMR_TIIE | TXx927_TMTITMR_TZCE; jmr3927_tmrptr->ccdr = JMR3927_TIMER_CCD; jmr3927_tmrptr->tcr = TXx927_TMTCR_TCE | TXx927_TMTCR_CCDE | TXx927_TMTCR_TMODE_ITVL; - setup_irq(JMR3927_IRQ_TICK, irq); + cd = &jmr3927_clock_event_device; + /* Calculate the min / max delta */ + cd->mult = div_sc((unsigned long) JMR3927_IMCLK, NSEC_PER_SEC, 32); + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + clockevents_register_device(cd); + + setup_irq(JMR3927_IRQ_TICK, &jmr3927_timer_irqaction); } #define DO_WRITE_THROUGH diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 95a356ef3910..a3afa39faae5 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -8,6 +8,8 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ ptrace.o reset.o semaphore.o setup.o signal.o syscall.o \ time.o topology.o traps.o unaligned.o +obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o + binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ irix5sys.o sysirix.o diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c new file mode 100644 index 000000000000..08b84d476c87 --- /dev/null +++ b/arch/mips/kernel/cevt-r4k.c @@ -0,0 +1,272 @@ +/* + * 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 + * for more details. + * + * Copyright (C) 2007 MIPS Technologies, Inc. + * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org> + */ +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/percpu.h> + +#include <asm/time.h> + +static int mips_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + unsigned int cnt; + int res; + +#ifdef CONFIG_MIPS_MT_SMTC + { + unsigned long flags, vpflags; + local_irq_save(flags); + vpflags = dvpe(); +#endif + cnt = read_c0_count(); + cnt += delta; + write_c0_compare(cnt); + res = ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; +#ifdef CONFIG_MIPS_MT_SMTC + evpe(vpflags); + local_irq_restore(flags); + } +#endif + return res; +} + +static void mips_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + /* Nothing to do ... */ +} + +static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); +static int cp0_timer_irq_installed; + +/* + * Timer ack for an R4k-compatible timer of a known frequency. + */ +static void c0_timer_ack(void) +{ + write_c0_compare(read_c0_compare()); +} + +/* + * Possibly handle a performance counter interrupt. + * Return true if the timer interrupt should not be checked + */ +static inline int handle_perf_irq(int r2) +{ + /* + * The performance counter overflow interrupt may be shared with the + * timer interrupt (cp0_perfcount_irq < 0). If it is and a + * performance counter has overflowed (perf_irq() == IRQ_HANDLED) + * and we can't reliably determine if a counter interrupt has also + * happened (!r2) then don't check for a timer interrupt. + */ + return (cp0_perfcount_irq < 0) && + perf_irq() == IRQ_HANDLED && + !r2; +} + +static irqreturn_t c0_compare_interrupt(int irq, void *dev_id) +{ + const int r2 = cpu_has_mips_r2; + struct clock_event_device *cd; + int cpu = smp_processor_id(); + + /* + * Suckage alert: + * Before R2 of the architecture there was no way to see if a + * performance counter interrupt was pending, so we have to run + * the performance counter interrupt handler anyway. + */ + if (handle_perf_irq(r2)) + goto out; + + /* + * The same applies to performance counter interrupts. But with the + * above we now know that the reason we got here must be a timer + * interrupt. Being the paranoiacs we are we check anyway. + */ + if (!r2 || (read_c0_cause() & (1 << 30))) { + c0_timer_ack(); +#ifdef CONFIG_MIPS_MT_SMTC + if (cpu_data[cpu].vpe_id) + goto out; + cpu = 0; +#endif + cd = &per_cpu(mips_clockevent_device, cpu); + cd->event_handler(cd); + } + +out: + return IRQ_HANDLED; +} + +static struct irqaction c0_compare_irqaction = { + .handler = c0_compare_interrupt, +#ifdef CONFIG_MIPS_MT_SMTC + .flags = IRQF_DISABLED, +#else + .flags = IRQF_DISABLED | IRQF_PERCPU, +#endif + .name = "timer", +}; + +#ifdef CONFIG_MIPS_MT_SMTC +DEFINE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); + +static void smtc_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ +} + +static void mips_broadcast(cpumask_t mask) +{ + unsigned int cpu; + + for_each_cpu_mask(cpu, mask) + smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); +} + +static void setup_smtc_dummy_clockevent_device(void) +{ + //uint64_t mips_freq = mips_hpt_^frequency; + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd; + + cd = &per_cpu(smtc_dummy_clockevent_device, cpu); + + cd->name = "SMTC"; + cd->features = CLOCK_EVT_FEAT_DUMMY; + + /* Calculate the min / max delta */ + cd->mult = 0; //div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); + cd->shift = 0; //32; + cd->max_delta_ns = 0; //clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = 0; //clockevent_delta2ns(0x30, cd); + + cd->rating = 200; + cd->irq = 17; //-1; +// if (cpu) +// cd->cpumask = CPU_MASK_ALL; // cpumask_of_cpu(cpu); +// else + cd->cpumask = cpumask_of_cpu(cpu); + + cd->set_mode = smtc_set_mode; + + cd->broadcast = mips_broadcast; + + clockevents_register_device(cd); +} +#endif + +static void mips_event_handler(struct clock_event_device *dev) +{ +} + +/* + * FIXME: This doesn't hold for the relocated E9000 compare interrupt. + */ +static int c0_compare_int_pending(void) +{ + return (read_c0_cause() >> cp0_compare_irq) & 0x100; +} + +static int c0_compare_int_usable(void) +{ + const unsigned int delta = 0x300000; + unsigned int cnt; + + /* + * IP7 already pending? Try to clear it by acking the timer. + */ + if (c0_compare_int_pending()) { + write_c0_compare(read_c0_compare()); + irq_disable_hazard(); + if (c0_compare_int_pending()) + return 0; + } + + cnt = read_c0_count(); + cnt += delta; + write_c0_compare(cnt); + + while ((long)(read_c0_count() - cnt) <= 0) + ; /* Wait for expiry */ + + if (!c0_compare_int_pending()) + return 0; + + write_c0_compare(read_c0_compare()); + irq_disable_hazard(); + if (c0_compare_int_pending()) + return 0; + + /* + * Feels like a real count / compare timer. + */ + return 1; +} + +void __cpuinit mips_clockevent_init(void) +{ + uint64_t mips_freq = mips_hpt_frequency; + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd; + unsigned int irq = MIPS_CPU_IRQ_BASE + 7; + + if (!cpu_has_counter) + return; + +#ifdef CONFIG_MIPS_MT_SMTC + setup_smtc_dummy_clockevent_device(); + + /* + * On SMTC we only register VPE0's compare interrupt as clockevent + * device. + */ + if (cpu) + return; +#endif + + if (!c0_compare_int_usable()) + return; + + cd = &per_cpu(mips_clockevent_device, cpu); + + cd->name = "MIPS"; + cd->features = CLOCK_EVT_FEAT_ONESHOT; + + /* Calculate the min / max delta */ + cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); + cd->shift = 32; + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + + cd->rating = 300; + cd->irq = irq; +#ifdef CONFIG_MIPS_MT_SMTC + cd->cpumask = CPU_MASK_ALL; +#else + cd->cpumask = cpumask_of_cpu(cpu); +#endif + cd->set_next_event = mips_next_event; + cd->set_mode = mips_set_mode; + cd->event_handler = mips_event_handler; + + clockevents_register_device(cd); + + if (!cp0_timer_irq_installed) { +#ifdef CONFIG_MIPS_MT_SMTC +#define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq) + setup_irq_smtc(irq, &c0_compare_irqaction, CPUCTR_IMASKBIT); +#else + setup_irq(irq, &c0_compare_irqaction); +#endif /* CONFIG_MIPS_MT_SMTC */ + cp0_timer_irq_installed = 1; + } +} diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index bf164a562acb..236768731063 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -27,16 +27,6 @@ #include <kernel-entry-init.h> - .macro ARC64_TWIDDLE_PC -#if defined(CONFIG_ARC64) || defined(CONFIG_MAPPED_KERNEL) - /* We get launched at a XKPHYS address but the kernel is linked to - run at a KSEG0 address, so jump there. */ - PTR_LA t0, \@f - jr t0 -\@: -#endif - .endm - /* * inputs are the text nasid in t1, data nasid in t2. */ @@ -157,7 +147,11 @@ NESTED(kernel_entry, 16, sp) # kernel entry point setup_c0_status_pri - ARC64_TWIDDLE_PC + /* We might not get launched at the address the kernel is linked to, + so we jump there. */ + PTR_LA t0, 0f + jr t0 +0: #ifdef CONFIG_MIPS_MT_SMTC /* diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index e4b5e647b142..ea7cfe766a8e 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -72,14 +72,6 @@ int update_persistent_clock(struct timespec now) return rtc_mips_set_mmss(now.tv_sec); } -/* how many counter cycles in a jiffy */ -static unsigned long cycles_per_jiffy __read_mostly; - -/* - * Null timer ack for systems not needing one (e.g. i8254). - */ -static void null_timer_ack(void) { /* nothing */ } - /* * Null high precision timer functions for systems lacking one. */ @@ -89,14 +81,6 @@ static cycle_t null_hpt_read(void) } /* - * Timer ack for an R4k-compatible timer of a known frequency. - */ -static void c0_timer_ack(void) -{ - write_c0_compare(read_c0_compare()); -} - -/* * High precision timer functions for a R4k-compatible timer. */ static cycle_t c0_hpt_read(void) @@ -105,7 +89,6 @@ static cycle_t c0_hpt_read(void) } int (*mips_timer_state)(void); -void (*mips_timer_ack)(void); /* * local_timer_interrupt() does profiling and process accounting @@ -135,35 +118,6 @@ int (*perf_irq)(void) = null_perf_irq; EXPORT_SYMBOL(perf_irq); /* - * Timer interrupt - */ -int cp0_compare_irq; - -/* - * Performance counter IRQ or -1 if shared with timer - */ -int cp0_perfcount_irq; -EXPORT_SYMBOL_GPL(cp0_perfcount_irq); - -/* - * Possibly handle a performance counter interrupt. - * Return true if the timer interrupt should not be checked - */ -static inline int handle_perf_irq(int r2) -{ - /* - * The performance counter overflow interrupt may be shared with the - * timer interrupt (cp0_perfcount_irq < 0). If it is and a - * performance counter has overflowed (perf_irq() == IRQ_HANDLED) - * and we can't reliably determine if a counter interrupt has also - * happened (!r2) then don't check for a timer interrupt. - */ - return (cp0_perfcount_irq < 0) && - perf_irq() == IRQ_HANDLED && - !r2; -} - -/* * time_init() - it does the following things. * * 1) plat_time_init() - @@ -228,84 +182,6 @@ struct clocksource clocksource_mips = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static int mips_next_event(unsigned long delta, - struct clock_event_device *evt) -{ - unsigned int cnt; - int res; - -#ifdef CONFIG_MIPS_MT_SMTC - { - unsigned long flags, vpflags; - local_irq_save(flags); - vpflags = dvpe(); -#endif - cnt = read_c0_count(); - cnt += delta; - write_c0_compare(cnt); - res = ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; -#ifdef CONFIG_MIPS_MT_SMTC - evpe(vpflags); - local_irq_restore(flags); - } -#endif - return res; -} - -static void mips_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - -static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); -static int cp0_timer_irq_installed; - -static irqreturn_t timer_interrupt(int irq, void *dev_id) -{ - const int r2 = cpu_has_mips_r2; - struct clock_event_device *cd; - int cpu = smp_processor_id(); - - /* - * Suckage alert: - * Before R2 of the architecture there was no way to see if a - * performance counter interrupt was pending, so we have to run - * the performance counter interrupt handler anyway. - */ - if (handle_perf_irq(r2)) - goto out; - - /* - * The same applies to performance counter interrupts. But with the - * above we now know that the reason we got here must be a timer - * interrupt. Being the paranoiacs we are we check anyway. - */ - if (!r2 || (read_c0_cause() & (1 << 30))) { - c0_timer_ack(); -#ifdef CONFIG_MIPS_MT_SMTC - if (cpu_data[cpu].vpe_id) - goto out; - cpu = 0; -#endif - cd = &per_cpu(mips_clockevent_device, cpu); - cd->event_handler(cd); - } - -out: - return IRQ_HANDLED; -} - -static struct irqaction timer_irqaction = { - .handler = timer_interrupt, -#ifdef CONFIG_MIPS_MT_SMTC - .flags = IRQF_DISABLED, -#else - .flags = IRQF_DISABLED | IRQF_PERCPU, -#endif - .name = "timer", -}; - static void __init init_mips_clocksource(void) { u64 temp; @@ -345,8 +221,6 @@ static void smtc_set_mode(enum clock_event_mode mode, { } -int dummycnt[NR_CPUS]; - static void mips_broadcast(cpumask_t mask) { unsigned int cpu; @@ -387,113 +261,6 @@ static void setup_smtc_dummy_clockevent_device(void) } #endif -static void mips_event_handler(struct clock_event_device *dev) -{ -} - -/* - * FIXME: This doesn't hold for the relocated E9000 compare interrupt. - */ -static int c0_compare_int_pending(void) -{ - return (read_c0_cause() >> cp0_compare_irq) & 0x100; -} - -static int c0_compare_int_usable(void) -{ - const unsigned int delta = 0x300000; - unsigned int cnt; - - /* - * IP7 already pending? Try to clear it by acking the timer. - */ - if (c0_compare_int_pending()) { - write_c0_compare(read_c0_compare()); - irq_disable_hazard(); - if (c0_compare_int_pending()) - return 0; - } - - cnt = read_c0_count(); - cnt += delta; - write_c0_compare(cnt); - - while ((long)(read_c0_count() - cnt) <= 0) - ; /* Wait for expiry */ - - if (!c0_compare_int_pending()) - return 0; - - write_c0_compare(read_c0_compare()); - irq_disable_hazard(); - if (c0_compare_int_pending()) - return 0; - - /* - * Feels like a real count / compare timer. - */ - return 1; -} - -void __cpuinit mips_clockevent_init(void) -{ - uint64_t mips_freq = mips_hpt_frequency; - unsigned int cpu = smp_processor_id(); - struct clock_event_device *cd; - unsigned int irq = MIPS_CPU_IRQ_BASE + 7; - - if (!cpu_has_counter) - return; - -#ifdef CONFIG_MIPS_MT_SMTC - setup_smtc_dummy_clockevent_device(); - - /* - * On SMTC we only register VPE0's compare interrupt as clockevent - * device. - */ - if (cpu) - return; -#endif - - if (!c0_compare_int_usable()) - return; - - cd = &per_cpu(mips_clockevent_device, cpu); - - cd->name = "MIPS"; - cd->features = CLOCK_EVT_FEAT_ONESHOT; - - /* Calculate the min / max delta */ - cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); - cd->shift = 32; - cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); - cd->min_delta_ns = clockevent_delta2ns(0x300, cd); - - cd->rating = 300; - cd->irq = irq; -#ifdef CONFIG_MIPS_MT_SMTC - cd->cpumask = CPU_MASK_ALL; -#else - cd->cpumask = cpumask_of_cpu(cpu); -#endif - cd->set_next_event = mips_next_event; - cd->set_mode = mips_set_mode; - cd->event_handler = mips_event_handler; - - clockevents_register_device(cd); - - if (!cp0_timer_irq_installed) { -#ifdef CONFIG_MIPS_MT_SMTC -#define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq) - setup_irq_smtc(irq, &timer_irqaction, CPUCTR_IMASKBIT); -#else - setup_irq(irq, &timer_irqaction); -#endif /* CONFIG_MIPS_MT_SMTC */ - cp0_timer_irq_installed = 1; - } -} - void __init time_init(void) { plat_time_init(); @@ -512,14 +279,6 @@ void __init time_init(void) if (!clocksource_mips.read) { /* No external high precision timer -- use R4k. */ clocksource_mips.read = c0_hpt_read; - - if (!mips_timer_state) { - /* No external timer interrupt -- use R4k. */ - mips_timer_ack = c0_timer_ack; - /* Calculate cache parameters. */ - cycles_per_jiffy = - (mips_hpt_frequency + HZ / 2) / HZ; - } } if (!mips_hpt_frequency) mips_hpt_frequency = calibrate_hpt(); @@ -528,29 +287,8 @@ void __init time_init(void) printk("Using %u.%03u MHz high precision timer.\n", ((mips_hpt_frequency + 500) / 1000) / 1000, ((mips_hpt_frequency + 500) / 1000) % 1000); - -#ifdef CONFIG_IRQ_CPU - setup_irq(MIPS_CPU_IRQ_BASE + 7, &timer_irqaction); -#endif } - if (!mips_timer_ack) - /* No timer interrupt ack (e.g. i8254). */ - mips_timer_ack = null_timer_ack; - - /* - * Call board specific timer interrupt setup. - * - * this pointer must be setup in machine setup routine. - * - * Even if a machine chooses to use a low-level timer interrupt, - * it still needs to setup the timer_irqaction. - * In that case, it might be better to set timer_irqaction.handler - * to be NULL function so that we are sure the high-level code - * is not invoked accidentally. - */ - plat_timer_setup(&timer_irqaction); - init_mips_clocksource(); mips_clockevent_init(); } diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index bbf01b81a4ff..7b78d137259f 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1336,6 +1336,17 @@ extern void cpu_cache_init(void); extern void tlb_init(void); extern void flush_tlb_handlers(void); +/* + * Timer interrupt + */ +int cp0_compare_irq; + +/* + * Performance counter IRQ or -1 if shared with timer + */ +int cp0_perfcount_irq; +EXPORT_SYMBOL_GPL(cp0_perfcount_irq); + void __init per_cpu_trap_init(void) { unsigned int cpu = smp_processor_id(); diff --git a/arch/mips/pmc-sierra/Kconfig b/arch/mips/pmc-sierra/Kconfig index abbd0bbfabd7..6b293ce0935f 100644 --- a/arch/mips/pmc-sierra/Kconfig +++ b/arch/mips/pmc-sierra/Kconfig @@ -4,11 +4,13 @@ choice config PMC_MSP4200_EVAL bool "PMC-Sierra MSP4200 Eval Board" + select CEVT_R4K select IRQ_MSP_SLP select HW_HAS_PCI config PMC_MSP4200_GW bool "PMC-Sierra MSP4200 VoIP Gateway" + select CEVT_R4K select IRQ_MSP_SLP select HW_HAS_PCI diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 856649cf9f1e..1bb692a3b319 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -374,14 +374,13 @@ int __devinit request_bridge_irq(struct bridge_controller *bc) return irq; } -extern void ip27_rt_timer_interrupt(void); - asmlinkage void plat_irq_dispatch(void) { unsigned long pending = read_c0_cause() & read_c0_status(); + extern unsigned int rt_timer_irq; if (pending & CAUSEF_IP4) - ip27_rt_timer_interrupt(); + do_IRQ(rt_timer_irq); else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */ ip27_do_irq_mask0(); else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */ diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index b7b3479b6bce..d467bf4f6c3f 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -3,6 +3,7 @@ * Copytight (C) 1999, 2000 Silicon Graphics, Inc. */ #include <linux/bcd.h> +#include <linux/clockchips.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -25,22 +26,8 @@ #include <asm/sn/sn0/ip27.h> #include <asm/sn/sn0/hub.h> -/* - * This is a hack; we really need to figure these values out dynamically - * - * Since 800 ns works very well with various HUB frequencies, such as - * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time. - * - * Ralf: which clock rate is used to feed the counter? - */ -#define NSEC_PER_CYCLE 800 -#define CYCLES_PER_SEC (NSEC_PER_SEC/NSEC_PER_CYCLE) -#define CYCLES_PER_JIFFY (CYCLES_PER_SEC/HZ) - #define TICK_SIZE (tick_nsec / 1000) -static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */ - #if 0 static int set_rtc_mmss(unsigned long nowtime) { @@ -86,36 +73,6 @@ static int set_rtc_mmss(unsigned long nowtime) } #endif -static unsigned int rt_timer_irq; - -void ip27_rt_timer_interrupt(void) -{ - int cpu = smp_processor_id(); - int cpuA = cputoslice(cpu) == 0; - unsigned int irq = rt_timer_irq; - - irq_enter(); - write_seqlock(&xtime_lock); - -again: - LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ - ct_cur[cpu] += CYCLES_PER_JIFFY; - LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]); - - if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) - goto again; - - kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */ - - if (cpu == 0) - do_timer(1); - - update_process_times(user_mode(get_irq_regs())); - - write_sequnlock(&xtime_lock); - irq_exit(); -} - /* Includes for ioc3_init(). */ #include <asm/sn/types.h> #include <asm/sn/sn0/addrs.h> @@ -154,6 +111,46 @@ unsigned long read_persistent_clock(void) return mktime(year, month, date, hour, min, sec); } +static int rt_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + int slice = cputoslice(cpu) == 0; + unsigned long cnt; + + cnt = LOCAL_HUB_L(PI_RT_COUNT); + cnt += delta; + LOCAL_HUB_S(slice ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, cnt); + + return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; +} + +static void rt_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* The only mode supported */ + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_RESUME: + /* Nothing to do */ + break; + } +} + +struct clock_event_device rt_clock_event_device = { + .name = "HUB-RT", + .features = CLOCK_EVT_FEAT_ONESHOT, + + .rating = 300, + .set_next_event = rt_set_next_event, + .set_mode = rt_set_mode, +}; + static void enable_rt_irq(unsigned int irq) { } @@ -171,6 +168,20 @@ static struct irq_chip rt_irq_type = { .eoi = enable_rt_irq, }; +unsigned int rt_timer_irq; + +static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *cd = &rt_clock_event_device; + unsigned int cpu = smp_processor_id(); + int slice = cputoslice(cpu) == 0; + + LOCAL_HUB_S(slice ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ + cd->event_handler(cd); + + return IRQ_HANDLED; +} + static struct irqaction rt_irqaction = { .handler = (irq_handler_t) ip27_rt_timer_interrupt, .flags = IRQF_DISABLED, @@ -178,26 +189,43 @@ static struct irqaction rt_irqaction = { .name = "timer" }; -void __init plat_timer_setup(struct irqaction *irq) +/* + * This is a hack; we really need to figure these values out dynamically + * + * Since 800 ns works very well with various HUB frequencies, such as + * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time. + * + * Ralf: which clock rate is used to feed the counter? + */ +#define NSEC_PER_CYCLE 800 +#define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE) + +static void __init ip27_rt_clock_event_init(void) { - int irqno = allocate_irqno(); + struct clock_event_device *cd = &rt_clock_event_device; + unsigned int cpu = smp_processor_id(); + int irq = allocate_irqno(); - if (irqno < 0) + if (irq < 0) panic("Can't allocate interrupt number for timer interrupt"); - set_irq_chip_and_handler(irqno, &rt_irq_type, handle_percpu_irq); + rt_timer_irq = irq; - /* over-write the handler, we use our own way */ - irq->handler = no_action; + cd->irq = irq, + cd->cpumask = cpumask_of_cpu(cpu), - /* setup irqaction */ - irq_desc[irqno].status |= IRQ_PER_CPU; - - rt_timer_irq = irqno; /* - * Only needed to get /proc/interrupt to display timer irq stats + * Calculate the min / max delta */ - setup_irq(irqno, &rt_irqaction); + cd->mult = + div_sc((unsigned long) CYCLES_PER_SEC, NSEC_PER_SEC, 32); + cd->shift = 32; + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + clockevents_register_device(cd); + + set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq); + setup_irq(irq, &rt_irqaction); } static cycle_t hub_rt_read(void) @@ -206,7 +234,7 @@ static cycle_t hub_rt_read(void) } struct clocksource ht_rt_clocksource = { - .name = "HUB", + .name = "HUB-RT", .rating = 200, .read = hub_rt_read, .mask = CLOCKSOURCE_MASK(52), @@ -214,11 +242,17 @@ struct clocksource ht_rt_clocksource = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -void __init plat_time_init(void) +static void __init ip27_rt_clocksource_init(void) { clocksource_register(&ht_rt_clocksource); } +void __init plat_time_init(void) +{ + ip27_rt_clock_event_init(); + ip27_rt_clocksource_init(); +} + void __init cpu_time_init(void) { lboard_t *board; @@ -248,17 +282,12 @@ void __init hub_rtc_init(cnodeid_t cnode) * node and timeouts will not happen there. */ if (get_compact_nodeid() == cnode) { - int cpu = smp_processor_id(); LOCAL_HUB_S(PI_RT_EN_A, 1); LOCAL_HUB_S(PI_RT_EN_B, 1); LOCAL_HUB_S(PI_PROF_EN_A, 0); LOCAL_HUB_S(PI_PROF_EN_B, 0); - ct_cur[cpu] = CYCLES_PER_JIFFY; - LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur[cpu]); LOCAL_HUB_S(PI_RT_COUNT, 0); LOCAL_HUB_S(PI_RT_PEND_A, 0); - LOCAL_HUB_S(PI_RT_COMPARE_B, ct_cur[cpu]); - LOCAL_HUB_S(PI_RT_COUNT, 0); LOCAL_HUB_S(PI_RT_PEND_B, 0); } } diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c index fc75bfcb0c0e..1024bf40bd9e 100644 --- a/arch/mips/sgi-ip32/ip32-setup.c +++ b/arch/mips/sgi-ip32/ip32-setup.c @@ -80,12 +80,6 @@ void __init plat_time_init(void) printk("%d MHz CPU detected\n", mips_hpt_frequency * 2 / 1000000); } -void __init plat_timer_setup(struct irqaction *irq) -{ - irq->handler = no_action; - setup_irq(MIPS_CPU_IRQ_BASE + 7, irq); -} - void __init plat_mem_setup(void) { board_be_init = ip32_be_init; diff --git a/arch/mips/vr41xx/Kconfig b/arch/mips/vr41xx/Kconfig index 8f4d3e74c230..eeb089f20c0d 100644 --- a/arch/mips/vr41xx/Kconfig +++ b/arch/mips/vr41xx/Kconfig @@ -5,6 +5,7 @@ choice config CASIO_E55 bool "CASIO CASSIOPEIA E-10/15/55/65" + select CEVT_R4K select DMA_NONCOHERENT select IRQ_CPU select ISA @@ -13,6 +14,7 @@ config CASIO_E55 config IBM_WORKPAD bool "IBM WorkPad z50" + select CEVT_R4K select DMA_NONCOHERENT select IRQ_CPU select ISA @@ -21,6 +23,7 @@ config IBM_WORKPAD config NEC_CMBVR4133 bool "NEC CMB-VR4133" + select CEVT_R4K select DMA_NONCOHERENT select IRQ_CPU select HW_HAS_PCI @@ -29,6 +32,7 @@ config NEC_CMBVR4133 config TANBAC_TB022X bool "TANBAC VR4131 multichip module and TANBAC VR4131DIMM" + select CEVT_R4K select DMA_NONCOHERENT select IRQ_CPU select HW_HAS_PCI @@ -43,6 +47,7 @@ config TANBAC_TB022X config VICTOR_MPC30X bool "Victor MP-C303/304" + select CEVT_R4K select DMA_NONCOHERENT select IRQ_CPU select HW_HAS_PCI @@ -52,6 +57,7 @@ config VICTOR_MPC30X config ZAO_CAPCELLA bool "ZAO Networks Capcella" + select CEVT_R4K select DMA_NONCOHERENT select IRQ_CPU select HW_HAS_PCI diff --git a/include/asm-mips/mach-ip27/kernel-entry-init.h b/include/asm-mips/mach-ip27/kernel-entry-init.h index c1a10314b317..624d66c7f290 100644 --- a/include/asm-mips/mach-ip27/kernel-entry-init.h +++ b/include/asm-mips/mach-ip27/kernel-entry-init.h @@ -46,7 +46,14 @@ lh t1, KV_RO_NASID_OFFSET(t0) lh t2, KV_RW_NASID_OFFSET(t0) MAPPED_KERNEL_SETUP_TLB - ARC64_TWIDDLE_PC + + /* + * We might not get launched at the address the kernel is linked to, + * so we jump there. + */ + PTR_LA t0, 0f + jr t0 +0: .endm #endif /* __ASM_MACH_IP27_KERNEL_ENTRY_H */ diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 35555bd5c52d..cf76f4f7435f 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -40,7 +40,6 @@ extern int rtc_mips_set_mmss(unsigned long); * mips_timer_ack may be NULL if the interrupt is self-recoverable. */ extern int (*mips_timer_state)(void); -extern void (*mips_timer_ack)(void); /* * High precision timer clocksource. @@ -76,6 +75,12 @@ extern int (*perf_irq)(void); /* * Initialize the calling CPU's compare interrupt as clockevent device */ +#ifdef CONFIG_CEVT_R4K extern void mips_clockevent_init(void); +#else +static inline void mips_clockevent_init(void) +{ +} +#endif #endif /* _ASM_TIME_H */ |