From 137877e4327075d839f15776cb6865ee171f2175 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 19 May 2015 09:50:32 +0100 Subject: MIPS: dump_tlb: Use tlbr hazard macros Use the new tlb read hazard macros from rather than the local BARRIER() macro which uses 7 ops regardless of the kernel configuration. We use mtc0_tlbr_hazard for the hazard between mtc0 to the index register and the tlbr, and tlb_read_hazard for the hazard between the tlbr and the mfc0 of the TLB registers written by tlbr. Signed-off-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10074/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'arch/mips/lib/dump_tlb.c') diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 32b9f21bfd85..a62dfacb60f7 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -40,12 +41,6 @@ static inline const char *msk2str(unsigned int mask) return ""; } -#define BARRIER() \ - __asm__ __volatile__( \ - ".set\tnoreorder\n\t" \ - "nop;nop;nop;nop;nop;nop;nop\n\t" \ - ".set\treorder"); - static void dump_tlb(int first, int last) { unsigned long s_entryhi, entryhi, asid; @@ -59,9 +54,9 @@ static void dump_tlb(int first, int last) for (i = first; i <= last; i++) { write_c0_index(i); - BARRIER(); + mtc0_tlbr_hazard(); tlb_read(); - BARRIER(); + tlb_read_hazard(); pagemask = read_c0_pagemask(); entryhi = read_c0_entryhi(); entrylo0 = read_c0_entrylo0(); -- cgit v1.2.3 From d1ce483e45ba86bc3b59ba46cca9ad044b09051e Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 19 May 2015 09:50:33 +0100 Subject: MIPS: dump_tlb: Refactor TLB matching Refactor the TLB matching code in dump_tlb() slightly so that the conditions which can cause a TLB entry to be skipped can be more easily extended. This should prevent the match condition getting unwieldy once it is updated to take further conditions into account. Signed-off-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10081/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 65 ++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 30 deletions(-) (limited to 'arch/mips/lib/dump_tlb.c') diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index a62dfacb60f7..17d05caa776d 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -46,6 +46,11 @@ static void dump_tlb(int first, int last) unsigned long s_entryhi, entryhi, asid; unsigned long long entrylo0, entrylo1; unsigned int s_index, s_pagemask, pagemask, c0, c1, i; +#ifdef CONFIG_32BIT + int width = 8; +#else + int width = 11; +#endif s_pagemask = read_c0_pagemask(); s_entryhi = read_c0_entryhi(); @@ -62,38 +67,38 @@ static void dump_tlb(int first, int last) entrylo0 = read_c0_entrylo0(); entrylo1 = read_c0_entrylo1(); - /* Unused entries have a virtual address of CKSEG0. */ - if ((entryhi & ~0x1ffffUL) != CKSEG0 - && (entryhi & 0xff) == asid) { -#ifdef CONFIG_32BIT - int width = 8; -#else - int width = 11; -#endif - /* - * Only print entries in use - */ - printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); + /* + * Prior to tlbinv, unused entries have a virtual address of + * CKSEG0. + */ + if ((entryhi & ~0x1ffffUL) == CKSEG0) + continue; + if ((entryhi & 0xff) != asid) + continue; + + /* + * Only print entries in use + */ + printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); - c0 = (entrylo0 >> 3) & 7; - c1 = (entrylo1 >> 3) & 7; + c0 = (entrylo0 >> 3) & 7; + c1 = (entrylo1 >> 3) & 7; - printk("va=%0*lx asid=%02lx\n", - width, (entryhi & ~0x1fffUL), - entryhi & 0xff); - printk("\t[pa=%0*llx c=%d d=%d v=%d g=%d] ", - width, - (entrylo0 << 6) & PAGE_MASK, c0, - (entrylo0 & 4) ? 1 : 0, - (entrylo0 & 2) ? 1 : 0, - (entrylo0 & 1) ? 1 : 0); - printk("[pa=%0*llx c=%d d=%d v=%d g=%d]\n", - width, - (entrylo1 << 6) & PAGE_MASK, c1, - (entrylo1 & 4) ? 1 : 0, - (entrylo1 & 2) ? 1 : 0, - (entrylo1 & 1) ? 1 : 0); - } + printk("va=%0*lx asid=%02lx\n", + width, (entryhi & ~0x1fffUL), + entryhi & 0xff); + printk("\t[pa=%0*llx c=%d d=%d v=%d g=%d] ", + width, + (entrylo0 << 6) & PAGE_MASK, c0, + (entrylo0 & 4) ? 1 : 0, + (entrylo0 & 2) ? 1 : 0, + (entrylo0 & 1) ? 1 : 0); + printk("[pa=%0*llx c=%d d=%d v=%d g=%d]\n", + width, + (entrylo1 << 6) & PAGE_MASK, c1, + (entrylo1 & 4) ? 1 : 0, + (entrylo1 & 2) ? 1 : 0, + (entrylo1 & 1) ? 1 : 0); } printk("\n"); -- cgit v1.2.3 From d7f5499dc22fbb45e9e6bab53be5e3b241122444 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 19 May 2015 09:50:34 +0100 Subject: MIPS: dump_tlb: Make use of EntryLo bit definitions Make use of recently added EntryLo bit definitions in mipsregs.h when dumping TLB contents. Signed-off-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10075/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 16 ++++++++-------- arch/mips/lib/r3k_dump_tlb.c | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'arch/mips/lib/dump_tlb.c') diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 17d05caa776d..f02cc554d720 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -81,8 +81,8 @@ static void dump_tlb(int first, int last) */ printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); - c0 = (entrylo0 >> 3) & 7; - c1 = (entrylo1 >> 3) & 7; + c0 = (entrylo0 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; + c1 = (entrylo1 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; printk("va=%0*lx asid=%02lx\n", width, (entryhi & ~0x1fffUL), @@ -90,15 +90,15 @@ static void dump_tlb(int first, int last) printk("\t[pa=%0*llx c=%d d=%d v=%d g=%d] ", width, (entrylo0 << 6) & PAGE_MASK, c0, - (entrylo0 & 4) ? 1 : 0, - (entrylo0 & 2) ? 1 : 0, - (entrylo0 & 1) ? 1 : 0); + (entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0, + (entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0, + (entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0); printk("[pa=%0*llx c=%d d=%d v=%d g=%d]\n", width, (entrylo1 << 6) & PAGE_MASK, c1, - (entrylo1 & 4) ? 1 : 0, - (entrylo1 & 2) ? 1 : 0, - (entrylo1 & 1) ? 1 : 0); + (entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0, + (entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0, + (entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0); } printk("\n"); diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index 975a13855116..e210f04b2bc3 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -47,10 +47,10 @@ static void dump_tlb(int first, int last) entryhi & PAGE_MASK, entryhi & ASID_MASK, entrylo0 & PAGE_MASK, - (entrylo0 & (1 << 11)) ? 1 : 0, - (entrylo0 & (1 << 10)) ? 1 : 0, - (entrylo0 & (1 << 9)) ? 1 : 0, - (entrylo0 & (1 << 8)) ? 1 : 0); + (entrylo0 & R3K_ENTRYLO_N) ? 1 : 0, + (entrylo0 & R3K_ENTRYLO_D) ? 1 : 0, + (entrylo0 & R3K_ENTRYLO_V) ? 1 : 0, + (entrylo0 & R3K_ENTRYLO_G) ? 1 : 0); } } printk("\n"); -- cgit v1.2.3 From 48269c78fb04a84b4d190cac8e1fbf24ded53505 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 19 May 2015 09:50:35 +0100 Subject: MIPS: dump_tlb: Take global bit into account The TLB only matches the ASID when the global bit isn't set, so dump_tlb() shouldn't really be skipping global entries just because the ASID doesn't match. Fix the condition to read the TLB entry's global bit from EntryLo0. Note that after a TLB read the global bits in both EntryLo registers reflect the same global bit in the TLB entry. Signed-off-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10079/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 10 +++++++++- arch/mips/lib/r3k_dump_tlb.c | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'arch/mips/lib/dump_tlb.c') diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index f02cc554d720..995c393e3342 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -73,7 +73,15 @@ static void dump_tlb(int first, int last) */ if ((entryhi & ~0x1ffffUL) == CKSEG0) continue; - if ((entryhi & 0xff) != asid) + /* + * ASID takes effect in absence of G (global) bit. + * We check both G bits, even though architecturally they should + * match one another, because some revisions of the SB1 core may + * leave only a single G bit set after a machine check exception + * due to duplicate TLB entry. + */ + if (!((entrylo0 | entrylo1) & MIPS_ENTRYLO_G) && + (entryhi & 0xff) != asid) continue; /* diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index e210f04b2bc3..1335e4394e33 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -35,8 +35,9 @@ static void dump_tlb(int first, int last) entrylo0 = read_c0_entrylo0(); /* Unused entries have a virtual address of KSEG0. */ - if ((entryhi & PAGE_MASK) != KSEG0 - && (entryhi & ASID_MASK) == asid) { + if ((entryhi & PAGE_MASK) != KSEG0 && + (entrylo0 & R3K_ENTRYLO_G || + (entryhi & ASID_MASK) == asid)) { /* * Only print entries in use */ -- cgit v1.2.3 From decebccd76e4da9bb096962c230b6ed740606e49 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 19 May 2015 09:50:36 +0100 Subject: MIPS: dump_tlb: Take EHINV bit into account The EHINV bit in EntryHi allows a TLB entry to be properly marked invalid so that EntryHi doesn't have to be set to a unique value to avoid machine check exceptions due to multiple matching entries. Unfortunately dump_tlb() doesn't take this into account so it will print all the uninteresting invalid TLB entries if the current ASID happens to be 00. Therefore add a condition to skip entries which are marked invalid with the EHINV bit. Signed-off-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10076/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/mips/lib/dump_tlb.c') diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 995c393e3342..3bcdd53c832f 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -67,6 +67,9 @@ static void dump_tlb(int first, int last) entrylo0 = read_c0_entrylo0(); entrylo1 = read_c0_entrylo1(); + /* EHINV bit marks entire entry as invalid */ + if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV) + continue; /* * Prior to tlbinv, unused entries have a virtual address of * CKSEG0. -- cgit v1.2.3 From c2bc435e4f2cd5f010063b49f68e5b2cfaccc84e Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 19 May 2015 09:50:37 +0100 Subject: MIPS: dump_tlb: Take RI/XI bits into account The RI/XI bits when present are above the PFN field in the EntryLo registers, at bits 63,62 when read with dmfc0, and bits 31,30 when read with mfc0. This makes them appear as part of the physical address, since the other bits are masked with PAGE_MASK, for example: Index: 253 pgmask=16kb va=77b18000 asid=75 [pa=1000744000 c=5 d=1 v=1 g=0] [pa=100134c000 c=5 d=1 v=1 g=0] The physical addresses have bit 36 set, which corresponds to bit 30 of EntryLo1, the XI bit. Explicitly mask off the RI and XI bits from the printed physical address, and print the RI and XI bits separately if they exist, giving output more like this: Index: 226 pgmask=16kb va=77be0000 asid=79 [ri=0 xi=1 pa=01288000 c=5 d=1 v=1 g=0] [ri=0 xi=0 pa=010e4000 c=5 d=0 v=1 g=0] Cc: linux-mips@linux-mips.org Cc: James Hogan Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/10080/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'arch/mips/lib/dump_tlb.c') diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 3bcdd53c832f..1fefd38aba08 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -44,7 +44,7 @@ static inline const char *msk2str(unsigned int mask) static void dump_tlb(int first, int last) { unsigned long s_entryhi, entryhi, asid; - unsigned long long entrylo0, entrylo1; + unsigned long long entrylo0, entrylo1, pa; unsigned int s_index, s_pagemask, pagemask, c0, c1, i; #ifdef CONFIG_32BIT int width = 8; @@ -98,15 +98,28 @@ static void dump_tlb(int first, int last) printk("va=%0*lx asid=%02lx\n", width, (entryhi & ~0x1fffUL), entryhi & 0xff); - printk("\t[pa=%0*llx c=%d d=%d v=%d g=%d] ", - width, - (entrylo0 << 6) & PAGE_MASK, c0, + /* RI/XI are in awkward places, so mask them off separately */ + pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); + pa = (pa << 6) & PAGE_MASK; + printk("\t["); + if (cpu_has_rixi) + printk("ri=%d xi=%d ", + (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0, + (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); + printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", + width, pa, c0, (entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0, (entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0, (entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0); - printk("[pa=%0*llx c=%d d=%d v=%d g=%d]\n", - width, - (entrylo1 << 6) & PAGE_MASK, c1, + /* RI/XI are in awkward places, so mask them off separately */ + pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); + pa = (pa << 6) & PAGE_MASK; + if (cpu_has_rixi) + printk("ri=%d xi=%d ", + (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0, + (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); + printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", + width, pa, c1, (entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0, (entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0, (entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0); -- cgit v1.2.3 From 24ca1d9896bb9bbd7625e3596bac4ea2fe74c725 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 19 May 2015 09:50:38 +0100 Subject: MIPS: dump_tlb: Take XPA into account XPA extends the physical addresses on MIPS32, including the EntryLo registers. Update dump_tlb() to concatenate the PFNX field from the high end of the EntryLo registers (as read by mfhc0). The width of physical and virtual addresses are also separated to show only 8 nibbles of virtual but 11 nibbles of physical with XPA. Signed-off-by: James Hogan Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10077/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'arch/mips/lib/dump_tlb.c') diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 1fefd38aba08..167f35634709 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -47,9 +47,13 @@ static void dump_tlb(int first, int last) unsigned long long entrylo0, entrylo1, pa; unsigned int s_index, s_pagemask, pagemask, c0, c1, i; #ifdef CONFIG_32BIT - int width = 8; + bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA); + int pwidth = xpa ? 11 : 8; + int vwidth = 8; #else - int width = 11; + bool xpa = false; + int pwidth = 11; + int vwidth = 11; #endif s_pagemask = read_c0_pagemask(); @@ -96,10 +100,12 @@ static void dump_tlb(int first, int last) c1 = (entrylo1 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; printk("va=%0*lx asid=%02lx\n", - width, (entryhi & ~0x1fffUL), + vwidth, (entryhi & ~0x1fffUL), entryhi & 0xff); /* RI/XI are in awkward places, so mask them off separately */ pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); + if (xpa) + pa |= (unsigned long long)readx_c0_entrylo0() << 30; pa = (pa << 6) & PAGE_MASK; printk("\t["); if (cpu_has_rixi) @@ -107,19 +113,21 @@ static void dump_tlb(int first, int last) (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0, (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", - width, pa, c0, + pwidth, pa, c0, (entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0, (entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0, (entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0); /* RI/XI are in awkward places, so mask them off separately */ pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); + if (xpa) + pa |= (unsigned long long)readx_c0_entrylo1() << 30; pa = (pa << 6) & PAGE_MASK; if (cpu_has_rixi) printk("ri=%d xi=%d ", (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0, (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", - width, pa, c1, + pwidth, pa, c1, (entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0, (entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0, (entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0); -- cgit v1.2.3