18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
48c2ecf20Sopenharmony_ci * Added mmcra[slot] support:
58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2007 Will Schmidt <willschm@us.ibm.com>, IBM
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/oprofile.h>
98c2ecf20Sopenharmony_ci#include <linux/smp.h>
108c2ecf20Sopenharmony_ci#include <asm/firmware.h>
118c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
128c2ecf20Sopenharmony_ci#include <asm/processor.h>
138c2ecf20Sopenharmony_ci#include <asm/cputable.h>
148c2ecf20Sopenharmony_ci#include <asm/rtas.h>
158c2ecf20Sopenharmony_ci#include <asm/oprofile_impl.h>
168c2ecf20Sopenharmony_ci#include <asm/reg.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define dbg(args...)
198c2ecf20Sopenharmony_ci#define OPROFILE_PM_PMCSEL_MSK      0xffULL
208c2ecf20Sopenharmony_ci#define OPROFILE_PM_UNIT_SHIFT      60
218c2ecf20Sopenharmony_ci#define OPROFILE_PM_UNIT_MSK        0xfULL
228c2ecf20Sopenharmony_ci#define OPROFILE_MAX_PMC_NUM        3
238c2ecf20Sopenharmony_ci#define OPROFILE_PMSEL_FIELD_WIDTH  8
248c2ecf20Sopenharmony_ci#define OPROFILE_UNIT_FIELD_WIDTH   4
258c2ecf20Sopenharmony_ci#define MMCRA_SIAR_VALID_MASK       0x10000000ULL
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic unsigned long reset_value[OP_MAX_COUNTER];
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic int oprofile_running;
308c2ecf20Sopenharmony_cistatic int use_slot_nums;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */
338c2ecf20Sopenharmony_cistatic u32 mmcr0_val;
348c2ecf20Sopenharmony_cistatic u64 mmcr1_val;
358c2ecf20Sopenharmony_cistatic u64 mmcra_val;
368c2ecf20Sopenharmony_cistatic u32 cntr_marked_events;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic int power7_marked_instr_event(u64 mmcr1)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	u64 psel, unit;
418c2ecf20Sopenharmony_ci	int pmc, cntr_marked_events = 0;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	/* Given the MMCR1 value, look at the field for each counter to
448c2ecf20Sopenharmony_ci	 * determine if it is a marked event.  Code based on the function
458c2ecf20Sopenharmony_ci	 * power7_marked_instr_event() in file arch/powerpc/perf/power7-pmu.c.
468c2ecf20Sopenharmony_ci	 */
478c2ecf20Sopenharmony_ci	for (pmc = 0; pmc < 4; pmc++) {
488c2ecf20Sopenharmony_ci		psel = mmcr1 & (OPROFILE_PM_PMCSEL_MSK
498c2ecf20Sopenharmony_ci				<< (OPROFILE_MAX_PMC_NUM - pmc)
508c2ecf20Sopenharmony_ci				* OPROFILE_PMSEL_FIELD_WIDTH);
518c2ecf20Sopenharmony_ci		psel = (psel >> ((OPROFILE_MAX_PMC_NUM - pmc)
528c2ecf20Sopenharmony_ci				 * OPROFILE_PMSEL_FIELD_WIDTH)) & ~1ULL;
538c2ecf20Sopenharmony_ci		unit = mmcr1 & (OPROFILE_PM_UNIT_MSK
548c2ecf20Sopenharmony_ci				<< (OPROFILE_PM_UNIT_SHIFT
558c2ecf20Sopenharmony_ci				    - (pmc * OPROFILE_PMSEL_FIELD_WIDTH )));
568c2ecf20Sopenharmony_ci		unit = unit >> (OPROFILE_PM_UNIT_SHIFT
578c2ecf20Sopenharmony_ci				- (pmc * OPROFILE_PMSEL_FIELD_WIDTH));
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		switch (psel >> 4) {
608c2ecf20Sopenharmony_ci		case 2:
618c2ecf20Sopenharmony_ci			cntr_marked_events |= (pmc == 1 || pmc == 3) << pmc;
628c2ecf20Sopenharmony_ci			break;
638c2ecf20Sopenharmony_ci		case 3:
648c2ecf20Sopenharmony_ci			if (psel == 0x3c) {
658c2ecf20Sopenharmony_ci				cntr_marked_events |= (pmc == 0) << pmc;
668c2ecf20Sopenharmony_ci				break;
678c2ecf20Sopenharmony_ci			}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci			if (psel == 0x3e) {
708c2ecf20Sopenharmony_ci				cntr_marked_events |= (pmc != 1) << pmc;
718c2ecf20Sopenharmony_ci				break;
728c2ecf20Sopenharmony_ci			}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci			cntr_marked_events |= 1 << pmc;
758c2ecf20Sopenharmony_ci			break;
768c2ecf20Sopenharmony_ci		case 4:
778c2ecf20Sopenharmony_ci		case 5:
788c2ecf20Sopenharmony_ci			cntr_marked_events |= (unit == 0xd) << pmc;
798c2ecf20Sopenharmony_ci			break;
808c2ecf20Sopenharmony_ci		case 6:
818c2ecf20Sopenharmony_ci			if (psel == 0x64)
828c2ecf20Sopenharmony_ci				cntr_marked_events |= (pmc >= 2) << pmc;
838c2ecf20Sopenharmony_ci			break;
848c2ecf20Sopenharmony_ci		case 8:
858c2ecf20Sopenharmony_ci			cntr_marked_events |= (unit == 0xd) << pmc;
868c2ecf20Sopenharmony_ci			break;
878c2ecf20Sopenharmony_ci		}
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci	return cntr_marked_events;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int power4_reg_setup(struct op_counter_config *ctr,
938c2ecf20Sopenharmony_ci			     struct op_system_config *sys,
948c2ecf20Sopenharmony_ci			     int num_ctrs)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	int i;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/*
998c2ecf20Sopenharmony_ci	 * The performance counter event settings are given in the mmcr0,
1008c2ecf20Sopenharmony_ci	 * mmcr1 and mmcra values passed from the user in the
1018c2ecf20Sopenharmony_ci	 * op_system_config structure (sys variable).
1028c2ecf20Sopenharmony_ci	 */
1038c2ecf20Sopenharmony_ci	mmcr0_val = sys->mmcr0;
1048c2ecf20Sopenharmony_ci	mmcr1_val = sys->mmcr1;
1058c2ecf20Sopenharmony_ci	mmcra_val = sys->mmcra;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Power 7+ and newer architectures:
1088c2ecf20Sopenharmony_ci	 * Determine which counter events in the group (the group of events is
1098c2ecf20Sopenharmony_ci	 * specified by the bit settings in the MMCR1 register) are marked
1108c2ecf20Sopenharmony_ci	 * events for use in the interrupt handler.  Do the calculation once
1118c2ecf20Sopenharmony_ci	 * before OProfile starts.  Information is used in the interrupt
1128c2ecf20Sopenharmony_ci	 * handler.  Starting with Power 7+ we only record the sample for
1138c2ecf20Sopenharmony_ci	 * marked events if the SIAR valid bit is set.  For non marked events
1148c2ecf20Sopenharmony_ci	 * the sample is always recorded.
1158c2ecf20Sopenharmony_ci	 */
1168c2ecf20Sopenharmony_ci	if (pvr_version_is(PVR_POWER7p))
1178c2ecf20Sopenharmony_ci		cntr_marked_events = power7_marked_instr_event(mmcr1_val);
1188c2ecf20Sopenharmony_ci	else
1198c2ecf20Sopenharmony_ci		cntr_marked_events = 0; /* For older processors, set the bit map
1208c2ecf20Sopenharmony_ci					 * to zero so the sample will always be
1218c2ecf20Sopenharmony_ci					 * be recorded.
1228c2ecf20Sopenharmony_ci					 */
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	for (i = 0; i < cur_cpu_spec->num_pmcs; ++i)
1258c2ecf20Sopenharmony_ci		reset_value[i] = 0x80000000UL - ctr[i].count;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/* setup user and kernel profiling */
1288c2ecf20Sopenharmony_ci	if (sys->enable_kernel)
1298c2ecf20Sopenharmony_ci		mmcr0_val &= ~MMCR0_KERNEL_DISABLE;
1308c2ecf20Sopenharmony_ci	else
1318c2ecf20Sopenharmony_ci		mmcr0_val |= MMCR0_KERNEL_DISABLE;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (sys->enable_user)
1348c2ecf20Sopenharmony_ci		mmcr0_val &= ~MMCR0_PROBLEM_DISABLE;
1358c2ecf20Sopenharmony_ci	else
1368c2ecf20Sopenharmony_ci		mmcr0_val |= MMCR0_PROBLEM_DISABLE;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (pvr_version_is(PVR_POWER4) || pvr_version_is(PVR_POWER4p) ||
1398c2ecf20Sopenharmony_ci	    pvr_version_is(PVR_970) || pvr_version_is(PVR_970FX) ||
1408c2ecf20Sopenharmony_ci	    pvr_version_is(PVR_970MP) || pvr_version_is(PVR_970GX) ||
1418c2ecf20Sopenharmony_ci	    pvr_version_is(PVR_POWER5) || pvr_version_is(PVR_POWER5p))
1428c2ecf20Sopenharmony_ci		use_slot_nums = 1;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return 0;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ciextern void ppc_enable_pmcs(void);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/*
1508c2ecf20Sopenharmony_ci * Older CPUs require the MMCRA sample bit to be always set, but newer
1518c2ecf20Sopenharmony_ci * CPUs only want it set for some groups. Eventually we will remove all
1528c2ecf20Sopenharmony_ci * knowledge of this bit in the kernel, oprofile userspace should be
1538c2ecf20Sopenharmony_ci * setting it when required.
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci * In order to keep current installations working we force the bit for
1568c2ecf20Sopenharmony_ci * those older CPUs. Once everyone has updated their oprofile userspace we
1578c2ecf20Sopenharmony_ci * can remove this hack.
1588c2ecf20Sopenharmony_ci */
1598c2ecf20Sopenharmony_cistatic inline int mmcra_must_set_sample(void)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	if (pvr_version_is(PVR_POWER4) || pvr_version_is(PVR_POWER4p) ||
1628c2ecf20Sopenharmony_ci	    pvr_version_is(PVR_970) || pvr_version_is(PVR_970FX) ||
1638c2ecf20Sopenharmony_ci	    pvr_version_is(PVR_970MP) || pvr_version_is(PVR_970GX))
1648c2ecf20Sopenharmony_ci		return 1;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return 0;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic int power4_cpu_setup(struct op_counter_config *ctr)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	unsigned int mmcr0 = mmcr0_val;
1728c2ecf20Sopenharmony_ci	unsigned long mmcra = mmcra_val;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	ppc_enable_pmcs();
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* set the freeze bit */
1778c2ecf20Sopenharmony_ci	mmcr0 |= MMCR0_FC;
1788c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR0, mmcr0);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	mmcr0 |= MMCR0_FCM1|MMCR0_PMXE|MMCR0_FCECE;
1818c2ecf20Sopenharmony_ci	mmcr0 |= MMCR0_PMC1CE|MMCR0_PMCjCE;
1828c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR0, mmcr0);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR1, mmcr1_val);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (mmcra_must_set_sample())
1878c2ecf20Sopenharmony_ci		mmcra |= MMCRA_SAMPLE_ENABLE;
1888c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCRA, mmcra);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	dbg("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(),
1918c2ecf20Sopenharmony_ci	    mfspr(SPRN_MMCR0));
1928c2ecf20Sopenharmony_ci	dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
1938c2ecf20Sopenharmony_ci	    mfspr(SPRN_MMCR1));
1948c2ecf20Sopenharmony_ci	dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(),
1958c2ecf20Sopenharmony_ci	    mfspr(SPRN_MMCRA));
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return 0;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic int power4_start(struct op_counter_config *ctr)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	int i;
2038c2ecf20Sopenharmony_ci	unsigned int mmcr0;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* set the PMM bit (see comment below) */
2068c2ecf20Sopenharmony_ci	mtmsr(mfmsr() | MSR_PMM);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
2098c2ecf20Sopenharmony_ci		if (ctr[i].enabled) {
2108c2ecf20Sopenharmony_ci			classic_ctr_write(i, reset_value[i]);
2118c2ecf20Sopenharmony_ci		} else {
2128c2ecf20Sopenharmony_ci			classic_ctr_write(i, 0);
2138c2ecf20Sopenharmony_ci		}
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	mmcr0 = mfspr(SPRN_MMCR0);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/*
2198c2ecf20Sopenharmony_ci	 * We must clear the PMAO bit on some (GQ) chips. Just do it
2208c2ecf20Sopenharmony_ci	 * all the time
2218c2ecf20Sopenharmony_ci	 */
2228c2ecf20Sopenharmony_ci	mmcr0 &= ~MMCR0_PMAO;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/*
2258c2ecf20Sopenharmony_ci	 * now clear the freeze bit, counting will not start until we
2268c2ecf20Sopenharmony_ci	 * rfid from this excetion, because only at that point will
2278c2ecf20Sopenharmony_ci	 * the PMM bit be cleared
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci	mmcr0 &= ~MMCR0_FC;
2308c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR0, mmcr0);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	oprofile_running = 1;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
2358c2ecf20Sopenharmony_ci	return 0;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic void power4_stop(void)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	unsigned int mmcr0;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* freeze counters */
2438c2ecf20Sopenharmony_ci	mmcr0 = mfspr(SPRN_MMCR0);
2448c2ecf20Sopenharmony_ci	mmcr0 |= MMCR0_FC;
2458c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR0, mmcr0);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	oprofile_running = 0;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	dbg("stop on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	mb();
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/* Fake functions used by canonicalize_pc */
2558c2ecf20Sopenharmony_cistatic void __used hypervisor_bucket(void)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic void __used rtas_bucket(void)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic void __used kernel_unknown_bucket(void)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci/*
2688c2ecf20Sopenharmony_ci * On GQ and newer the MMCRA stores the HV and PR bits at the time
2698c2ecf20Sopenharmony_ci * the SIAR was sampled. We use that to work out if the SIAR was sampled in
2708c2ecf20Sopenharmony_ci * the hypervisor, our exception vectors or RTAS.
2718c2ecf20Sopenharmony_ci * If the MMCRA_SAMPLE_ENABLE bit is set, we can use the MMCRA[slot] bits
2728c2ecf20Sopenharmony_ci * to more accurately identify the address of the sampled instruction. The
2738c2ecf20Sopenharmony_ci * mmcra[slot] bits represent the slot number of a sampled instruction
2748c2ecf20Sopenharmony_ci * within an instruction group.  The slot will contain a value between 1
2758c2ecf20Sopenharmony_ci * and 5 if MMCRA_SAMPLE_ENABLE is set, otherwise 0.
2768c2ecf20Sopenharmony_ci */
2778c2ecf20Sopenharmony_cistatic unsigned long get_pc(struct pt_regs *regs)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	unsigned long pc = mfspr(SPRN_SIAR);
2808c2ecf20Sopenharmony_ci	unsigned long mmcra;
2818c2ecf20Sopenharmony_ci	unsigned long slot;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* Can't do much about it */
2848c2ecf20Sopenharmony_ci	if (!cur_cpu_spec->oprofile_mmcra_sihv)
2858c2ecf20Sopenharmony_ci		return pc;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	mmcra = mfspr(SPRN_MMCRA);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (use_slot_nums && (mmcra & MMCRA_SAMPLE_ENABLE)) {
2908c2ecf20Sopenharmony_ci		slot = ((mmcra & MMCRA_SLOT) >> MMCRA_SLOT_SHIFT);
2918c2ecf20Sopenharmony_ci		if (slot > 1)
2928c2ecf20Sopenharmony_ci			pc += 4 * (slot - 1);
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* Were we in the hypervisor? */
2968c2ecf20Sopenharmony_ci	if (firmware_has_feature(FW_FEATURE_LPAR) &&
2978c2ecf20Sopenharmony_ci	    (mmcra & cur_cpu_spec->oprofile_mmcra_sihv))
2988c2ecf20Sopenharmony_ci		/* function descriptor madness */
2998c2ecf20Sopenharmony_ci		return *((unsigned long *)hypervisor_bucket);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* We were in userspace, nothing to do */
3028c2ecf20Sopenharmony_ci	if (mmcra & cur_cpu_spec->oprofile_mmcra_sipr)
3038c2ecf20Sopenharmony_ci		return pc;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_RTAS
3068c2ecf20Sopenharmony_ci	/* Were we in RTAS? */
3078c2ecf20Sopenharmony_ci	if (pc >= rtas.base && pc < (rtas.base + rtas.size))
3088c2ecf20Sopenharmony_ci		/* function descriptor madness */
3098c2ecf20Sopenharmony_ci		return *((unsigned long *)rtas_bucket);
3108c2ecf20Sopenharmony_ci#endif
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/* Were we in our exception vectors or SLB real mode miss handler? */
3138c2ecf20Sopenharmony_ci	if (pc < 0x1000000UL)
3148c2ecf20Sopenharmony_ci		return (unsigned long)__va(pc);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/* Not sure where we were */
3178c2ecf20Sopenharmony_ci	if (!is_kernel_addr(pc))
3188c2ecf20Sopenharmony_ci		/* function descriptor madness */
3198c2ecf20Sopenharmony_ci		return *((unsigned long *)kernel_unknown_bucket);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return pc;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int get_kernel(unsigned long pc, unsigned long mmcra)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	int is_kernel;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (!cur_cpu_spec->oprofile_mmcra_sihv) {
3298c2ecf20Sopenharmony_ci		is_kernel = is_kernel_addr(pc);
3308c2ecf20Sopenharmony_ci	} else {
3318c2ecf20Sopenharmony_ci		is_kernel = ((mmcra & cur_cpu_spec->oprofile_mmcra_sipr) == 0);
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return is_kernel;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic bool pmc_overflow(unsigned long val)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	if ((int)val < 0)
3408c2ecf20Sopenharmony_ci		return true;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/*
3438c2ecf20Sopenharmony_ci	 * Events on POWER7 can roll back if a speculative event doesn't
3448c2ecf20Sopenharmony_ci	 * eventually complete. Unfortunately in some rare cases they will
3458c2ecf20Sopenharmony_ci	 * raise a performance monitor exception. We need to catch this to
3468c2ecf20Sopenharmony_ci	 * ensure we reset the PMC. In all cases the PMC will be 256 or less
3478c2ecf20Sopenharmony_ci	 * cycles from overflow.
3488c2ecf20Sopenharmony_ci	 *
3498c2ecf20Sopenharmony_ci	 * We only do this if the first pass fails to find any overflowing
3508c2ecf20Sopenharmony_ci	 * PMCs because a user might set a period of less than 256 and we
3518c2ecf20Sopenharmony_ci	 * don't want to mistakenly reset them.
3528c2ecf20Sopenharmony_ci	 */
3538c2ecf20Sopenharmony_ci	if (pvr_version_is(PVR_POWER7) && ((0x80000000 - val) <= 256))
3548c2ecf20Sopenharmony_ci		return true;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return false;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic void power4_handle_interrupt(struct pt_regs *regs,
3608c2ecf20Sopenharmony_ci				    struct op_counter_config *ctr)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	unsigned long pc;
3638c2ecf20Sopenharmony_ci	int is_kernel;
3648c2ecf20Sopenharmony_ci	int val;
3658c2ecf20Sopenharmony_ci	int i;
3668c2ecf20Sopenharmony_ci	unsigned int mmcr0;
3678c2ecf20Sopenharmony_ci	unsigned long mmcra;
3688c2ecf20Sopenharmony_ci	bool siar_valid = false;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	mmcra = mfspr(SPRN_MMCRA);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	pc = get_pc(regs);
3738c2ecf20Sopenharmony_ci	is_kernel = get_kernel(pc, mmcra);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/* set the PMM bit (see comment below) */
3768c2ecf20Sopenharmony_ci	mtmsr(mfmsr() | MSR_PMM);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* Check that the SIAR  valid bit in MMCRA is set to 1. */
3798c2ecf20Sopenharmony_ci	if ((mmcra & MMCRA_SIAR_VALID_MASK) == MMCRA_SIAR_VALID_MASK)
3808c2ecf20Sopenharmony_ci		siar_valid = true;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
3838c2ecf20Sopenharmony_ci		val = classic_ctr_read(i);
3848c2ecf20Sopenharmony_ci		if (pmc_overflow(val)) {
3858c2ecf20Sopenharmony_ci			if (oprofile_running && ctr[i].enabled) {
3868c2ecf20Sopenharmony_ci				/* Power 7+ and newer architectures:
3878c2ecf20Sopenharmony_ci				 * If the event is a marked event, then only
3888c2ecf20Sopenharmony_ci				 * save the sample if the SIAR valid bit is
3898c2ecf20Sopenharmony_ci				 * set.  If the event is not marked, then
3908c2ecf20Sopenharmony_ci				 * always save the sample.
3918c2ecf20Sopenharmony_ci				 * Note, the Sample enable bit in the MMCRA
3928c2ecf20Sopenharmony_ci				 * register must be set to 1 if the group
3938c2ecf20Sopenharmony_ci				 * contains a marked event.
3948c2ecf20Sopenharmony_ci				 */
3958c2ecf20Sopenharmony_ci				if ((siar_valid &&
3968c2ecf20Sopenharmony_ci				     (cntr_marked_events & (1 << i)))
3978c2ecf20Sopenharmony_ci				    || !(cntr_marked_events & (1 << i)))
3988c2ecf20Sopenharmony_ci					oprofile_add_ext_sample(pc, regs, i,
3998c2ecf20Sopenharmony_ci								is_kernel);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci				classic_ctr_write(i, reset_value[i]);
4028c2ecf20Sopenharmony_ci			} else {
4038c2ecf20Sopenharmony_ci				classic_ctr_write(i, 0);
4048c2ecf20Sopenharmony_ci			}
4058c2ecf20Sopenharmony_ci		}
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	mmcr0 = mfspr(SPRN_MMCR0);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* reset the perfmon trigger */
4118c2ecf20Sopenharmony_ci	mmcr0 |= MMCR0_PMXE;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	/*
4148c2ecf20Sopenharmony_ci	 * We must clear the PMAO bit on some (GQ) chips. Just do it
4158c2ecf20Sopenharmony_ci	 * all the time
4168c2ecf20Sopenharmony_ci	 */
4178c2ecf20Sopenharmony_ci	mmcr0 &= ~MMCR0_PMAO;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/* Clear the appropriate bits in the MMCRA */
4208c2ecf20Sopenharmony_ci	mmcra &= ~cur_cpu_spec->oprofile_mmcra_clear;
4218c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCRA, mmcra);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/*
4248c2ecf20Sopenharmony_ci	 * now clear the freeze bit, counting will not start until we
4258c2ecf20Sopenharmony_ci	 * rfid from this exception, because only at that point will
4268c2ecf20Sopenharmony_ci	 * the PMM bit be cleared
4278c2ecf20Sopenharmony_ci	 */
4288c2ecf20Sopenharmony_ci	mmcr0 &= ~MMCR0_FC;
4298c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR0, mmcr0);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistruct op_powerpc_model op_model_power4 = {
4338c2ecf20Sopenharmony_ci	.reg_setup		= power4_reg_setup,
4348c2ecf20Sopenharmony_ci	.cpu_setup		= power4_cpu_setup,
4358c2ecf20Sopenharmony_ci	.start			= power4_start,
4368c2ecf20Sopenharmony_ci	.stop			= power4_stop,
4378c2ecf20Sopenharmony_ci	.handle_interrupt	= power4_handle_interrupt,
4388c2ecf20Sopenharmony_ci};
439