Browse Source

Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus

* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus:
  [MIPS] time: Make c0_compare_int_usable more bullet proof
  [MIPS] Kbuild: Use the new cc-cross-prefix feature.
  [MIPS] Fix include wrapper symbol to something sane.
  [MIPS] Malta: Delete dead code.
  [MIPS] time: Add GT641xx timer0 clockevent driver
  [MIPS] time: SMP-proofing of Sibyte clockevent/clocksource code.
  [MIPS] time: SMP/NUMA-proofing of IP27 HUB RT timer code.
  [MIPS] time: Fix calculation in clockevent_set_clock()
Linus Torvalds 18 years ago
parent
commit
f10f114f19

+ 4 - 0
arch/mips/Kconfig

@@ -66,6 +66,7 @@ config BCM47XX
 config MIPS_COBALT
 	bool "Cobalt Server"
 	select CEVT_R4K
+	select CEVT_GT641XX
 	select DMA_NONCOHERENT
 	select HW_HAS_PCI
 	select I8253
@@ -729,6 +730,9 @@ config ARCH_MAY_HAVE_PC_FDC
 config BOOT_RAW
 	bool
 
+config CEVT_GT641XX
+	bool
+
 config CEVT_R4K
 	bool
 

+ 0 - 12
arch/mips/Kconfig.debug

@@ -6,18 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
-config CROSSCOMPILE
-	bool "Are you using a crosscompiler"
-	help
-	  Say Y here if you are compiling the kernel on a different
-	  architecture than the one it is intended to run on.  This is just a
-	  convenience option which will select the appropriate value for
-	  the CROSS_COMPILE make variable which otherwise has to be passed on
-	  the command line from mips-linux-, mipsel-linux-, mips64-linux- and
-	  mips64el-linux- as appropriate for a particular kernel configuration.
-	  You will have to pass the value for CROSS_COMPILE manually if the
-	  name prefix for your tools is different.
-
 config CMDLINE
 	string "Default kernel command string"
 	default ""

+ 10 - 8
arch/mips/Makefile

@@ -18,15 +18,15 @@ cflags-y :=
 # Select the object file format to substitute into the linker script.
 #
 ifdef CONFIG_CPU_LITTLE_ENDIAN
-32bit-tool-prefix	= mipsel-linux-
-64bit-tool-prefix	= mips64el-linux-
+32bit-tool-archpref	= mipsel
+64bit-tool-archpref	= mips64el
 32bit-bfd		= elf32-tradlittlemips
 64bit-bfd		= elf64-tradlittlemips
 32bit-emul		= elf32ltsmip
 64bit-emul		= elf64ltsmip
 else
-32bit-tool-prefix	= mips-linux-
-64bit-tool-prefix	= mips64-linux-
+32bit-tool-archpref	= mips
+64bit-tool-archpref	= mips64
 32bit-bfd		= elf32-tradbigmips
 64bit-bfd		= elf64-tradbigmips
 32bit-emul		= elf32btsmip
@@ -34,16 +34,18 @@ else
 endif
 
 ifdef CONFIG_32BIT
-tool-prefix		= $(32bit-tool-prefix)
+tool-archpref		= $(32bit-tool-archpref)
 UTS_MACHINE		:= mips
 endif
 ifdef CONFIG_64BIT
-tool-prefix		= $(64bit-tool-prefix)
+tool-archpref		= $(64bit-tool-archpref)
 UTS_MACHINE		:= mips64
 endif
 
-ifdef CONFIG_CROSSCOMPILE
-CROSS_COMPILE		:= $(tool-prefix)
+ifneq ($(SUBARCH),$(ARCH))
+  ifeq ($(CROSS_COMPILE),)
+    CROSS_COMPILE := $(call cc-cross-prefix, $(tool-archpref)-linux-  $(tool-archpref)-gnu-linux-  $(tool-archpref)-unknown-gnu-linux-)
+  endif
 endif
 
 ifdef CONFIG_32BIT

+ 1 - 1
arch/mips/cobalt/Makefile

@@ -2,7 +2,7 @@
 # Makefile for the Cobalt micro systems family specific parts of the kernel
 #
 
-obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o
+obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o time.o
 
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_EARLY_PRINTK)	+= console.o

+ 3 - 21
arch/mips/cobalt/setup.c

@@ -9,19 +9,17 @@
  * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
  *
  */
-#include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
 #include <linux/pm.h>
 
 #include <asm/bootinfo.h>
-#include <asm/time.h>
-#include <asm/i8253.h>
-#include <asm/io.h>
 #include <asm/reboot.h>
 #include <asm/gt64120.h>
 
 #include <cobalt.h>
-#include <irq.h>
 
 extern void cobalt_machine_restart(char *command);
 extern void cobalt_machine_halt(void);
@@ -41,17 +39,6 @@ const char *get_system_type(void)
 	return "MIPS Cobalt";
 }
 
-void __init plat_timer_setup(struct irqaction *irq)
-{
-	/* Load timer value for HZ (TCLK is 50MHz) */
-	GT_WRITE(GT_TC0_OFS, 50*1000*1000 / HZ);
-
-	/* Enable timer0 */
-	GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
-
-	setup_irq(GT641XX_TIMER0_IRQ, irq);
-}
-
 /*
  * Cobalt doesn't have PS/2 keyboard/mouse interfaces,
  * keyboard conntroller is never used.
@@ -84,11 +71,6 @@ static struct resource cobalt_reserved_resources[] = {
 	},
 };
 
-void __init plat_time_init(void)
-{
-	setup_pit_timer();
-}
-
 void __init plat_mem_setup(void)
 {
 	int i;

+ 35 - 0
arch/mips/cobalt/time.c

@@ -0,0 +1,35 @@
+/*
+ *  Cobalt time initialization.
+ *
+ *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  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 option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/init.h>
+
+#include <asm/gt64120.h>
+#include <asm/i8253.h>
+#include <asm/time.h>
+
+#define GT641XX_BASE_CLOCK	50000000	/* 50MHz */
+
+void __init plat_time_init(void)
+{
+	setup_pit_timer();
+
+	gt641xx_set_base_clock(GT641XX_BASE_CLOCK);
+
+	mips_timer_state = gt641xx_timer0_state;
+}

+ 1 - 0
arch/mips/kernel/Makefile

@@ -9,6 +9,7 @@ obj-y		+= cpu-probe.o branch.o entry.o genex.o irq.o process.o \
 		   time.o topology.o traps.o unaligned.o
 
 obj-$(CONFIG_CEVT_R4K)		+= cevt-r4k.o
+obj-$(CONFIG_CEVT_GT641XX)	+= cevt-gt641xx.o
 
 binfmt_irix-objs	:= irixelf.o irixinv.o irixioctl.o irixsig.o	\
 			   irix5sys.o sysirix.o

+ 144 - 0
arch/mips/kernel/cevt-gt641xx.c

@@ -0,0 +1,144 @@
+/*
+ *  GT641xx clockevent routines.
+ *
+ *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  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 option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/gt64120.h>
+#include <asm/time.h>
+
+#include <irq.h>
+
+static DEFINE_SPINLOCK(gt641xx_timer_lock);
+static unsigned int gt641xx_base_clock;
+
+void gt641xx_set_base_clock(unsigned int clock)
+{
+	gt641xx_base_clock = clock;
+}
+
+int gt641xx_timer0_state(void)
+{
+	if (GT_READ(GT_TC0_OFS))
+		return 0;
+
+	GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
+	GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK);
+
+	return 1;
+}
+
+static int gt641xx_timer0_set_next_event(unsigned long delta,
+					 struct clock_event_device *evt)
+{
+	unsigned long flags;
+	u32 ctrl;
+
+	spin_lock_irqsave(&gt641xx_timer_lock, flags);
+
+	ctrl = GT_READ(GT_TC_CONTROL_OFS);
+	ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
+	ctrl |= GT_TC_CONTROL_ENTC0_MSK;
+
+	GT_WRITE(GT_TC0_OFS, delta);
+	GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
+
+	spin_unlock_irqrestore(&gt641xx_timer_lock, flags);
+
+	return 0;
+}
+
+static void gt641xx_timer0_set_mode(enum clock_event_mode mode,
+				    struct clock_event_device *evt)
+{
+	unsigned long flags;
+	u32 ctrl;
+
+	spin_lock_irqsave(&gt641xx_timer_lock, flags);
+
+	ctrl = GT_READ(GT_TC_CONTROL_OFS);
+	ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK;
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		ctrl |= GT_TC_CONTROL_ENTC0_MSK;
+		break;
+	default:
+		break;
+	}
+
+	GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
+
+	spin_unlock_irqrestore(&gt641xx_timer_lock, flags);
+}
+
+static void gt641xx_timer0_event_handler(struct clock_event_device *dev)
+{
+}
+
+static struct clock_event_device gt641xx_timer0_clockevent = {
+	.name		= "gt641xx-timer0",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.cpumask	= CPU_MASK_CPU0,
+	.irq		= GT641XX_TIMER0_IRQ,
+	.set_next_event	= gt641xx_timer0_set_next_event,
+	.set_mode	= gt641xx_timer0_set_mode,
+	.event_handler	= gt641xx_timer0_event_handler,
+};
+
+static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *cd = &gt641xx_timer0_clockevent;
+
+	cd->event_handler(cd);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction gt641xx_timer0_irqaction = {
+	.handler	= gt641xx_timer0_interrupt,
+	.flags		= IRQF_DISABLED | IRQF_PERCPU,
+	.name		= "gt641xx_timer0",
+};
+
+static int __init gt641xx_timer0_clockevent_init(void)
+{
+	struct clock_event_device *cd;
+
+	if (!gt641xx_base_clock)
+		return 0;
+
+	GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
+
+	cd = &gt641xx_timer0_clockevent;
+	cd->rating = 200 + gt641xx_base_clock / 10000000;
+	cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
+	cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
+	clockevent_set_clock(cd, gt641xx_base_clock);
+
+	clockevents_register_device(&gt641xx_timer0_clockevent);
+
+	return setup_irq(GT641XX_TIMER0_IRQ, &gt641xx_timer0_irqaction);
+}
+arch_initcall(gt641xx_timer0_clockevent_init);

+ 2 - 2
arch/mips/kernel/cevt-r4k.c

@@ -186,7 +186,7 @@ static int c0_compare_int_usable(void)
 	 * IP7 already pending?  Try to clear it by acking the timer.
 	 */
 	if (c0_compare_int_pending()) {
-		write_c0_compare(read_c0_compare());
+		write_c0_compare(read_c0_count());
 		irq_disable_hazard();
 		if (c0_compare_int_pending())
 			return 0;
@@ -202,7 +202,7 @@ static int c0_compare_int_usable(void)
 	if (!c0_compare_int_pending())
 		return 0;
 
-	write_c0_compare(read_c0_compare());
+	write_c0_compare(read_c0_count());
 	irq_disable_hazard();
 	if (c0_compare_int_pending())
 		return 0;

+ 2 - 2
arch/mips/kernel/time.c

@@ -195,8 +195,8 @@ void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
 
 	/* Find a shift value */
 	for (shift = 32; shift > 0; shift--) {
-		temp = (u64) NSEC_PER_SEC << shift;
-		do_div(temp, clock);
+		temp = (u64) clock << shift;
+		do_div(temp, NSEC_PER_SEC);
 		if ((temp >> 32) == 0)
 			break;
 	}

+ 0 - 13
arch/mips/mips-boards/generic/time.c

@@ -147,21 +147,8 @@ void __init plat_time_init(void)
 #endif
 }
 
