|
@@ -209,6 +209,19 @@ send_IPI_allbutself (int op)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Called with preemption disabled.
|
|
|
|
+ */
|
|
|
|
+static inline void
|
|
|
|
+send_IPI_mask(cpumask_t mask, int op)
|
|
|
|
+{
|
|
|
|
+ unsigned int cpu;
|
|
|
|
+
|
|
|
|
+ for_each_cpu_mask(cpu, mask) {
|
|
|
|
+ send_IPI_single(cpu, op);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Called with preemption disabled.
|
|
* Called with preemption disabled.
|
|
*/
|
|
*/
|
|
@@ -401,6 +414,75 @@ smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(smp_call_function_single);
|
|
EXPORT_SYMBOL(smp_call_function_single);
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * smp_call_function_mask(): Run a function on a set of other CPUs.
|
|
|
|
+ * <mask> The set of cpus to run on. Must not include the current cpu.
|
|
|
|
+ * <func> The function to run. This must be fast and non-blocking.
|
|
|
|
+ * <info> An arbitrary pointer to pass to the function.
|
|
|
|
+ * <wait> If true, wait (atomically) until function
|
|
|
|
+ * has completed on other CPUs.
|
|
|
|
+ *
|
|
|
|
+ * Returns 0 on success, else a negative status code.
|
|
|
|
+ *
|
|
|
|
+ * If @wait is true, then returns once @func has returned; otherwise
|
|
|
|
+ * it returns just before the target cpu calls @func.
|
|
|
|
+ *
|
|
|
|
+ * 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_mask(cpumask_t mask,
|
|
|
|
+ void (*func)(void *), void *info,
|
|
|
|
+ int wait)
|
|
|
|
+{
|
|
|
|
+ struct call_data_struct data;
|
|
|
|
+ cpumask_t allbutself;
|
|
|
|
+ int cpus;
|
|
|
|
+
|
|
|
|
+ spin_lock(&call_lock);
|
|
|
|
+ allbutself = cpu_online_map;
|
|
|
|
+ cpu_clear(smp_processor_id(), allbutself);
|
|
|
|
+
|
|
|
|
+ cpus_and(mask, mask, allbutself);
|
|
|
|
+ cpus = cpus_weight(mask);
|
|
|
|
+ if (!cpus) {
|
|
|
|
+ spin_unlock(&call_lock);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* 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);
|
|
|
|
+
|
|
|
|
+ call_data = &data;
|
|
|
|
+ mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC*/
|
|
|
|
+
|
|
|
|
+ /* Send a message to other CPUs */
|
|
|
|
+ if (cpus_equal(mask, allbutself))
|
|
|
|
+ send_IPI_allbutself(IPI_CALL_FUNC);
|
|
|
|
+ else
|
|
|
|
+ send_IPI_mask(mask, IPI_CALL_FUNC);
|
|
|
|
+
|
|
|
|
+ /* Wait for response */
|
|
|
|
+ while (atomic_read(&data.started) != cpus)
|
|
|
|
+ cpu_relax();
|
|
|
|
+
|
|
|
|
+ if (wait)
|
|
|
|
+ while (atomic_read(&data.finished) != cpus)
|
|
|
|
+ cpu_relax();
|
|
|
|
+ call_data = NULL;
|
|
|
|
+
|
|
|
|
+ spin_unlock(&call_lock);
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(smp_call_function_mask);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* this function sends a 'generic call function' IPI to all other CPUs
|
|
* this function sends a 'generic call function' IPI to all other CPUs
|
|
* in the system.
|
|
* in the system.
|