|
@@ -10,6 +10,7 @@
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/pci.h>
|
|
|
#include <linux/ptrace.h>
|
|
|
+#include <linux/syscore_ops.h>
|
|
|
|
|
|
#include <asm/apic.h>
|
|
|
|
|
@@ -816,6 +817,18 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static void ibs_eilvt_setup(void)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Force LVT offset assignment for family 10h: The offsets are
|
|
|
+ * not assigned by the BIOS for this family, so the OS is
|
|
|
+ * responsible for doing it. If the OS assignment fails, fall
|
|
|
+ * back to BIOS settings and try to setup this.
|
|
|
+ */
|
|
|
+ if (boot_cpu_data.x86 == 0x10)
|
|
|
+ force_ibs_eilvt_setup();
|
|
|
+}
|
|
|
+
|
|
|
static inline int get_ibs_lvt_offset(void)
|
|
|
{
|
|
|
u64 val;
|
|
@@ -851,6 +864,36 @@ static void clear_APIC_ibs(void *dummy)
|
|
|
setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
+
|
|
|
+static int perf_ibs_suspend(void)
|
|
|
+{
|
|
|
+ clear_APIC_ibs(NULL);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void perf_ibs_resume(void)
|
|
|
+{
|
|
|
+ ibs_eilvt_setup();
|
|
|
+ setup_APIC_ibs(NULL);
|
|
|
+}
|
|
|
+
|
|
|
+static struct syscore_ops perf_ibs_syscore_ops = {
|
|
|
+ .resume = perf_ibs_resume,
|
|
|
+ .suspend = perf_ibs_suspend,
|
|
|
+};
|
|
|
+
|
|
|
+static void perf_ibs_pm_init(void)
|
|
|
+{
|
|
|
+ register_syscore_ops(&perf_ibs_syscore_ops);
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+static inline void perf_ibs_pm_init(void) { }
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
static int
|
|
|
perf_ibs_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
|
|
|
{
|
|
@@ -877,18 +920,12 @@ static __init int amd_ibs_init(void)
|
|
|
if (!caps)
|
|
|
return -ENODEV; /* ibs not supported by the cpu */
|
|
|
|
|
|
- /*
|
|
|
- * Force LVT offset assignment for family 10h: The offsets are
|
|
|
- * not assigned by the BIOS for this family, so the OS is
|
|
|
- * responsible for doing it. If the OS assignment fails, fall
|
|
|
- * back to BIOS settings and try to setup this.
|
|
|
- */
|
|
|
- if (boot_cpu_data.x86 == 0x10)
|
|
|
- force_ibs_eilvt_setup();
|
|
|
+ ibs_eilvt_setup();
|
|
|
|
|
|
if (!ibs_eilvt_valid())
|
|
|
goto out;
|
|
|
|
|
|
+ perf_ibs_pm_init();
|
|
|
get_online_cpus();
|
|
|
ibs_caps = caps;
|
|
|
/* make ibs_caps visible to other cpus: */
|