summaryrefslogtreecommitdiff
path: root/arch/loongarch
diff options
context:
space:
mode:
authorWANG Xuerui <git@xen0n.name>2023-05-01 17:19:27 +0800
committerHuacai Chen <chenhuacai@loongson.cn>2023-05-01 17:19:27 +0800
commit98b90ede59472de5931b7e4d72c3ff948eaa19a4 (patch)
treec600622d80165cd026500e77625b798764408dd1 /arch/loongarch
parent5e3e784d35c41ca21251f92c243780c791100b02 (diff)
downloadlinux-98b90ede59472de5931b7e4d72c3ff948eaa19a4.tar.gz
LoongArch: Humanize the ESTAT line when showing registers
Example output looks like: [ xx.xxxxxx] ESTAT: 00001000 [INT] (IS=12 ECode=0 EsubCode=0) Signed-off-by: WANG Xuerui <git@xen0n.name> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Diffstat (limited to 'arch/loongarch')
-rw-r--r--arch/loongarch/kernel/traps.c82
1 files changed, 75 insertions, 7 deletions
diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
index 6376997f2ae9..748fe2f9aed0 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -234,11 +234,83 @@ static void print_ecfg(unsigned long x)
pr_cont(" VS=%d)\n", (int) FIELD_GET(CSR_ECFG_VS, x));
}
+static const char *humanize_exc_name(unsigned int ecode, unsigned int esubcode)
+{
+ /*
+ * LoongArch users and developers are probably more familiar with
+ * those names found in the ISA manual, so we are going to print out
+ * the latter. This will require some mapping.
+ */
+ switch (ecode) {
+ case EXCCODE_RSV: return "INT";
+ case EXCCODE_TLBL: return "PIL";
+ case EXCCODE_TLBS: return "PIS";
+ case EXCCODE_TLBI: return "PIF";
+ case EXCCODE_TLBM: return "PME";
+ case EXCCODE_TLBNR: return "PNR";
+ case EXCCODE_TLBNX: return "PNX";
+ case EXCCODE_TLBPE: return "PPI";
+ case EXCCODE_ADE:
+ switch (esubcode) {
+ case EXSUBCODE_ADEF: return "ADEF";
+ case EXSUBCODE_ADEM: return "ADEM";
+ }
+ break;
+ case EXCCODE_ALE: return "ALE";
+ case EXCCODE_BCE: return "BCE";
+ case EXCCODE_SYS: return "SYS";
+ case EXCCODE_BP: return "BRK";
+ case EXCCODE_INE: return "INE";
+ case EXCCODE_IPE: return "IPE";
+ case EXCCODE_FPDIS: return "FPD";
+ case EXCCODE_LSXDIS: return "SXD";
+ case EXCCODE_LASXDIS: return "ASXD";
+ case EXCCODE_FPE:
+ switch (esubcode) {
+ case EXCSUBCODE_FPE: return "FPE";
+ case EXCSUBCODE_VFPE: return "VFPE";
+ }
+ break;
+ case EXCCODE_WATCH:
+ switch (esubcode) {
+ case EXCSUBCODE_WPEF: return "WPEF";
+ case EXCSUBCODE_WPEM: return "WPEM";
+ }
+ break;
+ case EXCCODE_BTDIS: return "BTD";
+ case EXCCODE_BTE: return "BTE";
+ case EXCCODE_GSPR: return "GSPR";
+ case EXCCODE_HVC: return "HVC";
+ case EXCCODE_GCM:
+ switch (esubcode) {
+ case EXCSUBCODE_GCSC: return "GCSC";
+ case EXCSUBCODE_GCHC: return "GCHC";
+ }
+ break;
+ /*
+ * The manual did not mention the EXCCODE_SE case, but print out it
+ * nevertheless.
+ */
+ case EXCCODE_SE: return "SE";
+ }
+
+ return "???";
+}
+
+static void print_estat(unsigned long x)
+{
+ unsigned int ecode = FIELD_GET(CSR_ESTAT_EXC, x);
+ unsigned int esubcode = FIELD_GET(CSR_ESTAT_ESUBCODE, x);
+
+ printk("ESTAT: %08lx [%s] (", x, humanize_exc_name(ecode, esubcode));
+ print_intr_fragment("IS", FIELD_GET(CSR_ESTAT_IS, x));
+ pr_cont(" ECode=%d EsubCode=%d)\n", (int) ecode, (int) esubcode);
+}
+
static void __show_regs(const struct pt_regs *regs)
{
const int field = 2 * sizeof(unsigned long);
- unsigned int excsubcode;
- unsigned int exccode;
+ unsigned int exccode = FIELD_GET(CSR_ESTAT_EXC, regs->csr_estat);
show_regs_print_info(KERN_DEFAULT);
@@ -279,11 +351,7 @@ static void __show_regs(const struct pt_regs *regs)
print_prmd(regs->csr_prmd);
print_euen(regs->csr_euen);
print_ecfg(regs->csr_ecfg);
- printk("ESTAT: %08lx\n", regs->csr_estat);
-
- exccode = ((regs->csr_estat) & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;
- excsubcode = ((regs->csr_estat) & CSR_ESTAT_ESUBCODE) >> CSR_ESTAT_ESUBCODE_SHIFT;
- printk("ExcCode : %x (SubCode %x)\n", exccode, excsubcode);
+ print_estat(regs->csr_estat);
if (exccode >= EXCCODE_TLBL && exccode <= EXCCODE_ALE)
printk("BadVA : %0*lx\n", field, regs->csr_badvaddr);