-//static irqreturn_t mips_perf_interrupt(int irq, void *dev_id)
-//{
-//	return perf_irq();
-//}
-
-//static struct irqaction perf_irqaction = {
-//	.handler = mips_perf_interrupt,
-//	.flags = IRQF_DISABLED | IRQF_PERCPU,
-//	.name = "performance",
-//};
-
 void __init plat_perf_setup(void)
 {
-//	struct irqaction *irq = &perf_irqaction;
-
 	cp0_perfcount_irq = -1;
 
 #ifdef MSC01E_INT_BASE

+ 1 - 1
arch/mips/sgi-ip27/ip27-init.c

@@ -110,7 +110,7 @@ static void __init per_hub_init(cnodeid_t cnode)
 	}
 }
 
-void __init per_cpu_init(void)
+void __cpuinit per_cpu_init(void)
 {
 	int cpu = smp_processor_id();
 	int slice = LOCAL_HUB_L(PI_CPU_NUM);

+ 71 - 63
arch/mips/sgi-ip27/ip27-timer.c

@@ -111,8 +111,24 @@ 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)
+static void enable_rt_irq(unsigned int irq)
+{
+}
+
+static void disable_rt_irq(unsigned int irq)
+{
+}
+
+static struct irq_chip rt_irq_type = {
+	.name		= "SN HUB RT timer",
+	.ack		= disable_rt_irq,
+	.mask		= disable_rt_irq,
+	.mask_ack	= disable_rt_irq,
+	.unmask		= enable_rt_irq,
+	.eoi		= enable_rt_irq,
+};
+
+static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
 {
 	unsigned int cpu = smp_processor_id();
 	int slice = cputoslice(cpu) == 0;
@@ -129,50 +145,24 @@ static void rt_set_mode(enum clock_event_mode mode,
 		struct clock_event_device *evt)
 {
 	switch (mode) {
-	case CLOCK_EVT_MODE_PERIODIC:
+	case CLOCK_EVT_MODE_ONESHOT:
 		/* The only mode supported */
 		break;
 
+	case CLOCK_EVT_MODE_PERIODIC:
 	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)
-{
-}
-
-static void disable_rt_irq(unsigned int irq)
-{
-}
-
-static struct irq_chip rt_irq_type = {
-	.name		= "SN HUB RT timer",
-	.ack		= disable_rt_irq,
-	.mask		= disable_rt_irq,
-	.mask_ack	= disable_rt_irq,
-	.unmask		= enable_rt_irq,
-	.eoi		= enable_rt_irq,
-};
-
 unsigned int rt_timer_irq;
 
-static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id)
+static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
 {
-	struct clock_event_device *cd = &rt_clock_event_device;
+	struct clock_event_device *cd = dev_id;
 	unsigned int cpu = smp_processor_id();
 	int slice = cputoslice(cpu) == 0;
 
@@ -182,11 +172,10 @@ static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static struct irqaction rt_irqaction = {
-	.handler	= (irq_handler_t) ip27_rt_timer_interrupt,
-	.flags		= IRQF_DISABLED,
-	.mask		= CPU_MASK_NONE,
-	.name		= "timer"
+struct irqaction hub_rt_irqaction = {
+	.handler	= hub_rt_counter_handler,
+	.flags		= IRQF_DISABLED | IRQF_PERCPU,
+	.name		= "hub-rt",
 };
 
 /*
@@ -200,32 +189,48 @@ static struct irqaction rt_irqaction = {
 #define NSEC_PER_CYCLE		800
 #define CYCLES_PER_SEC		(NSEC_PER_SEC / NSEC_PER_CYCLE)
 
-static void __init ip27_rt_clock_event_init(void)
+static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
+static DEFINE_PER_CPU(char [11], hub_rt_name);
+
+static void __cpuinit hub_rt_clock_event_init(void)
 {
-	struct clock_event_device *cd = &rt_clock_event_device;
 	unsigned int cpu = smp_processor_id();
-	int irq = allocate_irqno();
-
-	if (irq < 0)
-		panic("Can't allocate interrupt number for timer interrupt");
-
-	rt_timer_irq = irq;
-
+	struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
+	unsigned char *name = per_cpu(hub_rt_name, cpu);
+	int irq = rt_timer_irq;
+
+	sprintf(name, "hub-rt %d", cpu);
+	cd->name		= "HUB-RT",
+	cd->features		= CLOCK_EVT_FEAT_ONESHOT,
+	clockevent_set_clock(cd, CYCLES_PER_SEC);
+	cd->max_delta_ns        = clockevent_delta2ns(0xfffffffffffff, cd);
+	cd->min_delta_ns        = clockevent_delta2ns(0x300, cd);
+	cd->rating		= 200,
 	cd->irq			= irq,
 	cd->cpumask		= cpumask_of_cpu(cpu),
-
-	/*
-	 * Calculate the min / max delta
-	 */
-	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);
+	cd->rating		= 300,
+	cd->set_next_event	= rt_next_event,
+	cd->set_mode		= rt_set_mode,
 	clockevents_register_device(cd);
+}
+
+static void __init hub_rt_clock_event_global_init(void)
+{
+	unsigned int irq;
+
+	do {
+		smp_wmb();
+		irq = rt_timer_irq;
+		if (irq)
+			break;
+
+		irq = allocate_irqno();
+		if (irq < 0)
+			panic("Allocation of irq number for timer failed");
+	} while (xchg(&rt_timer_irq, irq));
 
 	set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq);
-	setup_irq(irq, &rt_irqaction);
+	setup_irq(irq, &hub_rt_irqaction);
 }
 
 static cycle_t hub_rt_read(void)
