/* * This function sends a 'generic call function' IPI to all other CPUs * in the system. * * [SUMMARY] Run a function on all other CPUs. * <func> The function to run. This must be fast and non-blocking. * <info> An arbitrary pointer to pass to the function. * <nonatomic> currently unused. * <wait> If true, wait (atomically) until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. Does not return until * remote CPUs are nearly ready to execute <<func>> or are or have executed. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) { struct call_data_struct data; int ret = -1, cpus; u64 timeout; /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); data.func = func; data.info = info; atomic_set(&data.started, 0); data.wait = wait; if (wait) atomic_set(&data.finished, 0); spin_lock(&call_lock); /* Must grab online cpu count with preempt disabled, otherwise * it can change. */ cpus = num_online_cpus() - 1; if (!cpus) { ret = 0; goto out; } call_data = &data; smp_wmb(); /* Send a message to all other CPUs and wait for them to respond */ smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION); timeout = get_tb() + (u64) SMP_CALL_TIMEOUT * tb_ticks_per_sec; /* Wait for response */ while (atomic_read(&data.started) != cpus) { HMT_low(); if (get_tb() >= timeout) { printk("smp_call_function on cpu %d: other cpus not " "responding (%d)\n", smp_processor_id(), atomic_read(&data.started)); debugger(NULL); goto out; } } if (wait) { while (atomic_read(&data.finished) != cpus) { HMT_low(); if (get_tb() >= timeout) { printk("smp_call_function on cpu %d: other " "cpus not finishing (%d/%d)\n", smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); debugger(NULL); goto out; } } } ret = 0; out: call_data = NULL; HMT_medium(); spin_unlock(&call_lock); return ret; }
/* * These functions send a 'generic call function' IPI to other online * CPUS in the system. * * [SUMMARY] Run a function on other CPUs. * <func> The function to run. This must be fast and non-blocking. * <info> An arbitrary pointer to pass to the function. * <nonatomic> currently unused. * <wait> If true, wait (atomically) until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. Does not return until * remote CPUs are nearly ready to execute <<func>> or are or have executed. * <map> is a cpu map of the cpus to send IPI to. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ static int __smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, int wait, cpumask_t map) { struct call_data_struct data; int ret = -1, num_cpus; int cpu; u64 timeout; if (unlikely(smp_ops == NULL)) return ret; data.func = func; data.info = info; atomic_set(&data.started, 0); data.wait = wait; if (wait) atomic_set(&data.finished, 0); /* remove 'self' from the map */ if (cpu_isset(smp_processor_id(), map)) cpu_clear(smp_processor_id(), map); /* sanity check the map, remove any non-online processors. */ cpus_and(map, map, cpu_online_map); num_cpus = cpus_weight(map); if (!num_cpus) goto done; call_data = &data; smp_wmb(); /* Send a message to all CPUs in the map */ for_each_cpu_mask(cpu, map) smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION); timeout = get_tb() + (u64) SMP_CALL_TIMEOUT * tb_ticks_per_sec; /* Wait for indication that they have received the message */ while (atomic_read(&data.started) != num_cpus) { HMT_low(); if (get_tb() >= timeout) { printk("smp_call_function on cpu %d: other cpus not " "responding (%d)\n", smp_processor_id(), atomic_read(&data.started)); if (!ipi_fail_ok) debugger(NULL); goto out; } } /* optionally wait for the CPUs to complete */ if (wait) { while (atomic_read(&data.finished) != num_cpus) { HMT_low(); if (get_tb() >= timeout) { printk("smp_call_function on cpu %d: other " "cpus not finishing (%d/%d)\n", smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); debugger(NULL); goto out; } } } done: ret = 0; out: call_data = NULL; HMT_medium(); return ret; }
/* * This function sends a 'generic call function' IPI to all other CPUs * in the system. * * [SUMMARY] Run a function on all other CPUs. * <func> The function to run. This must be fast and non-blocking. * <info> An arbitrary pointer to pass to the function. * <nonatomic> currently unused. * <wait> If true, wait (atomically) until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. Does not return until * remote CPUs are nearly ready to execute <<func>> or are or have executed. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) { struct call_data_struct data; int ret = -1, cpus = smp_num_cpus-1; int timeout; if (!cpus) return 0; data.func = func; data.info = info; atomic_set(&data.started, 0); data.wait = wait; if (wait) atomic_set(&data.finished, 0); spin_lock_bh(&call_lock); call_data = &data; /* Send a message to all other CPUs and wait for them to respond */ smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION, 0, 0); /* Wait for response */ timeout = 8000000; while (atomic_read(&data.started) != cpus) { HMT_low(); if (--timeout == 0) { printk("smp_call_function on cpu %d: other cpus not responding (%d)\n", smp_processor_id(), atomic_read(&data.started)); #ifdef CONFIG_XMON xmon(0); #endif #ifdef CONFIG_KDB kdb(KDB_REASON_CALL,0, (kdb_eframe_t) 0); #endif #ifdef CONFIG_PPC_ISERIES HvCall_terminateMachineSrc(); #endif goto out; } barrier(); udelay(1); } if (wait) { timeout = 1000000; while (atomic_read(&data.finished) != cpus) { HMT_low(); if (--timeout == 0) { printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); #ifdef CONFIG_PPC_ISERIES HvCall_terminateMachineSrc(); #endif goto out; } barrier(); udelay(1); } } ret = 0; out: call_data = NULL; HMT_medium(); spin_unlock_bh(&call_lock); return ret; }