linux/arch/mips/cavium-octeon/smp.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2004-2008, 2009, 2010 Cavium Networks
   7 */
   8#include <linux/cpu.h>
   9#include <linux/init.h>
  10#include <linux/delay.h>
  11#include <linux/smp.h>
  12#include <linux/interrupt.h>
  13#include <linux/kernel_stat.h>
  14#include <linux/sched.h>
  15#include <linux/module.h>
  16
  17#include <asm/mmu_context.h>
  18#include <asm/time.h>
  19#include <asm/setup.h>
  20
  21#include <asm/octeon/octeon.h>
  22
  23#include "octeon_boot.h"
  24
  25volatile unsigned long octeon_processor_boot = 0xff;
  26volatile unsigned long octeon_processor_sp;
  27volatile unsigned long octeon_processor_gp;
  28
  29#ifdef CONFIG_HOTPLUG_CPU
  30uint64_t octeon_bootloader_entry_addr;
  31EXPORT_SYMBOL(octeon_bootloader_entry_addr);
  32#endif
  33
  34static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
  35{
  36        const int coreid = cvmx_get_core_num();
  37        uint64_t action;
  38
  39        /* Load the mailbox register to figure out what we're supposed to do */
  40        action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)) & 0xffff;
  41
  42        /* Clear the mailbox to clear the interrupt */
  43        cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
  44
  45        if (action & SMP_CALL_FUNCTION)
  46                smp_call_function_interrupt();
  47        if (action & SMP_RESCHEDULE_YOURSELF)
  48                scheduler_ipi();
  49
  50        /* Check if we've been told to flush the icache */
  51        if (action & SMP_ICACHE_FLUSH)
  52                asm volatile ("synci 0($0)\n");
  53        return IRQ_HANDLED;
  54}
  55
  56/**
  57 * Cause the function described by call_data to be executed on the passed
  58 * cpu.  When the function has finished, increment the finished field of
  59 * call_data.
  60 */
  61void octeon_send_ipi_single(int cpu, unsigned int action)
  62{
  63        int coreid = cpu_logical_map(cpu);
  64        /*
  65        pr_info("SMP: Mailbox send cpu=%d, coreid=%d, action=%u\n", cpu,
  66               coreid, action);
  67        */
  68        cvmx_write_csr(CVMX_CIU_MBOX_SETX(coreid), action);
  69}
  70
  71static inline void octeon_send_ipi_mask(const struct cpumask *mask,
  72                                        unsigned int action)
  73{
  74        unsigned int i;
  75
  76        for_each_cpu_mask(i, *mask)
  77                octeon_send_ipi_single(i, action);
  78}
  79
  80/**
  81 * Detect available CPUs, populate cpu_possible_mask
  82 */
  83static void octeon_smp_hotplug_setup(void)
  84{
  85#ifdef CONFIG_HOTPLUG_CPU
  86        struct linux_app_boot_info *labi;
  87
  88        labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER);
  89        if (labi->labi_signature != LABI_SIGNATURE)
  90                panic("The bootloader version on this board is incorrect.");
  91
  92        octeon_bootloader_entry_addr = labi->InitTLBStart_addr;
  93#endif
  94}
  95
  96static void octeon_smp_setup(void)
  97{
  98        const int coreid = cvmx_get_core_num();
  99        int cpus;
 100        int id;
 101        int core_mask = octeon_get_boot_coremask();
 102#ifdef CONFIG_HOTPLUG_CPU
 103        unsigned int num_cores = cvmx_octeon_num_cores();
 104#endif
 105
 106        /* The present CPUs are initially just the boot cpu (CPU 0). */
 107        for (id = 0; id < NR_CPUS; id++) {
 108                set_cpu_possible(id, id == 0);
 109                set_cpu_present(id, id == 0);
 110        }
 111
 112        __cpu_number_map[coreid] = 0;
 113        __cpu_logical_map[0] = coreid;
 114
 115        /* The present CPUs get the lowest CPU numbers. */
 116        cpus = 1;
 117        for (id = 0; id < NR_CPUS; id++) {
 118                if ((id != coreid) && (core_mask & (1 << id))) {
 119                        set_cpu_possible(cpus, true);
 120                        set_cpu_present(cpus, true);
 121                        __cpu_number_map[id] = cpus;
 122                        __cpu_logical_map[cpus] = id;
 123                        cpus++;
 124                }
 125        }
 126
 127#ifdef CONFIG_HOTPLUG_CPU
 128        /*
 129         * The possible CPUs are all those present on the chip.  We
 130         * will assign CPU numbers for possible cores as well.  Cores
 131         * are always consecutively numberd from 0.
 132         */
 133        for (id = 0; id < num_cores && id < NR_CPUS; id++) {
 134                if (!(core_mask & (1 << id))) {
 135                        set_cpu_possible(cpus, true);
 136                        __cpu_number_map[id] = cpus;
 137                        __cpu_logical_map[cpus] = id;
 138                        cpus++;
 139                }
 140        }
 141#endif
 142
 143        octeon_smp_hotplug_setup();
 144}
 145
 146/**
 147 * Firmware CPU startup hook
 148 *
 149 */
 150static void octeon_boot_secondary(int cpu, struct task_struct *idle)
 151{
 152        int count;
 153
 154        pr_info("SMP: Booting CPU%02d (CoreId %2d)...\n", cpu,
 155                cpu_logical_map(cpu));
 156
 157        octeon_processor_sp = __KSTK_TOS(idle);
 158        octeon_processor_gp = (unsigned long)(task_thread_info(idle));
 159        octeon_processor_boot = cpu_logical_map(cpu);
 160        mb();
 161
 162        count = 10000;
 163        while (octeon_processor_sp && count) {
 164                /* Waiting for processor to get the SP and GP */
 165                udelay(1);
 166                count--;
 167        }
 168        if (count == 0)
 169                pr_err("Secondary boot timeout\n");
 170}
 171
 172/**
 173 * After we've done initial boot, this function is called to allow the
 174 * board code to clean up state, if needed
 175 */
 176static void octeon_init_secondary(void)
 177{
 178        unsigned int sr;
 179
 180        sr = set_c0_status(ST0_BEV);
 181        write_c0_ebase((u32)ebase);
 182        write_c0_status(sr);
 183
 184        octeon_check_cpu_bist();
 185        octeon_init_cvmcount();
 186
 187        octeon_irq_setup_secondary();
 188}
 189
 190/**
 191 * Callout to firmware before smp_init
 192 *
 193 */
 194void octeon_prepare_cpus(unsigned int max_cpus)
 195{
 196#ifdef CONFIG_HOTPLUG_CPU
 197        struct linux_app_boot_info *labi;
 198
 199        labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER);
 200
 201        if (labi->labi_signature != LABI_SIGNATURE)
 202                panic("The bootloader version on this board is incorrect.");
 203#endif
 204        /*
 205         * Only the low order mailbox bits are used for IPIs, leave
 206         * the other bits alone.
 207         */
 208        cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffff);
 209        if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt,
 210                        IRQF_PERCPU | IRQF_NO_THREAD, "SMP-IPI",
 211                        mailbox_interrupt)) {
 212                panic("Cannot request_irq(OCTEON_IRQ_MBOX0)");
 213        }
 214}
 215
 216/**
 217 * Last chance for the board code to finish SMP initialization before
 218 * the CPU is "online".
 219 */
 220static void octeon_smp_finish(void)
 221{
 222#ifdef CONFIG_CAVIUM_GDB
 223        unsigned long tmp;
 224        /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0
 225           to be not masked by this core so we know the signal is received by
 226           someone */
 227        asm volatile ("dmfc0 %0, $22\n"
 228                      "ori   %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp));
 229#endif
 230
 231        octeon_user_io_init();
 232
 233        /* to generate the first CPU timer interrupt */
 234        write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
 235        local_irq_enable();
 236}
 237
 238/**
 239 * Hook for after all CPUs are online
 240 */
 241static void octeon_cpus_done(void)
 242{
 243#ifdef CONFIG_CAVIUM_GDB
 244        unsigned long tmp;
 245        /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0
 246           to be not masked by this core so we know the signal is received by
 247           someone */
 248        asm volatile ("dmfc0 %0, $22\n"
 249                      "ori   %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp));
 250#endif
 251}
 252
 253#ifdef CONFIG_HOTPLUG_CPU
 254
 255/* State of each CPU. */
 256DEFINE_PER_CPU(int, cpu_state);
 257
 258extern void fixup_irqs(void);
 259
 260static int octeon_cpu_disable(void)
 261{
 262        unsigned int cpu = smp_processor_id();
 263
 264        if (cpu == 0)
 265                return -EBUSY;
 266
 267        set_cpu_online(cpu, false);
 268        cpu_clear(cpu, cpu_callin_map);
 269        local_irq_disable();
 270        fixup_irqs();
 271        local_irq_enable();
 272
 273        flush_cache_all();
 274        local_flush_tlb_all();
 275
 276        return 0;
 277}
 278
 279static void octeon_cpu_die(unsigned int cpu)
 280{
 281        int coreid = cpu_logical_map(cpu);
 282        uint32_t mask, new_mask;
 283        const struct cvmx_bootmem_named_block_desc *block_desc;
 284
 285        while (per_cpu(cpu_state, cpu) != CPU_DEAD)
 286                cpu_relax();
 287
 288        /*
 289         * This is a bit complicated strategics of getting/settig available
 290         * cores mask, copied from bootloader
 291         */
 292
 293        mask = 1 << coreid;
 294        /* LINUX_APP_BOOT_BLOCK is initialized in bootoct binary */
 295        block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME);
 296
 297        if (!block_desc) {
 298                struct linux_app_boot_info *labi;
 299
 300                labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER);
 301
 302                labi->avail_coremask |= mask;
 303                new_mask = labi->avail_coremask;
 304        } else {                       /* alternative, already initialized */
 305                uint32_t *p = (uint32_t *)PHYS_TO_XKSEG_CACHED(block_desc->base_addr +
 306                                                               AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK);
 307                *p |= mask;
 308                new_mask = *p;
 309        }
 310
 311        pr_info("Reset core %d. Available Coremask = 0x%x \n", coreid, new_mask);
 312        mb();
 313        cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid);
 314        cvmx_write_csr(CVMX_CIU_PP_RST, 0);
 315}
 316
 317void play_dead(void)
 318{
 319        int cpu = cpu_number_map(cvmx_get_core_num());
 320
 321        idle_task_exit();
 322        octeon_processor_boot = 0xff;
 323        per_cpu(cpu_state, cpu) = CPU_DEAD;
 324
 325        mb();
 326
 327        while (1)       /* core will be reset here */
 328                ;
 329}
 330
 331extern void kernel_entry(unsigned long arg1, ...);
 332
 333static void start_after_reset(void)
 334{
 335        kernel_entry(0, 0, 0);  /* set a2 = 0 for secondary core */
 336}
 337
 338static int octeon_update_boot_vector(unsigned int cpu)
 339{
 340
 341        int coreid = cpu_logical_map(cpu);
 342        uint32_t avail_coremask;
 343        const struct cvmx_bootmem_named_block_desc *block_desc;
 344        struct boot_init_vector *boot_vect =
 345                (struct boot_init_vector *)PHYS_TO_XKSEG_CACHED(BOOTLOADER_BOOT_VECTOR);
 346
 347        block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME);
 348
 349        if (!block_desc) {
 350                struct linux_app_boot_info *labi;
 351
 352                labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER);
 353
 354                avail_coremask = labi->avail_coremask;
 355                labi->avail_coremask &= ~(1 << coreid);
 356        } else {                       /* alternative, already initialized */
 357                avail_coremask = *(uint32_t *)PHYS_TO_XKSEG_CACHED(
 358                        block_desc->base_addr + AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK);
 359        }
 360
 361        if (!(avail_coremask & (1 << coreid))) {
 362                /* core not available, assume, that catched by simple-executive */
 363                cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid);
 364                cvmx_write_csr(CVMX_CIU_PP_RST, 0);
 365        }
 366
 367        boot_vect[coreid].app_start_func_addr =
 368                (uint32_t) (unsigned long) start_after_reset;
 369        boot_vect[coreid].code_addr = octeon_bootloader_entry_addr;
 370
 371        mb();
 372
 373        cvmx_write_csr(CVMX_CIU_NMI, (1 << coreid) & avail_coremask);
 374
 375        return 0;
 376}
 377
 378static int octeon_cpu_callback(struct notifier_block *nfb,
 379        unsigned long action, void *hcpu)
 380{
 381        unsigned int cpu = (unsigned long)hcpu;
 382
 383        switch (action) {
 384        case CPU_UP_PREPARE:
 385                octeon_update_boot_vector(cpu);
 386                break;
 387        case CPU_ONLINE:
 388                pr_info("Cpu %d online\n", cpu);
 389                break;
 390        case CPU_DEAD:
 391                break;
 392        }
 393
 394        return NOTIFY_OK;
 395}
 396
 397static int register_cavium_notifier(void)
 398{
 399        hotcpu_notifier(octeon_cpu_callback, 0);
 400        return 0;
 401}
 402late_initcall(register_cavium_notifier);
 403
 404#endif  /* CONFIG_HOTPLUG_CPU */
 405
 406struct plat_smp_ops octeon_smp_ops = {
 407        .send_ipi_single        = octeon_send_ipi_single,
 408        .send_ipi_mask          = octeon_send_ipi_mask,
 409        .init_secondary         = octeon_init_secondary,
 410        .smp_finish             = octeon_smp_finish,
 411        .cpus_done              = octeon_cpus_done,
 412        .boot_secondary         = octeon_boot_secondary,
 413        .smp_setup              = octeon_smp_setup,
 414        .prepare_cpus           = octeon_prepare_cpus,
 415#ifdef CONFIG_HOTPLUG_CPU
 416        .cpu_disable            = octeon_cpu_disable,
 417        .cpu_die                = octeon_cpu_die,
 418#endif
 419};
 420