@@ -233,27 +238,29 @@ static cycle_t hub_rt_read(void)
 	return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
 }
 
-struct clocksource ht_rt_clocksource = {
+struct clocksource hub_rt_clocksource = {
 	.name	= "HUB-RT",
 	.rating	= 200,
 	.read	= hub_rt_read,
 	.mask	= CLOCKSOURCE_MASK(52),
-	.shift	= 32,
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init ip27_rt_clocksource_init(void)
+static void __init hub_rt_clocksource_init(void)
 {
-	clocksource_register(&ht_rt_clocksource);
+	struct clocksource *cs = &hub_rt_clocksource;
+
+	clocksource_set_clock(cs, CYCLES_PER_SEC);
+	clocksource_register(cs);
 }
 
 void __init plat_time_init(void)
 {
-	ip27_rt_clock_event_init();
-	ip27_rt_clocksource_init();
+	hub_rt_clocksource_init();
+	hub_rt_clock_event_global_init();
 }
 
-void __init cpu_time_init(void)
+void __cpuinit cpu_time_init(void)
 {
 	lboard_t *board;
 	klcpu_t *cpu;
@@ -271,6 +278,7 @@ void __init cpu_time_init(void)
 
 	printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
 
+	hub_rt_clock_event_init();
 	set_c0_status(SRB_TIMOCLK);
 }
 

+ 41 - 34
arch/mips/sibyte/bcm1480/irq.c

@@ -452,6 +452,43 @@ static void bcm1480_kgdb_interrupt(void)
 
 extern void bcm1480_mailbox_interrupt(void);
 
+static inline void dispatch_ip4(void)
+{
+	int cpu = smp_processor_id();
+	int irq = K_BCM1480_INT_TIMER_0 + cpu;
+
+	/* Reset the timer */
+	__raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
+	            IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
+
+	do_IRQ(irq);
+}
+
+static inline void dispatch_ip2(void)
+{
+	unsigned long long mask_h, mask_l;
+	unsigned int cpu = smp_processor_id();
+	unsigned long base;
+
+	/*
+	 * Default...we've hit an IP[2] interrupt, which means we've got to
+	 * check the 1480 interrupt registers to figure out what to do.  Need
+	 * to detect which CPU we're on, now that smp_affinity is supported.
+	 */
+	base = A_BCM1480_IMR_MAPPER(cpu);
+	mask_h = __raw_readq(
+		IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
+	mask_l = __raw_readq(
+		IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
+
+	if (mask_h) {
+		if (mask_h ^ 1)
+			do_IRQ(fls64(mask_h) - 1);
+		else if (mask_l)
+			do_IRQ(63 + fls64(mask_l));
+	}
+}
+
 asmlinkage void plat_irq_dispatch(void)
 {
 	unsigned int pending;
@@ -469,17 +506,8 @@ asmlinkage void plat_irq_dispatch(void)
 	else
 #endif
 
-	if (pending & CAUSEF_IP4) {
-		int cpu = smp_processor_id();
-		int irq = K_BCM1480_INT_TIMER_0 + cpu;
-
-		/* Reset the timer */
-		__raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
-		            IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
-
-		do_IRQ(irq);
-	}
-
+	if (pending & CAUSEF_IP4)
+		dispatch_ip4();
 #ifdef CONFIG_SMP
 	else if (pending & CAUSEF_IP3)
 		bcm1480_mailbox_interrupt();
@@ -490,27 +518,6 @@ asmlinkage void plat_irq_dispatch(void)
 		bcm1480_kgdb_interrupt();		/* KGDB (uart 1) */
 #endif
 
-	else if (pending & CAUSEF_IP2) {
-		unsigned long long mask_h, mask_l;
-		unsigned long base;
-
-		/*
-		 * Default...we've hit an IP[2] interrupt, which means we've
-		 * got to check the 1480 interrupt registers to figure out what
-		 * to do.  Need to detect which CPU we're on, now that
-		 * smp_affinity is supported.
-		 */
-		base = A_BCM1480_IMR_MAPPER(smp_processor_id());
-		mask_h = __raw_readq(
-			IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
-		mask_l = __raw_readq(
-			IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
-
-		if (mask_h) {
-			if (mask_h ^ 1)
-				do_IRQ(fls64(mask_h) - 1);
-			else
-				do_IRQ(63 + fls64(mask_l));
-		}
-	}
+	else if (pending & CAUSEF_IP2)
+		dispatch_ip2();
 }

+ 2 - 2
arch/mips/sibyte/bcm1480/smp.c

@@ -58,7 +58,7 @@ static void *mailbox_0_regs[] = {
 /*
  * SMP init and finish on secondary CPUs
  */
-void bcm1480_smp_init(void)
+void __cpuinit bcm1480_smp_init(void)
 {
 	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
 		STATUSF_IP1 | STATUSF_IP0;
@@ -67,7 +67,7 @@ void bcm1480_smp_init(void)
 	change_c0_status(ST0_IM, imask);
 }
 
-void bcm1480_smp_finish(void)
+void __cpuinit bcm1480_smp_finish(void)
 {
 	extern void sb1480_clockevent_init(void);
 

+ 50 - 67
arch/mips/sibyte/bcm1480/time.c

@@ -15,22 +15,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
-
-/*
- * These are routines to set up and handle interrupts from the
- * bcm1480 general purpose timer 0.  We're using the timer as a
- * system clock, so we set it up to run at 100 Hz.  On every
- * interrupt, we update our idea of what the time of day is,
- * then call do_timer() in the architecture-independent kernel
- * code to do general bookkeeping (e.g. update jiffies, run
- * bottom halves, etc.)
- */
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/percpu.h>
 #include <linux/spinlock.h>
 
-#include <asm/irq.h>
 #include <asm/addrspace.h>
 #include <asm/time.h>
 #include <asm/io.h>
@@ -47,33 +37,10 @@
 #define IMR_IP3_VAL	K_BCM1480_INT_MAP_I1
 #define IMR_IP4_VAL	K_BCM1480_INT_MAP_I2
 
-#ifdef CONFIG_SIMULATION
-#define BCM1480_HPT_VALUE	50000
-#else
-#define BCM1480_HPT_VALUE	1000000
-#endif
-
 extern int bcm1480_steal_irq(int irq);
 
-void __init plat_time_init(void)
-{
-	unsigned int cpu = smp_processor_id();
-	unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
-
-	BUG_ON(cpu > 3);	/* Only have 4 general purpose timers */
-
-	bcm1480_mask_irq(cpu, irq);
-
-	/* Map the timer interrupt to ip[4] of this cpu */
-	__raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H)
-	      + (irq<<3)));
-
-	bcm1480_unmask_irq(cpu, irq);
-	bcm1480_steal_irq(irq);
-}
-
 /*
- * The general purpose timer ticks at 1 Mhz independent if
+ * The general purpose timer ticks at 1MHz independent if
  * the rest of the system
  */
 static void sibyte_set_mode(enum clock_event_mode mode,
@@ -88,7 +55,7 @@ static void sibyte_set_mode(enum clock_event_mode mode,
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
 		__raw_writeq(0, timer_cfg);
-		__raw_writeq(BCM1480_HPT_VALUE / HZ - 1, timer_init);
+		__raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init);
 		__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
 			     timer_cfg);
 		break;
@@ -121,80 +88,96 @@ static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd)
 	return res;
 }
 
-static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
-
 static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
 {
 	unsigned int cpu = smp_processor_id();
-	struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
+	struct clock_event_device *cd = dev_id;
+	void __iomem *timer_cfg;
+
+	timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
 
 	/* Reset the timer */
 	__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
-	             IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
+	             timer_cfg);
 	cd->event_handler(cd);
 
 	return IRQ_HANDLED;
 }
 
-static struct irqaction sibyte_counter_irqaction = {
-	.handler	= sibyte_counter_handler,
-	.flags		= IRQF_DISABLED | IRQF_PERCPU,
-	.name		= "timer",
-};
+static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
+static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
+static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
 
-/*
- * This interrupt is "special" in that it doesn't use the request_irq
- * way to hook the irq line.  The timer interrupt is initialized early
- * enough to make this a major pain, and it's also firing enough to
- * warrant a bit of special case code.  bcm1480_timer_interrupt is
- * called directly from irq_handler.S when IP[4] is set during an
- * interrupt
- */
 void __cpuinit sb1480_clockevent_init(void)
 {
 	unsigned int cpu = smp_processor_id();
 	unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
+	struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
 	struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
+	unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
+
+	BUG_ON(cpu > 3);	/* Only have 4 general purpose timers */
 
-	cd->name		= "bcm1480-counter";
+	sprintf(name, "bcm1480-counter %d", cpu);
+	cd->name		= name;
 	cd->features		= CLOCK_EVT_FEAT_PERIODIC |
 				  CLOCK_EVT_MODE_ONESHOT;
+	clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
+	cd->max_delta_ns	= clockevent_delta2ns(0x7fffff, cd);
+	cd->min_delta_ns	= clockevent_delta2ns(1, cd);
+	cd->rating		= 200;
+	cd->irq			= irq;
+	cd->cpumask		= cpumask_of_cpu(cpu);
 	cd->set_next_event	= sibyte_next_event;
 	cd->set_mode		= sibyte_set_mode;
-	cd->irq			= irq;
-	clockevent_set_clock(cd, BCM1480_HPT_VALUE);
+	clockevents_register_device(cd);
+
+	bcm1480_mask_irq(cpu, irq);
+
+	/*
+	 * Map timer interrupt to IP[4] of this cpu
+	 */
+	__raw_writeq(IMR_IP4_VAL,
+		     IOADDR(A_BCM1480_IMR_REGISTER(cpu,
+			R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (irq << 3)));
 
-	setup_irq(irq, &sibyte_counter_irqaction);
+	bcm1480_unmask_irq(cpu, irq);
+	bcm1480_steal_irq(irq);
+
+	action->handler	= sibyte_counter_handler;
+	action->flags	= IRQF_DISABLED | IRQF_PERCPU;
+	action->name	= name;
+	action->dev_id	= cd;
+	setup_irq(irq, action);
 }
 
 static cycle_t bcm1480_hpt_read(void)
 {
-	/* We assume this function is called xtime_lock held. */
-	unsigned long count =
-		__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT)));
-	return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count;
+	return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT));
 }
 
 struct clocksource bcm1480_clocksource = {
-	.name	= "MIPS",
+	.name	= "zbbus-cycles",
 	.rating	= 200,
 	.read	= bcm1480_hpt_read,
-	.mask	= CLOCKSOURCE_MASK(32),
-	.shift	= 32,
+	.mask	= CLOCKSOURCE_MASK(64),
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 void __init sb1480_clocksource_init(void)
 {
 	struct clocksource *cs = &bcm1480_clocksource;
+	unsigned int plldiv;
+	unsigned long zbbus;
 
-	clocksource_set_clock(cs, BCM1480_HPT_VALUE);
+	plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
+	zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000);
+	clocksource_set_clock(cs, zbbus);
 	clocksource_register(cs);
 }
 
