Skip to content

Instantly share code, notes, and snippets.

@cyring
Last active May 9, 2024 18:57
Show Gist options
  • Save cyring/14556fc52e5bea5a564bdda5a0852f09 to your computer and use it in GitHub Desktop.
Save cyring/14556fc52e5bea5a564bdda5a0852f09 to your computer and use it in GitHub Desktop.
ARM PMU
Orange Pi 5+ (DTS)
@cyring
Copy link
Author

cyring commented Dec 30, 2023

psci_idle_init() -> psci_cpuidle_driver.probe = psci_cpuidle_probe() -> for_each_possible_cpu(cpu) {
    psci_idle_init_cpu()
    {
        enable_method = of_get_property(cpu_node, "enable-method", NULL);
        if (!enable_method || (strcmp(enable_method, "psci")))
                ret = -ENODEV;

        drv->name = "psci_idle";
        drv->states[0].enter = psci_enter_idle_state;
        drv->states[0].exit_latency = 1;
        drv->states[0].target_residency = 1;
        drv->states[0].power_usage = UINT_MAX;
        strcpy(drv->states[0].name, "WFI");
        strcpy(drv->states[0].desc, "ARM WFI");

        ret = dt_init_idle_driver(drv /* name = "psci_idle" */, psci_idle_state_match /* .compatible = "arm,idle-state" */, 1);
        if (ret <= 0)
                return ret ? : -ENODEV;

        ret = psci_cpu_init_idle(dev, drv, cpu, ret);

        ret = cpuidle_register(drv, NULL);
    }
}

@cyring
Copy link
Author

cyring commented Dec 30, 2023

static __cpuidle int psci_enter_idle_state(struct cpuidle_device *dev,
                                           struct cpuidle_driver *drv, int idx)
{
        u32 *state = __this_cpu_read(psci_cpuidle_data.psci_states);

        return CPU_PM_CPU_IDLE_ENTER_PARAM_RCU(psci_cpu_suspend_enter, idx, state[idx]);
}
int psci_cpu_suspend_enter(u32 state)
{
    if ( smc(PSCI_1_0_FN_PSCI_FEATURES /* = 0x84000000+10 */) & (0x1 << 1) ) {
        /* PSCI_1_0_EXT_POWER_STATE_TYPE_MASK (0x1 << 30) */

        psci_ops.cpu_suspend() -> cpu_suspend()
    }
    else
    {
        /* PSCI_0_2_POWER_STATE_TYPE_MASK (0x1 << 16) */

        cpu_suspend()
    }
}
cpu_suspend() -> __cpu_suspend_enter() -> " br	x8 " -> _cpu_resume -> cpu_do_resume

@cyring
Copy link
Author

cyring commented Dec 31, 2023

Comment on the disablement of PMU and AMU

#ifdef CONFIG_CPU_PM

SYM_FUNC_START(cpu_do_resume)

/*	reset_pmuserenr_el0 x0			** Disable PMU access from EL0 */
/*	reset_amuserenr_el0 x0			** Disable AMU access from EL0 */

	isb
	ret
SYM_FUNC_END(cpu_do_resume)
#endif
	.macro	reset_pmuserenr_el0, tmpreg
	mrs	\tmpreg, id_aa64dfr0_el1
	sbfx	\tmpreg, \tmpreg, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
	cmp	\tmpreg, #1			// Skip if no PMU present
	b.lt	9000f
	msr	pmuserenr_el0, xzr		// Disable PMU access from EL0
9000:
	.endm
	.macro	reset_amuserenr_el0, tmpreg
	mrs	\tmpreg, id_aa64pfr0_el1	// Check ID_AA64PFR0_EL1
	ubfx	\tmpreg, \tmpreg, #ID_AA64PFR0_EL1_AMU_SHIFT, #4
	cbz	\tmpreg, .Lskip_\@		// Skip if no AMU present
	msr_s	SYS_AMUSERENR_EL0, xzr		// Disable AMU access from EL0
.Lskip_\@:
	.endm

@cyring
Copy link
Author

cyring commented Dec 31, 2023

  • Disable CONFIG_ARM_PMUV3 w/ kernel 6
  • Disable CONFIG_ARM_PMU w/ kernel 5
  • Disable CONFIG_PERF_EVENTS
  • Disable CONFIG_KVM
  • drivers/perf/arm_pmuv3.c
static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
{
	armv8pmu_stop(cpu_pmu);

	armv8pmu_start(cpu_pmu);

	return IRQ_HANDLED;
}
armv8pmu_stop() -> armv8pmu_pmcr_write() -> write_pmcr() -> write_sysreg() -> __write_sysreg() -> pmcr_el0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment