/** * temac_indirect_busywait - Wait for current indirect register access * to complete. */ int temac_indirect_busywait(struct temac_local *lp) { ktime_t timeout = ktime_add_ns(ktime_get(), HARD_ACS_RDY_POLL_NS); spin_until_cond(hard_acs_rdy_or_timeout(lp, timeout)); if (WARN_ON(!hard_acs_rdy(lp))) return -ETIMEDOUT; else return 0; }
/* * - cpu is the target CPU (must not be this CPU), or NMI_IPI_ALL_OTHERS. * - fn is the target callback function. * - delay_us > 0 is the delay before giving up waiting for targets to * enter the handler, == 0 specifies indefinite delay. */ int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us) { unsigned long flags; int me = raw_smp_processor_id(); int ret = 1; BUG_ON(cpu == me); BUG_ON(cpu < 0 && cpu != NMI_IPI_ALL_OTHERS); if (unlikely(!smp_ops)) return 0; /* Take the nmi_ipi_busy count/lock with interrupts hard disabled */ nmi_ipi_lock_start(&flags); while (nmi_ipi_busy_count) { nmi_ipi_unlock_end(&flags); spin_until_cond(nmi_ipi_busy_count == 0); nmi_ipi_lock_start(&flags); } nmi_ipi_function = fn; if (cpu < 0) { /* ALL_OTHERS */ cpumask_copy(&nmi_ipi_pending_mask, cpu_online_mask); cpumask_clear_cpu(me, &nmi_ipi_pending_mask); } else { /* cpumask starts clear */ cpumask_set_cpu(cpu, &nmi_ipi_pending_mask); } nmi_ipi_busy_count++; nmi_ipi_unlock(); do_smp_send_nmi_ipi(cpu); while (!cpumask_empty(&nmi_ipi_pending_mask)) { udelay(1); if (delay_us) { delay_us--; if (!delay_us) break; } } nmi_ipi_lock(); if (!cpumask_empty(&nmi_ipi_pending_mask)) { /* Could not gather all CPUs */ ret = 0; cpumask_clear(&nmi_ipi_pending_mask); } nmi_ipi_busy_count--; nmi_ipi_unlock_end(&flags); return ret; }
static void nmi_ipi_lock_start(unsigned long *flags) { raw_local_irq_save(*flags); hard_irq_disable(); while (atomic_cmpxchg(&__nmi_ipi_lock, 0, 1) == 1) { raw_local_irq_restore(*flags); spin_until_cond(atomic_read(&__nmi_ipi_lock) == 0); raw_local_irq_save(*flags); hard_irq_disable(); } }
int __cpu_up(unsigned int cpu, struct task_struct *tidle) { int rc, c; /* * Don't allow secondary threads to come online if inhibited */ if (threads_per_core > 1 && secondaries_inhibited() && cpu_thread_in_subcore(cpu)) return -EBUSY; if (smp_ops == NULL || (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))) return -EINVAL; cpu_idle_thread_init(cpu, tidle); /* * The platform might need to allocate resources prior to bringing * up the CPU */ if (smp_ops->prepare_cpu) { rc = smp_ops->prepare_cpu(cpu); if (rc) return rc; } /* Make sure callin-map entry is 0 (can be leftover a CPU * hotplug */ cpu_callin_map[cpu] = 0; /* The information for processor bringup must * be written out to main store before we release * the processor. */ smp_mb(); /* wake up cpus */ DBG("smp: kicking cpu %d\n", cpu); rc = smp_ops->kick_cpu(cpu); if (rc) { pr_err("smp: failed starting cpu %d (rc %d)\n", cpu, rc); return rc; } /* * wait to see if the cpu made a callin (is actually up). * use this value that I found through experimentation. * -- Cort */ if (system_state < SYSTEM_RUNNING) for (c = 50000; c && !cpu_callin_map[cpu]; c--) udelay(100); #ifdef CONFIG_HOTPLUG_CPU else /* * CPUs can take much longer to come up in the * hotplug case. Wait five seconds. */ for (c = 5000; c && !cpu_callin_map[cpu]; c--) msleep(1); #endif if (!cpu_callin_map[cpu]) { printk(KERN_ERR "Processor %u is stuck.\n", cpu); return -ENOENT; } DBG("Processor %u found.\n", cpu); if (smp_ops->give_timebase) smp_ops->give_timebase(); /* Wait until cpu puts itself in the online & active maps */ spin_until_cond(cpu_online(cpu)); return 0; }
static void nmi_ipi_lock(void) { while (atomic_cmpxchg(&__nmi_ipi_lock, 0, 1) == 1) spin_until_cond(atomic_read(&__nmi_ipi_lock) == 0); }