-void __init bcm1480_hpt_setup(void)
+void __init plat_time_init(void)
 {
-	mips_hpt_frequency = BCM1480_HPT_VALUE;
 	sb1480_clocksource_init();
 	sb1480_clockevent_init();
 }

+ 19 - 16
arch/mips/sibyte/sb1250/irq.c

@@ -402,6 +402,22 @@ static void sb1250_kgdb_interrupt(void)
 
 extern void sb1250_mailbox_interrupt(void);
 
+static inline void dispatch_ip2(void)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned long long mask;
+
+	/*
+	 * Default...we've hit an IP[2] interrupt, which means we've got to
+	 * check the 1250 interrupt registers to figure out what to do.  Need
+	 * to detect which CPU we're on, now that smp_affinity is supported.
+	 */
+	mask = __raw_readq(IOADDR(A_IMR_REGISTER(cpu,
+				  R_IMR_INTERRUPT_STATUS_BASE)));
+	if (mask)
+		do_IRQ(fls64(mask) - 1);
+}
+
 asmlinkage void plat_irq_dispatch(void)
 {
 	unsigned int cpu = smp_processor_id();
@@ -434,21 +450,8 @@ asmlinkage void plat_irq_dispatch(void)
 		sb1250_kgdb_interrupt();
 #endif
 
-	else if (pending & CAUSEF_IP2) {
-		unsigned long long mask;
-
-		/*
-		 * Default...we've hit an IP[2] interrupt, which means we've
-		 * got to check the 1250 interrupt registers to figure out what
-		 * to do.  Need to detect which CPU we're on, now that
-		 * smp_affinity is supported.
-		 */
-		mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
-		                              R_IMR_INTERRUPT_STATUS_BASE)));
-		if (mask)
-			do_IRQ(fls64(mask) - 1);
-		else
-			spurious_interrupt();
-	} else
+	else if (pending & CAUSEF_IP2)
+		dispatch_ip2();
+	else
 		spurious_interrupt();
 }

