| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  *  linux/arch/m32r/kernel/smpboot.c | 
 | 3 |  *    orig : i386 2.4.10 | 
 | 4 |  * | 
 | 5 |  *  M32R SMP booting functions | 
 | 6 |  * | 
 | 7 |  *  Copyright (c) 2001, 2002, 2003  Hitoshi Yamamoto | 
 | 8 |  * | 
 | 9 |  *  Taken from i386 version. | 
 | 10 |  *	  (c) 1995 Alan Cox, Building #3 <alan@redhat.com> | 
 | 11 |  *	  (c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com> | 
 | 12 |  * | 
 | 13 |  *	Much of the core SMP work is based on previous work by Thomas Radke, to | 
 | 14 |  *	whom a great many thanks are extended. | 
 | 15 |  * | 
 | 16 |  *	Thanks to Intel for making available several different Pentium, | 
 | 17 |  *	Pentium Pro and Pentium-II/Xeon MP machines. | 
 | 18 |  *	Original development of Linux SMP code supported by Caldera. | 
 | 19 |  * | 
 | 20 |  *	This code is released under the GNU General Public License version 2 or | 
 | 21 |  *	later. | 
 | 22 |  * | 
 | 23 |  *	Fixes | 
 | 24 |  *		Felix Koop	:	NR_CPUS used properly | 
 | 25 |  *		Jose Renau	:	Handle single CPU case. | 
 | 26 |  *		Alan Cox	:	By repeated request | 
 | 27 |  *					8) - Total BogoMIP report. | 
 | 28 |  *		Greg Wright	:	Fix for kernel stacks panic. | 
 | 29 |  *		Erich Boleyn	:	MP v1.4 and additional changes. | 
 | 30 |  *	Matthias Sattler	:	Changes for 2.1 kernel map. | 
 | 31 |  *	Michel Lespinasse	:	Changes for 2.1 kernel map. | 
 | 32 |  *	Michael Chastain	:	Change trampoline.S to gnu as. | 
 | 33 |  *		Alan Cox	:	Dumb bug: 'B' step PPro's are fine | 
 | 34 |  *		Ingo Molnar	:	Added APIC timers, based on code | 
 | 35 |  *					from Jose Renau | 
 | 36 |  *		Ingo Molnar	:	various cleanups and rewrites | 
 | 37 |  *		Tigran Aivazian	:	fixed "0.00 in /proc/uptime on SMP" bug. | 
 | 38 |  *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs | 
 | 39 |  *		Martin J. Bligh	: 	Added support for multi-quad systems | 
 | 40 |  */ | 
 | 41 |  | 
| Hirokazu Takata | 7c1c4e5 | 2006-04-10 22:53:18 -0700 | [diff] [blame] | 42 | #include <linux/module.h> | 
| Ingo Molnar | 3baf63a | 2008-10-16 19:00:57 +0200 | [diff] [blame] | 43 | #include <linux/cpu.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | #include <linux/init.h> | 
| Hirokazu Takata | 7c1c4e5 | 2006-04-10 22:53:18 -0700 | [diff] [blame] | 45 | #include <linux/kernel.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 46 | #include <linux/mm.h> | 
| Mathieu Desnoyers | df0f65f | 2008-02-07 00:16:18 -0800 | [diff] [blame] | 47 | #include <linux/sched.h> | 
| Hirokazu Takata | cfcd8c4 | 2007-07-30 22:00:47 +0900 | [diff] [blame] | 48 | #include <linux/err.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 49 | #include <linux/irq.h> | 
 | 50 | #include <linux/bootmem.h> | 
 | 51 | #include <linux/delay.h> | 
 | 52 |  | 
 | 53 | #include <asm/io.h> | 
 | 54 | #include <asm/pgalloc.h> | 
 | 55 | #include <asm/tlbflush.h> | 
 | 56 |  | 
 | 57 | #define DEBUG_SMP | 
 | 58 | #ifdef DEBUG_SMP | 
 | 59 | #define Dprintk(x...) printk(x) | 
 | 60 | #else | 
 | 61 | #define Dprintk(x...) | 
 | 62 | #endif | 
 | 63 |  | 
 | 64 | extern cpumask_t cpu_initialized; | 
 | 65 |  | 
 | 66 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
 | 67 | /* Data structures and variables                                             */ | 
 | 68 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
 | 69 |  | 
 | 70 | /* Processor that is doing the boot up */ | 
 | 71 | static unsigned int bsp_phys_id = -1; | 
 | 72 |  | 
 | 73 | /* Bitmask of physically existing CPUs */ | 
 | 74 | physid_mask_t phys_cpu_present_map; | 
 | 75 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | cpumask_t cpu_bootout_map; | 
 | 77 | cpumask_t cpu_bootin_map; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 78 | static cpumask_t cpu_callin_map; | 
