Skip to content

Instantly share code, notes, and snippets.

@pratiksampat
Last active March 18, 2021 11:05
Show Gist options
  • Save pratiksampat/65ae79de1dfdfe0bbb591de957296252 to your computer and use it in GitHub Desktop.
Save pratiksampat/65ae79de1dfdfe0bbb591de957296252 to your computer and use it in GitHub Desktop.
From 4249d4f851105d611f03f4cebd3fe3813f2fe82b Mon Sep 17 00:00:00 2001
From: Pratik Rajesh Sampat <psampat@linux.ibm.com>
Date: Thu, 18 Feb 2021 12:16:30 +0530
Subject: [PATCH] SPR analysis framework
Track the SPR values before sleep and after wakeup and verify their
correctness by adding into the following buckets:
1. match
2. no match
3. increasing
4. invalid
If more SPRs need to be added, they need go into the "spr_list[]" in
spr_analysis.h. These SPRs also need to be added to
(saved/restored)_sprs() too in the format
local_paca->saved_spr_val[SPRN_X] = mfspr(SPRN_X);
This is needed because mfpsr is a compile time macro and cannot be
iterated over in runtime.
Signed-off-by: Pratik Rajesh Sampat <psampat@linux.ibm.com>
---
arch/powerpc/include/asm/paca.h | 12 +++
arch/powerpc/platforms/powernv/Makefile | 2 +-
arch/powerpc/platforms/powernv/idle.c | 7 ++
arch/powerpc/platforms/powernv/spr_analysis.c | 82 +++++++++++++++++++
arch/powerpc/platforms/powernv/spr_analysis.h | 10 +++
5 files changed, 112 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/platforms/powernv/spr_analysis.c
create mode 100644 arch/powerpc/platforms/powernv/spr_analysis.h
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index ec18ac818e3a..1004c82ed4f9 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -55,6 +55,13 @@ extern unsigned int debug_smp_processor_id(void); /* from linux/smp.h */
struct task_struct;
struct rtas_args;
+typedef enum {
+ mtch,
+ no_match,
+ increasing,
+ invalid
+} compare_t;
+
/*
* Defines the layout of the paca.
*
@@ -204,6 +211,11 @@ struct paca_struct {
#endif
};
};
+ struct {
+ u64 saved_spr_val[1024];
+ u64 restored_spr_val[1024];
+ compare_t bucket[1024];
+ };
#endif
#ifdef CONFIG_PPC_BOOK3S_64
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 2eb6ae150d1f..2d6b29d048cc 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -4,7 +4,7 @@ obj-y += idle.o opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
obj-y += opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
obj-y += opal-kmsg.o opal-powercap.o opal-psr.o opal-sensor-groups.o
-obj-y += ultravisor.o
+obj-y += ultravisor.o spr_analysis.o
obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o
obj-$(CONFIG_FA_DUMP) += opal-fadump.o
diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c
index 999997d9e9a9..cfeb59b8084b 100644
--- a/arch/powerpc/platforms/powernv/idle.c
+++ b/arch/powerpc/platforms/powernv/idle.c
@@ -26,6 +26,7 @@
#include "powernv.h"
#include "subcore.h"
+#include "spr_analysis.h"
/* Power ISA 3.0 allows for stop states 0x0 - 0xF */
#define MAX_STOP_STATE 0xF
@@ -693,8 +694,13 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
sprs.amor = mfspr(SPRN_AMOR);
sprs.uamor = mfspr(SPRN_UAMOR);
+ saved_sprs();
+
srr1 = isa300_idle_stop_mayloss(psscr); /* go idle */
+ restored_sprs();
+ verify_sprs();
+ trace_printk_spr_results(cpu);
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
local_paca->requested_psscr = 0;
#endif
@@ -1533,6 +1539,7 @@ static int __init pnv_init_idle_states(void)
pnv_disable_deep_states();
}
+ init_spr_list();
out:
return 0;
}
diff --git a/arch/powerpc/platforms/powernv/spr_analysis.c b/arch/powerpc/platforms/powernv/spr_analysis.c
new file mode 100644
index 000000000000..986ab8f72bae
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/spr_analysis.c
@@ -0,0 +1,82 @@
+#include <asm/smp.h>
+#include <linux/of.h>
+
+#include "spr_analysis.h"
+
+u64 spr_list[] = {
+ SPRN_LPCR,
+ SPRN_PTCR,
+ SPRN_PSSCR
+};
+
+/*
+ * To be refactored to allow iteration on mfspr()
+ */
+void saved_sprs(void) {
+ local_paca->saved_spr_val[SPRN_LPCR] = mfspr(SPRN_LPCR);
+ local_paca->saved_spr_val[SPRN_PTCR] = mfspr(SPRN_PTCR);
+ local_paca->saved_spr_val[SPRN_PSSCR] = mfspr(SPRN_PSSCR);
+}
+
+void restored_sprs(void) {
+ local_paca->restored_spr_val[SPRN_LPCR] = mfspr(SPRN_LPCR);
+ local_paca->restored_spr_val[SPRN_PTCR] = mfspr(SPRN_PTCR);
+ local_paca->restored_spr_val[SPRN_PSSCR] = mfspr(SPRN_PSSCR);
+}
+
+void verify_sprs(void) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(spr_list); i++) {
+ if (local_paca->saved_spr_val[spr_list[i]] ==
+ local_paca->restored_spr_val[spr_list[i]])
+ local_paca->bucket[spr_list[i]] = mtch;
+ else if (local_paca->saved_spr_val[spr_list[i]] <=
+ local_paca->restored_spr_val[spr_list[i]])
+ local_paca->bucket[spr_list[i]] = increasing;
+ else
+ local_paca->bucket[spr_list[i]] = no_match;
+
+ }
+}
+
+void trace_printk_spr_results(int cpu) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(spr_list); i++) {
+ switch(local_paca->bucket[spr_list[i]]){
+ case mtch:
+ trace_printk("cpu=%d SPR=0x%llx status=OK::saved=0x%llx restored=0x%llx\n",
+ cpu, spr_list[i],
+ local_paca->saved_spr_val[spr_list[i]],
+ local_paca->restored_spr_val[spr_list[i]]);
+ break;
+ case increasing:
+ trace_printk("cpu=%d SPR=0x%llx status=Increasing::saved=0x%llx restored=0x%llx\n",
+ cpu, spr_list[i],
+ local_paca->saved_spr_val[spr_list[i]],
+ local_paca->restored_spr_val[spr_list[i]]);
+ break;
+ case no_match:
+ trace_printk("cpu=%d SPR=0x%llx status=No match::saved=0x%llx restored=0x%llx\n",
+ cpu, spr_list[i],
+ local_paca->saved_spr_val[spr_list[i]],
+ local_paca->restored_spr_val[spr_list[i]]);
+ break;
+ case invalid:
+ default:
+ trace_printk("cpu=%d SPR=0x%llx status=Invalid::saved=0x%llx restored=0x%llx\n",
+ cpu, spr_list[i],
+ local_paca->saved_spr_val[spr_list[i]],
+ local_paca->restored_spr_val[spr_list[i]]);
+ }
+ }
+}
+
+void init_spr_list(void) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(spr_list); i++) {
+ local_paca->saved_spr_val[spr_list[i]] = 0;
+ local_paca->restored_spr_val[spr_list[i]] = 0;
+ local_paca->bucket[spr_list[i]] = invalid;
+ }
+}
diff --git a/arch/powerpc/platforms/powernv/spr_analysis.h b/arch/powerpc/platforms/powernv/spr_analysis.h
new file mode 100644
index 000000000000..f7e1873a0736
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/spr_analysis.h
@@ -0,0 +1,10 @@
+#ifndef SPR_ANALYSIS_H
+#define SPR_ANALYSIS_H
+
+extern void saved_sprs(void);
+extern void restored_sprs(void);
+extern void verify_sprs(void);
+extern void init_spr_list(void);
+extern void trace_printk_spr_results(int);
+
+#endif
\ No newline at end of file
--
2.17.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment