diff options
author | Ashok Raj <ashok.raj@intel.com> | 2005-04-22 17:44:40 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-04-22 17:44:40 -0400 |
commit | b8d8b883e6f029e99c35c88f853501740e322131 (patch) | |
tree | 391f2ade8823149f217991eb02911bf3dacce050 /arch/ia64/kernel/smpboot.c | |
parent | 7130667107cd3ab9d6802b69bab63c7d22f20bd4 (diff) |
[IA64] cpu hotplug: return offlined cpus to SAL
This patch is required to support cpu removal for IPF systems. Existing code
just fakes the real offline by keeping it run the idle thread, and polling
for the bit to re-appear in the cpu_state to get out of the idle loop.
For the cpu-offline to work correctly, we need to pass control of this CPU
back to SAL so it can continue in the boot-rendez mode. This gives the
SAL control to not pick this cpu as the monarch processor for global MCA
events, and addition does not wait for this cpu to checkin with SAL
for global MCA events as well. The handoff is implemented as documented in
SAL specification section 3.2.5.1 "OS_BOOT_RENDEZ to SAL return State"
Signed-off-by: Ashok Raj <ashok.raj@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/kernel/smpboot.c')
-rw-r--r-- | arch/ia64/kernel/smpboot.c | 81 |
1 files changed, 50 insertions, 31 deletions
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 5318f0cbfc26..ca1536db3394 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * 02/07/31 David Mosberger <davidm@hpl.hp.com> Switch over to hotplug-CPU boot-sequence. | 9 | * 02/07/31 David Mosberger <davidm@hpl.hp.com> Switch over to hotplug-CPU boot-sequence. |
10 | * smp_boot_cpus()/smp_commence() is replaced by | 10 | * smp_boot_cpus()/smp_commence() is replaced by |
11 | * smp_prepare_cpus()/__cpu_up()/smp_cpus_done(). | 11 | * smp_prepare_cpus()/__cpu_up()/smp_cpus_done(). |
12 | * 04/06/21 Ashok Raj <ashok.raj@intel.com> Added CPU Hotplug Support | ||
12 | */ | 13 | */ |
13 | #include <linux/config.h> | 14 | #include <linux/config.h> |
14 | 15 | ||
@@ -58,6 +59,37 @@ | |||
58 | #define Dprintk(x...) | 59 | #define Dprintk(x...) |
59 | #endif | 60 | #endif |
60 | 61 | ||
62 | #ifdef CONFIG_HOTPLUG_CPU | ||
63 | /* | ||
64 | * Store all idle threads, this can be reused instead of creating | ||
65 | * a new thread. Also avoids complicated thread destroy functionality | ||
66 | * for idle threads. | ||
67 | */ | ||
68 | struct task_struct *idle_thread_array[NR_CPUS]; | ||
69 | |||
70 | /* | ||
71 | * Global array allocated for NR_CPUS at boot time | ||
72 | */ | ||
73 | struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS]; | ||
74 | |||
75 | /* | ||
76 | * start_ap in head.S uses this to store current booting cpu | ||
77 | * info. | ||
78 | */ | ||
79 | struct sal_to_os_boot *sal_state_for_booting_cpu = &sal_boot_rendez_state[0]; | ||
80 | |||
81 | #define set_brendez_area(x) (sal_state_for_booting_cpu = &sal_boot_rendez_state[(x)]); | ||
82 | |||
83 | #define get_idle_for_cpu(x) (idle_thread_array[(x)]) | ||
84 | #define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p)) | ||
85 | |||
86 | #else | ||
87 | |||
88 | #define get_idle_for_cpu(x) (NULL) | ||
89 | #define set_idle_for_cpu(x,p) | ||
90 | #define set_brendez_area(x) | ||
91 | #endif | ||
92 | |||
61 | 93 | ||
62 | /* | 94 | /* |
63 | * ITC synchronization related stuff: | 95 | * ITC synchronization related stuff: |
@@ -345,7 +377,6 @@ start_secondary (void *unused) | |||
345 | { | 377 | { |
346 | /* Early console may use I/O ports */ | 378 | /* Early console may use I/O ports */ |
347 | ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase)); | 379 | ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase)); |
348 | |||
349 | Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id()); | 380 | Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id()); |
350 | efi_map_pal_code(); | 381 | efi_map_pal_code(); |
351 | cpu_init(); | 382 | cpu_init(); |
@@ -384,6 +415,13 @@ do_boot_cpu (int sapicid, int cpu) | |||
384 | .done = COMPLETION_INITIALIZER(c_idle.done), | 415 | .done = COMPLETION_INITIALIZER(c_idle.done), |
385 | }; | 416 | }; |
386 | DECLARE_WORK(work, do_fork_idle, &c_idle); | 417 | DECLARE_WORK(work, do_fork_idle, &c_idle); |
418 | |||
419 | c_idle.idle = get_idle_for_cpu(cpu); | ||
420 | if (c_idle.idle) { | ||
421 | init_idle(c_idle.idle, cpu); | ||
422 | goto do_rest; | ||
423 | } | ||
424 | |||
387 | /* | 425 | /* |
388 | * We can't use kernel_thread since we must avoid to reschedule the child. | 426 | * We can't use kernel_thread since we must avoid to reschedule the child. |
389 | */ | 427 | */ |
@@ -396,10 +434,15 @@ do_boot_cpu (int sapicid, int cpu) | |||
396 | 434 | ||
397 | if (IS_ERR(c_idle.idle)) | 435 | if (IS_ERR(c_idle.idle)) |
398 | panic("failed fork for CPU %d", cpu); | 436 | panic("failed fork for CPU %d", cpu); |
437 | |||
438 | set_idle_for_cpu(cpu, c_idle.idle); | ||
439 | |||
440 | do_rest: | ||
399 | task_for_booting_cpu = c_idle.idle; | 441 | task_for_booting_cpu = c_idle.idle; |
400 | 442 | ||
401 | Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); | 443 | Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); |
402 | 444 | ||
445 | set_brendez_area(cpu); | ||
403 | platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); | 446 | platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); |
404 | 447 | ||
405 | /* | 448 | /* |
@@ -555,16 +598,6 @@ void __devinit smp_prepare_boot_cpu(void) | |||
555 | #ifdef CONFIG_HOTPLUG_CPU | 598 | #ifdef CONFIG_HOTPLUG_CPU |
556 | extern void fixup_irqs(void); | 599 | extern void fixup_irqs(void); |
557 | /* must be called with cpucontrol mutex held */ | 600 | /* must be called with cpucontrol mutex held */ |
558 | static int __devinit cpu_enable(unsigned int cpu) | ||
559 | { | ||
560 | per_cpu(cpu_state,cpu) = CPU_UP_PREPARE; | ||
561 | wmb(); | ||
562 | |||
563 | while (!cpu_online(cpu)) | ||
564 | cpu_relax(); | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | int __cpu_disable(void) | 601 | int __cpu_disable(void) |
569 | { | 602 | { |
570 | int cpu = smp_processor_id(); | 603 | int cpu = smp_processor_id(); |
@@ -577,7 +610,7 @@ int __cpu_disable(void) | |||
577 | 610 | ||
578 | fixup_irqs(); | 611 | fixup_irqs(); |
579 | local_flush_tlb_all(); | 612 | local_flush_tlb_all(); |
580 | printk ("Disabled cpu %u\n", smp_processor_id()); | 613 | cpu_clear(cpu, cpu_callin_map); |
581 | return 0; | 614 | return 0; |
582 | } | 615 | } |
583 | 616 | ||
@@ -589,12 +622,7 @@ void __cpu_die(unsigned int cpu) | |||
589 | /* They ack this in play_dead by setting CPU_DEAD */ | 622 | /* They ack this in play_dead by setting CPU_DEAD */ |
590 | if (per_cpu(cpu_state, cpu) == CPU_DEAD) | 623 | if (per_cpu(cpu_state, cpu) == CPU_DEAD) |
591 | { | 624 | { |
592 | /* | 625 | printk ("CPU %d is now offline\n", cpu); |
593 | * TBD: Enable this when physical removal | ||
594 | * or when we put the processor is put in | ||
595 | * SAL_BOOT_RENDEZ mode | ||
596 | * cpu_clear(cpu, cpu_callin_map); | ||
597 | */ | ||
598 | return; | 626 | return; |
599 | } | 627 | } |
600 | msleep(100); | 628 | msleep(100); |
@@ -602,11 +630,6 @@ void __cpu_die(unsigned int cpu) | |||
602 | printk(KERN_ERR "CPU %u didn't die...\n", cpu); | 630 | printk(KERN_ERR "CPU %u didn't die...\n", cpu); |
603 | } | 631 | } |
604 | #else /* !CONFIG_HOTPLUG_CPU */ | 632 | #else /* !CONFIG_HOTPLUG_CPU */ |
605 | static int __devinit cpu_enable(unsigned int cpu) | ||
606 | { | ||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | int __cpu_disable(void) | 633 | int __cpu_disable(void) |
611 | { | 634 | { |
612 | return -ENOSYS; | 635 | return -ENOSYS; |
@@ -648,16 +671,12 @@ __cpu_up (unsigned int cpu) | |||
648 | return -EINVAL; | 671 | return -EINVAL; |
649 | 672 | ||
650 | /* | 673 | /* |
651 | * Already booted.. just enable and get outa idle lool | 674 | * Already booted cpu? not valid anymore since we dont |
675 | * do idle loop tightspin anymore. | ||
652 | */ | 676 | */ |
653 | if (cpu_isset(cpu, cpu_callin_map)) | 677 | if (cpu_isset(cpu, cpu_callin_map)) |
654 | { | 678 | return -EINVAL; |
655 | cpu_enable(cpu); | 679 | |
656 | local_irq_enable(); | ||
657 | while (!cpu_isset(cpu, cpu_online_map)) | ||
658 | mb(); | ||
659 | return 0; | ||
660 | } | ||
661 | /* Processor goes to start_secondary(), sets online flag */ | 680 | /* Processor goes to start_secondary(), sets online flag */ |
662 | ret = do_boot_cpu(sapicid, cpu); | 681 | ret = do_boot_cpu(sapicid, cpu); |
663 | if (ret < 0) | 682 | if (ret < 0) |