Path: blob/master/arch/powerpc/platforms/cell/smp.c
10818 views
/*1* SMP support for BPA machines.2*3* Dave Engebretsen, Peter Bergner, and4* Mike Corrigan {engebret|bergner|mikec}@us.ibm.com5*6* Plus various changes from other IBM teams...7*8* This program is free software; you can redistribute it and/or9* modify it under the terms of the GNU General Public License10* as published by the Free Software Foundation; either version11* 2 of the License, or (at your option) any later version.12*/1314#undef DEBUG1516#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/sched.h>19#include <linux/smp.h>20#include <linux/interrupt.h>21#include <linux/delay.h>22#include <linux/init.h>23#include <linux/spinlock.h>24#include <linux/cache.h>25#include <linux/err.h>26#include <linux/sysdev.h>27#include <linux/cpu.h>2829#include <asm/ptrace.h>30#include <asm/atomic.h>31#include <asm/irq.h>32#include <asm/page.h>33#include <asm/pgtable.h>34#include <asm/io.h>35#include <asm/prom.h>36#include <asm/smp.h>37#include <asm/paca.h>38#include <asm/machdep.h>39#include <asm/cputable.h>40#include <asm/firmware.h>41#include <asm/system.h>42#include <asm/rtas.h>43#include <asm/cputhreads.h>4445#include "interrupt.h"46#include <asm/udbg.h>4748#ifdef DEBUG49#define DBG(fmt...) udbg_printf(fmt)50#else51#define DBG(fmt...)52#endif5354/*55* The Primary thread of each non-boot processor was started from the OF client56* interface by prom_hold_cpus and is spinning on secondary_hold_spinloop.57*/58static cpumask_t of_spin_map;5960/**61* smp_startup_cpu() - start the given cpu62*63* At boot time, there is nothing to do for primary threads which were64* started from Open Firmware. For anything else, call RTAS with the65* appropriate start location.66*67* Returns:68* 0 - failure69* 1 - success70*/71static inline int __devinit smp_startup_cpu(unsigned int lcpu)72{73int status;74unsigned long start_here = __pa((u32)*((unsigned long *)75generic_secondary_smp_init));76unsigned int pcpu;77int start_cpu;7879if (cpumask_test_cpu(lcpu, &of_spin_map))80/* Already started by OF and sitting in spin loop */81return 1;8283pcpu = get_hard_smp_processor_id(lcpu);8485/* Fixup atomic count: it exited inside IRQ handler. */86task_thread_info(paca[lcpu].__current)->preempt_count = 0;8788/*89* If the RTAS start-cpu token does not exist then presume the90* cpu is already spinning.91*/92start_cpu = rtas_token("start-cpu");93if (start_cpu == RTAS_UNKNOWN_SERVICE)94return 1;9596status = rtas_call(start_cpu, 3, 1, NULL, pcpu, start_here, lcpu);97if (status != 0) {98printk(KERN_ERR "start-cpu failed: %i\n", status);99return 0;100}101102return 1;103}104105static int __init smp_iic_probe(void)106{107iic_request_IPIs();108109return cpumask_weight(cpu_possible_mask);110}111112static void __devinit smp_cell_setup_cpu(int cpu)113{114if (cpu != boot_cpuid)115iic_setup_cpu();116117/*118* change default DABRX to allow user watchpoints119*/120mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER);121}122123static int __devinit smp_cell_kick_cpu(int nr)124{125BUG_ON(nr < 0 || nr >= NR_CPUS);126127if (!smp_startup_cpu(nr))128return -ENOENT;129130/*131* The processor is currently spinning, waiting for the132* cpu_start field to become non-zero After we set cpu_start,133* the processor will continue on to secondary_start134*/135paca[nr].cpu_start = 1;136137return 0;138}139140static int smp_cell_cpu_bootable(unsigned int nr)141{142/* Special case - we inhibit secondary thread startup143* during boot if the user requests it. Odd-numbered144* cpus are assumed to be secondary threads.145*/146if (system_state < SYSTEM_RUNNING &&147cpu_has_feature(CPU_FTR_SMT) &&148!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)149return 0;150151return 1;152}153static struct smp_ops_t bpa_iic_smp_ops = {154.message_pass = iic_message_pass,155.probe = smp_iic_probe,156.kick_cpu = smp_cell_kick_cpu,157.setup_cpu = smp_cell_setup_cpu,158.cpu_bootable = smp_cell_cpu_bootable,159};160161/* This is called very early */162void __init smp_init_cell(void)163{164int i;165166DBG(" -> smp_init_cell()\n");167168smp_ops = &bpa_iic_smp_ops;169170/* Mark threads which are still spinning in hold loops. */171if (cpu_has_feature(CPU_FTR_SMT)) {172for_each_present_cpu(i) {173if (cpu_thread_in_core(i) == 0)174cpumask_set_cpu(i, &of_spin_map);175}176} else177cpumask_copy(&of_spin_map, cpu_present_mask);178179cpumask_clear_cpu(boot_cpuid, &of_spin_map);180181/* Non-lpar has additional take/give timebase */182if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {183smp_ops->give_timebase = rtas_give_timebase;184smp_ops->take_timebase = rtas_take_timebase;185}186187DBG(" <- smp_init_cell()\n");188}189190191