···844844config SMP845845 bool "Symmetric Multi-Processing (EXPERIMENTAL)"846846 depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)847847+ depends on GENERIC_CLOCKEVENTS847848 select USE_GENERIC_SMP_HELPERS849849+ select HAVE_ARM_SCU if ARCH_REALVIEW848850 help849851 This enables support for systems with more than one CPU. If you have850852 a system with only one CPU, like most personal computers, say N. If···863861 <http://www.linuxdoc.org/docs.html#howto>.864862865863 If you don't know what to do here, say N.864864+865865+config HAVE_ARM_SCU866866+ bool867867+ depends on SMP868868+ help869869+ This option enables support for the ARM system coherency unit870870+871871+config HAVE_ARM_TWD872872+ bool873873+ depends on SMP874874+ help875875+ This options enables support for the ARM timer and watchdog unit866876867877choice868878 prompt "Memory split"···916902 bool "Use local timer interrupts"917903 depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP)918904 default y905905+ select HAVE_ARM_TWD if ARCH_REALVIEW919906 help920907 Enable support for local timers on SMP platforms, rather then the921908 legacy IPI broadcast method. Local timers allows the system
···11+/*22+ * arch/arm/include/asm/localtimer.h33+ *44+ * Copyright (C) 2004-2005 ARM Ltd.55+ *66+ * This program is free software; you can redistribute it and/or modify77+ * it under the terms of the GNU General Public License version 2 as88+ * published by the Free Software Foundation.99+ */1010+#ifndef __ASM_ARM_LOCALTIMER_H1111+#define __ASM_ARM_LOCALTIMER_H1212+1313+struct clock_event_device;1414+1515+/*1616+ * Setup a per-cpu timer, whether it be a local timer or dummy broadcast1717+ */1818+void percpu_timer_setup(void);1919+2020+/*2121+ * Called from assembly, this is the local timer IRQ handler2222+ */2323+asmlinkage void do_local_timer(struct pt_regs *);2424+2525+2626+#ifdef CONFIG_LOCAL_TIMERS2727+2828+#ifdef CONFIG_HAVE_ARM_TWD2929+3030+#include "smp_twd.h"3131+3232+#define local_timer_ack() twd_timer_ack()3333+#define local_timer_stop() twd_timer_stop()3434+3535+#else3636+3737+/*3838+ * Platform provides this to acknowledge a local timer IRQ.3939+ * Returns true if the local timer IRQ is to be processed.4040+ */4141+int local_timer_ack(void);4242+4343+/*4444+ * Stop a local timer interrupt.4545+ */4646+void local_timer_stop(void);4747+4848+#endif4949+5050+/*5151+ * Setup a local timer interrupt for a CPU.5252+ */5353+void local_timer_setup(struct clock_event_device *);5454+5555+#else5656+5757+static inline void local_timer_stop(void)5858+{5959+}6060+6161+#endif6262+6363+#endif
+1-41
arch/arm/include/asm/smp.h
···4141asmlinkage void do_IPI(struct pt_regs *regs);42424343/*4444- * Setup the SMP cpu_possible_map4444+ * Setup the set of possible CPUs (via set_cpu_possible)4545 */4646extern void smp_init_cpus(void);4747···5454 * Raise an IPI cross call on CPUs in callmap.5555 */5656extern void smp_cross_call(const struct cpumask *mask);5757-5858-/*5959- * Broadcast a clock event to other CPUs.6060- */6161-extern void smp_timer_broadcast(const struct cpumask *mask);62576358/*6459 * Boot a secondary CPU, and assign it the specified idle task.···96101#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask9710298103/*9999- * Local timer interrupt handling function (can be IPI'ed).100100- */101101-extern void local_timer_interrupt(void);102102-103103-#ifdef CONFIG_LOCAL_TIMERS104104-105105-/*106106- * Stop a local timer interrupt.107107- */108108-extern void local_timer_stop(void);109109-110110-/*111111- * Platform provides this to acknowledge a local timer IRQ112112- */113113-extern int local_timer_ack(void);114114-115115-#else116116-117117-static inline void local_timer_stop(void)118118-{119119-}120120-121121-#endif122122-123123-/*124124- * Setup a local timer interrupt for a CPU.125125- */126126-extern void local_timer_setup(void);127127-128128-/*129104 * show local interrupt info130105 */131106extern void show_local_irqs(struct seq_file *);132132-133133-/*134134- * Called from assembly, this is the local timer IRQ handler135135- */136136-asmlinkage void do_local_timer(struct pt_regs *);137107138108#endif /* ifndef __ASM_ARM_SMP_H */
+7
arch/arm/include/asm/smp_scu.h
···11+#ifndef __ASMARM_ARCH_SCU_H22+#define __ASMARM_ARCH_SCU_H33+44+unsigned int scu_get_core_count(void __iomem *);55+void scu_enable(void __iomem *);66+77+#endif
···2222#include <linux/smp.h>2323#include <linux/seq_file.h>2424#include <linux/irq.h>2525+#include <linux/percpu.h>2626+#include <linux/clockchips.h>25272628#include <asm/atomic.h>2729#include <asm/cacheflush.h>···3432#include <asm/processor.h>3533#include <asm/tlbflush.h>3634#include <asm/ptrace.h>3535+#include <asm/localtimer.h>37363837/*3938 * as from 2.5, kernels no longer have an init_tasks structure···166163 * Take this CPU offline. Once we clear this, we can't return,167164 * and we must not schedule until we're ready to give up the cpu.168165 */169169- cpu_clear(cpu, cpu_online_map);166166+ set_cpu_online(cpu, false);170167171168 /*172169 * OK - migrate IRQs away from this CPU···277274 local_fiq_enable();278275279276 /*280280- * Setup local timer for this CPU.277277+ * Setup the percpu timer for this CPU.281278 */282282- local_timer_setup();279279+ percpu_timer_setup();283280284281 calibrate_delay();285282···288285 /*289286 * OK, now it's safe to let the boot CPU continue290287 */291291- cpu_set(cpu, cpu_online_map);288288+ set_cpu_online(cpu, true);292289293290 /*294291 * OK, it's off to the idle thread for us···386383 seq_putc(p, '\n');387384}388385386386+/*387387+ * Timer (local or broadcast) support388388+ */389389+static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);390390+389391static void ipi_timer(void)390392{393393+ struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);391394 irq_enter();392392- local_timer_interrupt();395395+ evt->event_handler(evt);393396 irq_exit();394397}395398···414405}415406#endif416407408408+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST409409+static void smp_timer_broadcast(const struct cpumask *mask)410410+{411411+ send_ipi_message(mask, IPI_TIMER);412412+}413413+414414+static void broadcast_timer_set_mode(enum clock_event_mode mode,415415+ struct clock_event_device *evt)416416+{417417+}418418+419419+static void local_timer_setup(struct clock_event_device *evt)420420+{421421+ evt->name = "dummy_timer";422422+ evt->features = CLOCK_EVT_FEAT_ONESHOT |423423+ CLOCK_EVT_FEAT_PERIODIC |424424+ CLOCK_EVT_FEAT_DUMMY;425425+ evt->rating = 400;426426+ evt->mult = 1;427427+ evt->set_mode = broadcast_timer_set_mode;428428+ evt->broadcast = smp_timer_broadcast;429429+430430+ clockevents_register_device(evt);431431+}432432+#endif433433+434434+void __cpuinit percpu_timer_setup(void)435435+{436436+ unsigned int cpu = smp_processor_id();437437+ struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);438438+439439+ evt->cpumask = cpumask_of(cpu);440440+441441+ local_timer_setup(evt);442442+}443443+417444static DEFINE_SPINLOCK(stop_lock);418445419446/*···462417 dump_stack();463418 spin_unlock(&stop_lock);464419465465- cpu_clear(cpu, cpu_online_map);420420+ set_cpu_online(cpu, false);466421467422 local_fiq_disable();468423 local_irq_disable();···544499void smp_send_reschedule(int cpu)545500{546501 send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);547547-}548548-549549-void smp_timer_broadcast(const struct cpumask *mask)550550-{551551- send_ipi_message(mask, IPI_TIMER);552502}553503554504void smp_send_stop(void)
+48
arch/arm/kernel/smp_scu.c
···11+/*22+ * linux/arch/arm/kernel/smp_scu.c33+ *44+ * Copyright (C) 2002 ARM Ltd.55+ * All Rights Reserved66+ *77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of the GNU General Public License version 2 as99+ * published by the Free Software Foundation.1010+ */1111+#include <linux/init.h>1212+#include <linux/io.h>1313+1414+#include <asm/smp_scu.h>1515+#include <asm/cacheflush.h>1616+1717+#define SCU_CTRL 0x001818+#define SCU_CONFIG 0x041919+#define SCU_CPU_STATUS 0x082020+#define SCU_INVALIDATE 0x0c2121+#define SCU_FPGA_REVISION 0x102222+2323+/*2424+ * Get the number of CPU cores from the SCU configuration2525+ */2626+unsigned int __init scu_get_core_count(void __iomem *scu_base)2727+{2828+ unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG);2929+ return (ncores & 0x03) + 1;3030+}3131+3232+/*3333+ * Enable the SCU3434+ */3535+void __init scu_enable(void __iomem *scu_base)3636+{3737+ u32 scu_ctrl;3838+3939+ scu_ctrl = __raw_readl(scu_base + SCU_CTRL);4040+ scu_ctrl |= 1;4141+ __raw_writel(scu_ctrl, scu_base + SCU_CTRL);4242+4343+ /*4444+ * Ensure that the data accessed by CPU0 before the SCU was4545+ * initialised is visible to the other CPUs.4646+ */4747+ flush_cache_all();4848+}
+175
arch/arm/kernel/smp_twd.c
···11+/*22+ * linux/arch/arm/kernel/smp_twd.c33+ *44+ * Copyright (C) 2002 ARM Ltd.55+ * All Rights Reserved66+ *77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of the GNU General Public License version 2 as99+ * published by the Free Software Foundation.1010+ */1111+#include <linux/init.h>1212+#include <linux/kernel.h>1313+#include <linux/delay.h>1414+#include <linux/device.h>1515+#include <linux/smp.h>1616+#include <linux/jiffies.h>1717+#include <linux/clockchips.h>1818+#include <linux/irq.h>1919+#include <linux/io.h>2020+2121+#include <asm/smp_twd.h>2222+#include <asm/hardware/gic.h>2323+2424+#define TWD_TIMER_LOAD 0x002525+#define TWD_TIMER_COUNTER 0x042626+#define TWD_TIMER_CONTROL 0x082727+#define TWD_TIMER_INTSTAT 0x0C2828+2929+#define TWD_WDOG_LOAD 0x203030+#define TWD_WDOG_COUNTER 0x243131+#define TWD_WDOG_CONTROL 0x283232+#define TWD_WDOG_INTSTAT 0x2C3333+#define TWD_WDOG_RESETSTAT 0x303434+#define TWD_WDOG_DISABLE 0x343535+3636+#define TWD_TIMER_CONTROL_ENABLE (1 << 0)3737+#define TWD_TIMER_CONTROL_ONESHOT (0 << 1)3838+#define TWD_TIMER_CONTROL_PERIODIC (1 << 1)3939+#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2)4040+4141+/* set up by the platform code */4242+void __iomem *twd_base;4343+4444+static unsigned long twd_timer_rate;4545+4646+static void twd_set_mode(enum clock_event_mode mode,4747+ struct clock_event_device *clk)4848+{4949+ unsigned long ctrl;5050+5151+ switch (mode) {5252+ case CLOCK_EVT_MODE_PERIODIC:5353+ /* timer load already set up */5454+ ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE5555+ | TWD_TIMER_CONTROL_PERIODIC;5656+ break;5757+ case CLOCK_EVT_MODE_ONESHOT:5858+ /* period set, and timer enabled in 'next_event' hook */5959+ ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;6060+ break;6161+ case CLOCK_EVT_MODE_UNUSED:6262+ case CLOCK_EVT_MODE_SHUTDOWN:6363+ default:6464+ ctrl = 0;6565+ }6666+6767+ __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);6868+}6969+7070+static int twd_set_next_event(unsigned long evt,7171+ struct clock_event_device *unused)7272+{7373+ unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);7474+7575+ ctrl |= TWD_TIMER_CONTROL_ENABLE;7676+7777+ __raw_writel(evt, twd_base + TWD_TIMER_COUNTER);7878+ __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);7979+8080+ return 0;8181+}8282+8383+/*8484+ * local_timer_ack: checks for a local timer interrupt.8585+ *8686+ * If a local timer interrupt has occurred, acknowledge and return 1.8787+ * Otherwise, return 0.8888+ */8989+int twd_timer_ack(void)9090+{9191+ if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {9292+ __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);9393+ return 1;9494+ }9595+9696+ return 0;9797+}9898+9999+static void __cpuinit twd_calibrate_rate(void)100100+{101101+ unsigned long load, count;102102+ u64 waitjiffies;103103+104104+ /*105105+ * If this is the first time round, we need to work out how fast106106+ * the timer ticks107107+ */108108+ if (twd_timer_rate == 0) {109109+ printk(KERN_INFO "Calibrating local timer... ");110110+111111+ /* Wait for a tick to start */112112+ waitjiffies = get_jiffies_64() + 1;113113+114114+ while (get_jiffies_64() < waitjiffies)115115+ udelay(10);116116+117117+ /* OK, now the tick has started, let's get the timer going */118118+ waitjiffies += 5;119119+120120+ /* enable, no interrupt or reload */121121+ __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);122122+123123+ /* maximum value */124124+ __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);125125+126126+ while (get_jiffies_64() < waitjiffies)127127+ udelay(10);128128+129129+ count = __raw_readl(twd_base + TWD_TIMER_COUNTER);130130+131131+ twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);132132+133133+ printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,134134+ (twd_timer_rate / 100000) % 100);135135+ }136136+137137+ load = twd_timer_rate / HZ;138138+139139+ __raw_writel(load, twd_base + TWD_TIMER_LOAD);140140+}141141+142142+/*143143+ * Setup the local clock events for a CPU.144144+ */145145+void __cpuinit twd_timer_setup(struct clock_event_device *clk)146146+{147147+ unsigned long flags;148148+149149+ twd_calibrate_rate();150150+151151+ clk->name = "local_timer";152152+ clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;153153+ clk->rating = 350;154154+ clk->set_mode = twd_set_mode;155155+ clk->set_next_event = twd_set_next_event;156156+ clk->shift = 20;157157+ clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);158158+ clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);159159+ clk->min_delta_ns = clockevent_delta2ns(0xf, clk);160160+161161+ /* Make sure our local interrupt controller has this enabled */162162+ local_irq_save(flags);163163+ get_irq_chip(clk->irq)->unmask(clk->irq);164164+ local_irq_restore(flags);165165+166166+ clockevents_register_device(clk);167167+}168168+169169+/*170170+ * take a local timer down171171+ */172172+void __cpuexit twd_timer_stop(void)173173+{174174+ __raw_writel(0, twd_base + TWD_TIMER_CONTROL);175175+}
···99 * published by the Free Software Foundation.1010 */1111#include <linux/init.h>1212-#include <linux/kernel.h>1313-#include <linux/delay.h>1414-#include <linux/device.h>1512#include <linux/smp.h>1616-#include <linux/jiffies.h>1717-#include <linux/percpu.h>1813#include <linux/clockchips.h>1919-#include <linux/irq.h>2020-#include <linux/io.h>21142222-#include <asm/hardware/arm_twd.h>2323-#include <asm/hardware/gic.h>2424-#include <mach/hardware.h>2515#include <asm/irq.h>2626-2727-static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);2828-2929-/*3030- * Used on SMP for either the local timer or IPI_TIMER3131- */3232-void local_timer_interrupt(void)3333-{3434- struct clock_event_device *clk = &__get_cpu_var(local_clockevent);3535-3636- clk->event_handler(clk);3737-}3838-3939-#ifdef CONFIG_LOCAL_TIMERS4040-4141-/* set up by the platform code */4242-void __iomem *twd_base;4343-4444-static unsigned long mpcore_timer_rate;4545-4646-static void local_timer_set_mode(enum clock_event_mode mode,4747- struct clock_event_device *clk)4848-{4949- unsigned long ctrl;5050-5151- switch(mode) {5252- case CLOCK_EVT_MODE_PERIODIC:5353- /* timer load already set up */5454- ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE5555- | TWD_TIMER_CONTROL_PERIODIC;5656- break;5757- case CLOCK_EVT_MODE_ONESHOT:5858- /* period set, and timer enabled in 'next_event' hook */5959- ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;6060- break;6161- case CLOCK_EVT_MODE_UNUSED:6262- case CLOCK_EVT_MODE_SHUTDOWN:6363- default:6464- ctrl = 0;6565- }6666-6767- __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);6868-}6969-7070-static int local_timer_set_next_event(unsigned long evt,7171- struct clock_event_device *unused)7272-{7373- unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);7474-7575- __raw_writel(evt, twd_base + TWD_TIMER_COUNTER);7676- __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, twd_base + TWD_TIMER_CONTROL);7777-7878- return 0;7979-}8080-8181-/*8282- * local_timer_ack: checks for a local timer interrupt.8383- *8484- * If a local timer interrupt has occurred, acknowledge and return 1.8585- * Otherwise, return 0.8686- */8787-int local_timer_ack(void)8888-{8989- if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {9090- __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);9191- return 1;9292- }9393-9494- return 0;9595-}9696-9797-static void __cpuinit twd_calibrate_rate(void)9898-{9999- unsigned long load, count;100100- u64 waitjiffies;101101-102102- /*103103- * If this is the first time round, we need to work out how fast104104- * the timer ticks105105- */106106- if (mpcore_timer_rate == 0) {107107- printk("Calibrating local timer... ");108108-109109- /* Wait for a tick to start */110110- waitjiffies = get_jiffies_64() + 1;111111-112112- while (get_jiffies_64() < waitjiffies)113113- udelay(10);114114-115115- /* OK, now the tick has started, let's get the timer going */116116- waitjiffies += 5;117117-118118- /* enable, no interrupt or reload */119119- __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);120120-121121- /* maximum value */122122- __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);123123-124124- while (get_jiffies_64() < waitjiffies)125125- udelay(10);126126-127127- count = __raw_readl(twd_base + TWD_TIMER_COUNTER);128128-129129- mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);130130-131131- printk("%lu.%02luMHz.\n", mpcore_timer_rate / 1000000,132132- (mpcore_timer_rate / 100000) % 100);133133- }134134-135135- load = mpcore_timer_rate / HZ;136136-137137- __raw_writel(load, twd_base + TWD_TIMER_LOAD);138138-}1616+#include <asm/smp_twd.h>1717+#include <asm/localtimer.h>1391814019/*14120 * Setup the local clock events for a CPU.14221 */143143-void __cpuinit local_timer_setup(void)2222+void __cpuinit local_timer_setup(struct clock_event_device *evt)14423{145145- unsigned int cpu = smp_processor_id();146146- struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);147147- unsigned long flags;148148-149149- twd_calibrate_rate();150150-151151- clk->name = "local_timer";152152- clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;153153- clk->rating = 350;154154- clk->set_mode = local_timer_set_mode;155155- clk->set_next_event = local_timer_set_next_event;156156- clk->irq = IRQ_LOCALTIMER;157157- clk->cpumask = cpumask_of(cpu);158158- clk->shift = 20;159159- clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift);160160- clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);161161- clk->min_delta_ns = clockevent_delta2ns(0xf, clk);162162-163163- /* Make sure our local interrupt controller has this enabled */164164- local_irq_save(flags);165165- get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER);166166- local_irq_restore(flags);167167-168168- clockevents_register_device(clk);2424+ evt->irq = IRQ_LOCALTIMER;2525+ twd_timer_setup(evt);16926}170170-171171-/*172172- * take a local timer down173173- */174174-void __cpuexit local_timer_stop(void)175175-{176176- __raw_writel(0, twd_base + TWD_TIMER_CONTROL);177177-}178178-179179-#else /* CONFIG_LOCAL_TIMERS */180180-181181-static void dummy_timer_set_mode(enum clock_event_mode mode,182182- struct clock_event_device *clk)183183-{184184-}185185-186186-void __cpuinit local_timer_setup(void)187187-{188188- unsigned int cpu = smp_processor_id();189189- struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);190190-191191- clk->name = "dummy_timer";192192- clk->features = CLOCK_EVT_FEAT_ONESHOT |193193- CLOCK_EVT_FEAT_PERIODIC |194194- CLOCK_EVT_FEAT_DUMMY;195195- clk->rating = 400;196196- clk->mult = 1;197197- clk->set_mode = dummy_timer_set_mode;198198- clk->broadcast = smp_timer_broadcast;199199- clk->cpumask = cpumask_of(cpu);200200-201201- clockevents_register_device(clk);202202-}203203-204204-#endif /* !CONFIG_LOCAL_TIMERS */
+15-34
arch/arm/mach-realview/platsmp.c
···1919#include <asm/cacheflush.h>2020#include <mach/hardware.h>2121#include <asm/mach-types.h>2222+#include <asm/localtimer.h>22232324#include <mach/board-eb.h>2425#include <mach/board-pb11mp.h>2525-#include <mach/scu.h>2626+#include <asm/smp_scu.h>26272728#include "core.h"2829···4544 return (void __iomem *)0;4645}47464848-static unsigned int __init get_core_count(void)4747+static inline unsigned int get_core_count(void)4948{5050- unsigned int ncores;5149 void __iomem *scu_base = scu_base_addr();5252-5353- if (scu_base) {5454- ncores = __raw_readl(scu_base + SCU_CONFIG);5555- ncores = (ncores & 0x03) + 1;5656- } else5757- ncores = 1;5858-5959- return ncores;6060-}6161-6262-/*6363- * Setup the SCU6464- */6565-static void scu_enable(void)6666-{6767- u32 scu_ctrl;6868- void __iomem *scu_base = scu_base_addr();6969-7070- scu_ctrl = __raw_readl(scu_base + SCU_CTRL);7171- scu_ctrl |= 1;7272- __raw_writel(scu_ctrl, scu_base + SCU_CTRL);5050+ if (scu_base)5151+ return scu_get_core_count(scu_base);5252+ return 1;7353}74547555static DEFINE_SPINLOCK(boot_lock);···166184 unsigned int i, ncores = get_core_count();167185168186 for (i = 0; i < ncores; i++)169169- cpu_set(i, cpu_possible_map);187187+ set_cpu_possible(i, true);170188}171189172190void __init smp_prepare_cpus(unsigned int max_cpus)···199217 if (max_cpus > ncores)200218 max_cpus = ncores;201219202202-#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)203203- /*204204- * Enable the local timer or broadcast device for the boot CPU.205205- */206206- local_timer_setup();207207-#endif208208-209220 /*210221 * Initialise the present map, which describes the set of CPUs211222 * actually populated at the present time.212223 */213224 for (i = 0; i < max_cpus; i++)214214- cpu_set(i, cpu_present_map);225225+ set_cpu_present(i, true);215226216227 /*217228 * Initialise the SCU if there are more than one CPU and let···214239 * WFI215240 */216241 if (max_cpus > 1) {217217- scu_enable();242242+ /*243243+ * Enable the local timer or broadcast device for the244244+ * boot CPU, but only if we have more than one CPU.245245+ */246246+ percpu_timer_setup();247247+248248+ scu_enable(scu_base_addr());218249 poke_milo();219250 }220251}