/*1* linux/arch/m32r/kernel/smpboot.c2* orig : i386 2.4.103*4* M32R SMP booting functions5*6* Copyright (c) 2001, 2002, 2003 Hitoshi Yamamoto7*8* Taken from i386 version.9* (c) 1995 Alan Cox, Building #3 <[email protected]>10* (c) 1998, 1999, 2000 Ingo Molnar <[email protected]>11*12* Much of the core SMP work is based on previous work by Thomas Radke, to13* whom a great many thanks are extended.14*15* Thanks to Intel for making available several different Pentium,16* Pentium Pro and Pentium-II/Xeon MP machines.17* Original development of Linux SMP code supported by Caldera.18*19* This code is released under the GNU General Public License version 2 or20* later.21*22* Fixes23* Felix Koop : NR_CPUS used properly24* Jose Renau : Handle single CPU case.25* Alan Cox : By repeated request26* 8) - Total BogoMIP report.27* Greg Wright : Fix for kernel stacks panic.28* Erich Boleyn : MP v1.4 and additional changes.29* Matthias Sattler : Changes for 2.1 kernel map.30* Michel Lespinasse : Changes for 2.1 kernel map.31* Michael Chastain : Change trampoline.S to gnu as.32* Alan Cox : Dumb bug: 'B' step PPro's are fine33* Ingo Molnar : Added APIC timers, based on code34* from Jose Renau35* Ingo Molnar : various cleanups and rewrites36* Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.37* Maciej W. Rozycki : Bits for genuine 82489DX APICs38* Martin J. Bligh : Added support for multi-quad systems39*/4041#include <linux/module.h>42#include <linux/cpu.h>43#include <linux/init.h>44#include <linux/kernel.h>45#include <linux/mm.h>46#include <linux/sched.h>47#include <linux/err.h>48#include <linux/irq.h>49#include <linux/bootmem.h>50#include <linux/delay.h>5152#include <asm/io.h>53#include <asm/pgalloc.h>54#include <asm/tlbflush.h>5556#define DEBUG_SMP57#ifdef DEBUG_SMP58#define Dprintk(x...) printk(x)59#else60#define Dprintk(x...)61#endif6263extern cpumask_t cpu_initialized;6465/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/66/* Data structures and variables */67/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/6869/* Processor that is doing the boot up */70static unsigned int bsp_phys_id = -1;7172/* Bitmask of physically existing CPUs */73physid_mask_t phys_cpu_present_map;7475cpumask_t cpu_bootout_map;76cpumask_t cpu_bootin_map;77static cpumask_t cpu_callin_map;78cpumask_t cpu_callout_map;79EXPORT_SYMBOL(cpu_callout_map);8081/* Per CPU bogomips and other parameters */82struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned;8384static int cpucount;85static cpumask_t smp_commenced_mask;8687extern struct {88void * spi;89unsigned short ss;90} stack_start;9192/* which physical physical ID maps to which logical CPU number */93static volatile int physid_2_cpu[NR_CPUS];94#define physid_to_cpu(physid) physid_2_cpu[physid]9596/* which logical CPU number maps to which physical ID */97volatile int cpu_2_physid[NR_CPUS];9899DEFINE_PER_CPU(int, prof_multiplier) = 1;100DEFINE_PER_CPU(int, prof_old_multiplier) = 1;101DEFINE_PER_CPU(int, prof_counter) = 1;102103spinlock_t ipi_lock[NR_IPIS];104105static unsigned int calibration_result;106107/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/108/* Function Prototypes */109/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/110111void smp_prepare_boot_cpu(void);112void smp_prepare_cpus(unsigned int);113static void init_ipi_lock(void);114static void do_boot_cpu(int);115int __cpu_up(unsigned int);116void smp_cpus_done(unsigned int);117118int start_secondary(void *);119static void smp_callin(void);120static void smp_online(void);121122static void show_mp_info(int);123static void smp_store_cpu_info(int);124static void show_cpu_info(int);125int setup_profiling_timer(unsigned int);126static void init_cpu_to_physid(void);127static void map_cpu_to_physid(int, int);128static void unmap_cpu_to_physid(int, int);129130/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/131/* Boot up APs Routines : BSP */132/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/133void __devinit smp_prepare_boot_cpu(void)134{135bsp_phys_id = hard_smp_processor_id();136physid_set(bsp_phys_id, phys_cpu_present_map);137set_cpu_online(0, true); /* BSP's cpu_id == 0 */138cpumask_set_cpu(0, &cpu_callout_map);139cpumask_set_cpu(0, &cpu_callin_map);140141/*142* Initialize the logical to physical CPU number mapping143*/144init_cpu_to_physid();145map_cpu_to_physid(0, bsp_phys_id);146current_thread_info()->cpu = 0;147}148149/*==========================================================================*150* Name: smp_prepare_cpus (old smp_boot_cpus)151*152* Description: This routine boot up APs.153*154* Born on Date: 2002.02.05155*156* Arguments: NONE157*158* Returns: void (cannot fail)159*160* Modification log:161* Date Who Description162* ---------- --- --------------------------------------------------------163* 2003-06-24 hy modify for linux-2.5.69164*165*==========================================================================*/166void __init smp_prepare_cpus(unsigned int max_cpus)167{168int phys_id;169unsigned long nr_cpu;170171nr_cpu = inl(M32R_FPGA_NUM_OF_CPUS_PORTL);172if (nr_cpu > NR_CPUS) {173printk(KERN_INFO "NUM_OF_CPUS reg. value [%ld] > NR_CPU [%d]",174nr_cpu, NR_CPUS);175goto smp_done;176}177for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++)178physid_set(phys_id, phys_cpu_present_map);179#ifndef CONFIG_HOTPLUG_CPU180init_cpu_present(cpu_possible_mask);181#endif182183show_mp_info(nr_cpu);184185init_ipi_lock();186187/*188* Setup boot CPU information189*/190smp_store_cpu_info(0); /* Final full version of the data */191192/*193* If SMP should be disabled, then really disable it!194*/195if (!max_cpus) {196printk(KERN_INFO "SMP mode deactivated by commandline.\n");197goto smp_done;198}199200/*201* Now scan the CPU present map and fire up the other CPUs.202*/203Dprintk("CPU present map : %lx\n", physids_coerce(phys_cpu_present_map));204205for (phys_id = 0 ; phys_id < NR_CPUS ; phys_id++) {206/*207* Don't even attempt to start the boot CPU!208*/209if (phys_id == bsp_phys_id)210continue;211212if (!physid_isset(phys_id, phys_cpu_present_map))213continue;214215if (max_cpus <= cpucount + 1)216continue;217218do_boot_cpu(phys_id);219220/*221* Make sure we unmap all failed CPUs222*/223if (physid_to_cpu(phys_id) == -1) {224physid_clear(phys_id, phys_cpu_present_map);225printk("phys CPU#%d not responding - " \226"cannot use it.\n", phys_id);227}228}229230smp_done:231Dprintk("Boot done.\n");232}233234/*235* init_ipi_lock : Initialize IPI locks.236*/237static void __init init_ipi_lock(void)238{239int ipi;240241for (ipi = 0 ; ipi < NR_IPIS ; ipi++)242spin_lock_init(&ipi_lock[ipi]);243}244245/*==========================================================================*246* Name: do_boot_cpu247*248* Description: This routine boot up one AP.249*250* Born on Date: 2002.02.05251*252* Arguments: phys_id - Target CPU physical ID253*254* Returns: void (cannot fail)255*256* Modification log:257* Date Who Description258* ---------- --- --------------------------------------------------------259* 2003-06-24 hy modify for linux-2.5.69260*261*==========================================================================*/262static void __init do_boot_cpu(int phys_id)263{264struct task_struct *idle;265unsigned long send_status, boot_status;266int timeout, cpu_id;267268cpu_id = ++cpucount;269270/*271* We can't use kernel_thread since we must avoid to272* reschedule the child.273*/274idle = fork_idle(cpu_id);275if (IS_ERR(idle))276panic("failed fork for CPU#%d.", cpu_id);277278idle->thread.lr = (unsigned long)start_secondary;279280map_cpu_to_physid(cpu_id, phys_id);281282/* So we see what's up */283printk("Booting processor %d/%d\n", phys_id, cpu_id);284stack_start.spi = (void *)idle->thread.sp;285task_thread_info(idle)->cpu = cpu_id;286287/*288* Send Startup IPI289* 1.IPI received by CPU#(phys_id).290* 2.CPU#(phys_id) enter startup_AP (arch/m32r/kernel/head.S)291* 3.CPU#(phys_id) enter start_secondary()292*/293send_status = 0;294boot_status = 0;295296cpumask_set_cpu(phys_id, &cpu_bootout_map);297298/* Send Startup IPI */299send_IPI_mask_phys(cpumask_of(phys_id), CPU_BOOT_IPI, 0);300301Dprintk("Waiting for send to finish...\n");302timeout = 0;303304/* Wait 100[ms] */305do {306Dprintk("+");307udelay(1000);308send_status = !cpumask_test_cpu(phys_id, &cpu_bootin_map);309} while (send_status && (timeout++ < 100));310311Dprintk("After Startup.\n");312313if (!send_status) {314/*315* allow APs to start initializing.316*/317Dprintk("Before Callout %d.\n", cpu_id);318cpumask_set_cpu(cpu_id, &cpu_callout_map);319Dprintk("After Callout %d.\n", cpu_id);320321/*322* Wait 5s total for a response323*/324for (timeout = 0; timeout < 5000; timeout++) {325if (cpumask_test_cpu(cpu_id, &cpu_callin_map))326break; /* It has booted */327udelay(1000);328}329330if (cpumask_test_cpu(cpu_id, &cpu_callin_map)) {331/* number CPUs logically, starting from 1 (BSP is 0) */332Dprintk("OK.\n");333} else {334boot_status = 1;335printk("Not responding.\n");336}337} else338printk("IPI never delivered???\n");339340if (send_status || boot_status) {341unmap_cpu_to_physid(cpu_id, phys_id);342cpumask_clear_cpu(cpu_id, &cpu_callout_map);343cpumask_clear_cpu(cpu_id, &cpu_callin_map);344cpumask_clear_cpu(cpu_id, &cpu_initialized);345cpucount--;346}347}348349int __cpuinit __cpu_up(unsigned int cpu_id)350{351int timeout;352353cpumask_set_cpu(cpu_id, &smp_commenced_mask);354355/*356* Wait 5s total for a response357*/358for (timeout = 0; timeout < 5000; timeout++) {359if (cpu_online(cpu_id))360break;361udelay(1000);362}363if (!cpu_online(cpu_id))364BUG();365366return 0;367}368369void __init smp_cpus_done(unsigned int max_cpus)370{371int cpu_id, timeout;372unsigned long bogosum = 0;373374for (timeout = 0; timeout < 5000; timeout++) {375if (cpumask_equal(&cpu_callin_map, cpu_online_mask))376break;377udelay(1000);378}379if (!cpumask_equal(&cpu_callin_map, cpu_online_mask))380BUG();381382for (cpu_id = 0 ; cpu_id < num_online_cpus() ; cpu_id++)383show_cpu_info(cpu_id);384385/*386* Allow the user to impress friends.387*/388Dprintk("Before bogomips.\n");389if (cpucount) {390for_each_cpu(cpu_id,cpu_online_mask)391bogosum += cpu_data[cpu_id].loops_per_jiffy;392393printk(KERN_INFO "Total of %d processors activated " \394"(%lu.%02lu BogoMIPS).\n", cpucount + 1,395bogosum / (500000 / HZ),396(bogosum / (5000 / HZ)) % 100);397Dprintk("Before bogocount - setting activated=1.\n");398}399}400401/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/402/* Activate a secondary processor Routines */403/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/404405/*==========================================================================*406* Name: start_secondary407*408* Description: This routine activate a secondary processor.409*410* Born on Date: 2002.02.05411*412* Arguments: *unused - currently unused.413*414* Returns: void (cannot fail)415*416* Modification log:417* Date Who Description418* ---------- --- --------------------------------------------------------419* 2003-06-24 hy modify for linux-2.5.69420*421*==========================================================================*/422int __init start_secondary(void *unused)423{424cpu_init();425preempt_disable();426smp_callin();427while (!cpumask_test_cpu(smp_processor_id(), &smp_commenced_mask))428cpu_relax();429430smp_online();431432/*433* low-memory mappings have been cleared, flush them from434* the local TLBs too.435*/436local_flush_tlb_all();437438cpu_idle();439return 0;440}441442/*==========================================================================*443* Name: smp_callin444*445* Description: This routine activate a secondary processor.446*447* Born on Date: 2002.02.05448*449* Arguments: NONE450*451* Returns: void (cannot fail)452*453* Modification log:454* Date Who Description455* ---------- --- --------------------------------------------------------456* 2003-06-24 hy modify for linux-2.5.69457*458*==========================================================================*/459static void __init smp_callin(void)460{461int phys_id = hard_smp_processor_id();462int cpu_id = smp_processor_id();463unsigned long timeout;464465if (cpumask_test_cpu(cpu_id, &cpu_callin_map)) {466printk("huh, phys CPU#%d, CPU#%d already present??\n",467phys_id, cpu_id);468BUG();469}470Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpu_id, phys_id);471472/* Waiting 2s total for startup (udelay is not yet working) */473timeout = jiffies + (2 * HZ);474while (time_before(jiffies, timeout)) {475/* Has the boot CPU finished it's STARTUP sequence ? */476if (cpumask_test_cpu(cpu_id, &cpu_callout_map))477break;478cpu_relax();479}480481if (!time_before(jiffies, timeout)) {482printk("BUG: CPU#%d started up but did not get a callout!\n",483cpu_id);484BUG();485}486487/* Allow the master to continue. */488cpumask_set_cpu(cpu_id, &cpu_callin_map);489}490491static void __init smp_online(void)492{493int cpu_id = smp_processor_id();494495notify_cpu_starting(cpu_id);496497local_irq_enable();498499/* Get our bogomips. */500calibrate_delay();501502/* Save our processor parameters */503smp_store_cpu_info(cpu_id);504505set_cpu_online(cpu_id, true);506}507508/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/509/* Boot up CPUs common Routines */510/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/511static void __init show_mp_info(int nr_cpu)512{513int i;514char cpu_model0[17], cpu_model1[17], cpu_ver[9];515516strncpy(cpu_model0, (char *)M32R_FPGA_CPU_NAME_ADDR, 16);517strncpy(cpu_model1, (char *)M32R_FPGA_MODEL_ID_ADDR, 16);518strncpy(cpu_ver, (char *)M32R_FPGA_VERSION_ADDR, 8);519520cpu_model0[16] = '\0';521for (i = 15 ; i >= 0 ; i--) {522if (cpu_model0[i] != ' ')523break;524cpu_model0[i] = '\0';525}526cpu_model1[16] = '\0';527for (i = 15 ; i >= 0 ; i--) {528if (cpu_model1[i] != ' ')529break;530cpu_model1[i] = '\0';531}532cpu_ver[8] = '\0';533for (i = 7 ; i >= 0 ; i--) {534if (cpu_ver[i] != ' ')535break;536cpu_ver[i] = '\0';537}538539printk(KERN_INFO "M32R-mp information\n");540printk(KERN_INFO " On-chip CPUs : %d\n", nr_cpu);541printk(KERN_INFO " CPU model : %s/%s(%s)\n", cpu_model0,542cpu_model1, cpu_ver);543}544545/*546* The bootstrap kernel entry code has set these up. Save them for547* a given CPU548*/549static void __init smp_store_cpu_info(int cpu_id)550{551struct cpuinfo_m32r *ci = cpu_data + cpu_id;552553*ci = boot_cpu_data;554ci->loops_per_jiffy = loops_per_jiffy;555}556557static void __init show_cpu_info(int cpu_id)558{559struct cpuinfo_m32r *ci = &cpu_data[cpu_id];560561printk("CPU#%d : ", cpu_id);562563#define PRINT_CLOCK(name, value) \564printk(name " clock %d.%02dMHz", \565((value) / 1000000), ((value) % 1000000) / 10000)566567PRINT_CLOCK("CPU", (int)ci->cpu_clock);568PRINT_CLOCK(", Bus", (int)ci->bus_clock);569printk(", loops_per_jiffy[%ld]\n", ci->loops_per_jiffy);570}571572/*573* the frequency of the profiling timer can be changed574* by writing a multiplier value into /proc/profile.575*/576int setup_profiling_timer(unsigned int multiplier)577{578int i;579580/*581* Sanity check. [at least 500 APIC cycles should be582* between APIC interrupts as a rule of thumb, to avoid583* irqs flooding us]584*/585if ( (!multiplier) || (calibration_result / multiplier < 500))586return -EINVAL;587588/*589* Set the new multiplier for each CPU. CPUs don't start using the590* new values until the next timer interrupt in which they do process591* accounting. At that time they also adjust their APIC timers592* accordingly.593*/594for_each_possible_cpu(i)595per_cpu(prof_multiplier, i) = multiplier;596597return 0;598}599600/* Initialize all maps between cpu number and apicids */601static void __init init_cpu_to_physid(void)602{603int i;604605for (i = 0 ; i < NR_CPUS ; i++) {606cpu_2_physid[i] = -1;607physid_2_cpu[i] = -1;608}609}610611/*612* set up a mapping between cpu and apicid. Uses logical apicids for multiquad,613* else physical apic ids614*/615static void __init map_cpu_to_physid(int cpu_id, int phys_id)616{617physid_2_cpu[phys_id] = cpu_id;618cpu_2_physid[cpu_id] = phys_id;619}620621/*622* undo a mapping between cpu and apicid. Uses logical apicids for multiquad,623* else physical apic ids624*/625static void __init unmap_cpu_to_physid(int cpu_id, int phys_id)626{627physid_2_cpu[phys_id] = -1;628cpu_2_physid[cpu_id] = -1;629}630631632