| Hirokazu Takata | 7c1c4e5 | 2006-04-10 22:53:18 -0700 | [diff] [blame] | 79 | cpumask_t cpu_callout_map; | 
 | 80 | EXPORT_SYMBOL(cpu_callout_map); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 |  | 
 | 82 | /* Per CPU bogomips and other parameters */ | 
 | 83 | struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned; | 
 | 84 |  | 
 | 85 | static int cpucount; | 
 | 86 | static cpumask_t smp_commenced_mask; | 
 | 87 |  | 
 | 88 | extern struct { | 
 | 89 | 	void * spi; | 
 | 90 | 	unsigned short ss; | 
 | 91 | } stack_start; | 
 | 92 |  | 
 | 93 | /* which physical physical ID maps to which logical CPU number */ | 
 | 94 | static volatile int physid_2_cpu[NR_CPUS]; | 
| Al Viro | e231a9c | 2005-08-23 22:47:17 +0100 | [diff] [blame] | 95 | #define physid_to_cpu(physid)	physid_2_cpu[physid] | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 |  | 
 | 97 | /* which logical CPU number maps to which physical ID */ | 
 | 98 | volatile int cpu_2_physid[NR_CPUS]; | 
 | 99 |  | 
 | 100 | DEFINE_PER_CPU(int, prof_multiplier) = 1; | 
 | 101 | DEFINE_PER_CPU(int, prof_old_multiplier) = 1; | 
 | 102 | DEFINE_PER_CPU(int, prof_counter) = 1; | 
 | 103 |  | 
 | 104 | spinlock_t ipi_lock[NR_IPIS]; | 
 | 105 |  | 
 | 106 | static unsigned int calibration_result; | 
 | 107 |  | 
 | 108 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
 | 109 | /* Function Prototypes                                                       */ | 
 | 110 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
 | 111 |  | 
 | 112 | void smp_prepare_boot_cpu(void); | 
 | 113 | void smp_prepare_cpus(unsigned int); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | static void init_ipi_lock(void); | 
 | 115 | static void do_boot_cpu(int); | 
 | 116 | int __cpu_up(unsigned int); | 
 | 117 | void smp_cpus_done(unsigned int); | 
 | 118 |  | 
 | 119 | int start_secondary(void *); | 
 | 120 | static void smp_callin(void); | 
 | 121 | static void smp_online(void); | 
 | 122 |  | 
 | 123 | static void show_mp_info(int); | 
 | 124 | static void smp_store_cpu_info(int); | 
 | 125 | static void show_cpu_info(int); | 
 | 126 | int setup_profiling_timer(unsigned int); | 
 | 127 | static void init_cpu_to_physid(void); | 
 | 128 | static void map_cpu_to_physid(int, int); | 
 | 129 | static void unmap_cpu_to_physid(int, int); | 
 | 130 |  | 
 | 131 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
