Path: blob/master/arch/mips/pmc-sierra/yosemite/smp.c
15118 views
#include <linux/linkage.h>1#include <linux/sched.h>2#include <linux/smp.h>34#include <asm/pmon.h>5#include <asm/titan_dep.h>6#include <asm/time.h>78#define LAUNCHSTACK_SIZE 256910static __cpuinitdata arch_spinlock_t launch_lock = __ARCH_SPIN_LOCK_UNLOCKED;1112static unsigned long secondary_sp __cpuinitdata;13static unsigned long secondary_gp __cpuinitdata;1415static unsigned char launchstack[LAUNCHSTACK_SIZE] __initdata16__attribute__((aligned(2 * sizeof(long))));1718static void __init prom_smp_bootstrap(void)19{20local_irq_disable();2122while (arch_spin_is_locked(&launch_lock));2324__asm__ __volatile__(25" move $sp, %0 \n"26" move $gp, %1 \n"27" j smp_bootstrap \n"28:29: "r" (secondary_sp), "r" (secondary_gp));30}3132/*33* PMON is a fragile beast. It'll blow up once the mappings it's littering34* right into the middle of KSEG3 are blown away so we have to grab the slave35* core early and keep it in a waiting loop.36*/37void __init prom_grab_secondary(void)38{39arch_spin_lock(&launch_lock);4041pmon_cpustart(1, &prom_smp_bootstrap,42launchstack + LAUNCHSTACK_SIZE, 0);43}4445void titan_mailbox_irq(void)46{47int cpu = smp_processor_id();48unsigned long status;4950switch (cpu) {51case 0:52status = OCD_READ(RM9000x2_OCD_INTP0STATUS3);53OCD_WRITE(RM9000x2_OCD_INTP0CLEAR3, status);5455if (status & 0x2)56smp_call_function_interrupt();57if (status & 0x4)58scheduler_ipi();59break;6061case 1:62status = OCD_READ(RM9000x2_OCD_INTP1STATUS3);63OCD_WRITE(RM9000x2_OCD_INTP1CLEAR3, status);6465if (status & 0x2)66smp_call_function_interrupt();67if (status & 0x4)68scheduler_ipi();69break;70}71}7273/*74* Send inter-processor interrupt75*/76static void yos_send_ipi_single(int cpu, unsigned int action)77{78/*79* Generate an INTMSG so that it can be sent over to the80* destination CPU. The INTMSG will put the STATUS bits81* based on the action desired. An alternative strategy82* is to write to the Interrupt Set register, read the83* Interrupt Status register and clear the Interrupt84* Clear register. The latter is preffered.85*/86switch (action) {87case SMP_RESCHEDULE_YOURSELF:88if (cpu == 1)89OCD_WRITE(RM9000x2_OCD_INTP1SET3, 4);90else91OCD_WRITE(RM9000x2_OCD_INTP0SET3, 4);92break;9394case SMP_CALL_FUNCTION:95if (cpu == 1)96OCD_WRITE(RM9000x2_OCD_INTP1SET3, 2);97else98OCD_WRITE(RM9000x2_OCD_INTP0SET3, 2);99break;100}101}102103static void yos_send_ipi_mask(const struct cpumask *mask, unsigned int action)104{105unsigned int i;106107for_each_cpu(i, mask)108yos_send_ipi_single(i, action);109}110111/*112* After we've done initial boot, this function is called to allow the113* board code to clean up state, if needed114*/115static void __cpuinit yos_init_secondary(void)116{117set_c0_status(ST0_CO | ST0_IE | ST0_IM);118}119120static void __cpuinit yos_smp_finish(void)121{122}123124/* Hook for after all CPUs are online */125static void yos_cpus_done(void)126{127}128129/*130* Firmware CPU startup hook131* Complicated by PMON's weird interface which tries to minimic the UNIX fork.132* It launches the next * available CPU and copies some information on the133* stack so the first thing we do is throw away that stuff and load useful134* values into the registers ...135*/136static void __cpuinit yos_boot_secondary(int cpu, struct task_struct *idle)137{138unsigned long gp = (unsigned long) task_thread_info(idle);139unsigned long sp = __KSTK_TOS(idle);140141secondary_sp = sp;142secondary_gp = gp;143144arch_spin_unlock(&launch_lock);145}146147/*148* Detect available CPUs, populate cpu_possible_map before smp_init149*150* We don't want to start the secondary CPU yet nor do we have a nice probing151* feature in PMON so we just assume presence of the secondary core.152*/153static void __init yos_smp_setup(void)154{155int i;156157cpus_clear(cpu_possible_map);158159for (i = 0; i < 2; i++) {160cpu_set(i, cpu_possible_map);161__cpu_number_map[i] = i;162__cpu_logical_map[i] = i;163}164}165166static void __init yos_prepare_cpus(unsigned int max_cpus)167{168/*169* Be paranoid. Enable the IPI only if we're really about to go SMP.170*/171if (cpus_weight(cpu_possible_map))172set_c0_status(STATUSF_IP5);173}174175struct plat_smp_ops yos_smp_ops = {176.send_ipi_single = yos_send_ipi_single,177.send_ipi_mask = yos_send_ipi_mask,178.init_secondary = yos_init_secondary,179.smp_finish = yos_smp_finish,180.cpus_done = yos_cpus_done,181.boot_secondary = yos_boot_secondary,182.smp_setup = yos_smp_setup,183.prepare_cpus = yos_prepare_cpus,184};185186187