1

arm64: Move MediaTek GIC quirk handling from irqchip to core

In commit 44bd78dd2b ("irqchip/gic-v3: Disable pseudo NMIs on
MediaTek devices w/ firmware issues") we added a method for detecting
MediaTek devices with broken firmware and disabled pseudo-NMI. While
that worked, it didn't address the problem at a deep enough level.

The fundamental issue with this broken firmware is that it's not
saving and restoring several important GICR registers. The current
list is believed to be:
* GICR_NUM_IPRIORITYR
* GICR_CTLR
* GICR_ISPENDR0
* GICR_ISACTIVER0
* GICR_NSACR

Pseudo-NMI didn't work because it was the only thing (currently) in
the kernel that relied on the broken registers, so forcing pseudo-NMI
off was an effective fix. However, it could be observed that calling
system_uses_irq_prio_masking() on these systems still returned
"true". That caused confusion and led to the need for
commit a07a594152 ("arm64: smp: avoid NMI IPIs with broken MediaTek
FW"). It's worried that the incorrect value returned by
system_uses_irq_prio_masking() on these systems will continue to
confuse future developers.

Let's fix the issue a little more completely by disabling IRQ
priorities at a deeper level in the kernel. Once we do this we can
revert some of the other bits of code dealing with this quirk.

This includes a partial revert of commit 44bd78dd2b
("irqchip/gic-v3: Disable pseudo NMIs on MediaTek devices w/ firmware
issues"). This isn't a full revert because it leaves some of the
changes to the "quirks" structure around in case future code needs it.

Suggested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20231107072651.v2.1.Ide945748593cffd8ff0feb9ae22b795935b944d6@changeid
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
Douglas Anderson 2023-11-07 07:26:56 -08:00 committed by Catalin Marinas
parent 403edfa436
commit 1d816ba168
2 changed files with 39 additions and 29 deletions

View File

@ -999,6 +999,37 @@ static void init_32bit_cpu_features(struct cpuinfo_32bit *info)
init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2); init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
} }
#ifdef CONFIG_ARM64_PSEUDO_NMI
static bool enable_pseudo_nmi;
static int __init early_enable_pseudo_nmi(char *p)
{
return kstrtobool(p, &enable_pseudo_nmi);
}
early_param("irqchip.gicv3_pseudo_nmi", early_enable_pseudo_nmi);
static __init void detect_system_supports_pseudo_nmi(void)
{
struct device_node *np;
if (!enable_pseudo_nmi)
return;
/*
* Detect broken MediaTek firmware that doesn't properly save and
* restore GIC priorities.
*/
np = of_find_compatible_node(NULL, NULL, "arm,gic-v3");
if (np && of_property_read_bool(np, "mediatek,broken-save-restore-fw")) {
pr_info("Pseudo-NMI disabled due to MediaTek Chromebook GICR save problem\n");
enable_pseudo_nmi = false;
}
of_node_put(np);
}
#else /* CONFIG_ARM64_PSEUDO_NMI */
static inline void detect_system_supports_pseudo_nmi(void) { }
#endif
void __init init_cpu_features(struct cpuinfo_arm64 *info) void __init init_cpu_features(struct cpuinfo_arm64 *info)
{ {
/* Before we start using the tables, make sure it is sorted */ /* Before we start using the tables, make sure it is sorted */
@ -1057,6 +1088,13 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
*/ */
init_cpucap_indirect_list(); init_cpucap_indirect_list();
/*
* Detect broken pseudo-NMI. Must be called _before_ the call to
* setup_boot_cpu_capabilities() since it interacts with
* can_use_gic_priorities().
*/
detect_system_supports_pseudo_nmi();
/* /*
* Detect and enable early CPU capabilities based on the boot CPU, * Detect and enable early CPU capabilities based on the boot CPU,
* after we have initialised the CPU feature infrastructure. * after we have initialised the CPU feature infrastructure.
@ -2085,14 +2123,6 @@ static void cpu_enable_e0pd(struct arm64_cpu_capabilities const *cap)
#endif /* CONFIG_ARM64_E0PD */ #endif /* CONFIG_ARM64_E0PD */
#ifdef CONFIG_ARM64_PSEUDO_NMI #ifdef CONFIG_ARM64_PSEUDO_NMI
static bool enable_pseudo_nmi;
static int __init early_enable_pseudo_nmi(char *p)
{
return kstrtobool(p, &enable_pseudo_nmi);
}
early_param("irqchip.gicv3_pseudo_nmi", early_enable_pseudo_nmi);
static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry, static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
int scope) int scope)
{ {

View File

@ -39,8 +39,7 @@
#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0) #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0)
#define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1) #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1)
#define FLAGS_WORKAROUND_MTK_GICR_SAVE (1ULL << 2) #define FLAGS_WORKAROUND_ASR_ERRATUM_8601001 (1ULL << 2)
#define FLAGS_WORKAROUND_ASR_ERRATUM_8601001 (1ULL << 3)
#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) #define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
@ -1779,15 +1778,6 @@ static bool gic_enable_quirk_msm8996(void *data)
return true; return true;
} }
static bool gic_enable_quirk_mtk_gicr(void *data)
{
struct gic_chip_data *d = data;
d->flags |= FLAGS_WORKAROUND_MTK_GICR_SAVE;
return true;
}
static bool gic_enable_quirk_cavium_38539(void *data) static bool gic_enable_quirk_cavium_38539(void *data)
{ {
struct gic_chip_data *d = data; struct gic_chip_data *d = data;
@ -1880,11 +1870,6 @@ static const struct gic_quirk gic_quirks[] = {
.compatible = "asr,asr8601-gic-v3", .compatible = "asr,asr8601-gic-v3",
.init = gic_enable_quirk_asr8601, .init = gic_enable_quirk_asr8601,
}, },
{
.desc = "GICv3: Mediatek Chromebook GICR save problem",
.property = "mediatek,broken-save-restore-fw",
.init = gic_enable_quirk_mtk_gicr,
},
{ {
.desc = "GICv3: HIP06 erratum 161010803", .desc = "GICv3: HIP06 erratum 161010803",
.iidr = 0x0204043b, .iidr = 0x0204043b,
@ -1946,11 +1931,6 @@ static void gic_enable_nmi_support(void)
if (!gic_prio_masking_enabled()) if (!gic_prio_masking_enabled())
return; return;
if (gic_data.flags & FLAGS_WORKAROUND_MTK_GICR_SAVE) {
pr_warn("Skipping NMI enable due to firmware issues\n");
return;
}
rdist_nmi_refs = kcalloc(gic_data.ppi_nr + SGI_NR, rdist_nmi_refs = kcalloc(gic_data.ppi_nr + SGI_NR,
sizeof(*rdist_nmi_refs), GFP_KERNEL); sizeof(*rdist_nmi_refs), GFP_KERNEL);
if (!rdist_nmi_refs) if (!rdist_nmi_refs)