| Simon Arlott | 5aa8b6c | 2007-10-20 01:14:39 +0200 | [diff] [blame] | 132 | /* Boot up APs Routines : BSP                                                */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
 | 134 | void __devinit smp_prepare_boot_cpu(void) | 
 | 135 | { | 
 | 136 | 	bsp_phys_id = hard_smp_processor_id(); | 
 | 137 | 	physid_set(bsp_phys_id, phys_cpu_present_map); | 
 | 138 | 	cpu_set(0, cpu_online_map);	/* BSP's cpu_id == 0 */ | 
 | 139 | 	cpu_set(0, cpu_callout_map); | 
 | 140 | 	cpu_set(0, cpu_callin_map); | 
 | 141 |  | 
 | 142 | 	/* | 
 | 143 | 	 * Initialize the logical to physical CPU number mapping | 
 | 144 | 	 */ | 
 | 145 | 	init_cpu_to_physid(); | 
 | 146 | 	map_cpu_to_physid(0, bsp_phys_id); | 
 | 147 | 	current_thread_info()->cpu = 0; | 
 | 148 | } | 
 | 149 |  | 
 | 150 | /*==========================================================================* | 
 | 151 |  * Name:         smp_prepare_cpus (old smp_boot_cpus) | 
 | 152 |  * | 
 | 153 |  * Description:  This routine boot up APs. | 
 | 154 |  * | 
 | 155 |  * Born on Date: 2002.02.05 | 
 | 156 |  * | 
 | 157 |  * Arguments:    NONE | 
 | 158 |  * | 
 | 159 |  * Returns:      void (cannot fail) | 
 | 160 |  * | 
 | 161 |  * Modification log: | 
 | 162 |  * Date       Who Description | 
 | 163 |  * ---------- --- -------------------------------------------------------- | 
 | 164 |  * 2003-06-24 hy  modify for linux-2.5.69 | 
 | 165 |  * | 
 | 166 |  *==========================================================================*/ | 
 | 167 | void __init smp_prepare_cpus(unsigned int max_cpus) | 
 | 168 | { | 
 | 169 | 	int phys_id; | 
 | 170 | 	unsigned long nr_cpu; | 
 | 171 |  | 
 | 172 | 	nr_cpu = inl(M32R_FPGA_NUM_OF_CPUS_PORTL); | 
 | 173 | 	if (nr_cpu > NR_CPUS) { | 
 | 174 | 		printk(KERN_INFO "NUM_OF_CPUS reg. value [%ld] > NR_CPU [%d]", | 
 | 175 | 			nr_cpu, NR_CPUS); | 
 | 176 | 		goto smp_done; | 
 | 177 | 	} | 
 | 178 | 	for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++) | 
 | 179 | 		physid_set(phys_id, phys_cpu_present_map); | 
