upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / arch / i386 / kernel / smp.c
index 5c4f178..c2888ac 100644 (file)
@@ -322,7 +322,7 @@ static inline void leave_mm (unsigned long cpu)
  * 2) Leave the mm if we are in the lazy tlb mode.
  */
 
-asmlinkage void smp_invalidate_interrupt (void)
+fastcall void smp_invalidate_interrupt(struct pt_regs *regs)
 {
        unsigned long cpu;
 
@@ -524,7 +524,10 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
  * <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.
+ * <wait> If 1, wait (atomically) until function has completed on other CPUs.
+ *        If 0, wait for the IPI to be received by other CPUs, but do not wait 
+ *        for the completion of the function on each CPU.  
+ *        If -1, do not wait for other CPUs to receive IPI.
  * [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.
  *
@@ -532,36 +535,50 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
  * hardware interrupt handler or from a bottom half handler.
  */
 {
-       struct call_data_struct data;
+       static struct call_data_struct dumpdata;
+       struct call_data_struct normaldata;
+       struct call_data_struct *data;
        int cpus = num_online_cpus()-1;
 
        if (!cpus)
                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);
+       /* Only if we are waiting for other CPU to ack */
+       WARN_ON(irqs_disabled() && wait >= 0);
 
        spin_lock(&call_lock);
-       call_data = &data;
+       if (wait == -1) {
+               /* if another cpu beat us, they win! */
+               if (dumpdata.func) {
+                       spin_unlock(&call_lock);
+                       return 0;
+               }
+               data = &dumpdata;
+       } else
+               data = &normaldata;
+
+       data->func = func;
+       data->info = info;
+       atomic_set(&data->started, 0);
+       data->wait = wait > 0 ? wait : 0;
+       if (wait > 0)
+               atomic_set(&data->finished, 0);
+
+       call_data = data;
        mb();
        
        /* Send a message to all other CPUs and wait for them to respond */
        send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 
        /* Wait for response */
-       while (atomic_read(&data.started) != cpus)
-               barrier();
+       if (wait >= 0)
+               while (atomic_read(&data->started) != cpus)
+                       cpu_relax();
 
-       if (wait)
-               while (atomic_read(&data.finished) != cpus)
-                       barrier();
+       if (wait > 0)
+               while (atomic_read(&data->finished) != cpus)
+                       cpu_relax();
        spin_unlock(&call_lock);
 
        return 0;
@@ -600,12 +617,12 @@ EXPORT_SYMBOL(smp_send_stop);
  * all the work is done automatically when
  * we return from the interrupt.
  */
-asmlinkage void smp_reschedule_interrupt(void)
+fastcall void smp_reschedule_interrupt(struct pt_regs *regs)
 {
        ack_APIC_irq();
 }
 
-asmlinkage void smp_call_function_interrupt(void)
+fastcall void smp_call_function_interrupt(struct pt_regs *regs)
 {
        void (*func) (void *info) = call_data->func;
        void *info = call_data->info;