18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Freescale Embedded oprofile support, based on ppc64 oprofile support
48c2ecf20Sopenharmony_ci * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2010 Freescale Semiconductor, Inc
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Author: Andy Fleming
98c2ecf20Sopenharmony_ci * Maintainer: Kumar Gala <galak@kernel.crashing.org>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/oprofile.h>
138c2ecf20Sopenharmony_ci#include <linux/smp.h>
148c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
158c2ecf20Sopenharmony_ci#include <asm/processor.h>
168c2ecf20Sopenharmony_ci#include <asm/cputable.h>
178c2ecf20Sopenharmony_ci#include <asm/reg_fsl_emb.h>
188c2ecf20Sopenharmony_ci#include <asm/page.h>
198c2ecf20Sopenharmony_ci#include <asm/pmc.h>
208c2ecf20Sopenharmony_ci#include <asm/oprofile_impl.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic unsigned long reset_value[OP_MAX_COUNTER];
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic int num_counters;
258c2ecf20Sopenharmony_cistatic int oprofile_running;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic inline u32 get_pmlca(int ctr)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	u32 pmlca;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	switch (ctr) {
328c2ecf20Sopenharmony_ci		case 0:
338c2ecf20Sopenharmony_ci			pmlca = mfpmr(PMRN_PMLCA0);
348c2ecf20Sopenharmony_ci			break;
358c2ecf20Sopenharmony_ci		case 1:
368c2ecf20Sopenharmony_ci			pmlca = mfpmr(PMRN_PMLCA1);
378c2ecf20Sopenharmony_ci			break;
388c2ecf20Sopenharmony_ci		case 2:
398c2ecf20Sopenharmony_ci			pmlca = mfpmr(PMRN_PMLCA2);
408c2ecf20Sopenharmony_ci			break;
418c2ecf20Sopenharmony_ci		case 3:
428c2ecf20Sopenharmony_ci			pmlca = mfpmr(PMRN_PMLCA3);
438c2ecf20Sopenharmony_ci			break;
448c2ecf20Sopenharmony_ci		case 4:
458c2ecf20Sopenharmony_ci			pmlca = mfpmr(PMRN_PMLCA4);
468c2ecf20Sopenharmony_ci			break;
478c2ecf20Sopenharmony_ci		case 5:
488c2ecf20Sopenharmony_ci			pmlca = mfpmr(PMRN_PMLCA5);
498c2ecf20Sopenharmony_ci			break;
508c2ecf20Sopenharmony_ci		default:
518c2ecf20Sopenharmony_ci			panic("Bad ctr number\n");
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	return pmlca;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline void set_pmlca(int ctr, u32 pmlca)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	switch (ctr) {
608c2ecf20Sopenharmony_ci		case 0:
618c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA0, pmlca);
628c2ecf20Sopenharmony_ci			break;
638c2ecf20Sopenharmony_ci		case 1:
648c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA1, pmlca);
658c2ecf20Sopenharmony_ci			break;
668c2ecf20Sopenharmony_ci		case 2:
678c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA2, pmlca);
688c2ecf20Sopenharmony_ci			break;
698c2ecf20Sopenharmony_ci		case 3:
708c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA3, pmlca);
718c2ecf20Sopenharmony_ci			break;
728c2ecf20Sopenharmony_ci		case 4:
738c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA4, pmlca);
748c2ecf20Sopenharmony_ci			break;
758c2ecf20Sopenharmony_ci		case 5:
768c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA5, pmlca);
778c2ecf20Sopenharmony_ci			break;
788c2ecf20Sopenharmony_ci		default:
798c2ecf20Sopenharmony_ci			panic("Bad ctr number\n");
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic inline unsigned int ctr_read(unsigned int i)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	switch(i) {
868c2ecf20Sopenharmony_ci		case 0:
878c2ecf20Sopenharmony_ci			return mfpmr(PMRN_PMC0);
888c2ecf20Sopenharmony_ci		case 1:
898c2ecf20Sopenharmony_ci			return mfpmr(PMRN_PMC1);
908c2ecf20Sopenharmony_ci		case 2:
918c2ecf20Sopenharmony_ci			return mfpmr(PMRN_PMC2);
928c2ecf20Sopenharmony_ci		case 3:
938c2ecf20Sopenharmony_ci			return mfpmr(PMRN_PMC3);
948c2ecf20Sopenharmony_ci		case 4:
958c2ecf20Sopenharmony_ci			return mfpmr(PMRN_PMC4);
968c2ecf20Sopenharmony_ci		case 5:
978c2ecf20Sopenharmony_ci			return mfpmr(PMRN_PMC5);
988c2ecf20Sopenharmony_ci		default:
998c2ecf20Sopenharmony_ci			return 0;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic inline void ctr_write(unsigned int i, unsigned int val)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	switch(i) {
1068c2ecf20Sopenharmony_ci		case 0:
1078c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMC0, val);
1088c2ecf20Sopenharmony_ci			break;
1098c2ecf20Sopenharmony_ci		case 1:
1108c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMC1, val);
1118c2ecf20Sopenharmony_ci			break;
1128c2ecf20Sopenharmony_ci		case 2:
1138c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMC2, val);
1148c2ecf20Sopenharmony_ci			break;
1158c2ecf20Sopenharmony_ci		case 3:
1168c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMC3, val);
1178c2ecf20Sopenharmony_ci			break;
1188c2ecf20Sopenharmony_ci		case 4:
1198c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMC4, val);
1208c2ecf20Sopenharmony_ci			break;
1218c2ecf20Sopenharmony_ci		case 5:
1228c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMC5, val);
1238c2ecf20Sopenharmony_ci			break;
1248c2ecf20Sopenharmony_ci		default:
1258c2ecf20Sopenharmony_ci			break;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void init_pmc_stop(int ctr)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
1338c2ecf20Sopenharmony_ci			PMLCA_FCM1 | PMLCA_FCM0);
1348c2ecf20Sopenharmony_ci	u32 pmlcb = 0;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	switch (ctr) {
1378c2ecf20Sopenharmony_ci		case 0:
1388c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA0, pmlca);
1398c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCB0, pmlcb);
1408c2ecf20Sopenharmony_ci			break;
1418c2ecf20Sopenharmony_ci		case 1:
1428c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA1, pmlca);
1438c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCB1, pmlcb);
1448c2ecf20Sopenharmony_ci			break;
1458c2ecf20Sopenharmony_ci		case 2:
1468c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA2, pmlca);
1478c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCB2, pmlcb);
1488c2ecf20Sopenharmony_ci			break;
1498c2ecf20Sopenharmony_ci		case 3:
1508c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA3, pmlca);
1518c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCB3, pmlcb);
1528c2ecf20Sopenharmony_ci			break;
1538c2ecf20Sopenharmony_ci		case 4:
1548c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA4, pmlca);
1558c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCB4, pmlcb);
1568c2ecf20Sopenharmony_ci			break;
1578c2ecf20Sopenharmony_ci		case 5:
1588c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCA5, pmlca);
1598c2ecf20Sopenharmony_ci			mtpmr(PMRN_PMLCB5, pmlcb);
1608c2ecf20Sopenharmony_ci			break;
1618c2ecf20Sopenharmony_ci		default:
1628c2ecf20Sopenharmony_ci			panic("Bad ctr number!\n");
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic void set_pmc_event(int ctr, int event)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	u32 pmlca;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	pmlca = get_pmlca(ctr);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	pmlca = (pmlca & ~PMLCA_EVENT_MASK) |
1738c2ecf20Sopenharmony_ci		((event << PMLCA_EVENT_SHIFT) &
1748c2ecf20Sopenharmony_ci		 PMLCA_EVENT_MASK);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	set_pmlca(ctr, pmlca);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic void set_pmc_user_kernel(int ctr, int user, int kernel)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	u32 pmlca;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	pmlca = get_pmlca(ctr);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if(user)
1868c2ecf20Sopenharmony_ci		pmlca &= ~PMLCA_FCU;
1878c2ecf20Sopenharmony_ci	else
1888c2ecf20Sopenharmony_ci		pmlca |= PMLCA_FCU;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if(kernel)
1918c2ecf20Sopenharmony_ci		pmlca &= ~PMLCA_FCS;
1928c2ecf20Sopenharmony_ci	else
1938c2ecf20Sopenharmony_ci		pmlca |= PMLCA_FCS;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	set_pmlca(ctr, pmlca);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic void set_pmc_marked(int ctr, int mark0, int mark1)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	u32 pmlca = get_pmlca(ctr);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if(mark0)
2038c2ecf20Sopenharmony_ci		pmlca &= ~PMLCA_FCM0;
2048c2ecf20Sopenharmony_ci	else
2058c2ecf20Sopenharmony_ci		pmlca |= PMLCA_FCM0;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if(mark1)
2088c2ecf20Sopenharmony_ci		pmlca &= ~PMLCA_FCM1;
2098c2ecf20Sopenharmony_ci	else
2108c2ecf20Sopenharmony_ci		pmlca |= PMLCA_FCM1;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	set_pmlca(ctr, pmlca);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic void pmc_start_ctr(int ctr, int enable)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	u32 pmlca = get_pmlca(ctr);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	pmlca &= ~PMLCA_FC;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (enable)
2228c2ecf20Sopenharmony_ci		pmlca |= PMLCA_CE;
2238c2ecf20Sopenharmony_ci	else
2248c2ecf20Sopenharmony_ci		pmlca &= ~PMLCA_CE;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	set_pmlca(ctr, pmlca);
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic void pmc_start_ctrs(int enable)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	u32 pmgc0 = mfpmr(PMRN_PMGC0);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	pmgc0 &= ~PMGC0_FAC;
2348c2ecf20Sopenharmony_ci	pmgc0 |= PMGC0_FCECE;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (enable)
2378c2ecf20Sopenharmony_ci		pmgc0 |= PMGC0_PMIE;
2388c2ecf20Sopenharmony_ci	else
2398c2ecf20Sopenharmony_ci		pmgc0 &= ~PMGC0_PMIE;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	mtpmr(PMRN_PMGC0, pmgc0);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic void pmc_stop_ctrs(void)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	u32 pmgc0 = mfpmr(PMRN_PMGC0);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	pmgc0 |= PMGC0_FAC;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	mtpmr(PMRN_PMGC0, pmgc0);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int fsl_emb_cpu_setup(struct op_counter_config *ctr)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	int i;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* freeze all counters */
2608c2ecf20Sopenharmony_ci	pmc_stop_ctrs();
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	for (i = 0;i < num_counters;i++) {
2638c2ecf20Sopenharmony_ci		init_pmc_stop(i);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		set_pmc_event(i, ctr[i].event);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return 0;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int fsl_emb_reg_setup(struct op_counter_config *ctr,
2748c2ecf20Sopenharmony_ci			     struct op_system_config *sys,
2758c2ecf20Sopenharmony_ci			     int num_ctrs)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int i;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	num_counters = num_ctrs;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	/* Our counters count up, and "count" refers to
2828c2ecf20Sopenharmony_ci	 * how much before the next interrupt, and we interrupt
2838c2ecf20Sopenharmony_ci	 * on overflow.  So we calculate the starting value
2848c2ecf20Sopenharmony_ci	 * which will give us "count" until overflow.
2858c2ecf20Sopenharmony_ci	 * Then we set the events on the enabled counters */
2868c2ecf20Sopenharmony_ci	for (i = 0; i < num_counters; ++i)
2878c2ecf20Sopenharmony_ci		reset_value[i] = 0x80000000UL - ctr[i].count;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int fsl_emb_start(struct op_counter_config *ctr)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	int i;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	mtmsr(mfmsr() | MSR_PMM);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	for (i = 0; i < num_counters; ++i) {
2998c2ecf20Sopenharmony_ci		if (ctr[i].enabled) {
3008c2ecf20Sopenharmony_ci			ctr_write(i, reset_value[i]);
3018c2ecf20Sopenharmony_ci			/* Set each enabled counter to only
3028c2ecf20Sopenharmony_ci			 * count when the Mark bit is *not* set */
3038c2ecf20Sopenharmony_ci			set_pmc_marked(i, 1, 0);
3048c2ecf20Sopenharmony_ci			pmc_start_ctr(i, 1);
3058c2ecf20Sopenharmony_ci		} else {
3068c2ecf20Sopenharmony_ci			ctr_write(i, 0);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci			/* Set the ctr to be stopped */
3098c2ecf20Sopenharmony_ci			pmc_start_ctr(i, 0);
3108c2ecf20Sopenharmony_ci		}
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* Clear the freeze bit, and enable the interrupt.
3148c2ecf20Sopenharmony_ci	 * The counters won't actually start until the rfi clears
3158c2ecf20Sopenharmony_ci	 * the PMM bit */
3168c2ecf20Sopenharmony_ci	pmc_start_ctrs(1);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	oprofile_running = 1;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
3218c2ecf20Sopenharmony_ci			mfpmr(PMRN_PMGC0));
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return 0;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic void fsl_emb_stop(void)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	/* freeze counters */
3298c2ecf20Sopenharmony_ci	pmc_stop_ctrs();
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	oprofile_running = 0;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(),
3348c2ecf20Sopenharmony_ci			mfpmr(PMRN_PMGC0));
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	mb();
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic void fsl_emb_handle_interrupt(struct pt_regs *regs,
3418c2ecf20Sopenharmony_ci				    struct op_counter_config *ctr)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	unsigned long pc;
3448c2ecf20Sopenharmony_ci	int is_kernel;
3458c2ecf20Sopenharmony_ci	int val;
3468c2ecf20Sopenharmony_ci	int i;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	pc = regs->nip;
3498c2ecf20Sopenharmony_ci	is_kernel = is_kernel_addr(pc);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	for (i = 0; i < num_counters; ++i) {
3528c2ecf20Sopenharmony_ci		val = ctr_read(i);
3538c2ecf20Sopenharmony_ci		if (val < 0) {
3548c2ecf20Sopenharmony_ci			if (oprofile_running && ctr[i].enabled) {
3558c2ecf20Sopenharmony_ci				oprofile_add_ext_sample(pc, regs, i, is_kernel);
3568c2ecf20Sopenharmony_ci				ctr_write(i, reset_value[i]);
3578c2ecf20Sopenharmony_ci			} else {
3588c2ecf20Sopenharmony_ci				ctr_write(i, 0);
3598c2ecf20Sopenharmony_ci			}
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* The freeze bit was set by the interrupt. */
3648c2ecf20Sopenharmony_ci	/* Clear the freeze bit, and reenable the interrupt.  The
3658c2ecf20Sopenharmony_ci	 * counters won't actually start until the rfi clears the PMM
3668c2ecf20Sopenharmony_ci	 * bit.  The PMM bit should not be set until after the interrupt
3678c2ecf20Sopenharmony_ci	 * is cleared to avoid it getting lost in some hypervisor
3688c2ecf20Sopenharmony_ci	 * environments.
3698c2ecf20Sopenharmony_ci	 */
3708c2ecf20Sopenharmony_ci	mtmsr(mfmsr() | MSR_PMM);
3718c2ecf20Sopenharmony_ci	pmc_start_ctrs(1);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistruct op_powerpc_model op_model_fsl_emb = {
3758c2ecf20Sopenharmony_ci	.reg_setup		= fsl_emb_reg_setup,
3768c2ecf20Sopenharmony_ci	.cpu_setup		= fsl_emb_cpu_setup,
3778c2ecf20Sopenharmony_ci	.start			= fsl_emb_start,
3788c2ecf20Sopenharmony_ci	.stop			= fsl_emb_stop,
3798c2ecf20Sopenharmony_ci	.handle_interrupt	= fsl_emb_handle_interrupt,
3808c2ecf20Sopenharmony_ci};
381