| Hirokazu Takata | 7c1c4e5 | 2006-04-10 22:53:18 -0700 | [diff] [blame] | 180 | #ifndef CONFIG_HOTPLUG_CPU | 
| Rusty Russell | 2377afd | 2009-09-24 09:34:47 -0600 | [diff] [blame] | 181 | 	init_cpu_present(&cpu_possible_map); | 
| Hirokazu Takata | 7c1c4e5 | 2006-04-10 22:53:18 -0700 | [diff] [blame] | 182 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 183 |  | 
 | 184 | 	show_mp_info(nr_cpu); | 
 | 185 |  | 
 | 186 | 	init_ipi_lock(); | 
 | 187 |  | 
 | 188 | 	/* | 
 | 189 | 	 * Setup boot CPU information | 
 | 190 | 	 */ | 
 | 191 | 	smp_store_cpu_info(0); /* Final full version of the data */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 |  | 
 | 193 | 	/* | 
 | 194 | 	 * If SMP should be disabled, then really disable it! | 
 | 195 | 	 */ | 
 | 196 | 	if (!max_cpus) { | 
 | 197 | 		printk(KERN_INFO "SMP mode deactivated by commandline.\n"); | 
 | 198 | 		goto smp_done; | 
 | 199 | 	} | 
 | 200 |  | 
 | 201 | 	/* | 
 | 202 | 	 * Now scan the CPU present map and fire up the other CPUs. | 
 | 203 | 	 */ | 
 | 204 | 	Dprintk("CPU present map : %lx\n", physids_coerce(phys_cpu_present_map)); | 
 | 205 |  | 
 | 206 | 	for (phys_id = 0 ; phys_id < NR_CPUS ; phys_id++) { | 
 | 207 | 		/* | 
 | 208 | 		 * Don't even attempt to start the boot CPU! | 
 | 209 | 		 */ | 
 | 210 | 		if (phys_id == bsp_phys_id) | 
 | 211 | 			continue; | 
 | 212 |  | 
 | 213 | 		if (!physid_isset(phys_id, phys_cpu_present_map)) | 
 | 214 | 			continue; | 
 | 215 |  | 
| Roel Kluin | d5a6d17 | 2009-09-21 17:04:03 -0700 | [diff] [blame] | 216 | 		if (max_cpus <= cpucount + 1) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 217 | 			continue; | 
 | 218 |  | 
 | 219 | 		do_boot_cpu(phys_id); | 
 | 220 |  | 
 | 221 | 		/* | 
 | 222 | 		 * Make sure we unmap all failed CPUs | 
 | 223 | 		 */ | 
 | 224 | 		if (physid_to_cpu(phys_id) == -1) { | 
 | 225 | 			physid_clear(phys_id, phys_cpu_present_map); | 
 | 226 | 			printk("phys CPU#%d not responding - " \ | 
 | 227 | 				"cannot use it.\n", phys_id); | 
 | 228 | 		} | 
 | 229 | 	} | 
 | 230 |  | 
 | 231 | smp_done: | 
 | 232 | 	Dprintk("Boot done.\n"); | 
 | 233 | } | 
 | 234 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | /* | 
 | 236 |  * init_ipi_lock : Initialize IPI locks. | 
 | 237 |  */ | 
 | 238 | static void __init init_ipi_lock(void) | 
 | 239 | { | 
 | 240 | 	int ipi; | 
 | 241 |  | 
 | 242 | 	for (ipi = 0 ; ipi < NR_IPIS ; ipi++) | 
 | 243 | 		spin_lock_init(&ipi_lock[ipi]); | 
 | 244 | } | 
 | 245 |  | 
 | 246 | /*==========================================================================* | 
 | 247 |  * Name:         do_boot_cpu | 
 | 248 |  * | 
 | 249 |  * Description:  This routine boot up one AP. | 
 | 250 |  * | 
 | 251 |  * Born on Date: 2002.02.05 | 
 | 252 |  * | 
 | 253 |  * Arguments:    phys_id - Target CPU physical ID | 
 | 254 |  * | 
 | 255 |  * Returns:      void (cannot fail) | 
 | 256 |  * | 
 | 257 |  * Modification log: | 
 | 258 |  * Date       Who Description | 
 | 259 |  * ---------- --- -------------------------------------------------------- | 
 | 260 |  * 2003-06-24 hy  modify for linux-2.5.69 | 
 | 261 |  * | 
 | 262 |  *==========================================================================*/ | 
 | 263 | static void __init do_boot_cpu(int phys_id) | 
 | 264 | { | 
 | 265 | 	struct task_struct *idle; | 
 | 266 | 	unsigned long send_status, boot_status; | 
 | 267 | 	int timeout, cpu_id; | 
 | 268 |  | 
 | 269 | 	cpu_id = ++cpucount; | 
 | 270 |  | 
 | 271 | 	/* | 
 | 272 | 	 * We can't use kernel_thread since we must avoid to | 
 | 273 | 	 * reschedule the child. | 
 | 274 | 	 */ | 
 | 275 | 	idle = fork_idle(cpu_id); | 
 | 276 | 	if (IS_ERR(idle)) | 
 | 277 | 		panic("failed fork for CPU#%d.", cpu_id); | 
 | 278 |  | 
 | 279 | 	idle->thread.lr = (unsigned long)start_secondary; | 
 | 280 |  | 
 | 281 | 	map_cpu_to_physid(cpu_id, phys_id); | 
 | 282 |  | 
 | 283 | 	/* So we see what's up   */ | 
 | 284 | 	printk("Booting processor %d/%d\n", phys_id, cpu_id); | 
 | 285 | 	stack_start.spi = (void *)idle->thread.sp; | 
| Al Viro | 6c3559fc | 2006-01-12 01:05:52 -0800 | [diff] [blame] | 286 | 	task_thread_info(idle)->cpu = cpu_id; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 287 |  | 
 | 288 | 	/* | 
 | 289 | 	 * Send Startup IPI | 
 | 290 | 	 *   1.IPI received by CPU#(phys_id). | 
 | 291 | 	 *   2.CPU#(phys_id) enter startup_AP (arch/m32r/kernel/head.S) | 
 | 292 | 	 *   3.CPU#(phys_id) enter start_secondary() | 
 | 293 | 	 */ | 
 | 294 | 	send_status = 0; | 
 | 295 | 	boot_status = 0; | 
 | 296 |  | 
 | 297 | 	cpu_set(phys_id, cpu_bootout_map); | 
 | 298 |  | 
 | 299 | 	/* Send Startup IPI */ | 
 | 300 | 	send_IPI_mask_phys(cpumask_of_cpu(phys_id), CPU_BOOT_IPI, 0); | 
 | 301 |  | 
 | 302 | 	Dprintk("Waiting for send to finish...\n"); | 
 | 303 | 	timeout = 0; | 
 | 304 |  | 
 | 305 | 	/* Wait 100[ms] */ | 
 | 306 | 	do { | 
 | 307 | 		Dprintk("+"); | 
 | 308 | 		udelay(1000); | 
 | 309 | 		send_status = !cpu_isset(phys_id, cpu_bootin_map); | 
 | 310 | 	} while (send_status && (timeout++ < 100)); | 
 | 311 |  | 
 | 312 | 	Dprintk("After Startup.\n"); | 
 | 313 |  | 
 | 314 | 	if (!send_status) { | 
 | 315 | 		/* | 
 | 316 | 		 * allow APs to start initializing. | 
 | 317 | 		 */ | 
 | 318 | 		Dprintk("Before Callout %d.\n", cpu_id); | 
 | 319 | 		cpu_set(cpu_id, cpu_callout_map); | 
 | 320 | 		Dprintk("After Callout %d.\n", cpu_id); | 
 | 321 |  | 
 | 322 | 		/* | 
 | 323 | 		 * Wait 5s total for a response | 
 | 324 | 		 */ | 
 | 325 | 		for (timeout = 0; timeout < 5000; timeout++) { | 
 | 326 | 			if (cpu_isset(cpu_id, cpu_callin_map)) | 
 | 327 | 				break;	/* It has booted */ | 
 | 328 | 			udelay(1000); | 
 | 329 | 		} | 
 | 330 |  | 
 | 331 | 		if (cpu_isset(cpu_id, cpu_callin_map)) { | 
 | 332 | 			/* number CPUs logically, starting from 1 (BSP is 0) */ | 
 | 333 | 			Dprintk("OK.\n"); | 
 | 334 | 		} else { | 
 | 335 | 			boot_status = 1; | 
 | 336 | 			printk("Not responding.\n"); | 
 | 337 | 		} | 
 | 338 | 	} else | 
 | 339 | 		printk("IPI never delivered???\n"); | 
 | 340 |  | 
 | 341 | 	if (send_status || boot_status) { | 
 | 342 | 		unmap_cpu_to_physid(cpu_id, phys_id); | 
 | 343 | 		cpu_clear(cpu_id, cpu_callout_map); | 
 | 344 | 		cpu_clear(cpu_id, cpu_callin_map); | 
 | 345 | 		cpu_clear(cpu_id, cpu_initialized); | 
 | 346 | 		cpucount--; | 
 | 347 | 	} | 
 | 348 | } | 
 | 349 |  | 
