Skip to content

Commit bee09ed

Browse files
rric-netIngo Molnar
authored and
Ingo Molnar
committed
perf/x86/amd/ibs: Fix waking up from S3 for AMD family 10h
On AMD family 10h we see following error messages while waking up from S3 for all non-boot CPUs leading to a failed IBS initialization: Enabling non-boot CPUs ... smpboot: Booting Node 0 Processor 1 APIC 0x1 [Firmware Bug]: cpu 1, try to use APIC500 (LVT offset 0) for vector 0x400, but the register is already in use for vector 0xf9 on another cpu perf: IBS APIC setup failed on cpu #1 process: Switch to broadcast mode on CPU1 CPU1 is up ... ACPI: Waking up from system sleep state S3 Reason for this is that during suspend the LVT offset for the IBS vector gets lost and needs to be reinialized while resuming. The offset is read from the IBSCTL msr. On family 10h the offset needs to be 1 as offset 0 is used for the MCE threshold interrupt, but firmware assings it for IBS to 0 too. The kernel needs to reprogram the vector. The msr is a readonly node msr, but a new value can be written via pci config space access. The reinitialization is implemented for family 10h in setup_ibs_ctl() which is forced during IBS setup. This patch fixes IBS setup after waking up from S3 by adding resume/supend hooks for the boot cpu which does the offset reinitialization. Marking it as stable to let distros pick up this fix. Signed-off-by: Robert Richter <rric@kernel.org> Signed-off-by: Peter Zijlstra <peterz@infradead.org> Cc: <stable@vger.kernel.org> v3.2.. Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: http://lkml.kernel.org/r/1389797849-5565-1-git-send-email-rric.net@gmail.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent c026b35 commit bee09ed

File tree

1 file changed

+45
-8
lines changed

1 file changed

+45
-8
lines changed

Diff for: arch/x86/kernel/cpu/perf_event_amd_ibs.c

+45-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/module.h>
1111
#include <linux/pci.h>
1212
#include <linux/ptrace.h>
13+
#include <linux/syscore_ops.h>
1314

1415
#include <asm/apic.h>
1516

@@ -816,6 +817,18 @@ static int force_ibs_eilvt_setup(void)
816817
return ret;
817818
}
818819

820+
static void ibs_eilvt_setup(void)
821+
{
822+
/*
823+
* Force LVT offset assignment for family 10h: The offsets are
824+
* not assigned by the BIOS for this family, so the OS is
825+
* responsible for doing it. If the OS assignment fails, fall
826+
* back to BIOS settings and try to setup this.
827+
*/
828+
if (boot_cpu_data.x86 == 0x10)
829+
force_ibs_eilvt_setup();
830+
}
831+
819832
static inline int get_ibs_lvt_offset(void)
820833
{
821834
u64 val;
@@ -851,6 +864,36 @@ static void clear_APIC_ibs(void *dummy)
851864
setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
852865
}
853866

867+
#ifdef CONFIG_PM
868+
869+
static int perf_ibs_suspend(void)
870+
{
871+
clear_APIC_ibs(NULL);
872+
return 0;
873+
}
874+
875+
static void perf_ibs_resume(void)
876+
{
877+
ibs_eilvt_setup();
878+
setup_APIC_ibs(NULL);
879+
}
880+
881+
static struct syscore_ops perf_ibs_syscore_ops = {
882+
.resume = perf_ibs_resume,
883+
.suspend = perf_ibs_suspend,
884+
};
885+
886+
static void perf_ibs_pm_init(void)
887+
{
888+
register_syscore_ops(&perf_ibs_syscore_ops);
889+
}
890+
891+
#else
892+
893+
static inline void perf_ibs_pm_init(void) { }
894+
895+
#endif
896+
854897
static int
855898
perf_ibs_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
856899
{
@@ -877,18 +920,12 @@ static __init int amd_ibs_init(void)
877920
if (!caps)
878921
return -ENODEV; /* ibs not supported by the cpu */
879922

880-
/*
881-
* Force LVT offset assignment for family 10h: The offsets are
882-
* not assigned by the BIOS for this family, so the OS is
883-
* responsible for doing it. If the OS assignment fails, fall
884-
* back to BIOS settings and try to setup this.
885-
*/
886-
if (boot_cpu_data.x86 == 0x10)
887-
force_ibs_eilvt_setup();
923+
ibs_eilvt_setup();
888924

889925
if (!ibs_eilvt_valid())
890926
goto out;
891927

928+
perf_ibs_pm_init();
892929
get_online_cpus();
893930
ibs_caps = caps;
894931
/* make ibs_caps visible to other cpus: */

0 commit comments

Comments
 (0)