LoongArch: Humanize the ESTAT line when showing registers
authorWANG Xuerui <git@xen0n.name>
Mon, 1 May 2023 09:19:27 +0000 (17:19 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Mon, 1 May 2023 09:19:27 +0000 (17:19 +0800)
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>
arch/loongarch/kernel/traps.c

index 6376997f2ae9b383064b07a32e9554db14ece5f6..748fe2f9aed06e066f1daa2ecb92340a0a2bf1bc 100644 (file)
@@ -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);