| Gautham R Shenoy | b282b6f | 2007-01-10 23:15:34 -0800 | [diff] [blame] | 350 | int __cpuinit __cpu_up(unsigned int cpu_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 351 | { | 
 | 352 | 	int timeout; | 
 | 353 |  | 
 | 354 | 	cpu_set(cpu_id, smp_commenced_mask); | 
 | 355 |  | 
 | 356 | 	/* | 
 | 357 | 	 * Wait 5s total for a response | 
 | 358 | 	 */ | 
 | 359 | 	for (timeout = 0; timeout < 5000; timeout++) { | 
 | 360 | 		if (cpu_isset(cpu_id, cpu_online_map)) | 
 | 361 | 			break; | 
 | 362 | 		udelay(1000); | 
 | 363 | 	} | 
 | 364 | 	if (!cpu_isset(cpu_id, cpu_online_map)) | 
 | 365 | 		BUG(); | 
 | 366 |  | 
 | 367 | 	return 0; | 
 | 368 | } | 
 | 369 |  | 
 | 370 | void __init smp_cpus_done(unsigned int max_cpus) | 
 | 371 | { | 
 | 372 | 	int cpu_id, timeout; | 
 | 373 | 	unsigned long bogosum = 0; | 
 | 374 |  | 
 | 375 | 	for (timeout = 0; timeout < 5000; timeout++) { | 
 | 376 | 		if (cpus_equal(cpu_callin_map, cpu_online_map)) | 
 | 377 | 			break; | 
 | 378 | 		udelay(1000); | 
 | 379 | 	} | 
 | 380 | 	if (!cpus_equal(cpu_callin_map, cpu_online_map)) | 
 | 381 | 		BUG(); | 
 | 382 |  | 
 | 383 | 	for (cpu_id = 0 ; cpu_id < num_online_cpus() ; cpu_id++) | 
 | 384 | 		show_cpu_info(cpu_id); | 
 | 385 |  | 
 | 386 | 	/* | 
 | 387 | 	 * Allow the user to impress friends. | 
 | 388 | 	 */ | 
 | 389 | 	Dprintk("Before bogomips.\n"); | 
 | 390 | 	if (cpucount) { | 
 | 391 | 		for_each_cpu_mask(cpu_id, cpu_online_map) | 
 | 392 | 			bogosum += cpu_data[cpu_id].loops_per_jiffy; | 
 | 393 |  | 
 | 394 | 		printk(KERN_INFO "Total of %d processors activated " \ | 
 | 395 | 			"(%lu.%02lu BogoMIPS).\n", cpucount + 1, | 
 | 396 | 			bogosum / (500000 / HZ), | 
 | 397 | 			(bogosum / (5000 / HZ)) % 100); | 
 | 398 | 		Dprintk("Before bogocount - setting activated=1.\n"); | 
 | 399 | 	} | 
 | 400 | } | 
 | 401 |  | 
 | 402 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
| Simon Arlott | 5aa8b6c | 2007-10-20 01:14:39 +0200 | [diff] [blame] | 403 | /* Activate a secondary processor Routines                                   */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 404 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
 | 405 |  | 
 | 406 | /*==========================================================================* | 
 | 407 |  * Name:         start_secondary | 
 | 408 |  * | 
 | 409 |  * Description:  This routine activate a secondary processor. | 
 | 410 |  * | 
 | 411 |  * Born on Date: 2002.02.05 | 
 | 412 |  * | 
 | 413 |  * Arguments:    *unused - currently unused. | 
 | 414 |  * | 
 | 415 |  * Returns:      void (cannot fail) | 
 | 416 |  * | 
 | 417 |  * Modification log: | 
 | 418 |  * Date       Who Description | 
 | 419 |  * ---------- --- -------------------------------------------------------- | 
 | 420 |  * 2003-06-24 hy  modify for linux-2.5.69 | 
 | 421 |  * | 
 | 422 |  *==========================================================================*/ | 
 | 423 | int __init start_secondary(void *unused) | 
 | 424 | { | 
 | 425 | 	cpu_init(); | 
| Nick Piggin | 5bfb5d6 | 2005-11-08 21:39:01 -0800 | [diff] [blame] | 426 | 	preempt_disable(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 427 | 	smp_callin(); | 
 | 428 | 	while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) | 
 | 429 | 		cpu_relax(); | 
 | 430 |  | 
 | 431 | 	smp_online(); | 
 | 432 |  | 
 | 433 | 	/* | 
 | 434 | 	 * low-memory mappings have been cleared, flush them from | 
 | 435 | 	 * the local TLBs too. | 
 | 436 | 	 */ | 
 | 437 | 	local_flush_tlb_all(); | 
 | 438 |  | 
 | 439 | 	cpu_idle(); | 
 | 440 | 	return 0; | 
 | 441 | } | 
 | 442 |  | 
 | 443 | /*==========================================================================* | 
 | 444 |  * Name:         smp_callin | 
 | 445 |  * | 
 | 446 |  * Description:  This routine activate a secondary processor. | 
 | 447 |  * | 
 | 448 |  * Born on Date: 2002.02.05 | 
 | 449 |  * | 
 | 450 |  * Arguments:    NONE | 
 | 451 |  * | 
 | 452 |  * Returns:      void (cannot fail) | 
 | 453 |  * | 
 | 454 |  * Modification log: | 
 | 455 |  * Date       Who Description | 
 | 456 |  * ---------- --- -------------------------------------------------------- | 
 | 457 |  * 2003-06-24 hy  modify for linux-2.5.69 | 
 | 458 |  * | 
 | 459 |  *==========================================================================*/ | 
 | 460 | static void __init smp_callin(void) | 
 | 461 | { | 
 | 462 | 	int phys_id = hard_smp_processor_id(); | 
 | 463 | 	int cpu_id = smp_processor_id(); | 
 | 464 | 	unsigned long timeout; | 
 | 465 |  | 
 | 466 | 	if (cpu_isset(cpu_id, cpu_callin_map)) { | 
 | 467 | 		printk("huh, phys CPU#%d, CPU#%d already present??\n", | 
 | 468 | 			phys_id, cpu_id); | 
 | 469 | 		BUG(); | 
 | 470 | 	} | 
 | 471 | 	Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpu_id, phys_id); | 
 | 472 |  | 
 | 473 | 	/* Waiting 2s total for startup (udelay is not yet working) */ | 
 | 474 | 	timeout = jiffies + (2 * HZ); | 
 | 475 | 	while (time_before(jiffies, timeout)) { | 
 | 476 | 		/* Has the boot CPU finished it's STARTUP sequence ? */ | 
 | 477 | 		if (cpu_isset(cpu_id, cpu_callout_map)) | 
 | 478 | 			break; | 
 | 479 | 		cpu_relax(); | 
 | 480 | 	} | 
 | 481 |  | 
 | 482 | 	if (!time_before(jiffies, timeout)) { | 
 | 483 | 		printk("BUG: CPU#%d started up but did not get a callout!\n", | 
 | 484 | 			cpu_id); | 
 | 485 | 		BUG(); | 
 | 486 | 	} | 
 | 487 |  | 
 | 488 | 	/* Allow the master to continue. */ | 
 | 489 | 	cpu_set(cpu_id, cpu_callin_map); | 
 | 490 | } | 
 | 491 |  | 
 | 492 | static void __init smp_online(void) | 
 | 493 | { | 
 | 494 | 	int cpu_id = smp_processor_id(); | 
 | 495 |  | 
| Manfred Spraul | e545a61 | 2008-09-07 16:57:22 +0200 | [diff] [blame] | 496 | 	notify_cpu_starting(cpu_id); | 
 | 497 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 498 | 	local_irq_enable(); | 
 | 499 |  | 
 | 500 | 	/* Get our bogomips. */ | 
 | 501 | 	calibrate_delay(); | 
 | 502 |  | 
 | 503 | 	/* Save our processor parameters */ | 
 | 504 |  	smp_store_cpu_info(cpu_id); | 
 | 505 |  | 
 | 506 | 	cpu_set(cpu_id, cpu_online_map); | 
 | 507 | } | 
 | 508 |  | 
 | 509 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
