Loading arch/arm/kernel/head.S +44 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ * linux/arch/arm/kernel/head.S * * Copyright (C) 1994-2002 Russell King * Copyright (c) 2003 ARM Limited * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as Loading Loading @@ -165,6 +167,48 @@ __mmap_switched: stmia r6, {r0, r4} @ Save control register values b start_kernel #if defined(CONFIG_SMP) .type secondary_startup, #function ENTRY(secondary_startup) /* * Common entry point for secondary CPUs. * * Ensure that we're in SVC mode, and IRQs are disabled. Lookup * the processor type - there is no need to check the machine type * as it has already been validated by the primary processor. */ msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC bl __lookup_processor_type movs r10, r5 @ invalid processor? moveq r0, #'p' @ yes, error 'p' beq __error /* * Use the page tables supplied from __cpu_up. */ adr r4, __secondary_data ldmia r4, {r5, r6, r13} @ address to jump to after sub r4, r4, r5 @ mmu has been enabled ldr r4, [r6, r4] @ get secondary_data.pgdir adr lr, __enable_mmu @ return address add pc, r10, #12 @ initialise processor @ (return control reg) /* * r6 = &secondary_data */ ENTRY(__secondary_switched) ldr sp, [r6, #4] @ get secondary_data.stack mov fp, #0 b secondary_start_kernel .type __secondary_data, %object __secondary_data: .long . .long secondary_data .long __secondary_switched #endif /* defined(CONFIG_SMP) */ /* Loading arch/arm/kernel/smp.c +107 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ #include <asm/atomic.h> #include <asm/cacheflush.h> #include <asm/cpu.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> #include <asm/processor.h> #include <asm/tlbflush.h> #include <asm/ptrace.h> Loading @@ -36,6 +39,13 @@ cpumask_t cpu_present_mask; cpumask_t cpu_online_map; /* * as from 2.5, kernels no longer have an init_tasks structure * so we need some other way of telling a new secondary core * where to place its SVC stack */ struct secondary_data secondary_data; /* * structures for inter-processor calls * - A collection of single bit ipi messages. Loading Loading @@ -71,6 +81,8 @@ static DEFINE_SPINLOCK(smp_call_function_lock); int __init __cpu_up(unsigned int cpu) { struct task_struct *idle; pgd_t *pgd; pmd_t *pmd; int ret; /* Loading @@ -83,10 +95,55 @@ int __init __cpu_up(unsigned int cpu) return PTR_ERR(idle); } /* * Allocate initial page tables to allow the new CPU to * enable the MMU safely. This essentially means a set * of our "standard" page tables, with the addition of * a 1:1 mapping for the physical address of the kernel. */ pgd = pgd_alloc(&init_mm); pmd = pmd_offset(pgd, PHYS_OFFSET); *pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) | PMD_TYPE_SECT | PMD_SECT_AP_WRITE); /* * We need to tell the secondary core where to find * its stack and the page tables. */ secondary_data.stack = (void *)idle->thread_info + THREAD_SIZE - 8; secondary_data.pgdir = virt_to_phys(pgd); wmb(); /* * Now bring the CPU into our world. */ ret = boot_secondary(cpu, idle); if (ret == 0) { unsigned long timeout; /* * CPU was successfully started, wait for it * to come online or time out. */ timeout = jiffies + HZ; while (time_before(jiffies, timeout)) { if (cpu_online(cpu)) break; udelay(10); barrier(); } if (!cpu_online(cpu)) ret = -EIO; } secondary_data.stack = 0; secondary_data.pgdir = 0; *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0); pgd_free(pgd); if (ret) { printk(KERN_CRIT "cpu_up: processor %d failed to boot\n", cpu); /* Loading @@ -97,6 +154,56 @@ int __init __cpu_up(unsigned int cpu) return ret; } /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. */ asmlinkage void __init secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; unsigned int cpu = smp_processor_id(); printk("CPU%u: Booted secondary processor\n", cpu); /* * All kernel threads share the same mm context; grab a * reference and switch to it. */ atomic_inc(&mm->mm_users); atomic_inc(&mm->mm_count); current->active_mm = mm; cpu_set(cpu, mm->cpu_vm_mask); cpu_switch_mm(mm->pgd, mm); enter_lazy_tlb(mm, current); cpu_init(); /* * Give the platform a chance to do its own initialisation. */ platform_secondary_init(cpu); /* * Enable local interrupts. */ local_irq_enable(); local_fiq_enable(); calibrate_delay(); smp_store_cpu_info(cpu); /* * OK, now it's safe to let the boot CPU continue */ cpu_set(cpu, cpu_online_map); /* * OK, it's off to the idle thread for us */ cpu_idle(); } /* * Called by both boot and secondaries to move global data into * per-processor storage. Loading arch/arm/mach-integrator/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -12,3 +12,4 @@ obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_PCI) += pci_v3.o pci.o obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o arch/arm/mach-integrator/core.c +19 −1 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/smp.h> #include <asm/hardware.h> #include <asm/irq.h> Loading Loading @@ -221,7 +222,24 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ timer1->TimerClear = 1; /* * the clock tick routines are only processed on the * primary CPU */ if (hard_smp_processor_id() == 0) { nmi_tick(); timer_tick(regs); #ifdef CONFIG_SMP smp_send_timer(); #endif } #ifdef CONFIG_SMP /* * this is the ARM equivalent of the APIC timer interrupt */ update_process_times(user_mode(regs)); #endif /* CONFIG_SMP */ write_sequnlock(&xtime_lock); Loading arch/arm/mach-integrator/headsmp.S 0 → 100644 +37 −0 Original line number Diff line number Diff line /* * linux/arch/arm/mach-integrator/headsmp.S * * Copyright (c) 2003 ARM Limited * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/linkage.h> #include <linux/init.h> __INIT /* * Integrator specific entry point for secondary CPUs. This provides * a "holding pen" into which all secondary cores are held until we're * ready for them to initialise. */ ENTRY(integrator_secondary_startup) adr r4, 1f ldmia r4, {r5, r6} sub r4, r4, r5 ldr r6, [r6, r4] pen: ldr r7, [r6] cmp r7, r0 bne pen /* * we've been released from the holding pen: secondary_stack * should now contain the SVC stack for this core */ b secondary_startup 1: .long . .long phys_pen_release Loading
arch/arm/kernel/head.S +44 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ * linux/arch/arm/kernel/head.S * * Copyright (C) 1994-2002 Russell King * Copyright (c) 2003 ARM Limited * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as Loading Loading @@ -165,6 +167,48 @@ __mmap_switched: stmia r6, {r0, r4} @ Save control register values b start_kernel #if defined(CONFIG_SMP) .type secondary_startup, #function ENTRY(secondary_startup) /* * Common entry point for secondary CPUs. * * Ensure that we're in SVC mode, and IRQs are disabled. Lookup * the processor type - there is no need to check the machine type * as it has already been validated by the primary processor. */ msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC bl __lookup_processor_type movs r10, r5 @ invalid processor? moveq r0, #'p' @ yes, error 'p' beq __error /* * Use the page tables supplied from __cpu_up. */ adr r4, __secondary_data ldmia r4, {r5, r6, r13} @ address to jump to after sub r4, r4, r5 @ mmu has been enabled ldr r4, [r6, r4] @ get secondary_data.pgdir adr lr, __enable_mmu @ return address add pc, r10, #12 @ initialise processor @ (return control reg) /* * r6 = &secondary_data */ ENTRY(__secondary_switched) ldr sp, [r6, #4] @ get secondary_data.stack mov fp, #0 b secondary_start_kernel .type __secondary_data, %object __secondary_data: .long . .long secondary_data .long __secondary_switched #endif /* defined(CONFIG_SMP) */ /* Loading
arch/arm/kernel/smp.c +107 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ #include <asm/atomic.h> #include <asm/cacheflush.h> #include <asm/cpu.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> #include <asm/processor.h> #include <asm/tlbflush.h> #include <asm/ptrace.h> Loading @@ -36,6 +39,13 @@ cpumask_t cpu_present_mask; cpumask_t cpu_online_map; /* * as from 2.5, kernels no longer have an init_tasks structure * so we need some other way of telling a new secondary core * where to place its SVC stack */ struct secondary_data secondary_data; /* * structures for inter-processor calls * - A collection of single bit ipi messages. Loading Loading @@ -71,6 +81,8 @@ static DEFINE_SPINLOCK(smp_call_function_lock); int __init __cpu_up(unsigned int cpu) { struct task_struct *idle; pgd_t *pgd; pmd_t *pmd; int ret; /* Loading @@ -83,10 +95,55 @@ int __init __cpu_up(unsigned int cpu) return PTR_ERR(idle); } /* * Allocate initial page tables to allow the new CPU to * enable the MMU safely. This essentially means a set * of our "standard" page tables, with the addition of * a 1:1 mapping for the physical address of the kernel. */ pgd = pgd_alloc(&init_mm); pmd = pmd_offset(pgd, PHYS_OFFSET); *pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) | PMD_TYPE_SECT | PMD_SECT_AP_WRITE); /* * We need to tell the secondary core where to find * its stack and the page tables. */ secondary_data.stack = (void *)idle->thread_info + THREAD_SIZE - 8; secondary_data.pgdir = virt_to_phys(pgd); wmb(); /* * Now bring the CPU into our world. */ ret = boot_secondary(cpu, idle); if (ret == 0) { unsigned long timeout; /* * CPU was successfully started, wait for it * to come online or time out. */ timeout = jiffies + HZ; while (time_before(jiffies, timeout)) { if (cpu_online(cpu)) break; udelay(10); barrier(); } if (!cpu_online(cpu)) ret = -EIO; } secondary_data.stack = 0; secondary_data.pgdir = 0; *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0); pgd_free(pgd); if (ret) { printk(KERN_CRIT "cpu_up: processor %d failed to boot\n", cpu); /* Loading @@ -97,6 +154,56 @@ int __init __cpu_up(unsigned int cpu) return ret; } /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. */ asmlinkage void __init secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; unsigned int cpu = smp_processor_id(); printk("CPU%u: Booted secondary processor\n", cpu); /* * All kernel threads share the same mm context; grab a * reference and switch to it. */ atomic_inc(&mm->mm_users); atomic_inc(&mm->mm_count); current->active_mm = mm; cpu_set(cpu, mm->cpu_vm_mask); cpu_switch_mm(mm->pgd, mm); enter_lazy_tlb(mm, current); cpu_init(); /* * Give the platform a chance to do its own initialisation. */ platform_secondary_init(cpu); /* * Enable local interrupts. */ local_irq_enable(); local_fiq_enable(); calibrate_delay(); smp_store_cpu_info(cpu); /* * OK, now it's safe to let the boot CPU continue */ cpu_set(cpu, cpu_online_map); /* * OK, it's off to the idle thread for us */ cpu_idle(); } /* * Called by both boot and secondaries to move global data into * per-processor storage. Loading
arch/arm/mach-integrator/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -12,3 +12,4 @@ obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_PCI) += pci_v3.o pci.o obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o
arch/arm/mach-integrator/core.c +19 −1 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/smp.h> #include <asm/hardware.h> #include <asm/irq.h> Loading Loading @@ -221,7 +222,24 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ timer1->TimerClear = 1; /* * the clock tick routines are only processed on the * primary CPU */ if (hard_smp_processor_id() == 0) { nmi_tick(); timer_tick(regs); #ifdef CONFIG_SMP smp_send_timer(); #endif } #ifdef CONFIG_SMP /* * this is the ARM equivalent of the APIC timer interrupt */ update_process_times(user_mode(regs)); #endif /* CONFIG_SMP */ write_sequnlock(&xtime_lock); Loading
arch/arm/mach-integrator/headsmp.S 0 → 100644 +37 −0 Original line number Diff line number Diff line /* * linux/arch/arm/mach-integrator/headsmp.S * * Copyright (c) 2003 ARM Limited * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/linkage.h> #include <linux/init.h> __INIT /* * Integrator specific entry point for secondary CPUs. This provides * a "holding pen" into which all secondary cores are held until we're * ready for them to initialise. */ ENTRY(integrator_secondary_startup) adr r4, 1f ldmia r4, {r5, r6} sub r4, r4, r5 ldr r6, [r6, r4] pen: ldr r7, [r6] cmp r7, r0 bne pen /* * we've been released from the holding pen: secondary_stack * should now contain the SVC stack for this core */ b secondary_startup 1: .long . .long phys_pen_release