···22 * linux/arch/arm/kernel/head.S33 *44 * Copyright (C) 1994-2002 Russell King55+ * Copyright (c) 2003 ARM Limited66+ * All Rights Reserved57 *68 * This program is free software; you can redistribute it and/or modify79 * it under the terms of the GNU General Public License version 2 as···166164 bic r4, r0, #CR_A @ Clear 'A' bit167165 stmia r6, {r0, r4} @ Save control register values168166 b start_kernel167167+168168+#if defined(CONFIG_SMP)169169+ .type secondary_startup, #function170170+ENTRY(secondary_startup)171171+ /*172172+ * Common entry point for secondary CPUs.173173+ *174174+ * Ensure that we're in SVC mode, and IRQs are disabled. Lookup175175+ * the processor type - there is no need to check the machine type176176+ * as it has already been validated by the primary processor.177177+ */178178+ msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC179179+ bl __lookup_processor_type180180+ movs r10, r5 @ invalid processor?181181+ moveq r0, #'p' @ yes, error 'p'182182+ beq __error183183+184184+ /*185185+ * Use the page tables supplied from __cpu_up.186186+ */187187+ adr r4, __secondary_data188188+ ldmia r4, {r5, r6, r13} @ address to jump to after189189+ sub r4, r4, r5 @ mmu has been enabled190190+ ldr r4, [r6, r4] @ get secondary_data.pgdir191191+ adr lr, __enable_mmu @ return address192192+ add pc, r10, #12 @ initialise processor193193+ @ (return control reg)194194+195195+ /*196196+ * r6 = &secondary_data197197+ */198198+ENTRY(__secondary_switched)199199+ ldr sp, [r6, #4] @ get secondary_data.stack200200+ mov fp, #0201201+ b secondary_start_kernel202202+203203+ .type __secondary_data, %object204204+__secondary_data:205205+ .long .206206+ .long secondary_data207207+ .long __secondary_switched208208+#endif /* defined(CONFIG_SMP) */169209170210171211
+1-1
arch/arm/kernel/setup.c
···328328 * cpu_init dumps the cache information, initialises SMP specific329329 * information, and sets up the per-CPU stacks.330330 */331331-void __init cpu_init(void)331331+void cpu_init(void)332332{333333 unsigned int cpu = smp_processor_id();334334 struct stack *stk = &stacks[cpu];
+107
arch/arm/kernel/smp.c
···2424#include <asm/atomic.h>2525#include <asm/cacheflush.h>2626#include <asm/cpu.h>2727+#include <asm/mmu_context.h>2828+#include <asm/pgtable.h>2929+#include <asm/pgalloc.h>2730#include <asm/processor.h>2831#include <asm/tlbflush.h>2932#include <asm/ptrace.h>···3835 */3936cpumask_t cpu_present_mask;4037cpumask_t cpu_online_map;3838+3939+/*4040+ * as from 2.5, kernels no longer have an init_tasks structure4141+ * so we need some other way of telling a new secondary core4242+ * where to place its SVC stack4343+ */4444+struct secondary_data secondary_data;41454246/*4347 * structures for inter-processor calls···8171int __init __cpu_up(unsigned int cpu)8272{8373 struct task_struct *idle;7474+ pgd_t *pgd;7575+ pmd_t *pmd;8476 int ret;85778678 /*···9684 }97859886 /*8787+ * Allocate initial page tables to allow the new CPU to8888+ * enable the MMU safely. This essentially means a set8989+ * of our "standard" page tables, with the addition of9090+ * a 1:1 mapping for the physical address of the kernel.9191+ */9292+ pgd = pgd_alloc(&init_mm);9393+ pmd = pmd_offset(pgd, PHYS_OFFSET);9494+ *pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) |9595+ PMD_TYPE_SECT | PMD_SECT_AP_WRITE);9696+9797+ /*9898+ * We need to tell the secondary core where to find9999+ * its stack and the page tables.100100+ */101101+ secondary_data.stack = (void *)idle->thread_info + THREAD_SIZE - 8;102102+ secondary_data.pgdir = virt_to_phys(pgd);103103+ wmb();104104+105105+ /*99106 * Now bring the CPU into our world.100107 */101108 ret = boot_secondary(cpu, idle);109109+ if (ret == 0) {110110+ unsigned long timeout;111111+112112+ /*113113+ * CPU was successfully started, wait for it114114+ * to come online or time out.115115+ */116116+ timeout = jiffies + HZ;117117+ while (time_before(jiffies, timeout)) {118118+ if (cpu_online(cpu))119119+ break;120120+121121+ udelay(10);122122+ barrier();123123+ }124124+125125+ if (!cpu_online(cpu))126126+ ret = -EIO;127127+ }128128+129129+ secondary_data.stack = 0;130130+ secondary_data.pgdir = 0;131131+132132+ *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0);133133+ pgd_free(pgd);134134+102135 if (ret) {103136 printk(KERN_CRIT "cpu_up: processor %d failed to boot\n", cpu);104137 /*···15295 }1539615497 return ret;9898+}9999+100100+/*101101+ * This is the secondary CPU boot entry. We're using this CPUs102102+ * idle thread stack, but a set of temporary page tables.103103+ */104104+asmlinkage void __init secondary_start_kernel(void)105105+{106106+ struct mm_struct *mm = &init_mm;107107+ unsigned int cpu = smp_processor_id();108108+109109+ printk("CPU%u: Booted secondary processor\n", cpu);110110+111111+ /*112112+ * All kernel threads share the same mm context; grab a113113+ * reference and switch to it.114114+ */115115+ atomic_inc(&mm->mm_users);116116+ atomic_inc(&mm->mm_count);117117+ current->active_mm = mm;118118+ cpu_set(cpu, mm->cpu_vm_mask);119119+ cpu_switch_mm(mm->pgd, mm);120120+ enter_lazy_tlb(mm, current);121121+122122+ cpu_init();123123+124124+ /*125125+ * Give the platform a chance to do its own initialisation.126126+ */127127+ platform_secondary_init(cpu);128128+129129+ /*130130+ * Enable local interrupts.131131+ */132132+ local_irq_enable();133133+ local_fiq_enable();134134+135135+ calibrate_delay();136136+137137+ smp_store_cpu_info(cpu);138138+139139+ /*140140+ * OK, now it's safe to let the boot CPU continue141141+ */142142+ cpu_set(cpu, cpu_online_map);143143+144144+ /*145145+ * OK, it's off to the idle thread for us146146+ */147147+ cpu_idle();155148}156149157150/*
···1414#include <linux/spinlock.h>1515#include <linux/interrupt.h>1616#include <linux/sched.h>1717+#include <linux/smp.h>17181819#include <asm/hardware.h>1920#include <asm/irq.h>···222221 */223222 timer1->TimerClear = 1;224223225225- timer_tick(regs);224224+ /*225225+ * the clock tick routines are only processed on the226226+ * primary CPU227227+ */228228+ if (hard_smp_processor_id() == 0) {229229+ nmi_tick();230230+ timer_tick(regs);231231+#ifdef CONFIG_SMP232232+ smp_send_timer();233233+#endif234234+ }235235+236236+#ifdef CONFIG_SMP237237+ /*238238+ * this is the ARM equivalent of the APIC timer interrupt239239+ */240240+ update_process_times(user_mode(regs));241241+#endif /* CONFIG_SMP */226242227243 write_sequnlock(&xtime_lock);228244
+37
arch/arm/mach-integrator/headsmp.S
···11+/*22+ * linux/arch/arm/mach-integrator/headsmp.S33+ *44+ * Copyright (c) 2003 ARM Limited55+ * 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/linkage.h>1212+#include <linux/init.h>1313+1414+ __INIT1515+1616+/*1717+ * Integrator specific entry point for secondary CPUs. This provides1818+ * a "holding pen" into which all secondary cores are held until we're1919+ * ready for them to initialise.2020+ */2121+ENTRY(integrator_secondary_startup)2222+ adr r4, 1f2323+ ldmia r4, {r5, r6}2424+ sub r4, r4, r52525+ ldr r6, [r6, r4]2626+pen: ldr r7, [r6]2727+ cmp r7, r02828+ bne pen2929+3030+ /*3131+ * we've been released from the holding pen: secondary_stack3232+ * should now contain the SVC stack for this core3333+ */3434+ b secondary_startup3535+3636+1: .long .3737+ .long phys_pen_release
···11+/*22+ * linux/arch/arm/mach-cintegrator/platsmp.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/sched.h>1414+#include <linux/errno.h>1515+#include <linux/mm.h>1616+1717+#include <asm/atomic.h>1818+#include <asm/delay.h>1919+#include <asm/mmu_context.h>2020+#include <asm/procinfo.h>2121+#include <asm/ptrace.h>2222+#include <asm/smp.h>2323+2424+extern void integrator_secondary_startup(void);2525+2626+/*2727+ * control for which core is the next to come out of the secondary2828+ * boot "holding pen"2929+ */3030+volatile int __initdata pen_release = -1;3131+unsigned long __initdata phys_pen_release = 0;3232+3333+static DEFINE_SPINLOCK(boot_lock);3434+3535+void __init platform_secondary_init(unsigned int cpu)3636+{3737+ /*3838+ * the primary core may have used a "cross call" soft interrupt3939+ * to get this processor out of WFI in the BootMonitor - make4040+ * sure that we are no longer being sent this soft interrupt4141+ */4242+ smp_cross_call_done(cpumask_of_cpu(cpu));4343+4444+ /*4545+ * if any interrupts are already enabled for the primary4646+ * core (e.g. timer irq), then they will not have been enabled4747+ * for us: do so4848+ */4949+ secondary_scan_irqs();5050+5151+ /*5252+ * let the primary processor know we're out of the5353+ * pen, then head off into the C entry point5454+ */5555+ pen_release = -1;5656+5757+ /*5858+ * Synchronise with the boot thread.5959+ */6060+ spin_lock(&boot_lock);6161+ spin_unlock(&boot_lock);6262+}6363+6464+int __init boot_secondary(unsigned int cpu, struct task_struct *idle)6565+{6666+ unsigned long timeout;6767+6868+ /*6969+ * set synchronisation state between this boot processor7070+ * and the secondary one7171+ */7272+ spin_lock(&boot_lock);7373+7474+ /*7575+ * The secondary processor is waiting to be released from7676+ * the holding pen - release it, then wait for it to flag7777+ * that it has been released by resetting pen_release.7878+ *7979+ * Note that "pen_release" is the hardware CPU ID, whereas8080+ * "cpu" is Linux's internal ID.8181+ */8282+ pen_release = cpu;8383+8484+ /*8585+ * XXX8686+ *8787+ * This is a later addition to the booting protocol: the8888+ * bootMonitor now puts secondary cores into WFI, so8989+ * poke_milo() no longer gets the cores moving; we need9090+ * to send a soft interrupt to wake the secondary core.9191+ * Use smp_cross_call() for this, since there's little9292+ * point duplicating the code here9393+ */9494+ smp_cross_call(cpumask_of_cpu(cpu));9595+9696+ timeout = jiffies + (1 * HZ);9797+ while (time_before(jiffies, timeout)) {9898+ if (pen_release == -1)9999+ break;100100+101101+ udelay(10);102102+ }103103+104104+ /*105105+ * now the secondary core is starting up let it run its106106+ * calibrations, then wait for it to finish107107+ */108108+ spin_unlock(&boot_lock);109109+110110+ return pen_release != -1 ? -ENOSYS : 0;111111+}112112+113113+static void __init poke_milo(void)114114+{115115+ extern void secondary_startup(void);116116+117117+ /* nobody is to be released from the pen yet */118118+ pen_release = -1;119119+120120+ phys_pen_release = virt_to_phys(&pen_release);121121+122122+ /*123123+ * write the address of secondary startup into the system-wide124124+ * flags register, then clear the bottom two bits, which is what125125+ * BootMonitor is waiting for126126+ */127127+#if 1128128+#define CINTEGRATOR_HDR_FLAGSS_OFFSET 0x30129129+ __raw_writel(virt_to_phys(integrator_secondary_startup),130130+ (IO_ADDRESS(INTEGRATOR_HDR_BASE) +131131+ CINTEGRATOR_HDR_FLAGSS_OFFSET));132132+#define CINTEGRATOR_HDR_FLAGSC_OFFSET 0x34133133+ __raw_writel(3,134134+ (IO_ADDRESS(INTEGRATOR_HDR_BASE) +135135+ CINTEGRATOR_HDR_FLAGSC_OFFSET));136136+#endif137137+138138+ mb();139139+}140140+141141+void __init smp_prepare_cpus(unsigned int max_cpus)142142+{143143+ unsigned int ncores = get_core_count();144144+ unsigned int cpu = smp_processor_id();145145+ int i;146146+147147+ /* sanity check */148148+ if (ncores == 0) {149149+ printk(KERN_ERR150150+ "Integrator/CP: strange CM count of 0? Default to 1\n");151151+152152+ ncores = 1;153153+ }154154+155155+ if (ncores > NR_CPUS) {156156+ printk(KERN_WARNING157157+ "Integrator/CP: no. of cores (%d) greater than configured "158158+ "maximum of %d - clipping\n",159159+ ncores, NR_CPUS);160160+ ncores = NR_CPUS;161161+ }162162+163163+ /*164164+ * start with some more config for the Boot CPU, now that165165+ * the world is a bit more alive (which was not the case166166+ * when smp_prepare_boot_cpu() was called)167167+ */168168+ smp_store_cpu_info(cpu);169169+170170+ /*171171+ * are we trying to boot more cores than exist?172172+ */173173+ if (max_cpus > ncores)174174+ max_cpus = ncores;175175+176176+ /*177177+ * Initialise the present mask - this tells us which CPUs should178178+ * be present.179179+ */180180+ for (i = 0; i < max_cpus; i++) {181181+ cpu_set(i, cpu_present_mask);182182+ }183183+184184+ /*185185+ * Do we need any more CPUs? If so, then let them know where186186+ * to start. Note that, on modern versions of MILO, the "poke"187187+ * doesn't actually do anything until each individual core is188188+ * sent a soft interrupt to get it out of WFI189189+ */190190+ if (max_cpus > 1)191191+ poke_milo();192192+}
+2
arch/arm/mach-pxa/pm.c
···133133 /* *** go zzz *** */134134 pxa_cpu_pm_enter(state);135135136136+ cpu_init();137137+136138 /* after sleeping, validate the checksum */137139 checksum = 0;138140 for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
+2
arch/arm/mach-sa1100/pm.c
···8888 /* go zzz */8989 sa1100_cpu_suspend();90909191+ cpu_init();9292+9193 /*9294 * Ensure not to come back here if it wasn't intended9395 */
···5555 */5656extern int boot_secondary(unsigned int cpu, struct task_struct *);57575858+/*5959+ * Perform platform specific initialisation of the specified CPU.6060+ */6161+extern void platform_secondary_init(unsigned int cpu);6262+6363+/*6464+ * Initial data for bringing up a secondary CPU.6565+ */6666+struct secondary_data {6767+ unsigned long pgdir;6868+ void *stack;6969+};7070+extern struct secondary_data secondary_data;7171+5872#endif /* ifndef __ASM_ARM_SMP_H */