diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-03-22 06:09:31 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-03-22 06:09:31 -0500 |
commit | 949ec2c8e6b7b89179b85baf6309c009e1a1b951 (patch) | |
tree | 2d9c3dde17ba8608aa07e96e6fffcc23f1cab39c /arch/ia64/kernel | |
parent | 55cca65e1995ad604ee87e22c76c17d5cbceb9d0 (diff) | |
parent | e952f31bce6e9f64db01f607abc46529ba57ac9e (diff) |
Merge branch 'master'
Diffstat (limited to 'arch/ia64/kernel')
-rw-r--r-- | arch/ia64/kernel/acpi.c | 14 | ||||
-rw-r--r-- | arch/ia64/kernel/entry.S | 14 | ||||
-rw-r--r-- | arch/ia64/kernel/iosapic.c | 6 | ||||
-rw-r--r-- | arch/ia64/kernel/irq.c | 13 | ||||
-rw-r--r-- | arch/ia64/kernel/mca.c | 90 | ||||
-rw-r--r-- | arch/ia64/kernel/perfmon.c | 5 | ||||
-rw-r--r-- | arch/ia64/kernel/signal.c | 101 | ||||
-rw-r--r-- | arch/ia64/kernel/smpboot.c | 114 | ||||
-rw-r--r-- | arch/ia64/kernel/time.c | 9 | ||||
-rw-r--r-- | arch/ia64/kernel/topology.c | 2 |
10 files changed, 208 insertions, 160 deletions
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index ecd44bdc8394..4722ec51c70c 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c | |||
@@ -284,19 +284,24 @@ acpi_parse_plat_int_src(acpi_table_entry_header * header, | |||
284 | return 0; | 284 | return 0; |
285 | } | 285 | } |
286 | 286 | ||
287 | #ifdef CONFIG_HOTPLUG_CPU | ||
287 | unsigned int can_cpei_retarget(void) | 288 | unsigned int can_cpei_retarget(void) |
288 | { | 289 | { |
289 | extern int cpe_vector; | 290 | extern int cpe_vector; |
291 | extern unsigned int force_cpei_retarget; | ||
290 | 292 | ||
291 | /* | 293 | /* |
292 | * Only if CPEI is supported and the override flag | 294 | * Only if CPEI is supported and the override flag |
293 | * is present, otherwise return that its re-targettable | 295 | * is present, otherwise return that its re-targettable |
294 | * if we are in polling mode. | 296 | * if we are in polling mode. |
295 | */ | 297 | */ |
296 | if (cpe_vector > 0 && !acpi_cpei_override) | 298 | if (cpe_vector > 0) { |
297 | return 0; | 299 | if (acpi_cpei_override || force_cpei_retarget) |
298 | else | 300 | return 1; |
299 | return 1; | 301 | else |
302 | return 0; | ||
303 | } | ||
304 | return 1; | ||
300 | } | 305 | } |
301 | 306 | ||
302 | unsigned int is_cpu_cpei_target(unsigned int cpu) | 307 | unsigned int is_cpu_cpei_target(unsigned int cpu) |
@@ -315,6 +320,7 @@ void set_cpei_target_cpu(unsigned int cpu) | |||
315 | { | 320 | { |
316 | acpi_cpei_phys_cpuid = cpu_physical_id(cpu); | 321 | acpi_cpei_phys_cpuid = cpu_physical_id(cpu); |
317 | } | 322 | } |
323 | #endif | ||
318 | 324 | ||
319 | unsigned int get_cpei_target_cpu(void) | 325 | unsigned int get_cpei_target_cpu(void) |
320 | { | 326 | { |
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 930fdfca6ddb..0e3eda99e549 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
@@ -1102,9 +1102,6 @@ skip_rbs_switch: | |||
1102 | st8 [r2]=r8 | 1102 | st8 [r2]=r8 |
1103 | st8 [r3]=r10 | 1103 | st8 [r3]=r10 |
1104 | .work_pending: | 1104 | .work_pending: |
1105 | tbit.nz p6,p0=r31,TIF_SIGDELAYED // signal delayed from MCA/INIT/NMI/PMI context? | ||
1106 | (p6) br.cond.sptk.few .sigdelayed | ||
1107 | ;; | ||
1108 | tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? | 1105 | tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? |
1109 | (p6) br.cond.sptk.few .notify | 1106 | (p6) br.cond.sptk.few .notify |
1110 | #ifdef CONFIG_PREEMPT | 1107 | #ifdef CONFIG_PREEMPT |
@@ -1131,17 +1128,6 @@ skip_rbs_switch: | |||
1131 | (pLvSys)br.cond.sptk.few .work_pending_syscall_end | 1128 | (pLvSys)br.cond.sptk.few .work_pending_syscall_end |
1132 | br.cond.sptk.many .work_processed_kernel // don't re-check | 1129 | br.cond.sptk.many .work_processed_kernel // don't re-check |
1133 | 1130 | ||
1134 | // There is a delayed signal that was detected in MCA/INIT/NMI/PMI context where | ||
1135 | // it could not be delivered. Deliver it now. The signal might be for us and | ||
1136 | // may set TIF_SIGPENDING, so redrive ia64_leave_* after processing the delayed | ||
1137 | // signal. | ||
1138 | |||
1139 | .sigdelayed: | ||
1140 | br.call.sptk.many rp=do_sigdelayed | ||
1141 | cmp.eq p6,p0=r0,r0 // p6 <- 1, always re-check | ||
1142 | (pLvSys)br.cond.sptk.few .work_pending_syscall_end | ||
1143 | br.cond.sptk.many .work_processed_kernel // re-check | ||
1144 | |||
1145 | .work_pending_syscall_end: | 1131 | .work_pending_syscall_end: |
1146 | adds r2=PT(R8)+16,r12 | 1132 | adds r2=PT(R8)+16,r12 |
1147 | adds r3=PT(R10)+16,r12 | 1133 | adds r3=PT(R10)+16,r12 |
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 574084f343fa..8832c553230a 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c | |||
@@ -631,6 +631,7 @@ get_target_cpu (unsigned int gsi, int vector) | |||
631 | { | 631 | { |
632 | #ifdef CONFIG_SMP | 632 | #ifdef CONFIG_SMP |
633 | static int cpu = -1; | 633 | static int cpu = -1; |
634 | extern int cpe_vector; | ||
634 | 635 | ||
635 | /* | 636 | /* |
636 | * In case of vector shared by multiple RTEs, all RTEs that | 637 | * In case of vector shared by multiple RTEs, all RTEs that |
@@ -653,6 +654,11 @@ get_target_cpu (unsigned int gsi, int vector) | |||
653 | if (!cpu_online(smp_processor_id())) | 654 | if (!cpu_online(smp_processor_id())) |
654 | return cpu_physical_id(smp_processor_id()); | 655 | return cpu_physical_id(smp_processor_id()); |
655 | 656 | ||
657 | #ifdef CONFIG_ACPI | ||
658 | if (cpe_vector > 0 && vector == IA64_CPEP_VECTOR) | ||
659 | return get_cpei_target_cpu(); | ||
660 | #endif | ||
661 | |||
656 | #ifdef CONFIG_NUMA | 662 | #ifdef CONFIG_NUMA |
657 | { | 663 | { |
658 | int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; | 664 | int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; |
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index d33244c32759..5ce908ef9c95 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c | |||
@@ -163,8 +163,19 @@ void fixup_irqs(void) | |||
163 | { | 163 | { |
164 | unsigned int irq; | 164 | unsigned int irq; |
165 | extern void ia64_process_pending_intr(void); | 165 | extern void ia64_process_pending_intr(void); |
166 | extern void ia64_disable_timer(void); | ||
167 | extern volatile int time_keeper_id; | ||
168 | |||
169 | ia64_disable_timer(); | ||
170 | |||
171 | /* | ||
172 | * Find a new timesync master | ||
173 | */ | ||
174 | if (smp_processor_id() == time_keeper_id) { | ||
175 | time_keeper_id = first_cpu(cpu_online_map); | ||
176 | printk ("CPU %d is now promoted to time-keeper master\n", time_keeper_id); | ||
177 | } | ||
166 | 178 | ||
167 | ia64_set_itv(1<<16); | ||
168 | /* | 179 | /* |
169 | * Phase 1: Locate irq's bound to this cpu and | 180 | * Phase 1: Locate irq's bound to this cpu and |
170 | * relocate them for cpu removal. | 181 | * relocate them for cpu removal. |
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index ee7eec9ee576..b57e723f194c 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c | |||
@@ -281,14 +281,10 @@ ia64_mca_log_sal_error_record(int sal_info_type) | |||
281 | ia64_sal_clear_state_info(sal_info_type); | 281 | ia64_sal_clear_state_info(sal_info_type); |
282 | } | 282 | } |
283 | 283 | ||
284 | /* | ||
285 | * platform dependent error handling | ||
286 | */ | ||
287 | #ifndef PLATFORM_MCA_HANDLERS | ||
288 | |||
289 | #ifdef CONFIG_ACPI | 284 | #ifdef CONFIG_ACPI |
290 | 285 | ||
291 | int cpe_vector = -1; | 286 | int cpe_vector = -1; |
287 | int ia64_cpe_irq = -1; | ||
292 | 288 | ||
293 | static irqreturn_t | 289 | static irqreturn_t |
294 | ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) | 290 | ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) |
@@ -377,8 +373,6 @@ ia64_mca_register_cpev (int cpev) | |||
377 | } | 373 | } |
378 | #endif /* CONFIG_ACPI */ | 374 | #endif /* CONFIG_ACPI */ |
379 | 375 | ||
380 | #endif /* PLATFORM_MCA_HANDLERS */ | ||
381 | |||
382 | /* | 376 | /* |
383 | * ia64_mca_cmc_vector_setup | 377 | * ia64_mca_cmc_vector_setup |
384 | * | 378 | * |
@@ -630,6 +624,32 @@ copy_reg(const u64 *fr, u64 fnat, u64 *tr, u64 *tnat) | |||
630 | *tnat |= (nat << tslot); | 624 | *tnat |= (nat << tslot); |
631 | } | 625 | } |
632 | 626 | ||
627 | /* Change the comm field on the MCA/INT task to include the pid that | ||
628 | * was interrupted, it makes for easier debugging. If that pid was 0 | ||
629 | * (swapper or nested MCA/INIT) then use the start of the previous comm | ||
630 | * field suffixed with its cpu. | ||
631 | */ | ||
632 | |||
633 | static void | ||
634 | ia64_mca_modify_comm(const task_t *previous_current) | ||
635 | { | ||
636 | char *p, comm[sizeof(current->comm)]; | ||
637 | if (previous_current->pid) | ||
638 | snprintf(comm, sizeof(comm), "%s %d", | ||
639 | current->comm, previous_current->pid); | ||
640 | else { | ||
641 | int l; | ||
642 | if ((p = strchr(previous_current->comm, ' '))) | ||
643 | l = p - previous_current->comm; | ||
644 | else | ||
645 | l = strlen(previous_current->comm); | ||
646 | snprintf(comm, sizeof(comm), "%s %*s %d", | ||
647 | current->comm, l, previous_current->comm, | ||
648 | task_thread_info(previous_current)->cpu); | ||
649 | } | ||
650 | memcpy(current->comm, comm, sizeof(current->comm)); | ||
651 | } | ||
652 | |||
633 | /* On entry to this routine, we are running on the per cpu stack, see | 653 | /* On entry to this routine, we are running on the per cpu stack, see |
634 | * mca_asm.h. The original stack has not been touched by this event. Some of | 654 | * mca_asm.h. The original stack has not been touched by this event. Some of |
635 | * the original stack's registers will be in the RBS on this stack. This stack | 655 | * the original stack's registers will be in the RBS on this stack. This stack |
@@ -648,7 +668,7 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
648 | struct ia64_sal_os_state *sos, | 668 | struct ia64_sal_os_state *sos, |
649 | const char *type) | 669 | const char *type) |
650 | { | 670 | { |
651 | char *p, comm[sizeof(current->comm)]; | 671 | char *p; |
652 | ia64_va va; | 672 | ia64_va va; |
653 | extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ | 673 | extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ |
654 | const pal_min_state_area_t *ms = sos->pal_min_state; | 674 | const pal_min_state_area_t *ms = sos->pal_min_state; |
@@ -721,6 +741,10 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
721 | /* Verify the previous stack state before we change it */ | 741 | /* Verify the previous stack state before we change it */ |
722 | if (user_mode(regs)) { | 742 | if (user_mode(regs)) { |
723 | msg = "occurred in user space"; | 743 | msg = "occurred in user space"; |
744 | /* previous_current is guaranteed to be valid when the task was | ||
745 | * in user space, so ... | ||
746 | */ | ||
747 | ia64_mca_modify_comm(previous_current); | ||
724 | goto no_mod; | 748 | goto no_mod; |
725 | } | 749 | } |
726 | if (r13 != sos->prev_IA64_KR_CURRENT) { | 750 | if (r13 != sos->prev_IA64_KR_CURRENT) { |
@@ -750,25 +774,7 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
750 | goto no_mod; | 774 | goto no_mod; |
751 | } | 775 | } |
752 | 776 | ||
753 | /* Change the comm field on the MCA/INT task to include the pid that | 777 | ia64_mca_modify_comm(previous_current); |
754 | * was interrupted, it makes for easier debugging. If that pid was 0 | ||
755 | * (swapper or nested MCA/INIT) then use the start of the previous comm | ||
756 | * field suffixed with its cpu. | ||
757 | */ | ||
758 | if (previous_current->pid) | ||
759 | snprintf(comm, sizeof(comm), "%s %d", | ||
760 | current->comm, previous_current->pid); | ||
761 | else { | ||
762 | int l; | ||
763 | if ((p = strchr(previous_current->comm, ' '))) | ||
764 | l = p - previous_current->comm; | ||
765 | else | ||
766 | l = strlen(previous_current->comm); | ||
767 | snprintf(comm, sizeof(comm), "%s %*s %d", | ||
768 | current->comm, l, previous_current->comm, | ||
769 | task_thread_info(previous_current)->cpu); | ||
770 | } | ||
771 | memcpy(current->comm, comm, sizeof(current->comm)); | ||
772 | 778 | ||
773 | /* Make the original task look blocked. First stack a struct pt_regs, | 779 | /* Make the original task look blocked. First stack a struct pt_regs, |
774 | * describing the state at the time of interrupt. mca_asm.S built a | 780 | * describing the state at the time of interrupt. mca_asm.S built a |
@@ -908,7 +914,7 @@ no_mod: | |||
908 | static void | 914 | static void |
909 | ia64_wait_for_slaves(int monarch) | 915 | ia64_wait_for_slaves(int monarch) |
910 | { | 916 | { |
911 | int c, wait = 0; | 917 | int c, wait = 0, missing = 0; |
912 | for_each_online_cpu(c) { | 918 | for_each_online_cpu(c) { |
913 | if (c == monarch) | 919 | if (c == monarch) |
914 | continue; | 920 | continue; |
@@ -919,15 +925,32 @@ ia64_wait_for_slaves(int monarch) | |||
919 | } | 925 | } |
920 | } | 926 | } |
921 | if (!wait) | 927 | if (!wait) |
922 | return; | 928 | goto all_in; |
923 | for_each_online_cpu(c) { | 929 | for_each_online_cpu(c) { |
924 | if (c == monarch) | 930 | if (c == monarch) |
925 | continue; | 931 | continue; |
926 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { | 932 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { |
927 | udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */ | 933 | udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */ |
934 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) | ||
935 | missing = 1; | ||
928 | break; | 936 | break; |
929 | } | 937 | } |
930 | } | 938 | } |
939 | if (!missing) | ||
940 | goto all_in; | ||
941 | printk(KERN_INFO "OS MCA slave did not rendezvous on cpu"); | ||
942 | for_each_online_cpu(c) { | ||
943 | if (c == monarch) | ||
944 | continue; | ||
945 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) | ||
946 | printk(" %d", c); | ||
947 | } | ||
948 | printk("\n"); | ||
949 | return; | ||
950 | |||
951 | all_in: | ||
952 | printk(KERN_INFO "All OS MCA slaves have reached rendezvous\n"); | ||
953 | return; | ||
931 | } | 954 | } |
932 | 955 | ||
933 | /* | 956 | /* |
@@ -953,6 +976,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
953 | task_t *previous_current; | 976 | task_t *previous_current; |
954 | 977 | ||
955 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ | 978 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ |
979 | console_loglevel = 15; /* make sure printks make it to console */ | ||
980 | printk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d monarch=%ld\n", | ||
981 | sos->proc_state_param, cpu, sos->monarch); | ||
982 | |||
956 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); | 983 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); |
957 | monarch_cpu = cpu; | 984 | monarch_cpu = cpu; |
958 | if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) | 985 | if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) |
@@ -1444,11 +1471,13 @@ void __devinit | |||
1444 | ia64_mca_cpu_init(void *cpu_data) | 1471 | ia64_mca_cpu_init(void *cpu_data) |
1445 | { | 1472 | { |
1446 | void *pal_vaddr; | 1473 | void *pal_vaddr; |
1474 | static int first_time = 1; | ||
1447 | 1475 | ||
1448 | if (smp_processor_id() == 0) { | 1476 | if (first_time) { |
1449 | void *mca_data; | 1477 | void *mca_data; |
1450 | int cpu; | 1478 | int cpu; |
1451 | 1479 | ||
1480 | first_time = 0; | ||
1452 | mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) | 1481 | mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) |
1453 | * NR_CPUS + KERNEL_STACK_SIZE); | 1482 | * NR_CPUS + KERNEL_STACK_SIZE); |
1454 | mca_data = (void *)(((unsigned long)mca_data + | 1483 | mca_data = (void *)(((unsigned long)mca_data + |
@@ -1704,6 +1733,7 @@ ia64_mca_late_init(void) | |||
1704 | desc = irq_descp(irq); | 1733 | desc = irq_descp(irq); |
1705 | desc->status |= IRQ_PER_CPU; | 1734 | desc->status |= IRQ_PER_CPU; |
1706 | setup_irq(irq, &mca_cpe_irqaction); | 1735 | setup_irq(irq, &mca_cpe_irqaction); |
1736 | ia64_cpe_irq = irq; | ||
1707 | } | 1737 | } |
1708 | ia64_mca_register_cpev(cpe_vector); | 1738 | ia64_mca_register_cpev(cpe_vector); |
1709 | IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n", __FUNCTION__); | 1739 | IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n", __FUNCTION__); |
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 9c5194b385da..077f21216b65 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c | |||
@@ -6722,6 +6722,7 @@ __initcall(pfm_init); | |||
6722 | void | 6722 | void |
6723 | pfm_init_percpu (void) | 6723 | pfm_init_percpu (void) |
6724 | { | 6724 | { |
6725 | static int first_time=1; | ||
6725 | /* | 6726 | /* |
6726 | * make sure no measurement is active | 6727 | * make sure no measurement is active |
6727 | * (may inherit programmed PMCs from EFI). | 6728 | * (may inherit programmed PMCs from EFI). |
@@ -6734,8 +6735,10 @@ pfm_init_percpu (void) | |||
6734 | */ | 6735 | */ |
6735 | pfm_unfreeze_pmu(); | 6736 | pfm_unfreeze_pmu(); |
6736 | 6737 | ||
6737 | if (smp_processor_id() == 0) | 6738 | if (first_time) { |
6738 | register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); | 6739 | register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); |
6740 | first_time=0; | ||
6741 | } | ||
6739 | 6742 | ||
6740 | ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR); | 6743 | ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR); |
6741 | ia64_srlz_d(); | 6744 | ia64_srlz_d(); |
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 463f6bb44d07..1d7903ee2126 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c | |||
@@ -588,104 +588,3 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) | |||
588 | } | 588 | } |
589 | return 0; | 589 | return 0; |
590 | } | 590 | } |
591 | |||
592 | /* Set a delayed signal that was detected in MCA/INIT/NMI/PMI context where it | ||
593 | * could not be delivered. It is important that the target process is not | ||
594 | * allowed to do any more work in user space. Possible cases for the target | ||
595 | * process: | ||
596 | * | ||
597 | * - It is sleeping and will wake up soon. Store the data in the current task, | ||
598 | * the signal will be sent when the current task returns from the next | ||
599 | * interrupt. | ||
600 | * | ||
601 | * - It is running in user context. Store the data in the current task, the | ||
602 | * signal will be sent when the current task returns from the next interrupt. | ||
603 | * | ||
604 | * - It is running in kernel context on this or another cpu and will return to | ||
605 | * user context. Store the data in the target task, the signal will be sent | ||
606 | * to itself when the target task returns to user space. | ||
607 | * | ||
608 | * - It is running in kernel context on this cpu and will sleep before | ||
609 | * returning to user context. Because this is also the current task, the | ||
610 | * signal will not get delivered and the task could sleep indefinitely. | ||
611 | * Store the data in the idle task for this cpu, the signal will be sent | ||
612 | * after the idle task processes its next interrupt. | ||
613 | * | ||
614 | * To cover all cases, store the data in the target task, the current task and | ||
615 | * the idle task on this cpu. Whatever happens, the signal will be delivered | ||
616 | * to the target task before it can do any useful user space work. Multiple | ||
617 | * deliveries have no unwanted side effects. | ||
618 | * | ||
619 | * Note: This code is executed in MCA/INIT/NMI/PMI context, with interrupts | ||
620 | * disabled. It must not take any locks nor use kernel structures or services | ||
621 | * that require locks. | ||
622 | */ | ||
623 | |||
624 | /* To ensure that we get the right pid, check its start time. To avoid extra | ||
625 | * include files in thread_info.h, convert the task start_time to unsigned long, | ||
626 | * giving us a cycle time of > 580 years. | ||
627 | */ | ||
628 | static inline unsigned long | ||
629 | start_time_ul(const struct task_struct *t) | ||
630 | { | ||
631 | return t->start_time.tv_sec * NSEC_PER_SEC + t->start_time.tv_nsec; | ||
632 | } | ||
633 | |||
634 | void | ||
635 | set_sigdelayed(pid_t pid, int signo, int code, void __user *addr) | ||
636 | { | ||
637 | struct task_struct *t; | ||
638 | unsigned long start_time = 0; | ||
639 | int i; | ||
640 | |||
641 | for (i = 1; i <= 3; ++i) { | ||
642 | switch (i) { | ||
643 | case 1: | ||
644 | t = find_task_by_pid(pid); | ||
645 | if (t) | ||
646 | start_time = start_time_ul(t); | ||
647 | break; | ||
648 | case 2: | ||
649 | t = current; | ||
650 | break; | ||
651 | default: | ||
652 | t = idle_task(smp_processor_id()); | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | if (!t) | ||
657 | return; | ||
658 | task_thread_info(t)->sigdelayed.signo = signo; | ||
659 | task_thread_info(t)->sigdelayed.code = code; | ||
660 | task_thread_info(t)->sigdelayed.addr = addr; | ||
661 | task_thread_info(t)->sigdelayed.start_time = start_time; | ||
662 | task_thread_info(t)->sigdelayed.pid = pid; | ||
663 | wmb(); | ||
664 | set_tsk_thread_flag(t, TIF_SIGDELAYED); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | /* Called from entry.S when it detects TIF_SIGDELAYED, a delayed signal that | ||
669 | * was detected in MCA/INIT/NMI/PMI context where it could not be delivered. | ||
670 | */ | ||
671 | |||
672 | void | ||
673 | do_sigdelayed(void) | ||
674 | { | ||
675 | struct siginfo siginfo; | ||
676 | pid_t pid; | ||
677 | struct task_struct *t; | ||
678 | |||
679 | clear_thread_flag(TIF_SIGDELAYED); | ||
680 | memset(&siginfo, 0, sizeof(siginfo)); | ||
681 | siginfo.si_signo = current_thread_info()->sigdelayed.signo; | ||
682 | siginfo.si_code = current_thread_info()->sigdelayed.code; | ||
683 | siginfo.si_addr = current_thread_info()->sigdelayed.addr; | ||
684 | pid = current_thread_info()->sigdelayed.pid; | ||
685 | t = find_task_by_pid(pid); | ||
686 | if (!t) | ||
687 | return; | ||
688 | if (current_thread_info()->sigdelayed.start_time != start_time_ul(t)) | ||
689 | return; | ||
690 | force_sig_info(siginfo.si_signo, &siginfo, t); | ||
691 | } | ||
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); |
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 307d01e15b2e..ac167436e936 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | extern unsigned long wall_jiffies; | 33 | extern unsigned long wall_jiffies; |
34 | 34 | ||
35 | #define TIME_KEEPER_ID 0 /* smp_processor_id() of time-keeper */ | 35 | volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */ |
36 | 36 | ||
37 | #ifdef CONFIG_IA64_DEBUG_IRQ | 37 | #ifdef CONFIG_IA64_DEBUG_IRQ |
38 | 38 | ||
@@ -71,7 +71,7 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) | |||
71 | 71 | ||
72 | new_itm += local_cpu_data->itm_delta; | 72 | new_itm += local_cpu_data->itm_delta; |
73 | 73 | ||
74 | if (smp_processor_id() == TIME_KEEPER_ID) { | 74 | if (smp_processor_id() == time_keeper_id) { |
75 | /* | 75 | /* |
76 | * Here we are in the timer irq handler. We have irqs locally | 76 | * Here we are in the timer irq handler. We have irqs locally |
77 | * disabled, but we don't know if the timer_bh is running on | 77 | * disabled, but we don't know if the timer_bh is running on |
@@ -236,6 +236,11 @@ static struct irqaction timer_irqaction = { | |||
236 | .name = "timer" | 236 | .name = "timer" |
237 | }; | 237 | }; |
238 | 238 | ||
239 | void __devinit ia64_disable_timer(void) | ||
240 | { | ||
241 | ia64_set_itv(1 << 16); | ||
242 | } | ||
243 | |||
239 | void __init | 244 | void __init |
240 | time_init (void) | 245 | time_init (void) |
241 | { | 246 | { |
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index 6e5eea19fa67..3b6fd798c4d6 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c | |||
@@ -36,7 +36,7 @@ int arch_register_cpu(int num) | |||
36 | parent = &sysfs_nodes[cpu_to_node(num)]; | 36 | parent = &sysfs_nodes[cpu_to_node(num)]; |
37 | #endif /* CONFIG_NUMA */ | 37 | #endif /* CONFIG_NUMA */ |
38 | 38 | ||
39 | #ifdef CONFIG_ACPI | 39 | #if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU) |
40 | /* | 40 | /* |
41 | * If CPEI cannot be re-targetted, and this is | 41 | * If CPEI cannot be re-targetted, and this is |
42 | * CPEI target, then dont create the control file | 42 | * CPEI target, then dont create the control file |