From: Jez Ng Since commit b33f3d2677b8 ("thermal: intel: hfi: Enable HFI only when required"), the kernel only programs HFI when a thermal netlink client subscribes to events. Before that, the first CPU of each package to come online wrote a fresh table address and enabled HFI, which replaced any setup a previous kernel left behind. Now, if the previous kernel left HFI enabled, for example across kexec, nothing touches it. Hardware keeps writing updates into the previous kernel's table, which is free memory in this kernel and can be allocated for anything. On dual-socket Sapphire Rapids systems kexec'ing from a 6.1 kernel into 7.0, these writes corrupted the inode hash table and caused oopses in find_inode_fast(). When the first CPU of a package comes online, check MSR_IA32_HW_FEEDBACK_CONFIG and disable HFI if it is already enabled. If a client subscribes later, HFI is re-enabled with this kernel's table as before. This narrows the window but cannot close it. Hardware may still write to the old table until the package's first CPU reaches the thermal online callback, which runs from a device initcall. On the systems above that was about 30 seconds after this kernel started, 21 of which were spent in acpi_init(). In testing there, hardware wrote the table once right after HFI was enabled and not again over several minutes, idle or with every CPU busy, but the rate under other loads is unknown. The complete fix is for the previous kernel to disable HFI on shutdown, as "thermal: intel: hfi: Disable HFI on shutdown and kexec" does; this covers previous kernels that do not. Also update the kernel-doc of intel_hfi_online(), which still described it as always enabling HFI. Fixes: b33f3d2677b8 ("thermal: intel: hfi: Enable HFI only when required") Cc: stable@vger.kernel.org Reviewed-by: Andrew James Reviewed-by: John Ranzie Signed-off-by: Jez Ng --- drivers/thermal/intel/intel_hfi.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/thermal/intel/intel_hfi.c b/drivers/thermal/intel/intel_hfi.c index 8ff094eccbaf..b97f8113930c 100644 --- a/drivers/thermal/intel/intel_hfi.c +++ b/drivers/thermal/intel/intel_hfi.c @@ -413,13 +413,14 @@ static bool hfi_disable_if_enabled(void) } /** - * intel_hfi_online() - Enable HFI on @cpu - * @cpu: CPU in which the HFI will be enabled + * intel_hfi_online() - Set up HFI on @cpu + * @cpu: CPU that is coming online * - * Enable the HFI to be used in @cpu. The HFI is enabled at the package - * level. The first CPU in the package to come online does the full HFI - * initialization. Subsequent CPUs will just link themselves to the HFI - * instance of their package. + * The HFI is enabled at the package level. The first CPU in the package to + * come online does the full HFI initialization, which includes disabling HFI + * if a previous kernel left it enabled. HFI is enabled only when there are + * thermal netlink clients. Subsequent CPUs will just link themselves to the + * HFI instance of their package. * * This function is called before enabling the thermal vector in the local APIC * in order to ensure that @cpu has an associated HFI instance when it receives @@ -462,6 +463,14 @@ void intel_hfi_online(unsigned int cpu) if (hfi_instance->hdr) goto enable; + /* + * A previous kernel may have left HFI enabled across kexec. Hardware + * would keep writing to that kernel's table, in memory this kernel now + * owns. + */ + if (hfi_disable_if_enabled()) + pr_info("HFI left enabled on package %u, disabled\n", pkg_id); + /* * Hardware is programmed with the physical address of the first page * frame of the table. Hence, the allocated memory must be page-aligned. -- 2.39.5