* Hacked for x86-64 by James Cleverdon from i386 architecture code by
  * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
  * James Cleverdon.
+ * Ashok Raj <ashok.raj@intel.com>
+ *     Removed IPI broadcast shortcut to support CPU hotplug
  */
 #include <linux/config.h>
 #include <linux/threads.h>
        apic_write_around(APIC_LDR, val);
 }
 
-static void flat_send_IPI_allbutself(int vector)
-{
-       /*
-        * if there are no other CPUs in the system then
-        * we get an APIC send error if we try to broadcast.
-        * thus we have to avoid sending IPIs in this case.
-        */
-       if (num_online_cpus() > 1)
-               __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
-}
-
-static void flat_send_IPI_all(int vector)
-{
-       __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
-}
-
 static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
 {
        unsigned long mask = cpus_addr(cpumask)[0];
        local_irq_restore(flags);
 }
 
+static void flat_send_IPI_allbutself(int vector)
+{
+       cpumask_t mask;
+       /*
+        * if there are no other CPUs in the system then
+        * we get an APIC send error if we try to broadcast.
+        * thus we have to avoid sending IPIs in this case.
+        */
+       int this_cpu = get_cpu();
+
+       mask = cpu_online_map;
+       cpu_clear(this_cpu, mask);
+
+       if (cpus_weight(mask) >= 1)
+               flat_send_IPI_mask(mask, vector);
+
+       put_cpu();
+}
+
+static void flat_send_IPI_all(int vector)
+{
+       flat_send_IPI_mask(cpu_online_map, vector);
+}
+
 static int flat_apic_id_registered(void)
 {
        return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map);
 
 
 static struct call_data_struct * call_data;
 
+void lock_ipi_call_lock(void)
+{
+       spin_lock_irq(&call_lock);
+}
+
+void unlock_ipi_call_lock(void)
+{
+       spin_unlock_irq(&call_lock);
+}
+
 /*
  * this function sends a 'generic call function' IPI to all other CPUs
  * in the system.
 
         */
        set_cpu_sibling_map(smp_processor_id());
 
+       /*
+        * We need to hold call_lock, so there is no inconsistency
+        * between the time smp_call_function() determines number of
+        * IPI receipients, and the time when the determination is made
+        * for which cpus receive the IPI in genapic_flat.c. Holding this
+        * lock helps us to not include this cpu in a currently in progress
+        * smp_call_function().
+        */
+       lock_ipi_call_lock();
+
        /*
         * Allow the master to continue.
         */
        cpu_set(smp_processor_id(), cpu_online_map);
+       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+       unlock_ipi_call_lock();
+
        mb();
 
        /* Wait for TSC sync to not schedule things before.
        cpu_set(me, cpu_callout_map);
        cpu_set(0, cpu_sibling_map[0]);
        cpu_set(0, cpu_core_map[0]);
+       per_cpu(cpu_state, me) = CPU_ONLINE;
 }
 
 /*
                return -ENOSYS;
        }
 
+       per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
        /* Boot it! */
        err = do_boot_cpu(cpu, apicid);
        if (err < 0) {
 
        for (i = 0; i < 10; i++) {
                /* They ack this in play_dead by setting CPU_DEAD */
-               if (per_cpu(cpu_state, cpu) == CPU_DEAD)
+               if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+                       printk ("CPU %d is now offline\n", cpu);
                        return;
+               }
                current->state = TASK_UNINTERRUPTIBLE;
                schedule_timeout(HZ/10);
        }
 
 extern void smp_alloc_memory(void);
 extern volatile unsigned long smp_invalidate_needed;
 extern int pic_mode;
+extern void lock_ipi_call_lock(void);
+extern void unlock_ipi_call_lock(void);
 extern int smp_num_siblings;
 extern void smp_flush_tlb(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);