linux/arch/mips/pmc-sierra/yosemite/smp.c
<<
>>
Prefs
   1#include <linux/linkage.h>
   2#include <linux/sched.h>
   3#include <linux/smp.h>
   4
   5#include <asm/pmon.h>
   6#include <asm/titan_dep.h>
   7#include <asm/time.h>
   8
   9#define LAUNCHSTACK_SIZE 256
  10
  11static __cpuinitdata DEFINE_SPINLOCK(launch_lock);
  12
  13static unsigned long secondary_sp __cpuinitdata;
  14static unsigned long secondary_gp __cpuinitdata;
  15
  16static unsigned char launchstack[LAUNCHSTACK_SIZE] __initdata
  17        __attribute__((aligned(2 * sizeof(long))));
  18
  19static void __init prom_smp_bootstrap(void)
  20{
  21        local_irq_disable();
  22
  23        while (spin_is_locked(&launch_lock));
  24
  25        __asm__ __volatile__(
  26        "       move    $sp, %0         \n"
  27        "       move    $gp, %1         \n"
  28        "       j       smp_bootstrap   \n"
  29        :
  30        : "r" (secondary_sp), "r" (secondary_gp));
  31}
  32
  33/*
  34 * PMON is a fragile beast.  It'll blow up once the mappings it's littering
  35 * right into the middle of KSEG3 are blown away so we have to grab the slave
  36 * core early and keep it in a waiting loop.
  37 */
  38void __init prom_grab_secondary(void)
  39{
  40        spin_lock(&launch_lock);
  41
  42        pmon_cpustart(1, &prom_smp_bootstrap,
  43                      launchstack + LAUNCHSTACK_SIZE, 0);
  44}
  45
  46void titan_mailbox_irq(void)
  47{
  48        int cpu = smp_processor_id();
  49        unsigned long status;
  50
  51        switch (cpu) {
  52        case 0:
  53                status = OCD_READ(RM9000x2_OCD_INTP0STATUS3);
  54                OCD_WRITE(RM9000x2_OCD_INTP0CLEAR3, status);
  55
  56                if (status & 0x2)
  57                        smp_call_function_interrupt();
  58                break;
  59
  60        case 1:
  61                status = OCD_READ(RM9000x2_OCD_INTP1STATUS3);
  62                OCD_WRITE(RM9000x2_OCD_INTP1CLEAR3, status);
  63
  64                if (status & 0x2)
  65                        smp_call_function_interrupt();
  66                break;
  67        }
  68}
  69
  70/*
  71 * Send inter-processor interrupt
  72 */
  73static void yos_send_ipi_single(int cpu, unsigned int action)
  74{
  75        /*
  76         * Generate an INTMSG so that it can be sent over to the
  77         * destination CPU. The INTMSG will put the STATUS bits
  78         * based on the action desired. An alternative strategy
  79         * is to write to the Interrupt Set register, read the
  80         * Interrupt Status register and clear the Interrupt
  81         * Clear register. The latter is preffered.
  82         */
  83        switch (action) {
  84        case SMP_RESCHEDULE_YOURSELF:
  85                if (cpu == 1)
  86                        OCD_WRITE(RM9000x2_OCD_INTP1SET3, 4);
  87                else
  88                        OCD_WRITE(RM9000x2_OCD_INTP0SET3, 4);
  89                break;
  90
  91        case SMP_CALL_FUNCTION:
  92                if (cpu == 1)
  93                        OCD_WRITE(RM9000x2_OCD_INTP1SET3, 2);
  94                else
  95                        OCD_WRITE(RM9000x2_OCD_INTP0SET3, 2);
  96                break;
  97        }
  98}
  99
 100static void yos_send_ipi_mask(const struct cpumask *mask, unsigned int action)
 101{
 102        unsigned int i;
 103
 104        for_each_cpu(i, mask)
 105                yos_send_ipi_single(i, action);
 106}
 107
 108/*
 109 *  After we've done initial boot, this function is called to allow the
 110 *  board code to clean up state, if needed
 111 */
 112static void __cpuinit yos_init_secondary(void)
 113{
 114        set_c0_status(ST0_CO | ST0_IE | ST0_IM);
 115}
 116
 117static void __cpuinit yos_smp_finish(void)
 118{
 119}
 120
 121/* Hook for after all CPUs are online */
 122static void yos_cpus_done(void)
 123{
 124}
 125
 126/*
 127 * Firmware CPU startup hook
 128 * Complicated by PMON's weird interface which tries to minimic the UNIX fork.
 129 * It launches the next * available CPU and copies some information on the
 130 * stack so the first thing we do is throw away that stuff and load useful
 131 * values into the registers ...
 132 */
 133static void __cpuinit yos_boot_secondary(int cpu, struct task_struct *idle)
 134{
 135        unsigned long gp = (unsigned long) task_thread_info(idle);
 136        unsigned long sp = __KSTK_TOS(idle);
 137
 138        secondary_sp = sp;
 139        secondary_gp = gp;
 140
 141        spin_unlock(&launch_lock);
 142}
 143
 144/*
 145 * Detect available CPUs, populate cpu_possible_map before smp_init
 146 *
 147 * We don't want to start the secondary CPU yet nor do we have a nice probing
 148 * feature in PMON so we just assume presence of the secondary core.
 149 */
 150static void __init yos_smp_setup(void)
 151{
 152        int i;
 153
 154        cpus_clear(cpu_possible_map);
 155
 156        for (i = 0; i < 2; i++) {
 157                cpu_set(i, cpu_possible_map);
 158                __cpu_number_map[i]     = i;
 159                __cpu_logical_map[i]    = i;
 160        }
 161}
 162
 163static void __init yos_prepare_cpus(unsigned int max_cpus)
 164{
 165        /*
 166         * Be paranoid.  Enable the IPI only if we're really about to go SMP.
 167         */
 168        if (cpus_weight(cpu_possible_map))
 169                set_c0_status(STATUSF_IP5);
 170}
 171
 172struct plat_smp_ops yos_smp_ops = {
 173        .send_ipi_single        = yos_send_ipi_single,
 174        .send_ipi_mask          = yos_send_ipi_mask,
 175        .init_secondary         = yos_init_secondary,
 176        .smp_finish             = yos_smp_finish,
 177        .cpus_done              = yos_cpus_done,
 178        .boot_secondary         = yos_boot_secondary,
 179        .smp_setup              = yos_smp_setup,
 180        .prepare_cpus           = yos_prepare_cpus,
 181};
 182