[PATCH] cpuidle, ACPI: Evaluate LPI arch_flags for broadcast timer

From: Oza Pawandeep
Date: Wed Jul 12 2023 - 13:25:23 EST


Arm® Functional Fixed Hardware Specification defines LPI states,
which provides an architectural context loss flags field
that can be used to describe the context that might be lost
when an LPI state is entered.

- Core context Lost
- General purpose registers.
- Floating point and SIMD registers.
- System registers, include the System register based
- generic timer for the core.
- Debug register in the core power domain.
- PMU registers in the core power domain.
- Trace register in the core power domain.
- Trace context loss
- GICR
- GICD

Qualcomm's custom CPUs preserves the architectural state,
including keeping the power domain for local timers active.
when core is power gated, the local timers are sufficient to
wake the core up without needing broadcast timer.

The patch fixes the evaluation of cpuidle arch_flags,
and moves only to broadcast timer if core context lost
is defined in ACPI LPI.

Signed-off-by: Oza Pawandeep <quic_poza@xxxxxxxxxxx>

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index bd68e1b7f29f..9c335968316c 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -42,6 +42,24 @@
#define ACPI_MADT_GICC_SPE (offsetof(struct acpi_madt_generic_interrupt, \
spe_interrupt) + sizeof(u16))

+/*
+ * Arm® Functional Fixed Hardware Specification Version 1.2.
+ * Table 2: Arm Architecture context loss flags
+ */
+#define CPUIDLE_CORE_CTXT BIT(0) /* Core context Lost */
+
+#ifndef arch_acpi_lpi_timer_stopped
+static __always_inline bool arch_acpi_lpi_timer_stopped(u32 arch_flags)
+{
+ return arch_flags & CPUIDLE_CORE_CTXT;
+}
+#define arch_acpi_lpi_timer_stopped arch_acpi_lpi_timer_stopped
+#endif
+
+#define CPUIDLE_TRACE_CTXT BIT(1) /* Trace context loss */
+#define CPUIDLE_GICR_CTXT BIT(2) /* GICR */
+#define CPUIDLE_GICD_CTXT BIT(3) /* GICD */
+
/* Basic configuration for ACPI */
#ifdef CONFIG_ACPI
pgprot_t __acpi_get_mem_attribute(phys_addr_t addr);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 9718d07cc2a2..8ea1f2b3bf96 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1221,7 +1221,7 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr)
strscpy(state->desc, lpi->desc, CPUIDLE_DESC_LEN);
state->exit_latency = lpi->wake_latency;
state->target_residency = lpi->min_residency;
- if (lpi->arch_flags)
+ if (arch_acpi_lpi_timer_stopped(lpi->arch_flags))
state->flags |= CPUIDLE_FLAG_TIMER_STOP;
if (i != 0 && lpi->entry_method == ACPI_CSTATE_FFH)
state->flags |= CPUIDLE_FLAG_RCU_IDLE;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index d584f94409e1..b24f1cd1cebb 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1471,6 +1471,14 @@ static inline int lpit_read_residency_count_address(u64 *address)
}
#endif

+#ifndef arch_acpi_lpi_timer_stopped
+static __always_inline bool arch_acpi_lpi_timer_stopped(u32 arch_flags)
+{
+ return (arch_flags != 0);
+}
+#define arch_acpi_lpi_timer_stopped arch_acpi_lpi_timer_stopped
+#endif
+
#ifdef CONFIG_ACPI_PPTT
int acpi_pptt_cpu_is_thread(unsigned int cpu);
int find_acpi_cpu_topology(unsigned int cpu, int level);
--
2.25.1