Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85bd1126 authored by Prasad Sodagudi's avatar Prasad Sodagudi Committed by Channagoud Kadabi
Browse files

perf: Add workaround for performance monitor irq burst



There is possibility of IRQ burst when back to back
performance monitor overflow interrupts raised.
Single interrupt line is used for all monitors on a CPU
and when multiple monitors are used simultaneously,
performance monitor overflow status register do no show
proper overflow status of each monitor. So add workaround
to disable all monitor overflow interrupts while handling
a monitor overflow interrupt.

Change-Id: I14a34b2258ddab19f8ed9a9e087129efd7b86ff4
Signed-off-by: default avatarPrasad Sodagudi <psodagud@codeaurora.org>
Signed-off-by: default avatarSrinivas Ramana <sramana@codeaurora.org>
[ckadabi: Resolved minor conflicts]
Signed-off-by: default avatarChannagoud Kadabi <ckadabi@codeaurora.org>
parent ade232c6
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -1393,6 +1393,17 @@ config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES
	  Space separated list of names of dtbs to append when
	  building a concatenated Image.gz-dtb.

config KRYO_PMU_WORKAROUND
	bool "Workaround for PMU IRQ burst"
	default n
	depends on ARM_PMU
	help
	  Disable Performance Monitor overflow interrupts
	  when handling an monitor IRQ, to avoid simultaneous
	  overflow interrupts from multiple monitors.

	  Enable this flag for effect SoCs.

config BUILD_ARM64_DT_OVERLAY
	bool "enable DT overlay compilation support"
	depends on OF
+55 −1
Original line number Diff line number Diff line
@@ -784,6 +784,41 @@ static void armv8pmu_start(struct arm_pmu *cpu_pmu)
	armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E);
	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
#ifdef CONFIG_KRYO_PMU_WORKAROUND
static inline u32 armv8pmu_get_enabled_ints(void)
{
	u32 int_enset;

	int_enset = read_sysreg(pmintenset_el1);
	write_sysreg(0xffffffff, pmintenclr_el1);
	isb();
	return int_enset;
}

static inline u32 armv8pmu_update_enabled_ints(u32 value, int idx, int set)
{
	if (set)
		value |=  BIT(ARMV8_IDX_TO_COUNTER(idx));
	else
		value &= ~(BIT(ARMV8_IDX_TO_COUNTER(idx)));

	return value;
}

static inline void armv8pmu_set_enabled_ints(u32 mask)
{
	write_sysreg(mask, pmintenset_el1);
	isb();
}
#else
static inline u32 armv8pmu_get_enabled_ints(void)
{ return 0; }

static inline u32 armv8pmu_update_enabled_ints(u32 value, int idx, int set)
{ return value; }

static inline void armv8pmu_set_enabled_ints(u32 mask) { }
#endif

static void armv8pmu_stop(struct arm_pmu *cpu_pmu)
{
@@ -803,6 +838,12 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
	struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
	struct pt_regs *regs;
	int idx;
	u32 enabled_ints;

	/*
	 * Get enabled the PMU interrupts and mask all PMU interrupts.
	 */
	enabled_ints = armv8pmu_get_enabled_ints();

	/*
	 * Get and reset the IRQ flags
@@ -846,8 +887,16 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
		if (!armpmu_event_set_period(event))
			continue;

		if (perf_event_overflow(event, &data, regs))
		if (perf_event_overflow(event, &data, regs)) {
			cpu_pmu->disable(event);

			/*
			 * Update the list of interrupts
			 * that should be reenabled.
			 */
			enabled_ints = armv8pmu_update_enabled_ints(
					enabled_ints, idx, 0);
		}
	}
	armv8pmu_start(cpu_pmu);

@@ -860,6 +909,11 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
	 */
	irq_work_run();

	/*
	 * Re-enable the PMU interrupts
	 */
	armv8pmu_set_enabled_ints(enabled_ints);

	return IRQ_HANDLED;
}