linux/arch/mips/loongson64/loongson-3/smp.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010, 2011, 2012, Lemote, Inc.
   3 * Author: Chen Huacai, chenhc@lemote.com
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License
   7 * as published by the Free Software Foundation; either version 2
   8 * of the License, or (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 */
  16
  17#include <linux/init.h>
  18#include <linux/cpu.h>
  19#include <linux/sched.h>
  20#include <linux/sched/hotplug.h>
  21#include <linux/sched/task_stack.h>
  22#include <linux/smp.h>
  23#include <linux/cpufreq.h>
  24#include <asm/processor.h>
  25#include <asm/time.h>
  26#include <asm/clock.h>
  27#include <asm/tlbflush.h>
  28#include <asm/cacheflush.h>
  29#include <loongson.h>
  30#include <workarounds.h>
  31
  32#include "smp.h"
  33
  34DEFINE_PER_CPU(int, cpu_state);
  35
  36static void *ipi_set0_regs[16];
  37static void *ipi_clear0_regs[16];
  38static void *ipi_status0_regs[16];
  39static void *ipi_en0_regs[16];
  40static void *ipi_mailbox_buf[16];
  41static uint32_t core0_c0count[NR_CPUS];
  42
  43/* read a 32bit value from ipi register */
  44#define loongson3_ipi_read32(addr) readl(addr)
  45/* read a 64bit value from ipi register */
  46#define loongson3_ipi_read64(addr) readq(addr)
  47/* write a 32bit value to ipi register */
  48#define loongson3_ipi_write32(action, addr)     \
  49        do {                                    \
  50                writel(action, addr);           \
  51                __wbflush();                    \
  52        } while (0)
  53/* write a 64bit value to ipi register */
  54#define loongson3_ipi_write64(action, addr)     \
  55        do {                                    \
  56                writeq(action, addr);           \
  57                __wbflush();                    \
  58        } while (0)
  59
  60static void ipi_set0_regs_init(void)
  61{
  62        ipi_set0_regs[0] = (void *)
  63                (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0);
  64        ipi_set0_regs[1] = (void *)
  65                (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0);
  66        ipi_set0_regs[2] = (void *)
  67                (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0);
  68        ipi_set0_regs[3] = (void *)
  69                (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0);
  70        ipi_set0_regs[4] = (void *)
  71                (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0);
  72        ipi_set0_regs[5] = (void *)
  73                (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0);
  74        ipi_set0_regs[6] = (void *)
  75                (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0);
  76        ipi_set0_regs[7] = (void *)
  77                (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0);
  78        ipi_set0_regs[8] = (void *)
  79                (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0);
  80        ipi_set0_regs[9] = (void *)
  81                (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0);
  82        ipi_set0_regs[10] = (void *)
  83                (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0);
  84        ipi_set0_regs[11] = (void *)
  85                (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0);
  86        ipi_set0_regs[12] = (void *)
  87                (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0);
  88        ipi_set0_regs[13] = (void *)
  89                (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0);
  90        ipi_set0_regs[14] = (void *)
  91                (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0);
  92        ipi_set0_regs[15] = (void *)
  93                (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0);
  94}
  95
  96static void ipi_clear0_regs_init(void)
  97{
  98        ipi_clear0_regs[0] = (void *)
  99                (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0);
 100        ipi_clear0_regs[1] = (void *)
 101                (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0);
 102        ipi_clear0_regs[2] = (void *)
 103                (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0);
 104        ipi_clear0_regs[3] = (void *)
 105                (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0);
 106        ipi_clear0_regs[4] = (void *)
 107                (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0);
 108        ipi_clear0_regs[5] = (void *)
 109                (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0);
 110        ipi_clear0_regs[6] = (void *)
 111                (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0);
 112        ipi_clear0_regs[7] = (void *)
 113                (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0);
 114        ipi_clear0_regs[8] = (void *)
 115                (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0);
 116        ipi_clear0_regs[9] = (void *)
 117                (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0);
 118        ipi_clear0_regs[10] = (void *)
 119                (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0);
 120        ipi_clear0_regs[11] = (void *)
 121                (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0);
 122        ipi_clear0_regs[12] = (void *)
 123                (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0);
 124        ipi_clear0_regs[13] = (void *)
 125                (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0);
 126        ipi_clear0_regs[14] = (void *)
 127                (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0);
 128        ipi_clear0_regs[15] = (void *)
 129                (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0);
 130}
 131
 132static void ipi_status0_regs_init(void)
 133{
 134        ipi_status0_regs[0] = (void *)
 135                (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0);
 136        ipi_status0_regs[1] = (void *)
 137                (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0);
 138        ipi_status0_regs[2] = (void *)
 139                (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0);
 140        ipi_status0_regs[3] = (void *)
 141                (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0);
 142        ipi_status0_regs[4] = (void *)
 143                (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0);
 144        ipi_status0_regs[5] = (void *)
 145                (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0);
 146        ipi_status0_regs[6] = (void *)
 147                (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0);
 148        ipi_status0_regs[7] = (void *)
 149                (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0);
 150        ipi_status0_regs[8] = (void *)
 151                (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0);
 152        ipi_status0_regs[9] = (void *)
 153                (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0);
 154        ipi_status0_regs[10] = (void *)
 155                (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0);
 156        ipi_status0_regs[11] = (void *)
 157                (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0);
 158        ipi_status0_regs[12] = (void *)
 159                (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0);
 160        ipi_status0_regs[13] = (void *)
 161                (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0);
 162        ipi_status0_regs[14] = (void *)
 163                (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0);
 164        ipi_status0_regs[15] = (void *)
 165                (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0);
 166}
 167
 168static void ipi_en0_regs_init(void)
 169{
 170        ipi_en0_regs[0] = (void *)
 171                (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0);
 172        ipi_en0_regs[1] = (void *)
 173                (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0);
 174        ipi_en0_regs[2] = (void *)
 175                (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0);
 176        ipi_en0_regs[3] = (void *)
 177                (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0);
 178        ipi_en0_regs[4] = (void *)
 179                (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0);
 180        ipi_en0_regs[5] = (void *)
 181                (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0);
 182        ipi_en0_regs[6] = (void *)
 183                (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0);
 184        ipi_en0_regs[7] = (void *)
 185                (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0);
 186        ipi_en0_regs[8] = (void *)
 187                (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0);
 188        ipi_en0_regs[9] = (void *)
 189                (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0);
 190        ipi_en0_regs[10] = (void *)
 191                (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0);
 192        ipi_en0_regs[11] = (void *)
 193                (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0);
 194        ipi_en0_regs[12] = (void *)
 195                (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0);
 196        ipi_en0_regs[13] = (void *)
 197                (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0);
 198        ipi_en0_regs[14] = (void *)
 199                (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0);
 200        ipi_en0_regs[15] = (void *)
 201                (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0);
 202}
 203
 204static void ipi_mailbox_buf_init(void)
 205{
 206        ipi_mailbox_buf[0] = (void *)
 207                (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF);
 208        ipi_mailbox_buf[1] = (void *)
 209                (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF);
 210        ipi_mailbox_buf[2] = (void *)
 211                (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF);
 212        ipi_mailbox_buf[3] = (void *)
 213                (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF);
 214        ipi_mailbox_buf[4] = (void *)
 215                (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF);
 216        ipi_mailbox_buf[5] = (void *)
 217                (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF);
 218        ipi_mailbox_buf[6] = (void *)
 219                (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF);
 220        ipi_mailbox_buf[7] = (void *)
 221                (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF);
 222        ipi_mailbox_buf[8] = (void *)
 223                (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF);
 224        ipi_mailbox_buf[9] = (void *)
 225                (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF);
 226        ipi_mailbox_buf[10] = (void *)
 227                (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF);
 228        ipi_mailbox_buf[11] = (void *)
 229                (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF);
 230        ipi_mailbox_buf[12] = (void *)
 231                (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF);
 232        ipi_mailbox_buf[13] = (void *)
 233                (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF);
 234        ipi_mailbox_buf[14] = (void *)
 235                (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF);
 236        ipi_mailbox_buf[15] = (void *)
 237                (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF);
 238}
 239
 240/*
 241 * Simple enough, just poke the appropriate ipi register
 242 */
 243static void loongson3_send_ipi_single(int cpu, unsigned int action)
 244{
 245        loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu_logical_map(cpu)]);
 246}
 247
 248static void
 249loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
 250{
 251        unsigned int i;
 252
 253        for_each_cpu(i, mask)
 254                loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu_logical_map(i)]);
 255}
 256
 257#define IPI_IRQ_OFFSET 6
 258
 259void loongson3_send_irq_by_ipi(int cpu, int irqs)
 260{
 261        loongson3_ipi_write32(irqs << IPI_IRQ_OFFSET, ipi_set0_regs[cpu_logical_map(cpu)]);
 262}
 263
 264void loongson3_ipi_interrupt(struct pt_regs *regs)
 265{
 266        int i, cpu = smp_processor_id();
 267        unsigned int action, c0count, irqs;
 268
 269        /* Load the ipi register to figure out what we're supposed to do */
 270        action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]);
 271        irqs = action >> IPI_IRQ_OFFSET;
 272
 273        /* Clear the ipi register to clear the interrupt */
 274        loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu_logical_map(cpu)]);
 275
 276        if (action & SMP_RESCHEDULE_YOURSELF)
 277                scheduler_ipi();
 278
 279        if (action & SMP_CALL_FUNCTION) {
 280                irq_enter();
 281                generic_smp_call_function_interrupt();
 282                irq_exit();
 283        }
 284
 285        if (action & SMP_ASK_C0COUNT) {
 286                BUG_ON(cpu != 0);
 287                c0count = read_c0_count();
 288                c0count = c0count ? c0count : 1;
 289                for (i = 1; i < nr_cpu_ids; i++)
 290                        core0_c0count[i] = c0count;
 291                __wbflush(); /* Let others see the result ASAP */
 292        }
 293
 294        if (irqs) {
 295                int irq;
 296                while ((irq = ffs(irqs))) {
 297                        do_IRQ(irq-1);
 298                        irqs &= ~(1<<(irq-1));
 299                }
 300        }
 301}
 302
 303#define MAX_LOOPS 800
 304/*
 305 * SMP init and finish on secondary CPUs
 306 */
 307static void loongson3_init_secondary(void)
 308{
 309        int i;
 310        uint32_t initcount;
 311        unsigned int cpu = smp_processor_id();
 312        unsigned int imask = STATUSF_IP7 | STATUSF_IP6 |
 313                             STATUSF_IP3 | STATUSF_IP2;
 314
 315        /* Set interrupt mask, but don't enable */
 316        change_c0_status(ST0_IM, imask);
 317
 318        for (i = 0; i < num_possible_cpus(); i++)
 319                loongson3_ipi_write32(0xffffffff, ipi_en0_regs[cpu_logical_map(i)]);
 320
 321        per_cpu(cpu_state, cpu) = CPU_ONLINE;
 322        cpu_set_core(&cpu_data[cpu],
 323                     cpu_logical_map(cpu) % loongson_sysconf.cores_per_package);
 324        cpu_data[cpu].package =
 325                cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
 326
 327        i = 0;
 328        core0_c0count[cpu] = 0;
 329        loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
 330        while (!core0_c0count[cpu]) {
 331                i++;
 332                cpu_relax();
 333        }
 334
 335        if (i > MAX_LOOPS)
 336                i = MAX_LOOPS;
 337        if (cpu_data[cpu].package)
 338                initcount = core0_c0count[cpu] + i;
 339        else /* Local access is faster for loops */
 340                initcount = core0_c0count[cpu] + i/2;
 341
 342        write_c0_count(initcount);
 343}
 344
 345static void loongson3_smp_finish(void)
 346{
 347        int cpu = smp_processor_id();
 348
 349        write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
 350        local_irq_enable();
 351        loongson3_ipi_write64(0,
 352                        (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x0));
 353        pr_info("CPU#%d finished, CP0_ST=%x\n",
 354                        smp_processor_id(), read_c0_status());
 355}
 356
 357static void __init loongson3_smp_setup(void)
 358{
 359        int i = 0, num = 0; /* i: physical id, num: logical id */
 360
 361        init_cpu_possible(cpu_none_mask);
 362
 363        /* For unified kernel, NR_CPUS is the maximum possible value,
 364         * loongson_sysconf.nr_cpus is the really present value */
 365        while (i < loongson_sysconf.nr_cpus) {
 366                if (loongson_sysconf.reserved_cpus_mask & (1<<i)) {
 367                        /* Reserved physical CPU cores */
 368                        __cpu_number_map[i] = -1;
 369                } else {
 370                        __cpu_number_map[i] = num;
 371                        __cpu_logical_map[num] = i;
 372                        set_cpu_possible(num, true);
 373                        num++;
 374                }
 375                i++;
 376        }
 377        pr_info("Detected %i available CPU(s)\n", num);
 378
 379        while (num < loongson_sysconf.nr_cpus) {
 380                __cpu_logical_map[num] = -1;
 381                num++;
 382        }
 383
 384        ipi_set0_regs_init();
 385        ipi_clear0_regs_init();
 386        ipi_status0_regs_init();
 387        ipi_en0_regs_init();
 388        ipi_mailbox_buf_init();
 389        cpu_set_core(&cpu_data[0],
 390                     cpu_logical_map(0) % loongson_sysconf.cores_per_package);
 391        cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package;
 392}
 393
 394static void __init loongson3_prepare_cpus(unsigned int max_cpus)
 395{
 396        init_cpu_present(cpu_possible_mask);
 397        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 398}
 399
 400/*
 401 * Setup the PC, SP, and GP of a secondary processor and start it runing!
 402 */
 403static int loongson3_boot_secondary(int cpu, struct task_struct *idle)
 404{
 405        unsigned long startargs[4];
 406
 407        pr_info("Booting CPU#%d...\n", cpu);
 408
 409        /* startargs[] are initial PC, SP and GP for secondary CPU */
 410        startargs[0] = (unsigned long)&smp_bootstrap;
 411        startargs[1] = (unsigned long)__KSTK_TOS(idle);
 412        startargs[2] = (unsigned long)task_thread_info(idle);
 413        startargs[3] = 0;
 414
 415        pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
 416                        cpu, startargs[0], startargs[1], startargs[2]);
 417
 418        loongson3_ipi_write64(startargs[3],
 419                        (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x18));
 420        loongson3_ipi_write64(startargs[2],
 421                        (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x10));
 422        loongson3_ipi_write64(startargs[1],
 423                        (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x8));
 424        loongson3_ipi_write64(startargs[0],
 425                        (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x0));
 426        return 0;
 427}
 428
 429#ifdef CONFIG_HOTPLUG_CPU
 430
 431static int loongson3_cpu_disable(void)
 432{
 433        unsigned long flags;
 434        unsigned int cpu = smp_processor_id();
 435
 436        if (cpu == 0)
 437                return -EBUSY;
 438
 439        set_cpu_online(cpu, false);
 440        calculate_cpu_foreign_map();
 441        local_irq_save(flags);
 442        fixup_irqs();
 443        local_irq_restore(flags);
 444        local_flush_tlb_all();
 445
 446        return 0;
 447}
 448
 449
 450static void loongson3_cpu_die(unsigned int cpu)
 451{
 452        while (per_cpu(cpu_state, cpu) != CPU_DEAD)
 453                cpu_relax();
 454
 455        mb();
 456}
 457
 458/* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
 459 * flush all L1 entries at first. Then, another core (usually Core 0) can
 460 * safely disable the clock of the target core. loongson3_play_dead() is
 461 * called via CKSEG1 (uncached and unmmaped) */
 462static void loongson3a_r1_play_dead(int *state_addr)
 463{
 464        register int val;
 465        register long cpuid, core, node, count;
 466        register void *addr, *base, *initfunc;
 467
 468        __asm__ __volatile__(
 469                "   .set push                     \n"
 470                "   .set noreorder                \n"
 471                "   li %[addr], 0x80000000        \n" /* KSEG0 */
 472                "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
 473                "   cache 0, 1(%[addr])           \n"
 474                "   cache 0, 2(%[addr])           \n"
 475                "   cache 0, 3(%[addr])           \n"
 476                "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
 477                "   cache 1, 1(%[addr])           \n"
 478                "   cache 1, 2(%[addr])           \n"
 479                "   cache 1, 3(%[addr])           \n"
 480                "   addiu %[sets], %[sets], -1    \n"
 481                "   bnez  %[sets], 1b             \n"
 482                "   addiu %[addr], %[addr], 0x20  \n"
 483                "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
 484                "   sw    %[val], (%[state_addr]) \n"
 485                "   sync                          \n"
 486                "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
 487                "   .set pop                      \n"
 488                : [addr] "=&r" (addr), [val] "=&r" (val)
 489                : [state_addr] "r" (state_addr),
 490                  [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
 491
 492        __asm__ __volatile__(
 493                "   .set push                         \n"
 494                "   .set noreorder                    \n"
 495                "   .set mips64                       \n"
 496                "   mfc0  %[cpuid], $15, 1            \n"
 497                "   andi  %[cpuid], 0x3ff             \n"
 498                "   dli   %[base], 0x900000003ff01000 \n"
 499                "   andi  %[core], %[cpuid], 0x3      \n"
 500                "   sll   %[core], 8                  \n" /* get core id */
 501                "   or    %[base], %[base], %[core]   \n"
 502                "   andi  %[node], %[cpuid], 0xc      \n"
 503                "   dsll  %[node], 42                 \n" /* get node id */
 504                "   or    %[base], %[base], %[node]   \n"
 505                "1: li    %[count], 0x100             \n" /* wait for init loop */
 506                "2: bnez  %[count], 2b                \n" /* limit mailbox access */
 507                "   addiu %[count], -1                \n"
 508                "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
 509                "   beqz  %[initfunc], 1b             \n"
 510                "   nop                               \n"
 511                "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
 512                "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
 513                "   ld    $a1, 0x38(%[base])          \n"
 514                "   jr    %[initfunc]                 \n" /* jump to initial PC */
 515                "   nop                               \n"
 516                "   .set pop                          \n"
 517                : [core] "=&r" (core), [node] "=&r" (node),
 518                  [base] "=&r" (base), [cpuid] "=&r" (cpuid),
 519                  [count] "=&r" (count), [initfunc] "=&r" (initfunc)
 520                : /* No Input */
 521                : "a1");
 522}
 523
 524static void loongson3a_r2r3_play_dead(int *state_addr)
 525{
 526        register int val;
 527        register long cpuid, core, node, count;
 528        register void *addr, *base, *initfunc;
 529
 530        __asm__ __volatile__(
 531                "   .set push                     \n"
 532                "   .set noreorder                \n"
 533                "   li %[addr], 0x80000000        \n" /* KSEG0 */
 534                "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
 535                "   cache 0, 1(%[addr])           \n"
 536                "   cache 0, 2(%[addr])           \n"
 537                "   cache 0, 3(%[addr])           \n"
 538                "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
 539                "   cache 1, 1(%[addr])           \n"
 540                "   cache 1, 2(%[addr])           \n"
 541                "   cache 1, 3(%[addr])           \n"
 542                "   addiu %[sets], %[sets], -1    \n"
 543                "   bnez  %[sets], 1b             \n"
 544                "   addiu %[addr], %[addr], 0x40  \n"
 545                "   li %[addr], 0x80000000        \n" /* KSEG0 */
 546                "2: cache 2, 0(%[addr])           \n" /* flush L1 VCache */
 547                "   cache 2, 1(%[addr])           \n"
 548                "   cache 2, 2(%[addr])           \n"
 549                "   cache 2, 3(%[addr])           \n"
 550                "   cache 2, 4(%[addr])           \n"
 551                "   cache 2, 5(%[addr])           \n"
 552                "   cache 2, 6(%[addr])           \n"
 553                "   cache 2, 7(%[addr])           \n"
 554                "   cache 2, 8(%[addr])           \n"
 555                "   cache 2, 9(%[addr])           \n"
 556                "   cache 2, 10(%[addr])          \n"
 557                "   cache 2, 11(%[addr])          \n"
 558                "   cache 2, 12(%[addr])          \n"
 559                "   cache 2, 13(%[addr])          \n"
 560                "   cache 2, 14(%[addr])          \n"
 561                "   cache 2, 15(%[addr])          \n"
 562                "   addiu %[vsets], %[vsets], -1  \n"
 563                "   bnez  %[vsets], 2b            \n"
 564                "   addiu %[addr], %[addr], 0x40  \n"
 565                "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
 566                "   sw    %[val], (%[state_addr]) \n"
 567                "   sync                          \n"
 568                "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
 569                "   .set pop                      \n"
 570                : [addr] "=&r" (addr), [val] "=&r" (val)
 571                : [state_addr] "r" (state_addr),
 572                  [sets] "r" (cpu_data[smp_processor_id()].dcache.sets),
 573                  [vsets] "r" (cpu_data[smp_processor_id()].vcache.sets));
 574
 575        __asm__ __volatile__(
 576                "   .set push                         \n"
 577                "   .set noreorder                    \n"
 578                "   .set mips64                       \n"
 579                "   mfc0  %[cpuid], $15, 1            \n"
 580                "   andi  %[cpuid], 0x3ff             \n"
 581                "   dli   %[base], 0x900000003ff01000 \n"
 582                "   andi  %[core], %[cpuid], 0x3      \n"
 583                "   sll   %[core], 8                  \n" /* get core id */
 584                "   or    %[base], %[base], %[core]   \n"
 585                "   andi  %[node], %[cpuid], 0xc      \n"
 586                "   dsll  %[node], 42                 \n" /* get node id */
 587                "   or    %[base], %[base], %[node]   \n"
 588                "1: li    %[count], 0x100             \n" /* wait for init loop */
 589                "2: bnez  %[count], 2b                \n" /* limit mailbox access */
 590                "   addiu %[count], -1                \n"
 591                "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
 592                "   beqz  %[initfunc], 1b             \n"
 593                "   nop                               \n"
 594                "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
 595                "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
 596                "   ld    $a1, 0x38(%[base])          \n"
 597                "   jr    %[initfunc]                 \n" /* jump to initial PC */
 598                "   nop                               \n"
 599                "   .set pop                          \n"
 600                : [core] "=&r" (core), [node] "=&r" (node),
 601                  [base] "=&r" (base), [cpuid] "=&r" (cpuid),
 602                  [count] "=&r" (count), [initfunc] "=&r" (initfunc)
 603                : /* No Input */
 604                : "a1");
 605}
 606
 607static void loongson3b_play_dead(int *state_addr)
 608{
 609        register int val;
 610        register long cpuid, core, node, count;
 611        register void *addr, *base, *initfunc;
 612
 613        __asm__ __volatile__(
 614                "   .set push                     \n"
 615                "   .set noreorder                \n"
 616                "   li %[addr], 0x80000000        \n" /* KSEG0 */
 617                "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
 618                "   cache 0, 1(%[addr])           \n"
 619                "   cache 0, 2(%[addr])           \n"
 620                "   cache 0, 3(%[addr])           \n"
 621                "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
 622                "   cache 1, 1(%[addr])           \n"
 623                "   cache 1, 2(%[addr])           \n"
 624                "   cache 1, 3(%[addr])           \n"
 625                "   addiu %[sets], %[sets], -1    \n"
 626                "   bnez  %[sets], 1b             \n"
 627                "   addiu %[addr], %[addr], 0x20  \n"
 628                "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
 629                "   sw    %[val], (%[state_addr]) \n"
 630                "   sync                          \n"
 631                "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
 632                "   .set pop                      \n"
 633                : [addr] "=&r" (addr), [val] "=&r" (val)
 634                : [state_addr] "r" (state_addr),
 635                  [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
 636
 637        __asm__ __volatile__(
 638                "   .set push                         \n"
 639                "   .set noreorder                    \n"
 640                "   .set mips64                       \n"
 641                "   mfc0  %[cpuid], $15, 1            \n"
 642                "   andi  %[cpuid], 0x3ff             \n"
 643                "   dli   %[base], 0x900000003ff01000 \n"
 644                "   andi  %[core], %[cpuid], 0x3      \n"
 645                "   sll   %[core], 8                  \n" /* get core id */
 646                "   or    %[base], %[base], %[core]   \n"
 647                "   andi  %[node], %[cpuid], 0xc      \n"
 648                "   dsll  %[node], 42                 \n" /* get node id */
 649                "   or    %[base], %[base], %[node]   \n"
 650                "   dsrl  %[node], 30                 \n" /* 15:14 */
 651                "   or    %[base], %[base], %[node]   \n"
 652                "1: li    %[count], 0x100             \n" /* wait for init loop */
 653                "2: bnez  %[count], 2b                \n" /* limit mailbox access */
 654                "   addiu %[count], -1                \n"
 655                "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
 656                "   beqz  %[initfunc], 1b             \n"
 657                "   nop                               \n"
 658                "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
 659                "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
 660                "   ld    $a1, 0x38(%[base])          \n"
 661                "   jr    %[initfunc]                 \n" /* jump to initial PC */
 662                "   nop                               \n"
 663                "   .set pop                          \n"
 664                : [core] "=&r" (core), [node] "=&r" (node),
 665                  [base] "=&r" (base), [cpuid] "=&r" (cpuid),
 666                  [count] "=&r" (count), [initfunc] "=&r" (initfunc)
 667                : /* No Input */
 668                : "a1");
 669}
 670
 671void play_dead(void)
 672{
 673        int *state_addr;
 674        unsigned int cpu = smp_processor_id();
 675        void (*play_dead_at_ckseg1)(int *);
 676
 677        idle_task_exit();
 678        switch (read_c0_prid() & PRID_REV_MASK) {
 679        case PRID_REV_LOONGSON3A_R1:
 680        default:
 681                play_dead_at_ckseg1 =
 682                        (void *)CKSEG1ADDR((unsigned long)loongson3a_r1_play_dead);
 683                break;
 684        case PRID_REV_LOONGSON3A_R2:
 685        case PRID_REV_LOONGSON3A_R3:
 686                play_dead_at_ckseg1 =
 687                        (void *)CKSEG1ADDR((unsigned long)loongson3a_r2r3_play_dead);
 688                break;
 689        case PRID_REV_LOONGSON3B_R1:
 690        case PRID_REV_LOONGSON3B_R2:
 691                play_dead_at_ckseg1 =
 692                        (void *)CKSEG1ADDR((unsigned long)loongson3b_play_dead);
 693                break;
 694        }
 695        state_addr = &per_cpu(cpu_state, cpu);
 696        mb();
 697        play_dead_at_ckseg1(state_addr);
 698}
 699
 700static int loongson3_disable_clock(unsigned int cpu)
 701{
 702        uint64_t core_id = cpu_core(&cpu_data[cpu]);
 703        uint64_t package_id = cpu_data[cpu].package;
 704
 705        if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
 706                LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id));
 707        } else {
 708                if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
 709                        LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
 710        }
 711        return 0;
 712}
 713
 714static int loongson3_enable_clock(unsigned int cpu)
 715{
 716        uint64_t core_id = cpu_core(&cpu_data[cpu]);
 717        uint64_t package_id = cpu_data[cpu].package;
 718
 719        if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
 720                LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id);
 721        } else {
 722                if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
 723                        LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
 724        }
 725        return 0;
 726}
 727
 728static int register_loongson3_notifier(void)
 729{
 730        return cpuhp_setup_state_nocalls(CPUHP_MIPS_SOC_PREPARE,
 731                                         "mips/loongson:prepare",
 732                                         loongson3_enable_clock,
 733                                         loongson3_disable_clock);
 734}
 735early_initcall(register_loongson3_notifier);
 736
 737#endif
 738
 739const struct plat_smp_ops loongson3_smp_ops = {
 740        .send_ipi_single = loongson3_send_ipi_single,
 741        .send_ipi_mask = loongson3_send_ipi_mask,
 742        .init_secondary = loongson3_init_secondary,
 743        .smp_finish = loongson3_smp_finish,
 744        .boot_secondary = loongson3_boot_secondary,
 745        .smp_setup = loongson3_smp_setup,
 746        .prepare_cpus = loongson3_prepare_cpus,
 747#ifdef CONFIG_HOTPLUG_CPU
 748        .cpu_disable = loongson3_cpu_disable,
 749        .cpu_die = loongson3_cpu_die,
 750#endif
 751};
 752