int smp_generic_kick_cpu(int nr) { if (nr < 0 || nr >= nr_cpu_ids) return -EINVAL; /* * The processor is currently spinning, waiting for the * cpu_start field to become non-zero After we set cpu_start, * the processor will continue on to secondary_start */ if (!paca[nr].cpu_start) { paca[nr].cpu_start = 1; smp_mb(); return 0; } #ifdef CONFIG_HOTPLUG_CPU /* * Ok it's not there, so it might be soft-unplugged, let's * try to bring it back */ generic_set_cpu_up(nr); smp_wmb(); smp_send_reschedule(nr); #endif /* CONFIG_HOTPLUG_CPU */ return 0; }
static int __cpuinit smp_85xx_kick_cpu(int nr) { unsigned long flags; const u64 *cpu_rel_addr; __iomem struct epapr_spin_table *spin_table; struct device_node *np; int hw_cpu = get_hard_smp_processor_id(nr); int ioremappable; int ret = 0; WARN_ON(nr < 0 || nr >= NR_CPUS); WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS); pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr); np = of_get_cpu_node(nr, NULL); cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL); if (cpu_rel_addr == NULL) { printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr); return -ENOENT; } /* * A secondary core could be in a spinloop in the bootpage * (0xfffff000), somewhere in highmem, or somewhere in lowmem. * The bootpage and highmem can be accessed via ioremap(), but * we need to directly access the spinloop if its in lowmem. */ ioremappable = *cpu_rel_addr > virt_to_phys(high_memory); /* Map the spin table */ if (ioremappable) spin_table = ioremap(*cpu_rel_addr, sizeof(struct epapr_spin_table)); else spin_table = phys_to_virt(*cpu_rel_addr); local_irq_save(flags); #ifdef CONFIG_PPC32 #ifdef CONFIG_HOTPLUG_CPU /* Corresponding to generic_set_cpu_dead() */ generic_set_cpu_up(nr); if (system_state == SYSTEM_RUNNING) { out_be32(&spin_table->addr_l, 0); /* * We don't set the BPTR register here since it already points * to the boot page properly. */ mpic_reset_core(hw_cpu); /* wait until core is ready... */ if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1, 10000, 100)) { pr_err("%s: timeout waiting for core %d to reset\n", __func__, hw_cpu); ret = -ENOENT; goto out; } /* clear the acknowledge status */ __secondary_hold_acknowledge = -1; } #endif out_be32(&spin_table->pir, hw_cpu); out_be32(&spin_table->addr_l, __pa(__early_start)); if (!ioremappable) flush_dcache_range((ulong)spin_table, (ulong)spin_table + sizeof(struct epapr_spin_table)); /* Wait a bit for the CPU to ack. */ if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu, 10000, 100)) { pr_err("%s: timeout waiting for core %d to ack\n", __func__, hw_cpu); ret = -ENOENT; goto out; } out: #else smp_generic_kick_cpu(nr); out_be32(&spin_table->pir, hw_cpu); out_be64((u64 *)(&spin_table->addr_h), __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); if (!ioremappable) flush_dcache_range((ulong)spin_table, (ulong)spin_table + sizeof(struct epapr_spin_table)); #endif local_irq_restore(flags); if (ioremappable) iounmap(spin_table); return ret; }