diff options
| -rw-r--r-- | arch/powerpc/kernel/smp.c | 3 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powermac/setup.c | 41 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powermac/smp.c | 166 |
3 files changed, 112 insertions, 98 deletions
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 65484b2200b3..0b47de07302d 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
| @@ -68,7 +68,8 @@ EXPORT_PER_CPU_SYMBOL(cpu_core_map); | |||
| 68 | /* SMP operations for this machine */ | 68 | /* SMP operations for this machine */ |
| 69 | struct smp_ops_t *smp_ops; | 69 | struct smp_ops_t *smp_ops; |
| 70 | 70 | ||
| 71 | static volatile unsigned int cpu_callin_map[NR_CPUS]; | 71 | /* Can't be static due to PowerMac hackery */ |
| 72 | volatile unsigned int cpu_callin_map[NR_CPUS]; | ||
| 72 | 73 | ||
| 73 | int smt_enabled_at_boot = 1; | 74 | int smt_enabled_at_boot = 1; |
| 74 | 75 | ||
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 86f69a4eb49b..c20522656367 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c | |||
| @@ -103,11 +103,6 @@ unsigned long smu_cmdbuf_abs; | |||
| 103 | EXPORT_SYMBOL(smu_cmdbuf_abs); | 103 | EXPORT_SYMBOL(smu_cmdbuf_abs); |
| 104 | #endif | 104 | #endif |
| 105 | 105 | ||
| 106 | #ifdef CONFIG_SMP | ||
| 107 | extern struct smp_ops_t psurge_smp_ops; | ||
| 108 | extern struct smp_ops_t core99_smp_ops; | ||
| 109 | #endif /* CONFIG_SMP */ | ||
| 110 | |||
| 111 | static void pmac_show_cpuinfo(struct seq_file *m) | 106 | static void pmac_show_cpuinfo(struct seq_file *m) |
| 112 | { | 107 | { |
| 113 | struct device_node *np; | 108 | struct device_node *np; |
| @@ -341,34 +336,6 @@ static void __init pmac_setup_arch(void) | |||
| 341 | ROOT_DEV = DEFAULT_ROOT_DEVICE; | 336 | ROOT_DEV = DEFAULT_ROOT_DEVICE; |
| 342 | #endif | 337 | #endif |
| 343 | 338 | ||
| 344 | #ifdef CONFIG_SMP | ||
| 345 | /* Check for Core99 */ | ||
| 346 | ic = of_find_node_by_name(NULL, "uni-n"); | ||
| 347 | if (!ic) | ||
| 348 | ic = of_find_node_by_name(NULL, "u3"); | ||
| 349 | if (!ic) | ||
| 350 | ic = of_find_node_by_name(NULL, "u4"); | ||
| 351 | if (ic) { | ||
| 352 | of_node_put(ic); | ||
| 353 | smp_ops = &core99_smp_ops; | ||
| 354 | } | ||
| 355 | #ifdef CONFIG_PPC32 | ||
| 356 | else { | ||
| 357 | /* | ||
| 358 | * We have to set bits in cpu_possible_map here since the | ||
| 359 | * secondary CPU(s) aren't in the device tree, and | ||
| 360 | * setup_per_cpu_areas only allocates per-cpu data for | ||
| 361 | * CPUs in the cpu_possible_map. | ||
| 362 | */ | ||
| 363 | int cpu; | ||
| 364 | |||
| 365 | for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu) | ||
| 366 | cpu_set(cpu, cpu_possible_map); | ||
| 367 | smp_ops = &psurge_smp_ops; | ||
| 368 | } | ||
| 369 | #endif | ||
| 370 | #endif /* CONFIG_SMP */ | ||
| 371 | |||
| 372 | #ifdef CONFIG_ADB | 339 | #ifdef CONFIG_ADB |
| 373 | if (strstr(cmd_line, "adb_sync")) { | 340 | if (strstr(cmd_line, "adb_sync")) { |
| 374 | extern int __adb_probe_sync; | 341 | extern int __adb_probe_sync; |
| @@ -512,6 +479,14 @@ static void __init pmac_init_early(void) | |||
| 512 | #ifdef CONFIG_PPC64 | 479 | #ifdef CONFIG_PPC64 |
| 513 | iommu_init_early_dart(); | 480 | iommu_init_early_dart(); |
| 514 | #endif | 481 | #endif |
| 482 | |||
| 483 | /* SMP Init has to be done early as we need to patch up | ||
| 484 | * cpu_possible_map before interrupt stacks are allocated | ||
| 485 | * or kaboom... | ||
| 486 | */ | ||
| 487 | #ifdef CONFIG_SMP | ||
| 488 | pmac_setup_smp(); | ||
| 489 | #endif | ||
| 515 | } | 490 | } |
| 516 | 491 | ||
| 517 | static int __init pmac_declare_of_platform_devices(void) | 492 | static int __init pmac_declare_of_platform_devices(void) |
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index cf1dbe758890..6d4da7b46b41 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
| @@ -64,10 +64,11 @@ | |||
| 64 | extern void __secondary_start_pmac_0(void); | 64 | extern void __secondary_start_pmac_0(void); |
| 65 | extern int pmac_pfunc_base_install(void); | 65 | extern int pmac_pfunc_base_install(void); |
| 66 | 66 | ||
| 67 | #ifdef CONFIG_PPC32 | 67 | static void (*pmac_tb_freeze)(int freeze); |
| 68 | static u64 timebase; | ||
| 69 | static int tb_req; | ||
| 68 | 70 | ||
| 69 | /* Sync flag for HW tb sync */ | 71 | #ifdef CONFIG_PPC32 |
| 70 | static volatile int sec_tb_reset = 0; | ||
| 71 | 72 | ||
| 72 | /* | 73 | /* |
| 73 | * Powersurge (old powermac SMP) support. | 74 | * Powersurge (old powermac SMP) support. |
| @@ -294,6 +295,9 @@ static int __init smp_psurge_probe(void) | |||
| 294 | psurge_quad_init(); | 295 | psurge_quad_init(); |
| 295 | /* All released cards using this HW design have 4 CPUs */ | 296 | /* All released cards using this HW design have 4 CPUs */ |
| 296 | ncpus = 4; | 297 | ncpus = 4; |
| 298 | /* No sure how timebase sync works on those, let's use SW */ | ||
| 299 | smp_ops->give_timebase = smp_generic_give_timebase; | ||
| 300 | smp_ops->take_timebase = smp_generic_take_timebase; | ||
| 297 | } else { | 301 | } else { |
| 298 | iounmap(quad_base); | 302 | iounmap(quad_base); |
| 299 | if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) { | 303 | if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) { |
| @@ -308,18 +312,15 @@ static int __init smp_psurge_probe(void) | |||
| 308 | psurge_start = ioremap(PSURGE_START, 4); | 312 | psurge_start = ioremap(PSURGE_START, 4); |
| 309 | psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); | 313 | psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); |
| 310 | 314 | ||
| 311 | /* | 315 | /* This is necessary because OF doesn't know about the |
| 312 | * This is necessary because OF doesn't know about the | ||
| 313 | * secondary cpu(s), and thus there aren't nodes in the | 316 | * secondary cpu(s), and thus there aren't nodes in the |
| 314 | * device tree for them, and smp_setup_cpu_maps hasn't | 317 | * device tree for them, and smp_setup_cpu_maps hasn't |
| 315 | * set their bits in cpu_possible_map and cpu_present_map. | 318 | * set their bits in cpu_present_map. |
| 316 | */ | 319 | */ |
| 317 | if (ncpus > NR_CPUS) | 320 | if (ncpus > NR_CPUS) |
| 318 | ncpus = NR_CPUS; | 321 | ncpus = NR_CPUS; |
| 319 | for (i = 1; i < ncpus ; ++i) { | 322 | for (i = 1; i < ncpus ; ++i) |
| 320 | cpu_set(i, cpu_present_map); | 323 | cpu_set(i, cpu_present_map); |
| 321 | set_hard_smp_processor_id(i, i); | ||
| 322 | } | ||
| 323 | 324 | ||
| 324 | if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352); | 325 | if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352); |
| 325 | 326 | ||
| @@ -329,8 +330,14 @@ static int __init smp_psurge_probe(void) | |||
| 329 | static void __init smp_psurge_kick_cpu(int nr) | 330 | static void __init smp_psurge_kick_cpu(int nr) |
| 330 | { | 331 | { |
| 331 | unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8; | 332 | unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8; |
| 332 | unsigned long a; | 333 | unsigned long a, flags; |
| 333 | int i; | 334 | int i, j; |
| 335 | |||
| 336 | /* Defining this here is evil ... but I prefer hiding that | ||
| 337 | * crap to avoid giving people ideas that they can do the | ||
| 338 | * same. | ||
| 339 | */ | ||
| 340 | extern volatile unsigned int cpu_callin_map[NR_CPUS]; | ||
| 334 | 341 | ||
| 335 | /* may need to flush here if secondary bats aren't setup */ | 342 | /* may need to flush here if secondary bats aren't setup */ |
| 336 | for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) | 343 | for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) |
| @@ -339,47 +346,52 @@ static void __init smp_psurge_kick_cpu(int nr) | |||
| 339 | 346 | ||
| 340 | if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353); | 347 | if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353); |
| 341 | 348 | ||
| 349 | /* This is going to freeze the timeebase, we disable interrupts */ | ||
| 350 | local_irq_save(flags); | ||
| 351 | |||
| 342 | out_be32(psurge_start, start); | 352 | out_be32(psurge_start, start); |
| 343 | mb(); | 353 | mb(); |
| 344 | 354 | ||
| 345 | psurge_set_ipi(nr); | 355 | psurge_set_ipi(nr); |
| 356 | |||
| 346 | /* | 357 | /* |
| 347 | * We can't use udelay here because the timebase is now frozen. | 358 | * We can't use udelay here because the timebase is now frozen. |
| 348 | */ | 359 | */ |
| 349 | for (i = 0; i < 2000; ++i) | 360 | for (i = 0; i < 2000; ++i) |
| 350 | barrier(); | 361 | asm volatile("nop" : : : "memory"); |
| 351 | psurge_clr_ipi(nr); | 362 | psurge_clr_ipi(nr); |
| 352 | 363 | ||
| 353 | if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354); | 364 | /* |
| 354 | } | 365 | * Also, because the timebase is frozen, we must not return to the |
| 355 | 366 | * caller which will try to do udelay's etc... Instead, we wait -here- | |
| 356 | /* | 367 | * for the CPU to callin. |
| 357 | * With the dual-cpu powersurge board, the decrementers and timebases | 368 | */ |
| 358 | * of both cpus are frozen after the secondary cpu is started up, | 369 | for (i = 0; i < 100000 && !cpu_callin_map[nr]; ++i) { |
| 359 | * until we give the secondary cpu another interrupt. This routine | 370 | for (j = 1; j < 10000; j++) |
| 360 | * uses this to get the timebases synchronized. | 371 | asm volatile("nop" : : : "memory"); |
| 361 | * -- paulus. | 372 | asm volatile("sync" : : : "memory"); |
| 362 | */ | 373 | } |
| 363 | static void __init psurge_dual_sync_tb(int cpu_nr) | 374 | if (!cpu_callin_map[nr]) |
| 364 | { | 375 | goto stuck; |
| 365 | int t; | 376 | |
| 366 | 377 | /* And we do the TB sync here too for standard dual CPU cards */ | |
| 367 | set_dec(tb_ticks_per_jiffy); | 378 | if (psurge_type == PSURGE_DUAL) { |
| 368 | /* XXX fixme */ | 379 | while(!tb_req) |
| 369 | set_tb(0, 0); | 380 | barrier(); |
| 370 | 381 | tb_req = 0; | |
| 371 | if (cpu_nr > 0) { | 382 | mb(); |
| 383 | timebase = get_tb(); | ||
| 384 | mb(); | ||
| 385 | while (timebase) | ||
| 386 | barrier(); | ||
| 372 | mb(); | 387 | mb(); |
| 373 | sec_tb_reset = 1; | ||
| 374 | return; | ||
| 375 | } | 388 | } |
| 389 | stuck: | ||
| 390 | /* now interrupt the secondary, restarting both TBs */ | ||
| 391 | if (psurge_type == PSURGE_DUAL) | ||
| 392 | psurge_set_ipi(1); | ||
| 376 | 393 | ||
| 377 | /* wait for the secondary to have reset its TB before proceeding */ | 394 | if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354); |
| 378 | for (t = 10000000; t > 0 && !sec_tb_reset; --t) | ||
| 379 | ; | ||
| 380 | |||
| 381 | /* now interrupt the secondary, starting both TBs */ | ||
| 382 | psurge_set_ipi(1); | ||
| 383 | } | 395 | } |
| 384 | 396 | ||
| 385 | static struct irqaction psurge_irqaction = { | 397 | static struct irqaction psurge_irqaction = { |
| @@ -390,36 +402,35 @@ static struct irqaction psurge_irqaction = { | |||
| 390 | 402 | ||
| 391 | static void __init smp_psurge_setup_cpu(int cpu_nr) | 403 | static void __init smp_psurge_setup_cpu(int cpu_nr) |
| 392 | { | 404 | { |
| 405 | if (cpu_nr != 0) | ||
| 406 | return; | ||
| 393 | 407 | ||
| 394 | if (cpu_nr == 0) { | 408 | /* reset the entry point so if we get another intr we won't |
| 395 | /* If we failed to start the second CPU, we should still | 409 | * try to startup again */ |
| 396 | * send it an IPI to start the timebase & DEC or we might | 410 | out_be32(psurge_start, 0x100); |
| 397 | * have them stuck. | 411 | if (setup_irq(30, &psurge_irqaction)) |
| 398 | */ | 412 | printk(KERN_ERR "Couldn't get primary IPI interrupt"); |
| 399 | if (num_online_cpus() < 2) { | ||
| 400 | if (psurge_type == PSURGE_DUAL) | ||
| 401 | psurge_set_ipi(1); | ||
| 402 | return; | ||
| 403 | } | ||
| 404 | /* reset the entry point so if we get another intr we won't | ||
| 405 | * try to startup again */ | ||
| 406 | out_be32(psurge_start, 0x100); | ||
| 407 | if (setup_irq(30, &psurge_irqaction)) | ||
| 408 | printk(KERN_ERR "Couldn't get primary IPI interrupt"); | ||
| 409 | } | ||
| 410 | |||
| 411 | if (psurge_type == PSURGE_DUAL) | ||
| 412 | psurge_dual_sync_tb(cpu_nr); | ||
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | void __init smp_psurge_take_timebase(void) | 415 | void __init smp_psurge_take_timebase(void) |
| 416 | { | 416 | { |
| 417 | /* Dummy implementation */ | 417 | if (psurge_type != PSURGE_DUAL) |
| 418 | return; | ||
| 419 | |||
| 420 | tb_req = 1; | ||
| 421 | mb(); | ||
| 422 | while (!timebase) | ||
| 423 | barrier(); | ||
| 424 | mb(); | ||
| 425 | set_tb(timebase >> 32, timebase & 0xffffffff); | ||
| 426 | timebase = 0; | ||
| 427 | mb(); | ||
| 428 | set_dec(tb_ticks_per_jiffy/2); | ||
| 418 | } | 429 | } |
| 419 | 430 | ||
| 420 | void __init smp_psurge_give_timebase(void) | 431 | void __init smp_psurge_give_timebase(void) |
| 421 | { | 432 | { |
| 422 | /* Dummy implementation */ | 433 | /* Nothing to do here */ |
| 423 | } | 434 | } |
| 424 | 435 | ||
| 425 | /* PowerSurge-style Macs */ | 436 | /* PowerSurge-style Macs */ |
| @@ -437,9 +448,6 @@ struct smp_ops_t psurge_smp_ops = { | |||
| 437 | * Core 99 and later support | 448 | * Core 99 and later support |
| 438 | */ | 449 | */ |
| 439 | 450 | ||
| 440 | static void (*pmac_tb_freeze)(int freeze); | ||
| 441 | static u64 timebase; | ||
| 442 | static int tb_req; | ||
| 443 | 451 | ||
| 444 | static void smp_core99_give_timebase(void) | 452 | static void smp_core99_give_timebase(void) |
| 445 | { | 453 | { |
| @@ -478,7 +486,6 @@ static void __devinit smp_core99_take_timebase(void) | |||
| 478 | set_tb(timebase >> 32, timebase & 0xffffffff); | 486 | set_tb(timebase >> 32, timebase & 0xffffffff); |
| 479 | timebase = 0; | 487 | timebase = 0; |
| 480 | mb(); | 488 | mb(); |
| 481 | set_dec(tb_ticks_per_jiffy/2); | ||
| 482 | 489 | ||
| 483 | local_irq_restore(flags); | 490 | local_irq_restore(flags); |
| 484 | } | 491 | } |
| @@ -920,3 +927,34 @@ struct smp_ops_t core99_smp_ops = { | |||
| 920 | # endif | 927 | # endif |
| 921 | #endif | 928 | #endif |
| 922 | }; | 929 | }; |
| 930 | |||
| 931 | void __init pmac_setup_smp(void) | ||
| 932 | { | ||
| 933 | struct device_node *np; | ||
| 934 | |||
| 935 | /* Check for Core99 */ | ||
| 936 | np = of_find_node_by_name(NULL, "uni-n"); | ||
| 937 | if (!np) | ||
| 938 | np = of_find_node_by_name(NULL, "u3"); | ||
| 939 | if (!np) | ||
| 940 | np = of_find_node_by_name(NULL, "u4"); | ||
| 941 | if (np) { | ||
| 942 | of_node_put(np); | ||
| 943 | smp_ops = &core99_smp_ops; | ||
| 944 | } | ||
| 945 | #ifdef CONFIG_PPC32 | ||
| 946 | else { | ||
| 947 | /* We have to set bits in cpu_possible_map here since the | ||
| 948 | * secondary CPU(s) aren't in the device tree. Various | ||
| 949 | * things won't be initialized for CPUs not in the possible | ||
| 950 | * map, so we really need to fix it up here. | ||
| 951 | */ | ||
| 952 | int cpu; | ||
| 953 | |||
| 954 | for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu) | ||
| 955 | cpu_set(cpu, cpu_possible_map); | ||
| 956 | smp_ops = &psurge_smp_ops; | ||
| 957 | } | ||
| 958 | #endif /* CONFIG_PPC32 */ | ||
| 959 | } | ||
| 960 | |||
