/* Initialize the counter set PMU to generate complete counter set data as * event raw data. This relies on the CPU Measurement Counter Facility device * already being loaded and initialized. */ static int __init cf_diag_init(void) { struct cpumf_ctr_info info; size_t need; int rc; if (!kernel_cpumcf_avail() || !stccm_avail() || qctri(&info)) return -ENODEV; cf_diag_get_cpu_speed(); /* Make sure the counter set data fits into predefined buffer. */ need = cf_diag_ctrset_maxsize(&info); if (need > sizeof(((struct cf_diag_csd *)0)->start)) { pr_err("Insufficient memory for PMU(cpum_cf_diag) need=%zu\n", need); return -ENOMEM; } /* Setup s390dbf facility */ cf_diag_dbg = debug_register(KMSG_COMPONENT, 2, 1, 128); if (!cf_diag_dbg) { pr_err("Registration of s390dbf(cpum_cf_diag) failed\n"); return -ENOMEM; } debug_register_view(cf_diag_dbg, &debug_sprintf_view); rc = perf_pmu_register(&cf_diag, "cpum_cf_diag", PERF_TYPE_RAW); if (rc) { debug_unregister_view(cf_diag_dbg, &debug_sprintf_view); debug_unregister(cf_diag_dbg); pr_err("Registration of PMU(cpum_cf_diag) failed with rc=%i\n", rc); } return rc; }
/* CPU-measurement alerts for the counter facility */ static void cpumf_measurement_alert(struct ext_code ext_code, unsigned int alert, unsigned long unused) { struct cpu_cf_events *cpuhw; if (!(alert & CPU_MF_INT_CF_MASK)) return; inc_irq_stat(IRQEXT_CMC); cpuhw = this_cpu_ptr(&cpu_cf_events); /* Measurement alerts are shared and might happen when the PMU * is not reserved. Ignore these alerts in this case. */ if (!(cpuhw->flags & PMU_F_RESERVED)) return; /* counter authorization change alert */ if (alert & CPU_MF_INT_CF_CACA) qctri(&cpuhw->info); /* loss of counter data alert */ if (alert & CPU_MF_INT_CF_LCDA) pr_err("CPU[%i] Counter data was lost\n", smp_processor_id()); /* loss of MT counter data alert */ if (alert & CPU_MF_INT_CF_MTDA) pr_warn("CPU[%i] MT counter data was lost\n", smp_processor_id()); /* store alert for special handling by in-kernel users */ atomic64_or(alert, &cpuhw->alert); }
/* Service level infrastructure */ static void sl_print_counter(struct seq_file *m) { struct cpumf_ctr_info ci; memset(&ci, 0, sizeof(ci)); if (qctri(&ci)) return; seq_printf(m, "CPU-MF: Counter facility: version=%u.%u " "authorization=%04x\n", ci.cfvn, ci.csvn, ci.auth_ctl); }
void print_debug_cf(void) { struct cpumf_ctr_info cf_info; int cpu = smp_processor_id(); memset(&cf_info, 0, sizeof(cf_info)); if (!qctri(&cf_info)) pr_info("CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n", cpu, cf_info.cfvn, cf_info.csvn, cf_info.auth_ctl, cf_info.enable_ctl, cf_info.act_ctl); }
static void cpum_cf_setup_cpu(void *flags) { struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); switch (*((int *) flags)) { case PMC_INIT: memset(&cpuhw->info, 0, sizeof(cpuhw->info)); qctri(&cpuhw->info); cpuhw->flags |= PMU_F_RESERVED; break; case PMC_RELEASE: cpuhw->flags &= ~PMU_F_RESERVED; break; } /* Disable CPU counter sets */ lcctl(0); }
void perf_event_print_debug(void) { struct cpumf_ctr_info cf_info; unsigned long flags; int cpu; if (!cpum_cf_avail()) return; local_irq_save(flags); cpu = smp_processor_id(); memset(&cf_info, 0, sizeof(cf_info)); if (!qctri(&cf_info)) { pr_info("CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n", cpu, cf_info.cfvn, cf_info.csvn, cf_info.auth_ctl, cf_info.enable_ctl, cf_info.act_ctl); print_hex_dump_bytes("CPUMF Query: ", DUMP_PREFIX_OFFSET, &cf_info, sizeof(cf_info)); } local_irq_restore(flags); }