Loading arch/x86/oprofile/nmi_int.c +113 −74 Original line number Diff line number Diff line Loading @@ -31,8 +31,9 @@ static struct op_x86_model_spec *model; static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); static DEFINE_PER_CPU(unsigned long, saved_lvtpc); /* 0 == registered but off, 1 == registered and on */ static int nmi_enabled = 0; /* must be protected with get_online_cpus()/put_online_cpus(): */ static int nmi_enabled; static int ctr_running; struct op_counter_config counter_config[OP_MAX_COUNTER]; Loading Loading @@ -61,12 +62,16 @@ static int profile_exceptions_notify(struct notifier_block *self, { struct die_args *args = (struct die_args *)data; int ret = NOTIFY_DONE; int cpu = smp_processor_id(); switch (val) { case DIE_NMI: case DIE_NMI_IPI: model->check_ctrs(args->regs, &per_cpu(cpu_msrs, cpu)); if (ctr_running) model->check_ctrs(args->regs, &__get_cpu_var(cpu_msrs)); else if (!nmi_enabled) break; else model->stop(&__get_cpu_var(cpu_msrs)); ret = NOTIFY_STOP; break; default: Loading Loading @@ -95,24 +100,36 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) static void nmi_cpu_start(void *dummy) { struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); if (!msrs->controls) WARN_ON_ONCE(1); else model->start(msrs); } static int nmi_start(void) { get_online_cpus(); on_each_cpu(nmi_cpu_start, NULL, 1); ctr_running = 1; put_online_cpus(); return 0; } static void nmi_cpu_stop(void *dummy) { struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); if (!msrs->controls) WARN_ON_ONCE(1); else model->stop(msrs); } static void nmi_stop(void) { get_online_cpus(); on_each_cpu(nmi_cpu_stop, NULL, 1); ctr_running = 0; put_online_cpus(); } #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX Loading Loading @@ -252,7 +269,10 @@ static int nmi_switch_event(void) if (nmi_multiplex_on() < 0) return -EINVAL; /* not necessary */ get_online_cpus(); if (ctr_running) on_each_cpu(nmi_cpu_switch, NULL, 1); put_online_cpus(); return 0; } Loading Loading @@ -344,50 +364,6 @@ static struct notifier_block profile_exceptions_nb = { .priority = 2 }; static int nmi_setup(void) { int err = 0; int cpu; if (!allocate_msrs()) return -ENOMEM; /* We need to serialize save and setup for HT because the subset * of msrs are distinct for save and setup operations */ /* Assume saved/restored counters are the same on all CPUs */ err = model->fill_in_addresses(&per_cpu(cpu_msrs, 0)); if (err) goto fail; for_each_possible_cpu(cpu) { if (!cpu) continue; memcpy(per_cpu(cpu_msrs, cpu).counters, per_cpu(cpu_msrs, 0).counters, sizeof(struct op_msr) * model->num_counters); memcpy(per_cpu(cpu_msrs, cpu).controls, per_cpu(cpu_msrs, 0).controls, sizeof(struct op_msr) * model->num_controls); mux_clone(cpu); } err = register_die_notifier(&profile_exceptions_nb); if (err) goto fail; on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; return 0; fail: free_msrs(); return err; } static void nmi_cpu_restore_registers(struct op_msrs *msrs) { struct op_msr *counters = msrs->counters; Loading Loading @@ -421,19 +397,24 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu)); apic_write(APIC_LVTERR, v); nmi_cpu_restore_registers(msrs); if (model->cpu_down) model->cpu_down(); } static void nmi_shutdown(void) static void nmi_cpu_up(void *dummy) { struct op_msrs *msrs; if (nmi_enabled) nmi_cpu_setup(dummy); if (ctr_running) nmi_cpu_start(dummy); } nmi_enabled = 0; on_each_cpu(nmi_cpu_shutdown, NULL, 1); unregister_die_notifier(&profile_exceptions_nb); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); free_msrs(); put_cpu_var(cpu_msrs); static void nmi_cpu_down(void *dummy) { if (ctr_running) nmi_cpu_stop(dummy); if (nmi_enabled) nmi_cpu_shutdown(dummy); } static int nmi_create_files(struct super_block *sb, struct dentry *root) Loading Loading @@ -465,7 +446,6 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) return 0; } #ifdef CONFIG_SMP static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, void *data) { Loading @@ -473,10 +453,10 @@ static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, switch (action) { case CPU_DOWN_FAILED: case CPU_ONLINE: smp_call_function_single(cpu, nmi_cpu_start, NULL, 0); smp_call_function_single(cpu, nmi_cpu_up, NULL, 0); break; case CPU_DOWN_PREPARE: smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1); smp_call_function_single(cpu, nmi_cpu_down, NULL, 1); break; } return NOTIFY_DONE; Loading @@ -485,7 +465,75 @@ static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, static struct notifier_block oprofile_cpu_nb = { .notifier_call = oprofile_cpu_notifier }; #endif static int nmi_setup(void) { int err = 0; int cpu; if (!allocate_msrs()) return -ENOMEM; /* We need to serialize save and setup for HT because the subset * of msrs are distinct for save and setup operations */ /* Assume saved/restored counters are the same on all CPUs */ err = model->fill_in_addresses(&per_cpu(cpu_msrs, 0)); if (err) goto fail; for_each_possible_cpu(cpu) { if (!cpu) continue; memcpy(per_cpu(cpu_msrs, cpu).counters, per_cpu(cpu_msrs, 0).counters, sizeof(struct op_msr) * model->num_counters); memcpy(per_cpu(cpu_msrs, cpu).controls, per_cpu(cpu_msrs, 0).controls, sizeof(struct op_msr) * model->num_controls); mux_clone(cpu); } nmi_enabled = 0; ctr_running = 0; barrier(); err = register_die_notifier(&profile_exceptions_nb); if (err) goto fail; get_online_cpus(); register_cpu_notifier(&oprofile_cpu_nb); on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; put_online_cpus(); return 0; fail: free_msrs(); return err; } static void nmi_shutdown(void) { struct op_msrs *msrs; get_online_cpus(); unregister_cpu_notifier(&oprofile_cpu_nb); on_each_cpu(nmi_cpu_shutdown, NULL, 1); nmi_enabled = 0; ctr_running = 0; put_online_cpus(); barrier(); unregister_die_notifier(&profile_exceptions_nb); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); free_msrs(); put_cpu_var(cpu_msrs); } #ifdef CONFIG_PM Loading Loading @@ -695,9 +743,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) return -ENODEV; } #ifdef CONFIG_SMP register_cpu_notifier(&oprofile_cpu_nb); #endif /* default values, can be overwritten by model */ ops->create_files = nmi_create_files; ops->setup = nmi_setup; Loading @@ -724,12 +769,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) void op_nmi_exit(void) { if (using_nmi) { if (using_nmi) exit_sysfs(); #ifdef CONFIG_SMP unregister_cpu_notifier(&oprofile_cpu_nb); #endif } if (model->exit) model->exit(); } arch/x86/oprofile/op_model_amd.c +16 −38 Original line number Diff line number Diff line Loading @@ -374,6 +374,15 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, val |= op_x86_get_ctrl(model, &counter_config[virt]); wrmsrl(msrs->controls[i].addr, val); } if (ibs_caps) setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0); } static void op_amd_cpu_shutdown(void) { if (ibs_caps) setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); } static int op_amd_check_ctrs(struct pt_regs * const regs, Loading Loading @@ -436,28 +445,16 @@ static void op_amd_stop(struct op_msrs const * const msrs) op_amd_stop_ibs(); } static u8 ibs_eilvt_off; static inline void apic_init_ibs_nmi_per_cpu(void *arg) { ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0); } static inline void apic_clear_ibs_nmi_per_cpu(void *arg) { setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); } static int init_ibs_nmi(void) static int __init_ibs_nmi(void) { #define IBSCTL_LVTOFFSETVAL (1 << 8) #define IBSCTL 0x1cc struct pci_dev *cpu_cfg; int nodes; u32 value = 0; u8 ibs_eilvt_off; /* per CPU setup */ on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1); ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); nodes = 0; cpu_cfg = NULL; Loading Loading @@ -487,21 +484,15 @@ static int init_ibs_nmi(void) return 0; } /* uninitialize the APIC for the IBS interrupts if needed */ static void clear_ibs_nmi(void) { on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); } /* initialize the APIC for the IBS interrupts if available */ static void ibs_init(void) static void init_ibs(void) { ibs_caps = get_ibs_caps(); if (!ibs_caps) return; if (init_ibs_nmi()) { if (__init_ibs_nmi()) { ibs_caps = 0; return; } Loading @@ -510,14 +501,6 @@ static void ibs_init(void) (unsigned)ibs_caps); } static void ibs_exit(void) { if (!ibs_caps) return; clear_ibs_nmi(); } static int (*create_arch_files)(struct super_block *sb, struct dentry *root); static int setup_ibs_files(struct super_block *sb, struct dentry *root) Loading Loading @@ -566,17 +549,12 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) static int op_amd_init(struct oprofile_operations *ops) { ibs_init(); init_ibs(); create_arch_files = ops->create_files; ops->create_files = setup_ibs_files; return 0; } static void op_amd_exit(void) { ibs_exit(); } struct op_x86_model_spec op_amd_spec = { .num_counters = NUM_COUNTERS, .num_controls = NUM_COUNTERS, Loading @@ -584,9 +562,9 @@ struct op_x86_model_spec op_amd_spec = { .reserved = MSR_AMD_EVENTSEL_RESERVED, .event_mask = OP_EVENT_MASK, .init = op_amd_init, .exit = op_amd_exit, .fill_in_addresses = &op_amd_fill_in_addresses, .setup_ctrs = &op_amd_setup_ctrs, .cpu_down = &op_amd_cpu_shutdown, .check_ctrs = &op_amd_check_ctrs, .start = &op_amd_start, .stop = &op_amd_stop, Loading arch/x86/oprofile/op_x86_model.h +1 −1 Original line number Diff line number Diff line Loading @@ -40,10 +40,10 @@ struct op_x86_model_spec { u64 reserved; u16 event_mask; int (*init)(struct oprofile_operations *ops); void (*exit)(void); int (*fill_in_addresses)(struct op_msrs * const msrs); void (*setup_ctrs)(struct op_x86_model_spec const *model, struct op_msrs const * const msrs); void (*cpu_down)(void); int (*check_ctrs)(struct pt_regs * const regs, struct op_msrs const * const msrs); void (*start)(struct op_msrs const * const msrs); Loading Loading
arch/x86/oprofile/nmi_int.c +113 −74 Original line number Diff line number Diff line Loading @@ -31,8 +31,9 @@ static struct op_x86_model_spec *model; static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); static DEFINE_PER_CPU(unsigned long, saved_lvtpc); /* 0 == registered but off, 1 == registered and on */ static int nmi_enabled = 0; /* must be protected with get_online_cpus()/put_online_cpus(): */ static int nmi_enabled; static int ctr_running; struct op_counter_config counter_config[OP_MAX_COUNTER]; Loading Loading @@ -61,12 +62,16 @@ static int profile_exceptions_notify(struct notifier_block *self, { struct die_args *args = (struct die_args *)data; int ret = NOTIFY_DONE; int cpu = smp_processor_id(); switch (val) { case DIE_NMI: case DIE_NMI_IPI: model->check_ctrs(args->regs, &per_cpu(cpu_msrs, cpu)); if (ctr_running) model->check_ctrs(args->regs, &__get_cpu_var(cpu_msrs)); else if (!nmi_enabled) break; else model->stop(&__get_cpu_var(cpu_msrs)); ret = NOTIFY_STOP; break; default: Loading Loading @@ -95,24 +100,36 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) static void nmi_cpu_start(void *dummy) { struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); if (!msrs->controls) WARN_ON_ONCE(1); else model->start(msrs); } static int nmi_start(void) { get_online_cpus(); on_each_cpu(nmi_cpu_start, NULL, 1); ctr_running = 1; put_online_cpus(); return 0; } static void nmi_cpu_stop(void *dummy) { struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); if (!msrs->controls) WARN_ON_ONCE(1); else model->stop(msrs); } static void nmi_stop(void) { get_online_cpus(); on_each_cpu(nmi_cpu_stop, NULL, 1); ctr_running = 0; put_online_cpus(); } #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX Loading Loading @@ -252,7 +269,10 @@ static int nmi_switch_event(void) if (nmi_multiplex_on() < 0) return -EINVAL; /* not necessary */ get_online_cpus(); if (ctr_running) on_each_cpu(nmi_cpu_switch, NULL, 1); put_online_cpus(); return 0; } Loading Loading @@ -344,50 +364,6 @@ static struct notifier_block profile_exceptions_nb = { .priority = 2 }; static int nmi_setup(void) { int err = 0; int cpu; if (!allocate_msrs()) return -ENOMEM; /* We need to serialize save and setup for HT because the subset * of msrs are distinct for save and setup operations */ /* Assume saved/restored counters are the same on all CPUs */ err = model->fill_in_addresses(&per_cpu(cpu_msrs, 0)); if (err) goto fail; for_each_possible_cpu(cpu) { if (!cpu) continue; memcpy(per_cpu(cpu_msrs, cpu).counters, per_cpu(cpu_msrs, 0).counters, sizeof(struct op_msr) * model->num_counters); memcpy(per_cpu(cpu_msrs, cpu).controls, per_cpu(cpu_msrs, 0).controls, sizeof(struct op_msr) * model->num_controls); mux_clone(cpu); } err = register_die_notifier(&profile_exceptions_nb); if (err) goto fail; on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; return 0; fail: free_msrs(); return err; } static void nmi_cpu_restore_registers(struct op_msrs *msrs) { struct op_msr *counters = msrs->counters; Loading Loading @@ -421,19 +397,24 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu)); apic_write(APIC_LVTERR, v); nmi_cpu_restore_registers(msrs); if (model->cpu_down) model->cpu_down(); } static void nmi_shutdown(void) static void nmi_cpu_up(void *dummy) { struct op_msrs *msrs; if (nmi_enabled) nmi_cpu_setup(dummy); if (ctr_running) nmi_cpu_start(dummy); } nmi_enabled = 0; on_each_cpu(nmi_cpu_shutdown, NULL, 1); unregister_die_notifier(&profile_exceptions_nb); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); free_msrs(); put_cpu_var(cpu_msrs); static void nmi_cpu_down(void *dummy) { if (ctr_running) nmi_cpu_stop(dummy); if (nmi_enabled) nmi_cpu_shutdown(dummy); } static int nmi_create_files(struct super_block *sb, struct dentry *root) Loading Loading @@ -465,7 +446,6 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) return 0; } #ifdef CONFIG_SMP static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, void *data) { Loading @@ -473,10 +453,10 @@ static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, switch (action) { case CPU_DOWN_FAILED: case CPU_ONLINE: smp_call_function_single(cpu, nmi_cpu_start, NULL, 0); smp_call_function_single(cpu, nmi_cpu_up, NULL, 0); break; case CPU_DOWN_PREPARE: smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1); smp_call_function_single(cpu, nmi_cpu_down, NULL, 1); break; } return NOTIFY_DONE; Loading @@ -485,7 +465,75 @@ static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, static struct notifier_block oprofile_cpu_nb = { .notifier_call = oprofile_cpu_notifier }; #endif static int nmi_setup(void) { int err = 0; int cpu; if (!allocate_msrs()) return -ENOMEM; /* We need to serialize save and setup for HT because the subset * of msrs are distinct for save and setup operations */ /* Assume saved/restored counters are the same on all CPUs */ err = model->fill_in_addresses(&per_cpu(cpu_msrs, 0)); if (err) goto fail; for_each_possible_cpu(cpu) { if (!cpu) continue; memcpy(per_cpu(cpu_msrs, cpu).counters, per_cpu(cpu_msrs, 0).counters, sizeof(struct op_msr) * model->num_counters); memcpy(per_cpu(cpu_msrs, cpu).controls, per_cpu(cpu_msrs, 0).controls, sizeof(struct op_msr) * model->num_controls); mux_clone(cpu); } nmi_enabled = 0; ctr_running = 0; barrier(); err = register_die_notifier(&profile_exceptions_nb); if (err) goto fail; get_online_cpus(); register_cpu_notifier(&oprofile_cpu_nb); on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; put_online_cpus(); return 0; fail: free_msrs(); return err; } static void nmi_shutdown(void) { struct op_msrs *msrs; get_online_cpus(); unregister_cpu_notifier(&oprofile_cpu_nb); on_each_cpu(nmi_cpu_shutdown, NULL, 1); nmi_enabled = 0; ctr_running = 0; put_online_cpus(); barrier(); unregister_die_notifier(&profile_exceptions_nb); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); free_msrs(); put_cpu_var(cpu_msrs); } #ifdef CONFIG_PM Loading Loading @@ -695,9 +743,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) return -ENODEV; } #ifdef CONFIG_SMP register_cpu_notifier(&oprofile_cpu_nb); #endif /* default values, can be overwritten by model */ ops->create_files = nmi_create_files; ops->setup = nmi_setup; Loading @@ -724,12 +769,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) void op_nmi_exit(void) { if (using_nmi) { if (using_nmi) exit_sysfs(); #ifdef CONFIG_SMP unregister_cpu_notifier(&oprofile_cpu_nb); #endif } if (model->exit) model->exit(); }
arch/x86/oprofile/op_model_amd.c +16 −38 Original line number Diff line number Diff line Loading @@ -374,6 +374,15 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, val |= op_x86_get_ctrl(model, &counter_config[virt]); wrmsrl(msrs->controls[i].addr, val); } if (ibs_caps) setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0); } static void op_amd_cpu_shutdown(void) { if (ibs_caps) setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); } static int op_amd_check_ctrs(struct pt_regs * const regs, Loading Loading @@ -436,28 +445,16 @@ static void op_amd_stop(struct op_msrs const * const msrs) op_amd_stop_ibs(); } static u8 ibs_eilvt_off; static inline void apic_init_ibs_nmi_per_cpu(void *arg) { ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0); } static inline void apic_clear_ibs_nmi_per_cpu(void *arg) { setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); } static int init_ibs_nmi(void) static int __init_ibs_nmi(void) { #define IBSCTL_LVTOFFSETVAL (1 << 8) #define IBSCTL 0x1cc struct pci_dev *cpu_cfg; int nodes; u32 value = 0; u8 ibs_eilvt_off; /* per CPU setup */ on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1); ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); nodes = 0; cpu_cfg = NULL; Loading Loading @@ -487,21 +484,15 @@ static int init_ibs_nmi(void) return 0; } /* uninitialize the APIC for the IBS interrupts if needed */ static void clear_ibs_nmi(void) { on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); } /* initialize the APIC for the IBS interrupts if available */ static void ibs_init(void) static void init_ibs(void) { ibs_caps = get_ibs_caps(); if (!ibs_caps) return; if (init_ibs_nmi()) { if (__init_ibs_nmi()) { ibs_caps = 0; return; } Loading @@ -510,14 +501,6 @@ static void ibs_init(void) (unsigned)ibs_caps); } static void ibs_exit(void) { if (!ibs_caps) return; clear_ibs_nmi(); } static int (*create_arch_files)(struct super_block *sb, struct dentry *root); static int setup_ibs_files(struct super_block *sb, struct dentry *root) Loading Loading @@ -566,17 +549,12 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) static int op_amd_init(struct oprofile_operations *ops) { ibs_init(); init_ibs(); create_arch_files = ops->create_files; ops->create_files = setup_ibs_files; return 0; } static void op_amd_exit(void) { ibs_exit(); } struct op_x86_model_spec op_amd_spec = { .num_counters = NUM_COUNTERS, .num_controls = NUM_COUNTERS, Loading @@ -584,9 +562,9 @@ struct op_x86_model_spec op_amd_spec = { .reserved = MSR_AMD_EVENTSEL_RESERVED, .event_mask = OP_EVENT_MASK, .init = op_amd_init, .exit = op_amd_exit, .fill_in_addresses = &op_amd_fill_in_addresses, .setup_ctrs = &op_amd_setup_ctrs, .cpu_down = &op_amd_cpu_shutdown, .check_ctrs = &op_amd_check_ctrs, .start = &op_amd_start, .stop = &op_amd_stop, Loading
arch/x86/oprofile/op_x86_model.h +1 −1 Original line number Diff line number Diff line Loading @@ -40,10 +40,10 @@ struct op_x86_model_spec { u64 reserved; u16 event_mask; int (*init)(struct oprofile_operations *ops); void (*exit)(void); int (*fill_in_addresses)(struct op_msrs * const msrs); void (*setup_ctrs)(struct op_x86_model_spec const *model, struct op_msrs const * const msrs); void (*cpu_down)(void); int (*check_ctrs)(struct pt_regs * const regs, struct op_msrs const * const msrs); void (*start)(struct op_msrs const * const msrs); Loading