+ 2 - 2
arch/mips/sibyte/sb1250/smp.c

@@ -46,7 +46,7 @@ static void *mailbox_regs[] = {
 /*
  * SMP init and finish on secondary CPUs
  */
-void sb1250_smp_init(void)
+void __cpuinit sb1250_smp_init(void)
 {
 	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
 		STATUSF_IP1 | STATUSF_IP0;
@@ -55,7 +55,7 @@ void sb1250_smp_init(void)
 	change_c0_status(ST0_IM, imask);
 }
 
-void sb1250_smp_finish(void)
+void __cpuinit sb1250_smp_finish(void)
 {
 	extern void sb1250_clockevent_init(void);
 

+ 44 - 44
arch/mips/sibyte/sb1250/time.c

@@ -52,26 +52,6 @@
 
 extern int sb1250_steal_irq(int irq);
 
-static cycle_t sb1250_hpt_read(void);
-
-void __init sb1250_hpt_setup(void)
-{
-	int cpu = smp_processor_id();
-
-	if (!cpu) {
-		/* Setup hpt using timer #3 but do not enable irq for it */
-		__raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
-		__raw_writeq(SB1250_HPT_VALUE,
-			     IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT)));
-		__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
-			     IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
-
-		mips_hpt_frequency = V_SCD_TIMER_FREQ;
-		clocksource_mips.read = sb1250_hpt_read;
-		clocksource_mips.mask = M_SCD_TIMER_INIT;
-	}
-}
-
 /*
  * The general purpose timer ticks at 1 Mhz independent if
  * the rest of the system
@@ -121,18 +101,14 @@ sibyte_next_event(unsigned long delta, struct clock_event_device *evt)
 	return 0;
 }
 
-struct clock_event_device sibyte_hpt_clockevent = {
-	.name		= "sb1250-counter",
-	.features	= CLOCK_EVT_FEAT_PERIODIC,
-	.set_mode	= sibyte_set_mode,
-	.set_next_event	= sibyte_next_event,
-	.shift		= 32,
-	.irq		= 0,
-};
-
 static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
 {
-	struct clock_event_device *cd = &sibyte_hpt_clockevent;
+	unsigned int cpu = smp_processor_id();
+	struct clock_event_device *cd = dev_id;
+
+	/* ACK interrupt */
+	____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
+		       IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
 
 	cd->event_handler(cd);
 
