[PATCH] tlbex: Deal with re-definition of label

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The microassembler used in tlbex.c does not notice if a label is redefined
resulting in relocations against such labels silently missrelocated.
The issues exists since commit add6eb04776db4189ea89f596cbcde31b899be9d
[Synthesize TLB exception handlers at runtime.] in 2.6.10 and went unnoticed
for so long because the relocations for the affected branches got computed
to do something *almost* sensible.

Over the past years there have been a few very mysterious reports about
weird things happening on QED/IDT RM5231 / RM5261 processors; I have
a little hope this bug might be the solution.  R4000/R4400 processors
are equally affected.

The fix is a bit cheesy.  Among other reasons this is because this was
easier to implement than a gas-like local label feature and also because
it gets away without a memory allocator.

Please test this.  Thanks,

  Ralf

Signed-off-by: Ralf Baechle <ralf@xxxxxxxxxxxxxx>

diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 42a5d55..1128c7a 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -147,7 +147,14 @@ enum label_id {
 	label_leave,
 	label_vmalloc,
 	label_vmalloc_done,
-	label_tlbw_hazard,
+	label_tlbw_hazard_0,
+	label_tlbw_hazard_1,
+	label_tlbw_hazard_2,
+	label_tlbw_hazard_3,
+	label_tlbw_hazard_4,
+	label_tlbw_hazard_5,
+	label_tlbw_hazard_6,
+	label_tlbw_hazard_7,
 	label_split,
 	label_tlbl_goaround1,
 	label_tlbl_goaround2,
@@ -166,7 +173,14 @@ UASM_L_LA(_second_part)
 UASM_L_LA(_leave)
 UASM_L_LA(_vmalloc)
 UASM_L_LA(_vmalloc_done)
-UASM_L_LA(_tlbw_hazard)
+UASM_L_LA(_tlbw_hazard_0)
+UASM_L_LA(_tlbw_hazard_1)
+UASM_L_LA(_tlbw_hazard_2)
+UASM_L_LA(_tlbw_hazard_3)
+UASM_L_LA(_tlbw_hazard_4)
+UASM_L_LA(_tlbw_hazard_5)
+UASM_L_LA(_tlbw_hazard_6)
+UASM_L_LA(_tlbw_hazard_7)
 UASM_L_LA(_split)
 UASM_L_LA(_tlbl_goaround1)
 UASM_L_LA(_tlbl_goaround2)
@@ -180,6 +194,72 @@ UASM_L_LA(_large_segbits_fault)
 UASM_L_LA(_tlb_huge_update)
 #endif
 
+static int hazard_instance;
+
+static void uasm_bgezl_hazard(u32 **p, struct uasm_reloc **r, int instance)
+{
+	switch (instance) {
+	case 0:
+		uasm_il_bgezl(p, r, 0, label_tlbw_hazard_0);
+		return;
+	case 1:
+		uasm_il_bgezl(p, r, 0, label_tlbw_hazard_1);
+		return;
+	case 2:
+		uasm_il_bgezl(p, r, 0, label_tlbw_hazard_2);
+		return;
+	case 3:
+		uasm_il_bgezl(p, r, 0, label_tlbw_hazard_3);
+		return;
+	case 4:
+		uasm_il_bgezl(p, r, 0, label_tlbw_hazard_4);
+		return;
+	case 5:
+		uasm_il_bgezl(p, r, 0, label_tlbw_hazard_5);
+		return;
+	case 6:
+		uasm_il_bgezl(p, r, 0, label_tlbw_hazard_6);
+		return;
+	case 7:
+		uasm_il_bgezl(p, r, 0, label_tlbw_hazard_7);
+		return;
+	default:
+		BUG();
+	}
+}
+
+static void uasm_bgezl_label(struct uasm_label **l, u32 **p, int instance)
+{
+	switch (instance) {
+	case 0:
+		uasm_l_tlbw_hazard_0(l, *p);
+		break;
+	case 1:
+		uasm_l_tlbw_hazard_1(l, *p);
+		break;
+	case 2:
+		uasm_l_tlbw_hazard_2(l, *p);
+		break;
+	case 3:
+		uasm_l_tlbw_hazard_3(l, *p);
+		break;
+	case 4:
+		uasm_l_tlbw_hazard_4(l, *p);
+		break;
+	case 5:
+		uasm_l_tlbw_hazard_5(l, *p);
+		break;
+	case 6:
+		uasm_l_tlbw_hazard_6(l, *p);
+		break;
+	case 7:
+		uasm_l_tlbw_hazard_7(l, *p);
+		break;
+	default:
+		BUG();
+	}
+}
+
 /*
  * For debug purposes.
  */
@@ -465,9 +545,10 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
 		 * This branch uses up a mtc0 hazard nop slot and saves
 		 * two nops after the tlbw instruction.
 		 */
-		uasm_il_bgezl(p, r, 0, label_tlbw_hazard);
+		uasm_bgezl_hazard(p, r, hazard_instance);
 		tlbw(p);
-		uasm_l_tlbw_hazard(l, *p);
+		uasm_bgezl_label(l, p, hazard_instance);
+		hazard_instance++;
 		uasm_i_nop(p);
 		break;
 
@@ -514,13 +595,15 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
 
 	case CPU_NEVADA:
 		uasm_i_nop(p); /* QED specifies 2 nops hazard */
+		uasm_i_nop(p); /* QED specifies 2 nops hazard */
 		/*
 		 * This branch uses up a mtc0 hazard nop slot and saves
 		 * a nop after the tlbw instruction.
 		 */
-		uasm_il_bgezl(p, r, 0, label_tlbw_hazard);
+		uasm_bgezl_hazard(p, r, hazard_instance);
 		tlbw(p);
-		uasm_l_tlbw_hazard(l, *p);
+		uasm_bgezl_label(l, p, hazard_instance);
+		hazard_instance++;
 		break;
 
 	case CPU_RM7000:



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux