diff options
Diffstat (limited to 'arch/x86/kernel')
| -rw-r--r-- | arch/x86/kernel/apb_timer.c | 29 | ||||
| -rw-r--r-- | arch/x86/kernel/apic/x2apic_cluster.c | 80 | ||||
| -rw-r--r-- | arch/x86/kernel/hpet.c | 69 | ||||
| -rw-r--r-- | arch/x86/kernel/tboot.c | 25 |
4 files changed, 82 insertions, 121 deletions
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index cefacbad1531..456316f6c868 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c | |||
| @@ -215,26 +215,18 @@ void apbt_setup_secondary_clock(void) | |||
| 215 | * cpu timers during the offline process due to the ordering of notification. | 215 | * cpu timers during the offline process due to the ordering of notification. |
| 216 | * the extra interrupt is harmless. | 216 | * the extra interrupt is harmless. |
| 217 | */ | 217 | */ |
| 218 | static int apbt_cpuhp_notify(struct notifier_block *n, | 218 | static int apbt_cpu_dead(unsigned int cpu) |
| 219 | unsigned long action, void *hcpu) | ||
| 220 | { | 219 | { |
| 221 | unsigned long cpu = (unsigned long)hcpu; | ||
| 222 | struct apbt_dev *adev = &per_cpu(cpu_apbt_dev, cpu); | 220 | struct apbt_dev *adev = &per_cpu(cpu_apbt_dev, cpu); |
| 223 | 221 | ||
| 224 | switch (action & ~CPU_TASKS_FROZEN) { | 222 | dw_apb_clockevent_pause(adev->timer); |
| 225 | case CPU_DEAD: | 223 | if (system_state == SYSTEM_RUNNING) { |
| 226 | dw_apb_clockevent_pause(adev->timer); | 224 | pr_debug("skipping APBT CPU %u offline\n", cpu); |
| 227 | if (system_state == SYSTEM_RUNNING) { | 225 | } else { |
| 228 | pr_debug("skipping APBT CPU %lu offline\n", cpu); | 226 | pr_debug("APBT clockevent for cpu %u offline\n", cpu); |
| 229 | } else { | 227 | dw_apb_clockevent_stop(adev->timer); |
| 230 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); | ||
| 231 | dw_apb_clockevent_stop(adev->timer); | ||
| 232 | } | ||
| 233 | break; | ||
| 234 | default: | ||
| 235 | pr_debug("APBT notified %lu, no action\n", action); | ||
| 236 | } | 228 | } |
| 237 | return NOTIFY_OK; | 229 | return 0; |
| 238 | } | 230 | } |
| 239 | 231 | ||
| 240 | static __init int apbt_late_init(void) | 232 | static __init int apbt_late_init(void) |
| @@ -242,9 +234,8 @@ static __init int apbt_late_init(void) | |||
| 242 | if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT || | 234 | if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT || |
| 243 | !apb_timer_block_enabled) | 235 | !apb_timer_block_enabled) |
| 244 | return 0; | 236 | return 0; |
| 245 | /* This notifier should be called after workqueue is ready */ | 237 | return cpuhp_setup_state(CPUHP_X86_APB_DEAD, "X86_APB_DEAD", NULL, |
| 246 | hotcpu_notifier(apbt_cpuhp_notify, -20); | 238 | apbt_cpu_dead); |
| 247 | return 0; | ||
| 248 | } | 239 | } |
| 249 | fs_initcall(apbt_late_init); | 240 | fs_initcall(apbt_late_init); |
| 250 | #else | 241 | #else |
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index 24170d0809ba..6368fa69d2af 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c | |||
| @@ -152,68 +152,48 @@ static void init_x2apic_ldr(void) | |||
| 152 | } | 152 | } |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | /* | 155 | /* |
| 156 | * At CPU state changes, update the x2apic cluster sibling info. | 156 | * At CPU state changes, update the x2apic cluster sibling info. |
| 157 | */ | 157 | */ |
| 158 | static int | 158 | int x2apic_prepare_cpu(unsigned int cpu) |
| 159 | update_clusterinfo(struct notifier_block *nfb, unsigned long action, void *hcpu) | ||
| 160 | { | 159 | { |
| 161 | unsigned int this_cpu = (unsigned long)hcpu; | 160 | if (!zalloc_cpumask_var(&per_cpu(cpus_in_cluster, cpu), GFP_KERNEL)) |
| 162 | unsigned int cpu; | 161 | return -ENOMEM; |
| 163 | int err = 0; | 162 | |
| 164 | 163 | if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL)) { | |
| 165 | switch (action) { | 164 | free_cpumask_var(per_cpu(cpus_in_cluster, cpu)); |
| 166 | case CPU_UP_PREPARE: | 165 | return -ENOMEM; |
| 167 | if (!zalloc_cpumask_var(&per_cpu(cpus_in_cluster, this_cpu), | ||
| 168 | GFP_KERNEL)) { | ||
| 169 | err = -ENOMEM; | ||
| 170 | } else if (!zalloc_cpumask_var(&per_cpu(ipi_mask, this_cpu), | ||
| 171 | GFP_KERNEL)) { | ||
| 172 | free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu)); | ||
| 173 | err = -ENOMEM; | ||
| 174 | } | ||
| 175 | break; | ||
| 176 | case CPU_UP_CANCELED: | ||
| 177 | case CPU_UP_CANCELED_FROZEN: | ||
| 178 | case CPU_DEAD: | ||
| 179 | for_each_online_cpu(cpu) { | ||
| 180 | if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu)) | ||
| 181 | continue; | ||
| 182 | cpumask_clear_cpu(this_cpu, per_cpu(cpus_in_cluster, cpu)); | ||
| 183 | cpumask_clear_cpu(cpu, per_cpu(cpus_in_cluster, this_cpu)); | ||
| 184 | } | ||
| 185 | free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu)); | ||
| 186 | free_cpumask_var(per_cpu(ipi_mask, this_cpu)); | ||
| 187 | break; | ||
| 188 | } | 166 | } |
| 189 | 167 | ||
| 190 | return notifier_from_errno(err); | 168 | return 0; |
| 191 | } | 169 | } |
| 192 | 170 | ||
| 193 | static struct notifier_block x2apic_cpu_notifier = { | 171 | int x2apic_dead_cpu(unsigned int this_cpu) |
| 194 | .notifier_call = update_clusterinfo, | ||
| 195 | }; | ||
| 196 | |||
| 197 | static int x2apic_init_cpu_notifier(void) | ||
| 198 | { | 172 | { |
| 199 | int cpu = smp_processor_id(); | 173 | int cpu; |
| 200 | |||
| 201 | zalloc_cpumask_var(&per_cpu(cpus_in_cluster, cpu), GFP_KERNEL); | ||
| 202 | zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL); | ||
| 203 | 174 | ||
| 204 | BUG_ON(!per_cpu(cpus_in_cluster, cpu) || !per_cpu(ipi_mask, cpu)); | 175 | for_each_online_cpu(cpu) { |
| 205 | 176 | if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu)) | |
| 206 | cpumask_set_cpu(cpu, per_cpu(cpus_in_cluster, cpu)); | 177 | continue; |
| 207 | register_hotcpu_notifier(&x2apic_cpu_notifier); | 178 | cpumask_clear_cpu(this_cpu, per_cpu(cpus_in_cluster, cpu)); |
| 208 | return 1; | 179 | cpumask_clear_cpu(cpu, per_cpu(cpus_in_cluster, this_cpu)); |
| 180 | } | ||
| 181 | free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu)); | ||
| 182 | free_cpumask_var(per_cpu(ipi_mask, this_cpu)); | ||
| 183 | return 0; | ||
| 209 | } | 184 | } |
| 210 | 185 | ||
| 211 | static int x2apic_cluster_probe(void) | 186 | static int x2apic_cluster_probe(void) |
| 212 | { | 187 | { |
| 213 | if (x2apic_mode) | 188 | int cpu = smp_processor_id(); |
| 214 | return x2apic_init_cpu_notifier(); | 189 | |
| 215 | else | 190 | if (!x2apic_mode) |
| 216 | return 0; | 191 | return 0; |
| 192 | |||
| 193 | cpumask_set_cpu(cpu, per_cpu(cpus_in_cluster, cpu)); | ||
| 194 | cpuhp_setup_state(CPUHP_X2APIC_PREPARE, "X2APIC_PREPARE", | ||
| 195 | x2apic_prepare_cpu, x2apic_dead_cpu); | ||
| 196 | return 1; | ||
| 217 | } | 197 | } |
| 218 | 198 | ||
| 219 | static const struct cpumask *x2apic_cluster_target_cpus(void) | 199 | static const struct cpumask *x2apic_cluster_target_cpus(void) |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index f112af7aa62e..3d747070fe67 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
| @@ -710,31 +710,29 @@ static void hpet_work(struct work_struct *w) | |||
| 710 | complete(&hpet_work->complete); | 710 | complete(&hpet_work->complete); |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | static int hpet_cpuhp_notify(struct notifier_block *n, | 713 | static int hpet_cpuhp_online(unsigned int cpu) |
| 714 | unsigned long action, void *hcpu) | ||
| 715 | { | 714 | { |
| 716 | unsigned long cpu = (unsigned long)hcpu; | ||
| 717 | struct hpet_work_struct work; | 715 | struct hpet_work_struct work; |
| 716 | |||
| 717 | INIT_DELAYED_WORK_ONSTACK(&work.work, hpet_work); | ||
| 718 | init_completion(&work.complete); | ||
| 719 | /* FIXME: add schedule_work_on() */ | ||
| 720 | schedule_delayed_work_on(cpu, &work.work, 0); | ||
| 721 | wait_for_completion(&work.complete); | ||
| 722 | destroy_delayed_work_on_stack(&work.work); | ||
| 723 | return 0; | ||
| 724 | } | ||
| 725 | |||
| 726 | static int hpet_cpuhp_dead(unsigned int cpu) | ||
| 727 | { | ||
| 718 | struct hpet_dev *hdev = per_cpu(cpu_hpet_dev, cpu); | 728 | struct hpet_dev *hdev = per_cpu(cpu_hpet_dev, cpu); |
| 719 | 729 | ||
| 720 | switch (action & ~CPU_TASKS_FROZEN) { | 730 | if (!hdev) |
| 721 | case CPU_ONLINE: | 731 | return 0; |
| 722 | INIT_DELAYED_WORK_ONSTACK(&work.work, hpet_work); | 732 | free_irq(hdev->irq, hdev); |
| 723 | init_completion(&work.complete); | 733 | hdev->flags &= ~HPET_DEV_USED; |
| 724 | /* FIXME: add schedule_work_on() */ | 734 | per_cpu(cpu_hpet_dev, cpu) = NULL; |
| 725 | schedule_delayed_work_on(cpu, &work.work, 0); | 735 | return 0; |
| 726 | wait_for_completion(&work.complete); | ||
| 727 | destroy_delayed_work_on_stack(&work.work); | ||
| 728 | break; | ||
| 729 | case CPU_DEAD: | ||
| 730 | if (hdev) { | ||
| 731 | free_irq(hdev->irq, hdev); | ||
| 732 | hdev->flags &= ~HPET_DEV_USED; | ||
| 733 | per_cpu(cpu_hpet_dev, cpu) = NULL; | ||
| 734 | } | ||
| 735 | break; | ||
| 736 | } | ||
| 737 | return NOTIFY_OK; | ||
| 738 | } | 736 | } |
| 739 | #else | 737 | #else |
| 740 | 738 | ||
| @@ -750,11 +748,8 @@ static void hpet_reserve_msi_timers(struct hpet_data *hd) | |||
| 750 | } | 748 | } |
| 751 | #endif | 749 | #endif |
| 752 | 750 | ||
| 753 | static int hpet_cpuhp_notify(struct notifier_block *n, | 751 | #define hpet_cpuhp_online NULL |
| 754 | unsigned long action, void *hcpu) | 752 | #define hpet_cpuhp_dead NULL |
| 755 | { | ||
| 756 | return NOTIFY_OK; | ||
| 757 | } | ||
| 758 | 753 | ||
| 759 | #endif | 754 | #endif |
| 760 | 755 | ||
| @@ -931,7 +926,7 @@ out_nohpet: | |||
| 931 | */ | 926 | */ |
| 932 | static __init int hpet_late_init(void) | 927 | static __init int hpet_late_init(void) |
| 933 | { | 928 | { |
| 934 | int cpu; | 929 | int ret; |
| 935 | 930 | ||
| 936 | if (boot_hpet_disable) | 931 | if (boot_hpet_disable) |
| 937 | return -ENODEV; | 932 | return -ENODEV; |
| @@ -961,16 +956,20 @@ static __init int hpet_late_init(void) | |||
| 961 | if (boot_cpu_has(X86_FEATURE_ARAT)) | 956 | if (boot_cpu_has(X86_FEATURE_ARAT)) |
| 962 | return 0; | 957 | return 0; |
| 963 | 958 | ||
| 964 | cpu_notifier_register_begin(); | ||
| 965 | for_each_online_cpu(cpu) { | ||
| 966 | hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu); | ||
| 967 | } | ||
| 968 | |||
| 969 | /* This notifier should be called after workqueue is ready */ | 959 | /* This notifier should be called after workqueue is ready */ |
| 970 | __hotcpu_notifier(hpet_cpuhp_notify, -20); | 960 | ret = cpuhp_setup_state(CPUHP_AP_X86_HPET_ONLINE, "AP_X86_HPET_ONLINE", |
| 971 | cpu_notifier_register_done(); | 961 | hpet_cpuhp_online, NULL); |
| 972 | 962 | if (ret) | |
| 963 | return ret; | ||
| 964 | ret = cpuhp_setup_state(CPUHP_X86_HPET_DEAD, "X86_HPET_DEAD", NULL, | ||
| 965 | hpet_cpuhp_dead); | ||
| 966 | if (ret) | ||
| 967 | goto err_cpuhp; | ||
| 973 | return 0; | 968 | return 0; |
| 969 | |||
| 970 | err_cpuhp: | ||
| 971 | cpuhp_remove_state(CPUHP_AP_X86_HPET_ONLINE); | ||
| 972 | return ret; | ||
| 974 | } | 973 | } |
| 975 | fs_initcall(hpet_late_init); | 974 | fs_initcall(hpet_late_init); |
| 976 | 975 | ||
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index 9b0185fbe3eb..654f6c66fe45 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c | |||
| @@ -323,25 +323,16 @@ static int tboot_wait_for_aps(int num_aps) | |||
| 323 | return !(atomic_read((atomic_t *)&tboot->num_in_wfs) == num_aps); | 323 | return !(atomic_read((atomic_t *)&tboot->num_in_wfs) == num_aps); |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | static int tboot_cpu_callback(struct notifier_block *nfb, unsigned long action, | 326 | static int tboot_dying_cpu(unsigned int cpu) |
| 327 | void *hcpu) | ||
| 328 | { | 327 | { |
| 329 | switch (action) { | 328 | atomic_inc(&ap_wfs_count); |
| 330 | case CPU_DYING: | 329 | if (num_online_cpus() == 1) { |
| 331 | atomic_inc(&ap_wfs_count); | 330 | if (tboot_wait_for_aps(atomic_read(&ap_wfs_count))) |
| 332 | if (num_online_cpus() == 1) | 331 | return -EBUSY; |
| 333 | if (tboot_wait_for_aps(atomic_read(&ap_wfs_count))) | ||
| 334 | return NOTIFY_BAD; | ||
| 335 | break; | ||
| 336 | } | 332 | } |
| 337 | return NOTIFY_OK; | 333 | return 0; |
| 338 | } | 334 | } |
| 339 | 335 | ||
| 340 | static struct notifier_block tboot_cpu_notifier = | ||
| 341 | { | ||
| 342 | .notifier_call = tboot_cpu_callback, | ||
| 343 | }; | ||
| 344 | |||
| 345 | #ifdef CONFIG_DEBUG_FS | 336 | #ifdef CONFIG_DEBUG_FS |
| 346 | 337 | ||
| 347 | #define TBOOT_LOG_UUID { 0x26, 0x25, 0x19, 0xc0, 0x30, 0x6b, 0xb4, 0x4d, \ | 338 | #define TBOOT_LOG_UUID { 0x26, 0x25, 0x19, 0xc0, 0x30, 0x6b, 0xb4, 0x4d, \ |
| @@ -417,8 +408,8 @@ static __init int tboot_late_init(void) | |||
| 417 | tboot_create_trampoline(); | 408 | tboot_create_trampoline(); |
| 418 | 409 | ||
| 419 | atomic_set(&ap_wfs_count, 0); | 410 | atomic_set(&ap_wfs_count, 0); |
| 420 | register_hotcpu_notifier(&tboot_cpu_notifier); | 411 | cpuhp_setup_state(CPUHP_AP_X86_TBOOT_DYING, "AP_X86_TBOOT_DYING", NULL, |
| 421 | 412 | tboot_dying_cpu); | |
| 422 | #ifdef CONFIG_DEBUG_FS | 413 | #ifdef CONFIG_DEBUG_FS |
| 423 | debugfs_create_file("tboot_log", S_IRUSR, | 414 | debugfs_create_file("tboot_log", S_IRUSR, |
| 424 | arch_debugfs_dir, NULL, &tboot_log_fops); | 415 | arch_debugfs_dir, NULL, &tboot_log_fops); |