@@ -145,15 +121,35 @@ static struct irqaction sibyte_irqaction = {
 	.name		= "timer",
 };
 
+static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
+static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
+static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
+
 void __cpuinit sb1250_clockevent_init(void)
 {
-	struct clock_event_device *cd = &sibyte_hpt_clockevent;
 	unsigned int cpu = smp_processor_id();
-	int irq = K_INT_TIMER_0 + cpu;
+	unsigned int irq = K_INT_TIMER_0 + cpu;
+	struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
+	struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
+	unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
 
 	/* Only have 4 general purpose timers, and we use last one as hpt */
 	BUG_ON(cpu > 2);
 
+	sprintf(name, "bcm1480-counter %d", cpu);
+	cd->name		= name;
+	cd->features		= CLOCK_EVT_FEAT_PERIODIC |
+				  CLOCK_EVT_MODE_ONESHOT;
+	clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
+	cd->max_delta_ns	= clockevent_delta2ns(0x7fffff, cd);
+	cd->min_delta_ns	= clockevent_delta2ns(1, cd);
+	cd->rating		= 200;
+	cd->irq			= irq;
+	cd->cpumask		= cpumask_of_cpu(cpu);
+	cd->set_next_event	= sibyte_next_event;
+	cd->set_mode		= sibyte_set_mode;
+	clockevents_register_device(cd);
+
 	sb1250_mask_irq(cpu, irq);
 
 	/* Map the timer interrupt to ip[4] of this cpu */
@@ -165,17 +161,11 @@ void __cpuinit sb1250_clockevent_init(void)
 	sb1250_unmask_irq(cpu, irq);
 	sb1250_steal_irq(irq);
 
-	/*
-	 * This interrupt is "special" in that it doesn't use the request_irq
-	 * way to hook the irq line.  The timer interrupt is initialized early
-	 * enough to make this a major pain, and it's also firing enough to
-	 * warrant a bit of special case code.  sb1250_timer_interrupt is
-	 * called directly from irq_handler.S when IP[4] is set during an
-	 * interrupt
-	 */
+	action->handler	= sibyte_counter_handler;
+	action->flags	= IRQF_DISABLED | IRQF_PERCPU;
+	action->name	= name;
+	action->dev_id	= cd;
 	setup_irq(irq, &sibyte_irqaction);
-
-	clockevents_register_device(cd);
 }
 
 /*
@@ -195,8 +185,7 @@ struct clocksource bcm1250_clocksource = {
 	.name	= "MIPS",
 	.rating	= 200,
 	.read	= sb1250_hpt_read,
-	.mask	= CLOCKSOURCE_MASK(32),
-	.shift	= 32,
+	.mask	= CLOCKSOURCE_MASK(23),
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -204,6 +193,17 @@ void __init sb1250_clocksource_init(void)
 {
 	struct clocksource *cs = &bcm1250_clocksource;
 
+	/* Setup hpt using timer #3 but do not enable irq for it */
+	__raw_writeq(0,
+		     IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
+						 R_SCD_TIMER_CFG)));
+	__raw_writeq(SB1250_HPT_VALUE,
+		     IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
+						 R_SCD_TIMER_INIT)));
+	__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
+		     IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
+						 R_SCD_TIMER_CFG)));
+
 	clocksource_set_clock(cs, V_SCD_TIMER_FREQ);
 	clocksource_register(cs);
 }

