Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'smp' into devel

authored by

Russell King and committed by
Russell King
c7f7ff17 a22f277b

+398 -307
+15
arch/arm/Kconfig
··· 844 844 config SMP 845 845 bool "Symmetric Multi-Processing (EXPERIMENTAL)" 846 846 depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP) 847 + depends on GENERIC_CLOCKEVENTS 847 848 select USE_GENERIC_SMP_HELPERS 849 + select HAVE_ARM_SCU if ARCH_REALVIEW 848 850 help 849 851 This enables support for systems with more than one CPU. If you have 850 852 a system with only one CPU, like most personal computers, say N. If ··· 863 861 <http://www.linuxdoc.org/docs.html#howto>. 864 862 865 863 If you don't know what to do here, say N. 864 + 865 + config HAVE_ARM_SCU 866 + bool 867 + depends on SMP 868 + help 869 + This option enables support for the ARM system coherency unit 870 + 871 + config HAVE_ARM_TWD 872 + bool 873 + depends on SMP 874 + help 875 + This options enables support for the ARM timer and watchdog unit 866 876 867 877 choice 868 878 prompt "Memory split" ··· 916 902 bool "Use local timer interrupts" 917 903 depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP) 918 904 default y 905 + select HAVE_ARM_TWD if ARCH_REALVIEW 919 906 help 920 907 Enable support for local timers on SMP platforms, rather then the 921 908 legacy IPI broadcast method. Local timers allows the system
-21
arch/arm/include/asm/hardware/arm_twd.h
··· 1 - #ifndef __ASM_HARDWARE_TWD_H 2 - #define __ASM_HARDWARE_TWD_H 3 - 4 - #define TWD_TIMER_LOAD 0x00 5 - #define TWD_TIMER_COUNTER 0x04 6 - #define TWD_TIMER_CONTROL 0x08 7 - #define TWD_TIMER_INTSTAT 0x0C 8 - 9 - #define TWD_WDOG_LOAD 0x20 10 - #define TWD_WDOG_COUNTER 0x24 11 - #define TWD_WDOG_CONTROL 0x28 12 - #define TWD_WDOG_INTSTAT 0x2C 13 - #define TWD_WDOG_RESETSTAT 0x30 14 - #define TWD_WDOG_DISABLE 0x34 15 - 16 - #define TWD_TIMER_CONTROL_ENABLE (1 << 0) 17 - #define TWD_TIMER_CONTROL_ONESHOT (0 << 1) 18 - #define TWD_TIMER_CONTROL_PERIODIC (1 << 1) 19 - #define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2) 20 - 21 - #endif
+63
arch/arm/include/asm/localtimer.h
··· 1 + /* 2 + * arch/arm/include/asm/localtimer.h 3 + * 4 + * Copyright (C) 2004-2005 ARM Ltd. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + #ifndef __ASM_ARM_LOCALTIMER_H 11 + #define __ASM_ARM_LOCALTIMER_H 12 + 13 + struct clock_event_device; 14 + 15 + /* 16 + * Setup a per-cpu timer, whether it be a local timer or dummy broadcast 17 + */ 18 + void percpu_timer_setup(void); 19 + 20 + /* 21 + * Called from assembly, this is the local timer IRQ handler 22 + */ 23 + asmlinkage void do_local_timer(struct pt_regs *); 24 + 25 + 26 + #ifdef CONFIG_LOCAL_TIMERS 27 + 28 + #ifdef CONFIG_HAVE_ARM_TWD 29 + 30 + #include "smp_twd.h" 31 + 32 + #define local_timer_ack() twd_timer_ack() 33 + #define local_timer_stop() twd_timer_stop() 34 + 35 + #else 36 + 37 + /* 38 + * Platform provides this to acknowledge a local timer IRQ. 39 + * Returns true if the local timer IRQ is to be processed. 40 + */ 41 + int local_timer_ack(void); 42 + 43 + /* 44 + * Stop a local timer interrupt. 45 + */ 46 + void local_timer_stop(void); 47 + 48 + #endif 49 + 50 + /* 51 + * Setup a local timer interrupt for a CPU. 52 + */ 53 + void local_timer_setup(struct clock_event_device *); 54 + 55 + #else 56 + 57 + static inline void local_timer_stop(void) 58 + { 59 + } 60 + 61 + #endif 62 + 63 + #endif
+1 -41
arch/arm/include/asm/smp.h
··· 41 41 asmlinkage void do_IPI(struct pt_regs *regs); 42 42 43 43 /* 44 - * Setup the SMP cpu_possible_map 44 + * Setup the set of possible CPUs (via set_cpu_possible) 45 45 */ 46 46 extern void smp_init_cpus(void); 47 47 ··· 54 54 * Raise an IPI cross call on CPUs in callmap. 55 55 */ 56 56 extern void smp_cross_call(const struct cpumask *mask); 57 - 58 - /* 59 - * Broadcast a clock event to other CPUs. 60 - */ 61 - extern void smp_timer_broadcast(const struct cpumask *mask); 62 57 63 58 /* 64 59 * Boot a secondary CPU, and assign it the specified idle task. ··· 96 101 #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask 97 102 98 103 /* 99 - * Local timer interrupt handling function (can be IPI'ed). 100 - */ 101 - extern void local_timer_interrupt(void); 102 - 103 - #ifdef CONFIG_LOCAL_TIMERS 104 - 105 - /* 106 - * Stop a local timer interrupt. 107 - */ 108 - extern void local_timer_stop(void); 109 - 110 - /* 111 - * Platform provides this to acknowledge a local timer IRQ 112 - */ 113 - extern int local_timer_ack(void); 114 - 115 - #else 116 - 117 - static inline void local_timer_stop(void) 118 - { 119 - } 120 - 121 - #endif 122 - 123 - /* 124 - * Setup a local timer interrupt for a CPU. 125 - */ 126 - extern void local_timer_setup(void); 127 - 128 - /* 129 104 * show local interrupt info 130 105 */ 131 106 extern void show_local_irqs(struct seq_file *); 132 - 133 - /* 134 - * Called from assembly, this is the local timer IRQ handler 135 - */ 136 - asmlinkage void do_local_timer(struct pt_regs *); 137 107 138 108 #endif /* ifndef __ASM_ARM_SMP_H */
+7
arch/arm/include/asm/smp_scu.h
··· 1 + #ifndef __ASMARM_ARCH_SCU_H 2 + #define __ASMARM_ARCH_SCU_H 3 + 4 + unsigned int scu_get_core_count(void __iomem *); 5 + void scu_enable(void __iomem *); 6 + 7 + #endif
+12
arch/arm/include/asm/smp_twd.h
··· 1 + #ifndef __ASMARM_SMP_TWD_H 2 + #define __ASMARM_SMP_TWD_H 3 + 4 + struct clock_event_device; 5 + 6 + extern void __iomem *twd_base; 7 + 8 + void twd_timer_stop(void); 9 + int twd_timer_ack(void); 10 + void twd_timer_setup(struct clock_event_device *); 11 + 12 + #endif
+2
arch/arm/kernel/Makefile
··· 22 22 obj-$(CONFIG_ISA_DMA) += dma-isa.o 23 23 obj-$(CONFIG_PCI) += bios32.o isa.o 24 24 obj-$(CONFIG_SMP) += smp.o 25 + obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o 26 + obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o 25 27 obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o 26 28 obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o 27 29 obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o
+51 -11
arch/arm/kernel/smp.c
··· 22 22 #include <linux/smp.h> 23 23 #include <linux/seq_file.h> 24 24 #include <linux/irq.h> 25 + #include <linux/percpu.h> 26 + #include <linux/clockchips.h> 25 27 26 28 #include <asm/atomic.h> 27 29 #include <asm/cacheflush.h> ··· 34 32 #include <asm/processor.h> 35 33 #include <asm/tlbflush.h> 36 34 #include <asm/ptrace.h> 35 + #include <asm/localtimer.h> 37 36 38 37 /* 39 38 * as from 2.5, kernels no longer have an init_tasks structure ··· 166 163 * Take this CPU offline. Once we clear this, we can't return, 167 164 * and we must not schedule until we're ready to give up the cpu. 168 165 */ 169 - cpu_clear(cpu, cpu_online_map); 166 + set_cpu_online(cpu, false); 170 167 171 168 /* 172 169 * OK - migrate IRQs away from this CPU ··· 277 274 local_fiq_enable(); 278 275 279 276 /* 280 - * Setup local timer for this CPU. 277 + * Setup the percpu timer for this CPU. 281 278 */ 282 - local_timer_setup(); 279 + percpu_timer_setup(); 283 280 284 281 calibrate_delay(); 285 282 ··· 288 285 /* 289 286 * OK, now it's safe to let the boot CPU continue 290 287 */ 291 - cpu_set(cpu, cpu_online_map); 288 + set_cpu_online(cpu, true); 292 289 293 290 /* 294 291 * OK, it's off to the idle thread for us ··· 386 383 seq_putc(p, '\n'); 387 384 } 388 385 386 + /* 387 + * Timer (local or broadcast) support 388 + */ 389 + static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); 390 + 389 391 static void ipi_timer(void) 390 392 { 393 + struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); 391 394 irq_enter(); 392 - local_timer_interrupt(); 395 + evt->event_handler(evt); 393 396 irq_exit(); 394 397 } 395 398 ··· 414 405 } 415 406 #endif 416 407 408 + #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 409 + static void smp_timer_broadcast(const struct cpumask *mask) 410 + { 411 + send_ipi_message(mask, IPI_TIMER); 412 + } 413 + 414 + static void broadcast_timer_set_mode(enum clock_event_mode mode, 415 + struct clock_event_device *evt) 416 + { 417 + } 418 + 419 + static void local_timer_setup(struct clock_event_device *evt) 420 + { 421 + evt->name = "dummy_timer"; 422 + evt->features = CLOCK_EVT_FEAT_ONESHOT | 423 + CLOCK_EVT_FEAT_PERIODIC | 424 + CLOCK_EVT_FEAT_DUMMY; 425 + evt->rating = 400; 426 + evt->mult = 1; 427 + evt->set_mode = broadcast_timer_set_mode; 428 + evt->broadcast = smp_timer_broadcast; 429 + 430 + clockevents_register_device(evt); 431 + } 432 + #endif 433 + 434 + void __cpuinit percpu_timer_setup(void) 435 + { 436 + unsigned int cpu = smp_processor_id(); 437 + struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); 438 + 439 + evt->cpumask = cpumask_of(cpu); 440 + 441 + local_timer_setup(evt); 442 + } 443 + 417 444 static DEFINE_SPINLOCK(stop_lock); 418 445 419 446 /* ··· 462 417 dump_stack(); 463 418 spin_unlock(&stop_lock); 464 419 465 - cpu_clear(cpu, cpu_online_map); 420 + set_cpu_online(cpu, false); 466 421 467 422 local_fiq_disable(); 468 423 local_irq_disable(); ··· 544 499 void smp_send_reschedule(int cpu) 545 500 { 546 501 send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); 547 - } 548 - 549 - void smp_timer_broadcast(const struct cpumask *mask) 550 - { 551 - send_ipi_message(mask, IPI_TIMER); 552 502 } 553 503 554 504 void smp_send_stop(void)
+48
arch/arm/kernel/smp_scu.c
··· 1 + /* 2 + * linux/arch/arm/kernel/smp_scu.c 3 + * 4 + * Copyright (C) 2002 ARM Ltd. 5 + * All Rights Reserved 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + #include <linux/init.h> 12 + #include <linux/io.h> 13 + 14 + #include <asm/smp_scu.h> 15 + #include <asm/cacheflush.h> 16 + 17 + #define SCU_CTRL 0x00 18 + #define SCU_CONFIG 0x04 19 + #define SCU_CPU_STATUS 0x08 20 + #define SCU_INVALIDATE 0x0c 21 + #define SCU_FPGA_REVISION 0x10 22 + 23 + /* 24 + * Get the number of CPU cores from the SCU configuration 25 + */ 26 + unsigned int __init scu_get_core_count(void __iomem *scu_base) 27 + { 28 + unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG); 29 + return (ncores & 0x03) + 1; 30 + } 31 + 32 + /* 33 + * Enable the SCU 34 + */ 35 + void __init scu_enable(void __iomem *scu_base) 36 + { 37 + u32 scu_ctrl; 38 + 39 + scu_ctrl = __raw_readl(scu_base + SCU_CTRL); 40 + scu_ctrl |= 1; 41 + __raw_writel(scu_ctrl, scu_base + SCU_CTRL); 42 + 43 + /* 44 + * Ensure that the data accessed by CPU0 before the SCU was 45 + * initialised is visible to the other CPUs. 46 + */ 47 + flush_cache_all(); 48 + }
+175
arch/arm/kernel/smp_twd.c
··· 1 + /* 2 + * linux/arch/arm/kernel/smp_twd.c 3 + * 4 + * Copyright (C) 2002 ARM Ltd. 5 + * All Rights Reserved 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + #include <linux/init.h> 12 + #include <linux/kernel.h> 13 + #include <linux/delay.h> 14 + #include <linux/device.h> 15 + #include <linux/smp.h> 16 + #include <linux/jiffies.h> 17 + #include <linux/clockchips.h> 18 + #include <linux/irq.h> 19 + #include <linux/io.h> 20 + 21 + #include <asm/smp_twd.h> 22 + #include <asm/hardware/gic.h> 23 + 24 + #define TWD_TIMER_LOAD 0x00 25 + #define TWD_TIMER_COUNTER 0x04 26 + #define TWD_TIMER_CONTROL 0x08 27 + #define TWD_TIMER_INTSTAT 0x0C 28 + 29 + #define TWD_WDOG_LOAD 0x20 30 + #define TWD_WDOG_COUNTER 0x24 31 + #define TWD_WDOG_CONTROL 0x28 32 + #define TWD_WDOG_INTSTAT 0x2C 33 + #define TWD_WDOG_RESETSTAT 0x30 34 + #define TWD_WDOG_DISABLE 0x34 35 + 36 + #define TWD_TIMER_CONTROL_ENABLE (1 << 0) 37 + #define TWD_TIMER_CONTROL_ONESHOT (0 << 1) 38 + #define TWD_TIMER_CONTROL_PERIODIC (1 << 1) 39 + #define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2) 40 + 41 + /* set up by the platform code */ 42 + void __iomem *twd_base; 43 + 44 + static unsigned long twd_timer_rate; 45 + 46 + static void twd_set_mode(enum clock_event_mode mode, 47 + struct clock_event_device *clk) 48 + { 49 + unsigned long ctrl; 50 + 51 + switch (mode) { 52 + case CLOCK_EVT_MODE_PERIODIC: 53 + /* timer load already set up */ 54 + ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE 55 + | TWD_TIMER_CONTROL_PERIODIC; 56 + break; 57 + case CLOCK_EVT_MODE_ONESHOT: 58 + /* period set, and timer enabled in 'next_event' hook */ 59 + ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT; 60 + break; 61 + case CLOCK_EVT_MODE_UNUSED: 62 + case CLOCK_EVT_MODE_SHUTDOWN: 63 + default: 64 + ctrl = 0; 65 + } 66 + 67 + __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL); 68 + } 69 + 70 + static int twd_set_next_event(unsigned long evt, 71 + struct clock_event_device *unused) 72 + { 73 + unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL); 74 + 75 + ctrl |= TWD_TIMER_CONTROL_ENABLE; 76 + 77 + __raw_writel(evt, twd_base + TWD_TIMER_COUNTER); 78 + __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL); 79 + 80 + return 0; 81 + } 82 + 83 + /* 84 + * local_timer_ack: checks for a local timer interrupt. 85 + * 86 + * If a local timer interrupt has occurred, acknowledge and return 1. 87 + * Otherwise, return 0. 88 + */ 89 + int twd_timer_ack(void) 90 + { 91 + if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) { 92 + __raw_writel(1, twd_base + TWD_TIMER_INTSTAT); 93 + return 1; 94 + } 95 + 96 + return 0; 97 + } 98 + 99 + static void __cpuinit twd_calibrate_rate(void) 100 + { 101 + unsigned long load, count; 102 + u64 waitjiffies; 103 + 104 + /* 105 + * If this is the first time round, we need to work out how fast 106 + * the timer ticks 107 + */ 108 + if (twd_timer_rate == 0) { 109 + printk(KERN_INFO "Calibrating local timer... "); 110 + 111 + /* Wait for a tick to start */ 112 + waitjiffies = get_jiffies_64() + 1; 113 + 114 + while (get_jiffies_64() < waitjiffies) 115 + udelay(10); 116 + 117 + /* OK, now the tick has started, let's get the timer going */ 118 + waitjiffies += 5; 119 + 120 + /* enable, no interrupt or reload */ 121 + __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL); 122 + 123 + /* maximum value */ 124 + __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER); 125 + 126 + while (get_jiffies_64() < waitjiffies) 127 + udelay(10); 128 + 129 + count = __raw_readl(twd_base + TWD_TIMER_COUNTER); 130 + 131 + twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); 132 + 133 + printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000, 134 + (twd_timer_rate / 100000) % 100); 135 + } 136 + 137 + load = twd_timer_rate / HZ; 138 + 139 + __raw_writel(load, twd_base + TWD_TIMER_LOAD); 140 + } 141 + 142 + /* 143 + * Setup the local clock events for a CPU. 144 + */ 145 + void __cpuinit twd_timer_setup(struct clock_event_device *clk) 146 + { 147 + unsigned long flags; 148 + 149 + twd_calibrate_rate(); 150 + 151 + clk->name = "local_timer"; 152 + clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; 153 + clk->rating = 350; 154 + clk->set_mode = twd_set_mode; 155 + clk->set_next_event = twd_set_next_event; 156 + clk->shift = 20; 157 + clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift); 158 + clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); 159 + clk->min_delta_ns = clockevent_delta2ns(0xf, clk); 160 + 161 + /* Make sure our local interrupt controller has this enabled */ 162 + local_irq_save(flags); 163 + get_irq_chip(clk->irq)->unmask(clk->irq); 164 + local_irq_restore(flags); 165 + 166 + clockevents_register_device(clk); 167 + } 168 + 169 + /* 170 + * take a local timer down 171 + */ 172 + void __cpuexit twd_timer_stop(void) 173 + { 174 + __raw_writel(0, twd_base + TWD_TIMER_CONTROL); 175 + }
+2 -1
arch/arm/mach-realview/Makefile
··· 7 7 obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o 8 8 obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o 9 9 obj-$(CONFIG_MACH_REALVIEW_PBA8) += realview_pba8.o 10 - obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o 10 + obj-$(CONFIG_SMP) += platsmp.o headsmp.o 11 11 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 12 + obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
-3
arch/arm/mach-realview/core.h
··· 51 51 extern struct mmc_platform_data realview_mmc1_plat_data; 52 52 extern struct clcd_board clcd_plat_data; 53 53 extern void __iomem *gic_cpu_base_addr; 54 - #ifdef CONFIG_LOCAL_TIMERS 55 - extern void __iomem *twd_base; 56 - #endif 57 54 extern void __iomem *timer0_va_base; 58 55 extern void __iomem *timer1_va_base; 59 56 extern void __iomem *timer2_va_base;
-13
arch/arm/mach-realview/include/mach/scu.h
··· 1 - #ifndef __ASMARM_ARCH_SCU_H 2 - #define __ASMARM_ARCH_SCU_H 3 - 4 - /* 5 - * SCU registers 6 - */ 7 - #define SCU_CTRL 0x00 8 - #define SCU_CONFIG 0x04 9 - #define SCU_CPU_STATUS 0x08 10 - #define SCU_INVALIDATE 0x0c 11 - #define SCU_FPGA_REVISION 0x10 12 - 13 - #endif
+5 -183
arch/arm/mach-realview/localtimer.c
··· 9 9 * published by the Free Software Foundation. 10 10 */ 11 11 #include <linux/init.h> 12 - #include <linux/kernel.h> 13 - #include <linux/delay.h> 14 - #include <linux/device.h> 15 12 #include <linux/smp.h> 16 - #include <linux/jiffies.h> 17 - #include <linux/percpu.h> 18 13 #include <linux/clockchips.h> 19 - #include <linux/irq.h> 20 - #include <linux/io.h> 21 14 22 - #include <asm/hardware/arm_twd.h> 23 - #include <asm/hardware/gic.h> 24 - #include <mach/hardware.h> 25 15 #include <asm/irq.h> 26 - 27 - static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); 28 - 29 - /* 30 - * Used on SMP for either the local timer or IPI_TIMER 31 - */ 32 - void local_timer_interrupt(void) 33 - { 34 - struct clock_event_device *clk = &__get_cpu_var(local_clockevent); 35 - 36 - clk->event_handler(clk); 37 - } 38 - 39 - #ifdef CONFIG_LOCAL_TIMERS 40 - 41 - /* set up by the platform code */ 42 - void __iomem *twd_base; 43 - 44 - static unsigned long mpcore_timer_rate; 45 - 46 - static void local_timer_set_mode(enum clock_event_mode mode, 47 - struct clock_event_device *clk) 48 - { 49 - unsigned long ctrl; 50 - 51 - switch(mode) { 52 - case CLOCK_EVT_MODE_PERIODIC: 53 - /* timer load already set up */ 54 - ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE 55 - | TWD_TIMER_CONTROL_PERIODIC; 56 - break; 57 - case CLOCK_EVT_MODE_ONESHOT: 58 - /* period set, and timer enabled in 'next_event' hook */ 59 - ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT; 60 - break; 61 - case CLOCK_EVT_MODE_UNUSED: 62 - case CLOCK_EVT_MODE_SHUTDOWN: 63 - default: 64 - ctrl = 0; 65 - } 66 - 67 - __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL); 68 - } 69 - 70 - static int local_timer_set_next_event(unsigned long evt, 71 - struct clock_event_device *unused) 72 - { 73 - unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL); 74 - 75 - __raw_writel(evt, twd_base + TWD_TIMER_COUNTER); 76 - __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, twd_base + TWD_TIMER_CONTROL); 77 - 78 - return 0; 79 - } 80 - 81 - /* 82 - * local_timer_ack: checks for a local timer interrupt. 83 - * 84 - * If a local timer interrupt has occurred, acknowledge and return 1. 85 - * Otherwise, return 0. 86 - */ 87 - int local_timer_ack(void) 88 - { 89 - if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) { 90 - __raw_writel(1, twd_base + TWD_TIMER_INTSTAT); 91 - return 1; 92 - } 93 - 94 - return 0; 95 - } 96 - 97 - static void __cpuinit twd_calibrate_rate(void) 98 - { 99 - unsigned long load, count; 100 - u64 waitjiffies; 101 - 102 - /* 103 - * If this is the first time round, we need to work out how fast 104 - * the timer ticks 105 - */ 106 - if (mpcore_timer_rate == 0) { 107 - printk("Calibrating local timer... "); 108 - 109 - /* Wait for a tick to start */ 110 - waitjiffies = get_jiffies_64() + 1; 111 - 112 - while (get_jiffies_64() < waitjiffies) 113 - udelay(10); 114 - 115 - /* OK, now the tick has started, let's get the timer going */ 116 - waitjiffies += 5; 117 - 118 - /* enable, no interrupt or reload */ 119 - __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL); 120 - 121 - /* maximum value */ 122 - __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER); 123 - 124 - while (get_jiffies_64() < waitjiffies) 125 - udelay(10); 126 - 127 - count = __raw_readl(twd_base + TWD_TIMER_COUNTER); 128 - 129 - mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); 130 - 131 - printk("%lu.%02luMHz.\n", mpcore_timer_rate / 1000000, 132 - (mpcore_timer_rate / 100000) % 100); 133 - } 134 - 135 - load = mpcore_timer_rate / HZ; 136 - 137 - __raw_writel(load, twd_base + TWD_TIMER_LOAD); 138 - } 16 + #include <asm/smp_twd.h> 17 + #include <asm/localtimer.h> 139 18 140 19 /* 141 20 * Setup the local clock events for a CPU. 142 21 */ 143 - void __cpuinit local_timer_setup(void) 22 + void __cpuinit local_timer_setup(struct clock_event_device *evt) 144 23 { 145 - unsigned int cpu = smp_processor_id(); 146 - struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); 147 - unsigned long flags; 148 - 149 - twd_calibrate_rate(); 150 - 151 - clk->name = "local_timer"; 152 - clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; 153 - clk->rating = 350; 154 - clk->set_mode = local_timer_set_mode; 155 - clk->set_next_event = local_timer_set_next_event; 156 - clk->irq = IRQ_LOCALTIMER; 157 - clk->cpumask = cpumask_of(cpu); 158 - clk->shift = 20; 159 - clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift); 160 - clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); 161 - clk->min_delta_ns = clockevent_delta2ns(0xf, clk); 162 - 163 - /* Make sure our local interrupt controller has this enabled */ 164 - local_irq_save(flags); 165 - get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER); 166 - local_irq_restore(flags); 167 - 168 - clockevents_register_device(clk); 24 + evt->irq = IRQ_LOCALTIMER; 25 + twd_timer_setup(evt); 169 26 } 170 - 171 - /* 172 - * take a local timer down 173 - */ 174 - void __cpuexit local_timer_stop(void) 175 - { 176 - __raw_writel(0, twd_base + TWD_TIMER_CONTROL); 177 - } 178 - 179 - #else /* CONFIG_LOCAL_TIMERS */ 180 - 181 - static void dummy_timer_set_mode(enum clock_event_mode mode, 182 - struct clock_event_device *clk) 183 - { 184 - } 185 - 186 - void __cpuinit local_timer_setup(void) 187 - { 188 - unsigned int cpu = smp_processor_id(); 189 - struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); 190 - 191 - clk->name = "dummy_timer"; 192 - clk->features = CLOCK_EVT_FEAT_ONESHOT | 193 - CLOCK_EVT_FEAT_PERIODIC | 194 - CLOCK_EVT_FEAT_DUMMY; 195 - clk->rating = 400; 196 - clk->mult = 1; 197 - clk->set_mode = dummy_timer_set_mode; 198 - clk->broadcast = smp_timer_broadcast; 199 - clk->cpumask = cpumask_of(cpu); 200 - 201 - clockevents_register_device(clk); 202 - } 203 - 204 - #endif /* !CONFIG_LOCAL_TIMERS */
+15 -34
arch/arm/mach-realview/platsmp.c
··· 19 19 #include <asm/cacheflush.h> 20 20 #include <mach/hardware.h> 21 21 #include <asm/mach-types.h> 22 + #include <asm/localtimer.h> 22 23 23 24 #include <mach/board-eb.h> 24 25 #include <mach/board-pb11mp.h> 25 - #include <mach/scu.h> 26 + #include <asm/smp_scu.h> 26 27 27 28 #include "core.h" 28 29 ··· 45 44 return (void __iomem *)0; 46 45 } 47 46 48 - static unsigned int __init get_core_count(void) 47 + static inline unsigned int get_core_count(void) 49 48 { 50 - unsigned int ncores; 51 49 void __iomem *scu_base = scu_base_addr(); 52 - 53 - if (scu_base) { 54 - ncores = __raw_readl(scu_base + SCU_CONFIG); 55 - ncores = (ncores & 0x03) + 1; 56 - } else 57 - ncores = 1; 58 - 59 - return ncores; 60 - } 61 - 62 - /* 63 - * Setup the SCU 64 - */ 65 - static void scu_enable(void) 66 - { 67 - u32 scu_ctrl; 68 - void __iomem *scu_base = scu_base_addr(); 69 - 70 - scu_ctrl = __raw_readl(scu_base + SCU_CTRL); 71 - scu_ctrl |= 1; 72 - __raw_writel(scu_ctrl, scu_base + SCU_CTRL); 50 + if (scu_base) 51 + return scu_get_core_count(scu_base); 52 + return 1; 73 53 } 74 54 75 55 static DEFINE_SPINLOCK(boot_lock); ··· 166 184 unsigned int i, ncores = get_core_count(); 167 185 168 186 for (i = 0; i < ncores; i++) 169 - cpu_set(i, cpu_possible_map); 187 + set_cpu_possible(i, true); 170 188 } 171 189 172 190 void __init smp_prepare_cpus(unsigned int max_cpus) ··· 199 217 if (max_cpus > ncores) 200 218 max_cpus = ncores; 201 219 202 - #if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) 203 - /* 204 - * Enable the local timer or broadcast device for the boot CPU. 205 - */ 206 - local_timer_setup(); 207 - #endif 208 - 209 220 /* 210 221 * Initialise the present map, which describes the set of CPUs 211 222 * actually populated at the present time. 212 223 */ 213 224 for (i = 0; i < max_cpus; i++) 214 - cpu_set(i, cpu_present_map); 225 + set_cpu_present(i, true); 215 226 216 227 /* 217 228 * Initialise the SCU if there are more than one CPU and let ··· 214 239 * WFI 215 240 */ 216 241 if (max_cpus > 1) { 217 - scu_enable(); 242 + /* 243 + * Enable the local timer or broadcast device for the 244 + * boot CPU, but only if we have more than one CPU. 245 + */ 246 + percpu_timer_setup(); 247 + 248 + scu_enable(scu_base_addr()); 218 249 poke_milo(); 219 250 } 220 251 }
+1
arch/arm/mach-realview/realview_eb.c
··· 32 32 #include <asm/hardware/gic.h> 33 33 #include <asm/hardware/icst307.h> 34 34 #include <asm/hardware/cache-l2x0.h> 35 + #include <asm/localtimer.h> 35 36 36 37 #include <asm/mach/arch.h> 37 38 #include <asm/mach/map.h>
+1
arch/arm/mach-realview/realview_pb11mp.c
··· 32 32 #include <asm/hardware/gic.h> 33 33 #include <asm/hardware/icst307.h> 34 34 #include <asm/hardware/cache-l2x0.h> 35 + #include <asm/localtimer.h> 35 36 36 37 #include <asm/mach/arch.h> 37 38 #include <asm/mach/flash.h>