/* 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);
}
Пример #3
0
/* 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);
}
Пример #4
0
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);
}
Пример #6
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);
}