Loading arch/x86/kernel/cpu/perf_event.c +46 −13 Original line number Diff line number Diff line Loading @@ -1154,7 +1154,7 @@ static int x86_pmu_handle_irq(struct pt_regs *regs) /* * event overflow */ handled = 1; handled++; data.period = event->hw.last_period; if (!x86_perf_event_set_period(event)) Loading Loading @@ -1200,12 +1200,20 @@ void perf_events_lapic_init(void) apic_write(APIC_LVTPC, APIC_DM_NMI); } struct pmu_nmi_state { unsigned int marked; int handled; }; static DEFINE_PER_CPU(struct pmu_nmi_state, pmu_nmi); static int __kprobes perf_event_nmi_handler(struct notifier_block *self, unsigned long cmd, void *__args) { struct die_args *args = __args; struct pt_regs *regs; unsigned int this_nmi; int handled; if (!atomic_read(&active_events)) return NOTIFY_DONE; Loading @@ -1214,22 +1222,47 @@ perf_event_nmi_handler(struct notifier_block *self, case DIE_NMI: case DIE_NMI_IPI: break; case DIE_NMIUNKNOWN: this_nmi = percpu_read(irq_stat.__nmi_count); if (this_nmi != __get_cpu_var(pmu_nmi).marked) /* let the kernel handle the unknown nmi */ return NOTIFY_DONE; /* * This one is a PMU back-to-back nmi. Two events * trigger 'simultaneously' raising two back-to-back * NMIs. If the first NMI handles both, the latter * will be empty and daze the CPU. So, we drop it to * avoid false-positive 'unknown nmi' messages. */ return NOTIFY_STOP; default: return NOTIFY_DONE; } regs = args->regs; apic_write(APIC_LVTPC, APIC_DM_NMI); handled = x86_pmu.handle_irq(args->regs); if (!handled) return NOTIFY_DONE; this_nmi = percpu_read(irq_stat.__nmi_count); if ((handled > 1) || /* the next nmi could be a back-to-back nmi */ ((__get_cpu_var(pmu_nmi).marked == this_nmi) && (__get_cpu_var(pmu_nmi).handled > 1))) { /* * Can't rely on the handled return value to say it was our NMI, two * events could trigger 'simultaneously' raising two back-to-back NMIs. * We could have two subsequent back-to-back nmis: The * first handles more than one counter, the 2nd * handles only one counter and the 3rd handles no * counter. * * If the first NMI handles both, the latter will be empty and daze * the CPU. * This is the 2nd nmi because the previous was * handling more than one counter. We will mark the * next (3rd) and then drop it if unhandled. */ x86_pmu.handle_irq(regs); __get_cpu_var(pmu_nmi).marked = this_nmi + 1; __get_cpu_var(pmu_nmi).handled = handled; } return NOTIFY_STOP; } Loading arch/x86/kernel/cpu/perf_event_intel.c +9 −6 Original line number Diff line number Diff line Loading @@ -712,7 +712,8 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) struct perf_sample_data data; struct cpu_hw_events *cpuc; int bit, loops; u64 ack, status; u64 status; int handled = 0; perf_sample_data_init(&data, 0); Loading @@ -728,6 +729,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) loops = 0; again: intel_pmu_ack_status(status); if (++loops > 100) { WARN_ONCE(1, "perfevents: irq loop stuck!\n"); perf_event_print_debug(); Loading @@ -736,19 +738,22 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) } inc_irq_stat(apic_perf_irqs); ack = status; intel_pmu_lbr_read(); /* * PEBS overflow sets bit 62 in the global status register */ if (__test_and_clear_bit(62, (unsigned long *)&status)) if (__test_and_clear_bit(62, (unsigned long *)&status)) { handled++; x86_pmu.drain_pebs(regs); } for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) { struct perf_event *event = cpuc->events[bit]; handled++; if (!test_bit(bit, cpuc->active_mask)) continue; Loading @@ -761,8 +766,6 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) x86_pmu_stop(event); } intel_pmu_ack_status(ack); /* * Repeat if there is more work to be done: */ Loading @@ -772,7 +775,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) done: intel_pmu_enable_all(0); return 1; return handled; } static struct event_constraint * Loading arch/x86/kernel/cpu/perf_event_p4.c +1 −1 Original line number Diff line number Diff line Loading @@ -936,7 +936,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) inc_irq_stat(apic_perf_irqs); } return handled > 0; return handled; } /* Loading arch/x86/oprofile/nmi_int.c +17 −5 Original line number Diff line number Diff line Loading @@ -568,8 +568,13 @@ static int __init init_sysfs(void) int error; error = sysdev_class_register(&oprofile_sysclass); if (!error) if (error) return error; error = sysdev_register(&device_oprofile); if (error) sysdev_class_unregister(&oprofile_sysclass); return error; } Loading @@ -580,8 +585,10 @@ static void exit_sysfs(void) } #else #define init_sysfs() do { } while (0) #define exit_sysfs() do { } while (0) static inline int init_sysfs(void) { return 0; } static inline void exit_sysfs(void) { } #endif /* CONFIG_PM */ static int __init p4_init(char **cpu_type) Loading Loading @@ -695,6 +702,8 @@ int __init op_nmi_init(struct oprofile_operations *ops) char *cpu_type = NULL; int ret = 0; using_nmi = 0; if (!cpu_has_apic) return -ENODEV; Loading Loading @@ -774,7 +783,10 @@ int __init op_nmi_init(struct oprofile_operations *ops) mux_init(ops); init_sysfs(); ret = init_sysfs(); if (ret) return ret; using_nmi = 1; printk(KERN_INFO "oprofile: using NMI interrupt.\n"); return 0; Loading drivers/oprofile/buffer_sync.c +14 −13 Original line number Diff line number Diff line Loading @@ -141,16 +141,6 @@ static struct notifier_block module_load_nb = { .notifier_call = module_load_notify, }; static void end_sync(void) { end_cpu_work(); /* make sure we don't leak task structs */ process_task_mortuary(); process_task_mortuary(); } int sync_start(void) { int err; Loading @@ -158,7 +148,7 @@ int sync_start(void) if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL)) return -ENOMEM; start_cpu_work(); mutex_lock(&buffer_mutex); err = task_handoff_register(&task_free_nb); if (err) Loading @@ -173,7 +163,10 @@ int sync_start(void) if (err) goto out4; start_cpu_work(); out: mutex_unlock(&buffer_mutex); return err; out4: profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); Loading @@ -182,7 +175,6 @@ int sync_start(void) out2: task_handoff_unregister(&task_free_nb); out1: end_sync(); free_cpumask_var(marked_cpus); goto out; } Loading @@ -190,11 +182,20 @@ int sync_start(void) void sync_stop(void) { /* flush buffers */ mutex_lock(&buffer_mutex); end_cpu_work(); unregister_module_notifier(&module_load_nb); profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); task_handoff_unregister(&task_free_nb); end_sync(); mutex_unlock(&buffer_mutex); flush_scheduled_work(); /* make sure we don't leak task structs */ process_task_mortuary(); process_task_mortuary(); free_cpumask_var(marked_cpus); } Loading Loading
arch/x86/kernel/cpu/perf_event.c +46 −13 Original line number Diff line number Diff line Loading @@ -1154,7 +1154,7 @@ static int x86_pmu_handle_irq(struct pt_regs *regs) /* * event overflow */ handled = 1; handled++; data.period = event->hw.last_period; if (!x86_perf_event_set_period(event)) Loading Loading @@ -1200,12 +1200,20 @@ void perf_events_lapic_init(void) apic_write(APIC_LVTPC, APIC_DM_NMI); } struct pmu_nmi_state { unsigned int marked; int handled; }; static DEFINE_PER_CPU(struct pmu_nmi_state, pmu_nmi); static int __kprobes perf_event_nmi_handler(struct notifier_block *self, unsigned long cmd, void *__args) { struct die_args *args = __args; struct pt_regs *regs; unsigned int this_nmi; int handled; if (!atomic_read(&active_events)) return NOTIFY_DONE; Loading @@ -1214,22 +1222,47 @@ perf_event_nmi_handler(struct notifier_block *self, case DIE_NMI: case DIE_NMI_IPI: break; case DIE_NMIUNKNOWN: this_nmi = percpu_read(irq_stat.__nmi_count); if (this_nmi != __get_cpu_var(pmu_nmi).marked) /* let the kernel handle the unknown nmi */ return NOTIFY_DONE; /* * This one is a PMU back-to-back nmi. Two events * trigger 'simultaneously' raising two back-to-back * NMIs. If the first NMI handles both, the latter * will be empty and daze the CPU. So, we drop it to * avoid false-positive 'unknown nmi' messages. */ return NOTIFY_STOP; default: return NOTIFY_DONE; } regs = args->regs; apic_write(APIC_LVTPC, APIC_DM_NMI); handled = x86_pmu.handle_irq(args->regs); if (!handled) return NOTIFY_DONE; this_nmi = percpu_read(irq_stat.__nmi_count); if ((handled > 1) || /* the next nmi could be a back-to-back nmi */ ((__get_cpu_var(pmu_nmi).marked == this_nmi) && (__get_cpu_var(pmu_nmi).handled > 1))) { /* * Can't rely on the handled return value to say it was our NMI, two * events could trigger 'simultaneously' raising two back-to-back NMIs. * We could have two subsequent back-to-back nmis: The * first handles more than one counter, the 2nd * handles only one counter and the 3rd handles no * counter. * * If the first NMI handles both, the latter will be empty and daze * the CPU. * This is the 2nd nmi because the previous was * handling more than one counter. We will mark the * next (3rd) and then drop it if unhandled. */ x86_pmu.handle_irq(regs); __get_cpu_var(pmu_nmi).marked = this_nmi + 1; __get_cpu_var(pmu_nmi).handled = handled; } return NOTIFY_STOP; } Loading
arch/x86/kernel/cpu/perf_event_intel.c +9 −6 Original line number Diff line number Diff line Loading @@ -712,7 +712,8 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) struct perf_sample_data data; struct cpu_hw_events *cpuc; int bit, loops; u64 ack, status; u64 status; int handled = 0; perf_sample_data_init(&data, 0); Loading @@ -728,6 +729,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) loops = 0; again: intel_pmu_ack_status(status); if (++loops > 100) { WARN_ONCE(1, "perfevents: irq loop stuck!\n"); perf_event_print_debug(); Loading @@ -736,19 +738,22 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) } inc_irq_stat(apic_perf_irqs); ack = status; intel_pmu_lbr_read(); /* * PEBS overflow sets bit 62 in the global status register */ if (__test_and_clear_bit(62, (unsigned long *)&status)) if (__test_and_clear_bit(62, (unsigned long *)&status)) { handled++; x86_pmu.drain_pebs(regs); } for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) { struct perf_event *event = cpuc->events[bit]; handled++; if (!test_bit(bit, cpuc->active_mask)) continue; Loading @@ -761,8 +766,6 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) x86_pmu_stop(event); } intel_pmu_ack_status(ack); /* * Repeat if there is more work to be done: */ Loading @@ -772,7 +775,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) done: intel_pmu_enable_all(0); return 1; return handled; } static struct event_constraint * Loading
arch/x86/kernel/cpu/perf_event_p4.c +1 −1 Original line number Diff line number Diff line Loading @@ -936,7 +936,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) inc_irq_stat(apic_perf_irqs); } return handled > 0; return handled; } /* Loading
arch/x86/oprofile/nmi_int.c +17 −5 Original line number Diff line number Diff line Loading @@ -568,8 +568,13 @@ static int __init init_sysfs(void) int error; error = sysdev_class_register(&oprofile_sysclass); if (!error) if (error) return error; error = sysdev_register(&device_oprofile); if (error) sysdev_class_unregister(&oprofile_sysclass); return error; } Loading @@ -580,8 +585,10 @@ static void exit_sysfs(void) } #else #define init_sysfs() do { } while (0) #define exit_sysfs() do { } while (0) static inline int init_sysfs(void) { return 0; } static inline void exit_sysfs(void) { } #endif /* CONFIG_PM */ static int __init p4_init(char **cpu_type) Loading Loading @@ -695,6 +702,8 @@ int __init op_nmi_init(struct oprofile_operations *ops) char *cpu_type = NULL; int ret = 0; using_nmi = 0; if (!cpu_has_apic) return -ENODEV; Loading Loading @@ -774,7 +783,10 @@ int __init op_nmi_init(struct oprofile_operations *ops) mux_init(ops); init_sysfs(); ret = init_sysfs(); if (ret) return ret; using_nmi = 1; printk(KERN_INFO "oprofile: using NMI interrupt.\n"); return 0; Loading
drivers/oprofile/buffer_sync.c +14 −13 Original line number Diff line number Diff line Loading @@ -141,16 +141,6 @@ static struct notifier_block module_load_nb = { .notifier_call = module_load_notify, }; static void end_sync(void) { end_cpu_work(); /* make sure we don't leak task structs */ process_task_mortuary(); process_task_mortuary(); } int sync_start(void) { int err; Loading @@ -158,7 +148,7 @@ int sync_start(void) if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL)) return -ENOMEM; start_cpu_work(); mutex_lock(&buffer_mutex); err = task_handoff_register(&task_free_nb); if (err) Loading @@ -173,7 +163,10 @@ int sync_start(void) if (err) goto out4; start_cpu_work(); out: mutex_unlock(&buffer_mutex); return err; out4: profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); Loading @@ -182,7 +175,6 @@ int sync_start(void) out2: task_handoff_unregister(&task_free_nb); out1: end_sync(); free_cpumask_var(marked_cpus); goto out; } Loading @@ -190,11 +182,20 @@ int sync_start(void) void sync_stop(void) { /* flush buffers */ mutex_lock(&buffer_mutex); end_cpu_work(); unregister_module_notifier(&module_load_nb); profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); task_handoff_unregister(&task_free_nb); end_sync(); mutex_unlock(&buffer_mutex); flush_scheduled_work(); /* make sure we don't leak task structs */ process_task_mortuary(); process_task_mortuary(); free_cpumask_var(marked_cpus); } Loading