int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * Don't know why we need this when realview and omap2 appear not to, but * the secondary CPU doesn't start without it. */ write_pen_release(cpu); gic_raise_softirq(cpumask_of(cpu), 1); /* Wake the CPU from WFI */ /* Give the secondary CPU time to get going */ timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; } spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; /* * set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * The secondary processor is waiting to be released from * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. */ write_pen_release(cpu); gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { if (pen_release == -1) break; } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { /* * Set synchronisation state between this boot processor * and the secondary one */ raw_spin_lock(&boot_lock); /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap_secondary_startup() routine will hold the secondary core till * the AuxCoreBoot1 register is updated with cpu state * A barrier is added to ensure that write buffer is drained */ omap_modify_auxcoreboot0(0x200, 0xfffffdff); flush_cache_all(); smp_wmb(); gic_raise_softirq(cpumask_of(cpu), 1); /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ raw_spin_unlock(&boot_lock); return 0; }
static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) { static struct clockdomain *cpu1_clkdm; static bool booted; void __iomem *base = omap_get_wakeupgen_base(); /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap_secondary_startup() routine will hold the secondary core till * the AuxCoreBoot1 register is updated with cpu state * A barrier is added to ensure that write buffer is drained */ if (omap_secure_apis_support()) omap_modify_auxcoreboot0(0x200, 0xfffffdff); else __raw_writel(0x20, base + OMAP_AUX_CORE_BOOT_0); flush_cache_all(); smp_wmb(); if (!cpu1_clkdm) cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); /* * The SGI(Software Generated Interrupts) are not wakeup capable * from low power states. This is known limitation on OMAP4 and * needs to be worked around by using software forced clockdomain * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to * software force wakeup. The clockdomain is then put back to * hardware supervised mode. * More details can be found in OMAP4430 TRM - Version J * Section : * 4.3.4.2 Power States of CPU0 and CPU1 */ if (booted) { clkdm_wakeup(cpu1_clkdm); clkdm_allow_idle(cpu1_clkdm); } else { dsb_sev(); booted = true; } gic_raise_softirq(cpumask_of(cpu), 0); /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return 0; }
int __init arch_smp_start_cpu(u32 cpu) { const struct vmm_cpumask *mask = get_cpu_mask(cpu); /* Wakeup target cpu from wfe/wfi by sending an IPI */ gic_raise_softirq(mask, 0); return VMM_OK; }
static int __init scu_cpu_boot(unsigned int cpu) { const struct vmm_cpumask *mask = get_cpu_mask(cpu); /* Wakeup target cpu from wfe/wfi by sending an IPI */ gic_raise_softirq(mask, 0); return VMM_OK; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { int ret; int flag = 0; unsigned long timeout; pr_debug("Starting secondary CPU %d\n", cpu); preset_lpj = loops_per_jiffy; if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags)) flag = cold_boot_flags[cpu]; else __WARN(); if (per_cpu(cold_boot_done, cpu) == false) { init_cpu_debug_counter_for_cold_boot(); ret = scm_set_boot_addr((void *) virt_to_phys(msm_secondary_startup), flag); if (ret == 0) release_secondary(cpu); else printk(KERN_DEBUG "Failed to set secondary core boot " "address\n"); per_cpu(cold_boot_done, cpu) = true; } spin_lock(&boot_lock); /* * The secondary processor is waiting to be released from * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. * * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ write_pen_release(cpu_logical_map(cpu)); gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(10); } spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; static int cold_boot_done; /* Only need to bring cpu out of reset this way once */ if (cold_boot_done == false) { prepare_cold_cpu(cpu); cold_boot_done = true; } /* * set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * The secondary processor is waiting to be released from * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. * * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ pen_release = cpu; __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(10); } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
int boot_secondary(unsigned int cpu, struct task_struct *idle) { int ret; int flag = 0; unsigned long timeout; pr_debug("Starting secondary CPU %d\n", cpu); preset_lpj = loops_per_jiffy; if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags)) flag = cold_boot_flags[cpu]; else __WARN(); if (per_cpu(cold_boot_done, cpu) == false) { ret = scm_set_boot_addr((void *) virt_to_phys(msm_secondary_startup), flag); if (ret == 0) release_secondary(cpu); else printk(KERN_DEBUG "Failed to set secondary core boot " "address\n"); per_cpu(cold_boot_done, cpu) = true; init_cpu_debug_counter_for_cold_boot(); } spin_lock(&boot_lock); pen_release = cpu_logical_map(cpu); __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; dmac_inv_range((void *)&pen_release, (void *)(&pen_release+sizeof(pen_release))); udelay(10); } spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
static int __cpuinit emev2_boot_secondary(unsigned int cpu, struct task_struct *idle) { cpu = cpu_logical_map(cpu); /* enable cache coherency */ modify_scu_cpu_psr(0, 3 << (cpu * 8)); /* Tell ROM loader about our vector (in headsmp.S) */ emev2_set_boot_vector(__pa(shmobile_secondary_vector)); gic_raise_softirq(cpumask_of(cpu), 1); return 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * This is really belt and braces; we hold unintended secondary * CPUs in the holding pen until we're ready for them. However, * since we haven't sent them a soft interrupt, they shouldn't * be there. */ write_pen_release(cpu); #if 1 //debug { volatile int *ptr = &pen_release; printk("pen_release = 0x%08x, addr= 0x%08x, pen_release ptr = 0x%08x\n ",pen_release,(unsigned int)&pen_release,*ptr); } #endif /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(10); } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
/* Executed by primary CPU, brings other CPUs out of reset. Called at boot as well as when a CPU is coming out of shutdown induced by echo 0 > /sys/devices/.../cpuX. */ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { int cnt = 0; int ret; int flag = 0; pr_debug("Starting secondary CPU %d\n", cpu); /* Set preset_lpj to avoid subsequent lpj recalculations */ preset_lpj = loops_per_jiffy; if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags)) flag = cold_boot_flags[cpu]; else __WARN(); if (per_cpu(cold_boot_done, cpu) == false) { ret = scm_set_boot_addr((void *) virt_to_phys(msm_secondary_startup), flag); if (ret == 0) release_secondary(cpu); else printk(KERN_DEBUG "Failed to set secondary core boot " "address\n"); per_cpu(cold_boot_done, cpu) = true; } pen_release = cpu; dmac_flush_range((void *)&pen_release, (void *)(&pen_release + sizeof(pen_release))); __asm__("sev"); mb(); /* Use smp_cross_call() to send a soft interrupt to wake up * the other core. */ gic_raise_softirq(cpumask_of(cpu), 1); while (pen_release != 0xFFFFFFFF) { dmac_inv_range((void *)&pen_release, (void *)(&pen_release+sizeof(pen_release))); usleep(500); if (cnt++ >= 10) break; } return 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; edb_putstr("boot_secondary\n"); /* * set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * This is really belt and braces; we hold unintended secondary * CPUs in the holding pen until we're ready for them. However, * since we haven't sent them a soft interrupt, they shouldn't * be there. */ pen_release = cpu; __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); wmb(); /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ gic_raise_softirq(cpumask_of(cpu), (GIC_SECURE_INT_FLAG | 1)); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(10); } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
static int __cpuinit release_from_pen(unsigned int cpu) { unsigned long timeout; /* Set preset_lpj to avoid subsequent lpj recalculations */ preset_lpj = loops_per_jiffy; /* * set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * The secondary processor is waiting to be released from * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. * * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ write_pen_release(cpu_logical_map(cpu)); /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(10); } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * This is really belt and braces; we hold unintended secondary * CPUs in the holding pen until we're ready for them. However, * since we haven't sent them a soft interrupt, they shouldn't * be there. */ write_pen_release(cpu_logical_map(cpu)); /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); __raw_writel(virt_to_phys(wmt_secondary_startup), CPU1_BOOT_REG); gic_raise_softirq(cpumask_of(cpu), 1); if (pen_release == -1) break; udelay(10); } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
void pxa1908_gic_raise_softirq(const struct cpumask *mask, unsigned int irq) { unsigned int val = 0; int targ_cpu; gic_raise_softirq(mask, irq); /* Don't touch any reg when axi timeout occurs */ if (keep_silent) return; /* * Set the wakeup bits to make sure the core(s) can respond to * the IPI interrupt. * If the target core(s) is alive, this operation is ignored by * the APMU. After the core wakes up, these corresponding bits * are clearly automatically by PMU hardware. */ preempt_disable(); for_each_cpu(targ_cpu, mask) { BUG_ON(targ_cpu >= CONFIG_NR_CPUS); val |= APMU_WAKEUP_CORE(targ_cpu); }
int __init arch_smp_start_cpu(u32 cpu) { const struct vmm_cpumask *mask; int rc; struct vmm_devtree_node *node; virtual_addr_t ca9_pmu_base; if (cpu == 0) { /* Nothing to do for first CPU */ return VMM_OK; } /* Get the PMU node in the dev tree */ node = vmm_devtree_getnode(VMM_DEVTREE_PATH_SEPARATOR_STRING VMM_DEVTREE_HOSTINFO_NODE_NAME VMM_DEVTREE_PATH_SEPARATOR_STRING "pmu"); if (!node) { return VMM_EFAIL; } /* map the PMU physical address to virtual address */ rc = vmm_devtree_regmap(node, &ca9_pmu_base, 0); if (rc) { return rc; } mask = get_cpu_mask(cpu); /* Write the entry address for the secondary cpus */ vmm_writel((u32)_load_start, (void *)ca9_pmu_base + 0x814); /* unmap the PMU node */ rc = vmm_devtree_regunmap(node, ca9_pmu_base, 0); /* Wakeup target cpu from wfe/wfi by sending an IPI */ gic_raise_softirq(mask, 0); return rc; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; preset_lpj = loops_per_jiffy; if (per_cpu(cold_boot_done, cpu) == false) { if (msm8625_release_secondary(cpu)) { pr_err("Failed to release core %u\n", cpu); return -ENODEV; } per_cpu(cold_boot_done, cpu) = true; } spin_lock(&boot_lock); write_pen_release(cpu); if (per_cpu(power_collapsed, cpu)) { gic_configure_and_raise(cpu_data[cpu].ipc_irq, cpu); raise_clear_spi(cpu, true); } else { gic_raise_softirq(cpumask_of(cpu), 1); } timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(10); } spin_unlock(&boot_lock); return 0; }
void arch_smp_ipi_trigger(const struct vmm_cpumask *dest) { /* Send IPI1 to other cores */ gic_raise_softirq(dest, 1); }
static int __cpuinit highbank_boot_secondary(unsigned int cpu, struct task_struct *idle) { gic_raise_softirq(cpumask_of(cpu), 0); return 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * The secondary processor is waiting to be released from * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. * * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ write_pen_release(cpu); if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) { __raw_writel(S5P_CORE_LOCAL_PWR_EN, S5P_ARM_CORE1_CONFIGURATION); timeout = 10; /* wait max 10 ms until cpu1 is on */ while ((__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) { if (timeout-- == 0) break; mdelay(1); } if (timeout == 0) { printk(KERN_ERR "cpu1 power enable failed"); spin_unlock(&boot_lock); return -ETIMEDOUT; } } /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)), CPU1_BOOT_REG); gic_raise_softirq(cpumask_of(cpu), 1); if (pen_release == -1) break; udelay(10); } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
int __cpuinit msm8625_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; preset_lpj = loops_per_jiffy; if (per_cpu(cold_boot_done, cpu) == false) { if (msm8625_release_secondary(cpu)) { pr_err("Failed to release core %u\n", cpu); return -ENODEV; } per_cpu(cold_boot_done, cpu) = true; } /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * This is really belt and braces; we hold unintended secondary * CPUs in the holding pen until we're ready for them. However, * since we haven't sent them a soft interrupt, they shouldn't * be there. */ write_pen_release(cpu); /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. * * power_collapsed is the flag which will be updated for Powercollapse. * Once we are out of PC, as secondary cores will be in the state of * GDFS which needs to be brought out by raising an SPI. */ if (per_cpu(power_collapsed, cpu)) { gic_configure_and_raise(cpu_data[cpu].ipc_irq, cpu); raise_clear_spi(cpu, true); } else { gic_raise_softirq(cpumask_of(cpu), 1); } timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(10); } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; /* */ spin_lock(&boot_lock); /* */ write_pen_release(cpu_logical_map(cpu)); if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) { __raw_writel(S5P_CORE_LOCAL_PWR_EN, S5P_ARM_CORE1_CONFIGURATION); timeout = 10; /* */ while ((__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) { if (timeout-- == 0) break; mdelay(1); } if (timeout == 0) { printk(KERN_ERR "cpu1 power enable failed"); spin_unlock(&boot_lock); return -ETIMEDOUT; } } /* */ timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); __raw_writel(virt_to_phys(exynos4_secondary_startup), CPU1_BOOT_REG); gic_raise_softirq(cpumask_of(cpu), 1); if (pen_release == -1) break; udelay(10); } /* */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) { static struct clockdomain *cpu1_clkdm; static bool booted; void __iomem *base = omap_get_wakeupgen_base(); /* * Set synchronisation state between this boot processor * and the secondary one */ raw_spin_lock(&boot_lock); /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap_secondary_startup() routine will hold the secondary core till * the AuxCoreBoot1 register is updated with cpu state * A barrier is added to ensure that write buffer is drained */ if (omap_secure_apis_support()) omap_modify_auxcoreboot0(0x200, 0xfffffdff); else __raw_writel(0x20, base + OMAP_AUX_CORE_BOOT_0); flush_cache_all(); smp_wmb(); if (!cpu1_clkdm) cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); /* * The SGI(Software Generated Interrupts) are not wakeup capable * from low power states. This is known limitation on OMAP4 and * needs to be worked around by using software forced clockdomain * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to * software force wakeup. The clockdomain is then put back to * hardware supervised mode. * More details can be found in OMAP4430 TRM - Version J * Section : * 4.3.4.2 Power States of CPU0 and CPU1 */ if (booted) { /* * GIC distributor control register has changed between * CortexA9 r1pX and r2pX. The Control Register secure * banked version is now composed of 2 bits: * bit 0 == Secure Enable * bit 1 == Non-Secure Enable * The Non-Secure banked register has not changed * Because the ROM Code is based on the r1pX GIC, the CPU1 * GIC restoration will cause a problem to CPU0 Non-Secure SW. * The workaround must be: * 1) Before doing the CPU1 wakeup, CPU0 must disable * the GIC distributor * 2) CPU1 must re-enable the GIC distributor on * it's wakeup path. */ if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { local_irq_disable(); gic_dist_disable(); } clkdm_wakeup(cpu1_clkdm); clkdm_allow_idle(cpu1_clkdm); if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { while (gic_dist_disabled()) { udelay(1); cpu_relax(); } gic_timer_retrigger(); local_irq_enable(); } } else { dsb_sev(); booted = true; } gic_raise_softirq(cpumask_of(cpu), 0); /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ raw_spin_unlock(&boot_lock); return 0; }
int boot_secondary(unsigned int cpu, struct task_struct *idle) { gic_raise_softirq(cpumask_of(cpu), 0); return 0; }
int boot_secondary(unsigned int cpu, struct task_struct *idle) { int ret; int flag = 0; unsigned long timeout; pr_debug("Starting secondary CPU %d\n", cpu); /* Set preset_lpj to avoid subsequent lpj recalculations */ preset_lpj = loops_per_jiffy; if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags)) flag = cold_boot_flags[cpu]; else __WARN(); if (per_cpu(cold_boot_done, cpu) == false) { ret = scm_set_boot_addr((void *) virt_to_phys(msm_secondary_startup), flag); if (ret == 0) release_secondary(cpu); else printk(KERN_DEBUG "Failed to set secondary core boot " "address\n"); per_cpu(cold_boot_done, cpu) = true; init_cpu_debug_counter_for_cold_boot(); } /* * set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * The secondary processor is waiting to be released from * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. * * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ pen_release = cpu_logical_map(cpu); __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; dmac_inv_range((void *)&pen_release, (void *)(&pen_release+sizeof(pen_release))); udelay(10); } /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { #ifdef CONFIG_CAPRI_DORMANT_MODE u32 boot_2nd_addr; #endif unsigned long timeout; /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * The secondary processor is waiting to be released from * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. * * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ pen_release = cpu; smp_wmb(); flush_cache_all(); #ifdef CONFIG_OUTER_CACHE outer_flush_all(); #endif #ifdef CONFIG_CAPRI_DORMANT_MODE /* Let go of the secondary core */ boot_2nd_addr = readl_relaxed(KONA_CHIPREG_VA+CHIPREG_BOOT_2ND_ADDR_OFFSET); boot_2nd_addr |= 1; writel_relaxed(boot_2nd_addr, KONA_CHIPREG_VA+CHIPREG_BOOT_2ND_ADDR_OFFSET); #endif /* * Send the secondary CPU a soft interrupt. This will * wake it up in case the secondary CPU is in WFI state. */ gic_raise_softirq(cpumask_of(cpu), 1); /* Sample code to wait till the second core acknowledges * while ( readl_relaxed(KONA_CHIPREG_VA+CHIPREG_BOOT_2ND_ADDR_OFFSET) * & 1 ); */ timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); if (pen_release == -1) break; udelay(10); } /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return pen_release != -1 ? -ENOSYS : 0; }