| Simon Arlott | 5aa8b6c | 2007-10-20 01:14:39 +0200 | [diff] [blame] | 510 | /* Boot up CPUs common Routines                                              */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 511 | /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ | 
 | 512 | static void __init show_mp_info(int nr_cpu) | 
 | 513 | { | 
 | 514 | 	int i; | 
 | 515 | 	char cpu_model0[17], cpu_model1[17], cpu_ver[9]; | 
 | 516 |  | 
 | 517 | 	strncpy(cpu_model0, (char *)M32R_FPGA_CPU_NAME_ADDR, 16); | 
 | 518 | 	strncpy(cpu_model1, (char *)M32R_FPGA_MODEL_ID_ADDR, 16); | 
 | 519 | 	strncpy(cpu_ver, (char *)M32R_FPGA_VERSION_ADDR, 8); | 
 | 520 |  | 
 | 521 | 	cpu_model0[16] = '\0'; | 
 | 522 | 	for (i = 15 ; i >= 0 ; i--) { | 
 | 523 | 		if (cpu_model0[i] != ' ') | 
 | 524 | 			break; | 
 | 525 | 		cpu_model0[i] = '\0'; | 
 | 526 | 	} | 
 | 527 | 	cpu_model1[16] = '\0'; | 
 | 528 | 	for (i = 15 ; i >= 0 ; i--) { | 
 | 529 | 		if (cpu_model1[i] != ' ') | 
 | 530 | 			break; | 
 | 531 | 		cpu_model1[i] = '\0'; | 
 | 532 | 	} | 
 | 533 | 	cpu_ver[8] = '\0'; | 
 | 534 | 	for (i = 7 ; i >= 0 ; i--) { | 
 | 535 | 		if (cpu_ver[i] != ' ') | 
 | 536 | 			break; | 
 | 537 | 		cpu_ver[i] = '\0'; | 
 | 538 | 	} | 
 | 539 |  | 
 | 540 | 	printk(KERN_INFO "M32R-mp information\n"); | 
 | 541 | 	printk(KERN_INFO "  On-chip CPUs : %d\n", nr_cpu); | 
 | 542 | 	printk(KERN_INFO "  CPU model : %s/%s(%s)\n", cpu_model0, | 
 | 543 | 		cpu_model1, cpu_ver); | 
 | 544 | } | 
 | 545 |  | 
 | 546 | /* | 
 | 547 |  * The bootstrap kernel entry code has set these up. Save them for | 
 | 548 |  * a given CPU | 
 | 549 |  */ | 
 | 550 | static void __init smp_store_cpu_info(int cpu_id) | 
 | 551 | { | 
 | 552 | 	struct cpuinfo_m32r *ci = cpu_data + cpu_id; | 
 | 553 |  | 
 | 554 | 	*ci = boot_cpu_data; | 
 | 555 | 	ci->loops_per_jiffy = loops_per_jiffy; | 
 | 556 | } | 
 | 557 |  | 
 | 558 | static void __init show_cpu_info(int cpu_id) | 
 | 559 | { | 
 | 560 | 	struct cpuinfo_m32r *ci = &cpu_data[cpu_id]; | 
 | 561 |  | 
 | 562 | 	printk("CPU#%d : ", cpu_id); | 
 | 563 |  | 
 | 564 | #define PRINT_CLOCK(name, value) \ | 
 | 565 | 	printk(name " clock %d.%02dMHz", \ | 
 | 566 | 		((value) / 1000000), ((value) % 1000000) / 10000) | 
 | 567 |  | 
 | 568 | 	PRINT_CLOCK("CPU", (int)ci->cpu_clock); | 
 | 569 | 	PRINT_CLOCK(", Bus", (int)ci->bus_clock); | 
 | 570 | 	printk(", loops_per_jiffy[%ld]\n", ci->loops_per_jiffy); | 
 | 571 | } | 
 | 572 |  | 
 | 573 | /* | 
 | 574 |  * the frequency of the profiling timer can be changed | 
 | 575 |  * by writing a multiplier value into /proc/profile. | 
 | 576 |  */ | 
 | 577 | int setup_profiling_timer(unsigned int multiplier) | 
 | 578 | { | 
 | 579 | 	int i; | 
 | 580 |  | 
 | 581 | 	/* | 
 | 582 | 	 * Sanity check. [at least 500 APIC cycles should be | 
 | 583 | 	 * between APIC interrupts as a rule of thumb, to avoid | 
 | 584 | 	 * irqs flooding us] | 
 | 585 | 	 */ | 
 | 586 | 	if ( (!multiplier) || (calibration_result / multiplier < 500)) | 
 | 587 | 		return -EINVAL; | 
 | 588 |  | 
 | 589 | 	/* | 
 | 590 | 	 * Set the new multiplier for each CPU. CPUs don't start using the | 
 | 591 | 	 * new values until the next timer interrupt in which they do process | 
 | 592 | 	 * accounting. At that time they also adjust their APIC timers | 
 | 593 | 	 * accordingly. | 
 | 594 | 	 */ | 
| Rusty Russell | 9e2f913 | 2009-01-01 10:12:14 +1030 | [diff] [blame] | 595 | 	for_each_possible_cpu(i) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 596 | 		per_cpu(prof_multiplier, i) = multiplier; | 
 | 597 |  | 
 | 598 | 	return 0; | 
 | 599 | } | 
 | 600 |  | 
 | 601 | /* Initialize all maps between cpu number and apicids */ | 
 | 602 | static void __init init_cpu_to_physid(void) | 
 | 603 | { | 
 | 604 | 	int  i; | 
 | 605 |  | 
 | 606 | 	for (i = 0 ; i < NR_CPUS ; i++) { | 
 | 607 | 		cpu_2_physid[i] = -1; | 
 | 608 | 		physid_2_cpu[i] = -1; | 
 | 609 | 	} | 
 | 610 | } | 
 | 611 |  | 
 | 612 | /* | 
 | 613 |  * set up a mapping between cpu and apicid. Uses logical apicids for multiquad, | 
 | 614 |  * else physical apic ids | 
 | 615 |  */ | 
 | 616 | static void __init map_cpu_to_physid(int cpu_id, int phys_id) | 
 | 617 | { | 
 | 618 | 	physid_2_cpu[phys_id] = cpu_id; | 
 | 619 | 	cpu_2_physid[cpu_id] = phys_id; | 
 | 620 | } | 
 | 621 |  | 
 | 622 | /* | 
 | 623 |  * undo a mapping between cpu and apicid. Uses logical apicids for multiquad, | 
 | 624 |  * else physical apic ids | 
 | 625 |  */ | 
 | 626 | static void __init unmap_cpu_to_physid(int cpu_id, int phys_id) | 
 | 627 | { | 
 | 628 | 	physid_2_cpu[phys_id] = -1; | 
 | 629 | 	cpu_2_physid[cpu_id] = -1; | 
 | 630 | } |