* flush all L1 entries at first. Then, another core (usually Core 0) can
  * safely disable the clock of the target core. loongson3_play_dead() is
  * called via CKSEG1 (uncached and unmmaped) */
-static void loongson3a_r1_play_dead(int *state_addr)
+static void loongson3_type1_play_dead(int *state_addr)
 {
        register int val;
        register long cpuid, core, node, count;
                : "a1");
 }
 
-static void loongson3a_r2r3_play_dead(int *state_addr)
+static void loongson3_type2_play_dead(int *state_addr)
 {
        register int val;
        register long cpuid, core, node, count;
                "   cache 1, 3(%[addr])           \n"
                "   addiu %[sets], %[sets], -1    \n"
                "   bnez  %[sets], 1b             \n"
-               "   addiu %[addr], %[addr], 0x40  \n"
-               "   li %[addr], 0x80000000        \n" /* KSEG0 */
-               "2: cache 2, 0(%[addr])           \n" /* flush L1 VCache */
-               "   cache 2, 1(%[addr])           \n"
-               "   cache 2, 2(%[addr])           \n"
-               "   cache 2, 3(%[addr])           \n"
-               "   cache 2, 4(%[addr])           \n"
-               "   cache 2, 5(%[addr])           \n"
-               "   cache 2, 6(%[addr])           \n"
-               "   cache 2, 7(%[addr])           \n"
-               "   cache 2, 8(%[addr])           \n"
-               "   cache 2, 9(%[addr])           \n"
-               "   cache 2, 10(%[addr])          \n"
-               "   cache 2, 11(%[addr])          \n"
-               "   cache 2, 12(%[addr])          \n"
-               "   cache 2, 13(%[addr])          \n"
-               "   cache 2, 14(%[addr])          \n"
-               "   cache 2, 15(%[addr])          \n"
-               "   addiu %[vsets], %[vsets], -1  \n"
-               "   bnez  %[vsets], 2b            \n"
-               "   addiu %[addr], %[addr], 0x40  \n"
+               "   addiu %[addr], %[addr], 0x20  \n"
                "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
                "   sw    %[val], (%[state_addr]) \n"
                "   sync                          \n"
                "   .set pop                      \n"
                : [addr] "=&r" (addr), [val] "=&r" (val)
                : [state_addr] "r" (state_addr),
-                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets),
-                 [vsets] "r" (cpu_data[smp_processor_id()].vcache.sets));
+                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
 
        __asm__ __volatile__(
                "   .set push                         \n"
                "   andi  %[node], %[cpuid], 0xc      \n"
                "   dsll  %[node], 42                 \n" /* get node id */
                "   or    %[base], %[base], %[node]   \n"
+               "   dsrl  %[node], 30                 \n" /* 15:14 */
+               "   or    %[base], %[base], %[node]   \n"
                "1: li    %[count], 0x100             \n" /* wait for init loop */
                "2: bnez  %[count], 2b                \n" /* limit mailbox access */
                "   addiu %[count], -1                \n"
                : "a1");
 }
 
-static void loongson3b_play_dead(int *state_addr)
+static void loongson3_type3_play_dead(int *state_addr)
 {
        register int val;
        register long cpuid, core, node, count;
                "   cache 1, 3(%[addr])           \n"
                "   addiu %[sets], %[sets], -1    \n"
                "   bnez  %[sets], 1b             \n"
-               "   addiu %[addr], %[addr], 0x20  \n"
+               "   addiu %[addr], %[addr], 0x40  \n"
+               "   li %[addr], 0x80000000        \n" /* KSEG0 */
+               "2: cache 2, 0(%[addr])           \n" /* flush L1 VCache */
+               "   cache 2, 1(%[addr])           \n"
+               "   cache 2, 2(%[addr])           \n"
+               "   cache 2, 3(%[addr])           \n"
+               "   cache 2, 4(%[addr])           \n"
+               "   cache 2, 5(%[addr])           \n"
+               "   cache 2, 6(%[addr])           \n"
+               "   cache 2, 7(%[addr])           \n"
+               "   cache 2, 8(%[addr])           \n"
+               "   cache 2, 9(%[addr])           \n"
+               "   cache 2, 10(%[addr])          \n"
+               "   cache 2, 11(%[addr])          \n"
+               "   cache 2, 12(%[addr])          \n"
+               "   cache 2, 13(%[addr])          \n"
+               "   cache 2, 14(%[addr])          \n"
+               "   cache 2, 15(%[addr])          \n"
+               "   addiu %[vsets], %[vsets], -1  \n"
+               "   bnez  %[vsets], 2b            \n"
+               "   addiu %[addr], %[addr], 0x40  \n"
                "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
                "   sw    %[val], (%[state_addr]) \n"
                "   sync                          \n"
                "   .set pop                      \n"
                : [addr] "=&r" (addr), [val] "=&r" (val)
                : [state_addr] "r" (state_addr),
-                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
+                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets),
+                 [vsets] "r" (cpu_data[smp_processor_id()].vcache.sets));
 
        __asm__ __volatile__(
                "   .set push                         \n"
                "   andi  %[node], %[cpuid], 0xc      \n"
                "   dsll  %[node], 42                 \n" /* get node id */
                "   or    %[base], %[base], %[node]   \n"
-               "   dsrl  %[node], 30                 \n" /* 15:14 */
-               "   or    %[base], %[base], %[node]   \n"
                "1: li    %[count], 0x100             \n" /* wait for init loop */
                "2: bnez  %[count], 2b                \n" /* limit mailbox access */
                "   addiu %[count], -1                \n"
 
 void play_dead(void)
 {
-       int *state_addr;
+       int prid_imp, prid_rev, *state_addr;
        unsigned int cpu = smp_processor_id();
        void (*play_dead_at_ckseg1)(int *);
 
        idle_task_exit();
-       switch (read_c0_prid() & PRID_REV_MASK) {
+
+       prid_imp = read_c0_prid() & PRID_IMP_MASK;
+       prid_rev = read_c0_prid() & PRID_REV_MASK;
+
+       if (prid_imp == PRID_IMP_LOONGSON_64G) {
+               play_dead_at_ckseg1 =
+                       (void *)CKSEG1ADDR((unsigned long)loongson3_type3_play_dead);
+               goto out;
+       }
+
+       switch (prid_rev) {
        case PRID_REV_LOONGSON3A_R1:
        default:
                play_dead_at_ckseg1 =
-                       (void *)CKSEG1ADDR((unsigned long)loongson3a_r1_play_dead);
+                       (void *)CKSEG1ADDR((unsigned long)loongson3_type1_play_dead);
+               break;
+       case PRID_REV_LOONGSON3B_R1:
+       case PRID_REV_LOONGSON3B_R2:
+               play_dead_at_ckseg1 =
+                       (void *)CKSEG1ADDR((unsigned long)loongson3_type2_play_dead);
                break;
        case PRID_REV_LOONGSON3A_R2_0:
        case PRID_REV_LOONGSON3A_R2_1:
        case PRID_REV_LOONGSON3A_R3_0:
        case PRID_REV_LOONGSON3A_R3_1:
                play_dead_at_ckseg1 =
-                       (void *)CKSEG1ADDR((unsigned long)loongson3a_r2r3_play_dead);
-               break;
-       case PRID_REV_LOONGSON3B_R1:
-       case PRID_REV_LOONGSON3B_R2:
-               play_dead_at_ckseg1 =
-                       (void *)CKSEG1ADDR((unsigned long)loongson3b_play_dead);
+                       (void *)CKSEG1ADDR((unsigned long)loongson3_type3_play_dead);
                break;
        }
+
+out:
        state_addr = &per_cpu(cpu_state, cpu);
        mb();
        play_dead_at_ckseg1(state_addr);