+ 5 - 0
include/asm-mips/gt64120.h

@@ -21,6 +21,8 @@
 #ifndef _ASM_GT64120_H
 #define _ASM_GT64120_H
 
+#include <linux/clocksource.h>
+
 #include <asm/addrspace.h>
 #include <asm/byteorder.h>
 
@@ -572,4 +574,7 @@
 #define GT_READ(ofs)		le32_to_cpu(__GT_READ(ofs))
 #define GT_WRITE(ofs, data)	__GT_WRITE(ofs, cpu_to_le32(data))
 
+extern void gt641xx_set_base_clock(unsigned int clock);
+extern int gt641xx_timer0_state(void);
+
 #endif /* _ASM_GT64120_H */

+ 3 - 3
include/asm-mips/i8253.h

@@ -2,8 +2,8 @@
  *  Machine specific IO port address definition for generic.
  *  Written by Osamu Tomita <tomita@cinet.co.jp>
  */
-#ifndef _MACH_IO_PORTS_H
-#define _MACH_IO_PORTS_H
+#ifndef __ASM_I8253_H
+#define __ASM_I8253_H
 
 /* i8253A PIT registers */
 #define PIT_MODE		0x43
@@ -27,4 +27,4 @@
 
 extern void setup_pit_timer(void);
 
-#endif /* !_MACH_IO_PORTS_H */
+#endif /* __ASM_I8253_H */

+ 0 - 2
include/asm-mips/sibyte/sb1250.h

@@ -45,13 +45,11 @@ extern unsigned int soc_type;
 extern unsigned int periph_rev;
 extern unsigned int zbbus_mhz;
 
-extern void sb1250_hpt_setup(void);
 extern void sb1250_time_init(void);
 extern void sb1250_mask_irq(int cpu, int irq);
 extern void sb1250_unmask_irq(int cpu, int irq);
 extern void sb1250_smp_finish(void);
 
-extern void bcm1480_hpt_setup(void);
 extern void bcm1480_time_init(void);
 extern void bcm1480_mask_irq(int cpu, int irq);
 extern void bcm1480_unmask_irq(int cpu, int irq);