diff options
Diffstat (limited to 'arch/ia64/kernel/smpboot.c')
| -rw-r--r-- | arch/ia64/kernel/smpboot.c | 114 |
1 files changed, 108 insertions, 6 deletions
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index b681ef34a86e..c4b633b36dab 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c | |||
| @@ -70,6 +70,12 @@ | |||
| 70 | #endif | 70 | #endif |
| 71 | 71 | ||
| 72 | #ifdef CONFIG_HOTPLUG_CPU | 72 | #ifdef CONFIG_HOTPLUG_CPU |
| 73 | #ifdef CONFIG_PERMIT_BSP_REMOVE | ||
| 74 | #define bsp_remove_ok 1 | ||
| 75 | #else | ||
| 76 | #define bsp_remove_ok 0 | ||
| 77 | #endif | ||
| 78 | |||
| 73 | /* | 79 | /* |
| 74 | * Store all idle threads, this can be reused instead of creating | 80 | * Store all idle threads, this can be reused instead of creating |
| 75 | * a new thread. Also avoids complicated thread destroy functionality | 81 | * a new thread. Also avoids complicated thread destroy functionality |
| @@ -104,7 +110,7 @@ struct sal_to_os_boot *sal_state_for_booting_cpu = &sal_boot_rendez_state[0]; | |||
| 104 | /* | 110 | /* |
| 105 | * ITC synchronization related stuff: | 111 | * ITC synchronization related stuff: |
| 106 | */ | 112 | */ |
| 107 | #define MASTER 0 | 113 | #define MASTER (0) |
| 108 | #define SLAVE (SMP_CACHE_BYTES/8) | 114 | #define SLAVE (SMP_CACHE_BYTES/8) |
| 109 | 115 | ||
| 110 | #define NUM_ROUNDS 64 /* magic value */ | 116 | #define NUM_ROUNDS 64 /* magic value */ |
| @@ -151,6 +157,27 @@ char __initdata no_int_routing; | |||
| 151 | 157 | ||
| 152 | unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ | 158 | unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ |
| 153 | 159 | ||
| 160 | #ifdef CONFIG_FORCE_CPEI_RETARGET | ||
| 161 | #define CPEI_OVERRIDE_DEFAULT (1) | ||
| 162 | #else | ||
| 163 | #define CPEI_OVERRIDE_DEFAULT (0) | ||
| 164 | #endif | ||
| 165 | |||
| 166 | unsigned int force_cpei_retarget = CPEI_OVERRIDE_DEFAULT; | ||
| 167 | |||
| 168 | static int __init | ||
| 169 | cmdl_force_cpei(char *str) | ||
| 170 | { | ||
| 171 | int value=0; | ||
| 172 | |||
| 173 | get_option (&str, &value); | ||
| 174 | force_cpei_retarget = value; | ||
| 175 | |||
| 176 | return 1; | ||
| 177 | } | ||
| 178 | |||
| 179 | __setup("force_cpei=", cmdl_force_cpei); | ||
| 180 | |||
| 154 | static int __init | 181 | static int __init |
| 155 | nointroute (char *str) | 182 | nointroute (char *str) |
| 156 | { | 183 | { |
| @@ -161,6 +188,27 @@ nointroute (char *str) | |||
| 161 | 188 | ||
| 162 | __setup("nointroute", nointroute); | 189 | __setup("nointroute", nointroute); |
| 163 | 190 | ||
| 191 | static void fix_b0_for_bsp(void) | ||
| 192 | { | ||
| 193 | #ifdef CONFIG_HOTPLUG_CPU | ||
| 194 | int cpuid; | ||
| 195 | static int fix_bsp_b0 = 1; | ||
| 196 | |||
| 197 | cpuid = smp_processor_id(); | ||
| 198 | |||
| 199 | /* | ||
| 200 | * Cache the b0 value on the first AP that comes up | ||
| 201 | */ | ||
| 202 | if (!(fix_bsp_b0 && cpuid)) | ||
| 203 | return; | ||
| 204 | |||
| 205 | sal_boot_rendez_state[0].br[0] = sal_boot_rendez_state[cpuid].br[0]; | ||
| 206 | printk ("Fixed BSP b0 value from CPU %d\n", cpuid); | ||
| 207 | |||
| 208 | fix_bsp_b0 = 0; | ||
| 209 | #endif | ||
| 210 | } | ||
| 211 | |||
| 164 | void | 212 | void |
| 165 | sync_master (void *arg) | 213 | sync_master (void *arg) |
| 166 | { | 214 | { |
| @@ -327,8 +375,9 @@ smp_setup_percpu_timer (void) | |||
| 327 | static void __devinit | 375 | static void __devinit |
| 328 | smp_callin (void) | 376 | smp_callin (void) |
| 329 | { | 377 | { |
| 330 | int cpuid, phys_id; | 378 | int cpuid, phys_id, itc_master; |
| 331 | extern void ia64_init_itm(void); | 379 | extern void ia64_init_itm(void); |
| 380 | extern volatile int time_keeper_id; | ||
| 332 | 381 | ||
| 333 | #ifdef CONFIG_PERFMON | 382 | #ifdef CONFIG_PERFMON |
| 334 | extern void pfm_init_percpu(void); | 383 | extern void pfm_init_percpu(void); |
| @@ -336,6 +385,7 @@ smp_callin (void) | |||
| 336 | 385 | ||
| 337 | cpuid = smp_processor_id(); | 386 | cpuid = smp_processor_id(); |
| 338 | phys_id = hard_smp_processor_id(); | 387 | phys_id = hard_smp_processor_id(); |
| 388 | itc_master = time_keeper_id; | ||
| 339 | 389 | ||
| 340 | if (cpu_online(cpuid)) { | 390 | if (cpu_online(cpuid)) { |
| 341 | printk(KERN_ERR "huh, phys CPU#0x%x, CPU#0x%x already present??\n", | 391 | printk(KERN_ERR "huh, phys CPU#0x%x, CPU#0x%x already present??\n", |
| @@ -343,6 +393,8 @@ smp_callin (void) | |||
| 343 | BUG(); | 393 | BUG(); |
| 344 | } | 394 | } |
| 345 | 395 | ||
| 396 | fix_b0_for_bsp(); | ||
| 397 | |||
| 346 | lock_ipi_calllock(); | 398 | lock_ipi_calllock(); |
| 347 | cpu_set(cpuid, cpu_online_map); | 399 | cpu_set(cpuid, cpu_online_map); |
| 348 | unlock_ipi_calllock(); | 400 | unlock_ipi_calllock(); |
| @@ -365,8 +417,8 @@ smp_callin (void) | |||
| 365 | * calls spin_unlock_bh(), which calls spin_unlock_bh(), which calls | 417 | * calls spin_unlock_bh(), which calls spin_unlock_bh(), which calls |
| 366 | * local_bh_enable(), which bugs out if irqs are not enabled... | 418 | * local_bh_enable(), which bugs out if irqs are not enabled... |
| 367 | */ | 419 | */ |
| 368 | Dprintk("Going to syncup ITC with BP.\n"); | 420 | Dprintk("Going to syncup ITC with ITC Master.\n"); |
| 369 | ia64_sync_itc(0); | 421 | ia64_sync_itc(itc_master); |
| 370 | } | 422 | } |
| 371 | 423 | ||
| 372 | /* | 424 | /* |
| @@ -635,6 +687,47 @@ remove_siblinginfo(int cpu) | |||
| 635 | } | 687 | } |
| 636 | 688 | ||
| 637 | extern void fixup_irqs(void); | 689 | extern void fixup_irqs(void); |
| 690 | |||
| 691 | int migrate_platform_irqs(unsigned int cpu) | ||
| 692 | { | ||
| 693 | int new_cpei_cpu; | ||
| 694 | irq_desc_t *desc = NULL; | ||
| 695 | cpumask_t mask; | ||
| 696 | int retval = 0; | ||
| 697 | |||
| 698 | /* | ||
| 699 | * dont permit CPEI target to removed. | ||
| 700 | */ | ||
| 701 | if (cpe_vector > 0 && is_cpu_cpei_target(cpu)) { | ||
| 702 | printk ("CPU (%d) is CPEI Target\n", cpu); | ||
| 703 | if (can_cpei_retarget()) { | ||
| 704 | /* | ||
| 705 | * Now re-target the CPEI to a different processor | ||
| 706 | */ | ||
| 707 | new_cpei_cpu = any_online_cpu(cpu_online_map); | ||
| 708 | mask = cpumask_of_cpu(new_cpei_cpu); | ||
| 709 | set_cpei_target_cpu(new_cpei_cpu); | ||
| 710 | desc = irq_descp(ia64_cpe_irq); | ||
| 711 | /* | ||
| 712 | * Switch for now, immediatly, we need to do fake intr | ||
| 713 | * as other interrupts, but need to study CPEI behaviour with | ||
| 714 | * polling before making changes. | ||
| 715 | */ | ||
| 716 | if (desc) { | ||
| 717 | desc->handler->disable(ia64_cpe_irq); | ||
| 718 | desc->handler->set_affinity(ia64_cpe_irq, mask); | ||
| 719 | desc->handler->enable(ia64_cpe_irq); | ||
| 720 | printk ("Re-targetting CPEI to cpu %d\n", new_cpei_cpu); | ||
| 721 | } | ||
| 722 | } | ||
| 723 | if (!desc) { | ||
| 724 | printk ("Unable to retarget CPEI, offline cpu [%d] failed\n", cpu); | ||
| 725 | retval = -EBUSY; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | return retval; | ||
| 729 | } | ||
| 730 | |||
| 638 | /* must be called with cpucontrol mutex held */ | 731 | /* must be called with cpucontrol mutex held */ |
| 639 | int __cpu_disable(void) | 732 | int __cpu_disable(void) |
| 640 | { | 733 | { |
| @@ -643,8 +736,17 @@ int __cpu_disable(void) | |||
| 643 | /* | 736 | /* |
| 644 | * dont permit boot processor for now | 737 | * dont permit boot processor for now |
| 645 | */ | 738 | */ |
| 646 | if (cpu == 0) | 739 | if (cpu == 0 && !bsp_remove_ok) { |
| 647 | return -EBUSY; | 740 | printk ("Your platform does not support removal of BSP\n"); |
| 741 | return (-EBUSY); | ||
| 742 | } | ||
| 743 | |||
| 744 | cpu_clear(cpu, cpu_online_map); | ||
| 745 | |||
| 746 | if (migrate_platform_irqs(cpu)) { | ||
| 747 | cpu_set(cpu, cpu_online_map); | ||
| 748 | return (-EBUSY); | ||
| 749 | } | ||
| 648 | 750 | ||
| 649 | remove_siblinginfo(cpu); | 751 | remove_siblinginfo(cpu); |
| 650 | cpu_clear(cpu, cpu_online_map); | 752 | cpu_clear(cpu, cpu_online_map); |
