static int exynos5_cpu_power_up(void __iomem *power, int cpu) { unsigned int timeout; if ( !exynos_cpu_power_state(power, cpu) ) { exynos_cpu_power_up(power, cpu); timeout = 10; /* wait max 10 ms until cpu is on */ while ( exynos_cpu_power_state(power, cpu) != S5P_CORE_LOCAL_PWR_EN ) { if ( timeout-- == 0 ) break; mdelay(1); } if ( timeout == 0 ) { dprintk(XENLOG_ERR, "CPU%d power enable failed", cpu); return -ETIMEDOUT; } } return 0; }
static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; u32 mpidr = cpu_logical_map(cpu); u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); int ret = -ENOSYS; /* * 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 core ID, whereas * "cpu" is Linux's internal ID. */ write_pen_release(core_id); if (!soc_is_exynos5440() && !exynos_cpu_power_state(core_id)) { exynos_cpu_power_up(core_id); timeout = 10; /* wait max 10 ms until cpu1 is on */ while (exynos_cpu_power_state(core_id) != 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)) { unsigned long boot_addr; smp_rmb(); boot_addr = virt_to_phys(exynos4_secondary_startup); /* * Try to set boot address using firmware first * and fall back to boot register if it fails. */ ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); if (ret && ret != -ENOSYS) goto fail; if (ret == -ENOSYS) { void __iomem *boot_reg = cpu_boot_reg(core_id); if (IS_ERR(boot_reg)) { ret = PTR_ERR(boot_reg); goto fail; } __raw_writel(boot_addr, cpu_boot_reg(core_id)); } call_firmware_op(cpu_boot, core_id); arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 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 */ fail: spin_unlock(&boot_lock); return pen_release != -1 ? ret : 0; }