[MIPS] vpe: handle halting TCs in an errata safe way.
authorNigel Stephens <nigel@mips.com>
Thu, 8 Nov 2007 13:25:51 +0000 (13:25 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 15 Nov 2007 23:21:50 +0000 (23:21 +0000)
Adds a JR.HB after halting a TC, to ensure that the TC has really halted.
only modifies the TCSTATUS register when the TC is safely halted.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/vpe.c

index 436a64ff3989485feebd20b388212b832738f37f..38bd33fa2a23ae123a6bb725a58197115d3cc281 100644 (file)
@@ -1003,6 +1003,7 @@ static void cleanup_tc(struct tc *tc)
        write_tc_c0_tcstatus(tmp);
 
        write_tc_c0_tchalt(TCHALT_H);
        write_tc_c0_tcstatus(tmp);
 
        write_tc_c0_tchalt(TCHALT_H);
+       mips_ihb();
 
        /* bind it to anything other than VPE1 */
 //     write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
 
        /* bind it to anything other than VPE1 */
 //     write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
@@ -1235,9 +1236,12 @@ int vpe_free(vpe_handle vpe)
        settc(t->index);
        write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
 
        settc(t->index);
        write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
 
-       /* mark the TC unallocated and halt'ed */
-       write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
+       /* halt the TC */
        write_tc_c0_tchalt(TCHALT_H);
        write_tc_c0_tchalt(TCHALT_H);
+       mips_ihb();
+
+       /* mark the TC unallocated */
+       write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
 
        v->state = VPE_STATE_UNUSED;
 
 
        v->state = VPE_STATE_UNUSED;
 
@@ -1533,14 +1537,16 @@ static int __init vpe_module_init(void)
                                t->pvpe = get_vpe(0);   /* set the parent vpe */
                        }
 
                                t->pvpe = get_vpe(0);   /* set the parent vpe */
                        }
 
+                       /* halt the TC */
+                       write_tc_c0_tchalt(TCHALT_H);
+                       mips_ihb();
+
                        tmp = read_tc_c0_tcstatus();
 
                        /* mark not activated and not dynamically allocatable */
                        tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
                        tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
                        write_tc_c0_tcstatus(tmp);
                        tmp = read_tc_c0_tcstatus();
 
                        /* mark not activated and not dynamically allocatable */
                        tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
                        tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
                        write_tc_c0_tcstatus(tmp);
-
-                       write_tc_c0_tchalt(TCHALT_H);
                }
        }
 
                }
        }