linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / ia64 / kernel / smpboot.c
index 6203ed4..b681ef3 100644 (file)
@@ -21,6 +21,7 @@
  * 05/01/30 Suresh Siddha <suresh.b.siddha@intel.com>
  *                                             Setup cpu_sibling_map and cpu_core_map
  */
+#include <linux/config.h>
 
 #include <linux/module.h>
 #include <linux/acpi.h>
 #endif
 
 #ifdef CONFIG_HOTPLUG_CPU
-#ifdef CONFIG_PERMIT_BSP_REMOVE
-#define bsp_remove_ok  1
-#else
-#define bsp_remove_ok  0
-#endif
-
 /*
  * Store all idle threads, this can be reused instead of creating
  * a new thread. Also avoids complicated thread destroy functionality
@@ -109,7 +104,7 @@ struct sal_to_os_boot *sal_state_for_booting_cpu = &sal_boot_rendez_state[0];
 /*
  * ITC synchronization related stuff:
  */
-#define MASTER (0)
+#define MASTER 0
 #define SLAVE  (SMP_CACHE_BYTES/8)
 
 #define NUM_ROUNDS     64      /* magic value */
@@ -124,7 +119,7 @@ extern void __devinit calibrate_delay (void);
 extern void start_ap (void);
 extern unsigned long ia64_iobase;
 
-struct task_struct *task_for_booting_cpu;
+task_t *task_for_booting_cpu;
 
 /*
  * State for each CPU
@@ -156,27 +151,6 @@ char __initdata no_int_routing;
 
 unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */
 
-#ifdef CONFIG_FORCE_CPEI_RETARGET
-#define CPEI_OVERRIDE_DEFAULT  (1)
-#else
-#define CPEI_OVERRIDE_DEFAULT  (0)
-#endif
-
-unsigned int force_cpei_retarget = CPEI_OVERRIDE_DEFAULT;
-
-static int __init
-cmdl_force_cpei(char *str)
-{
-       int value=0;
-
-       get_option (&str, &value);
-       force_cpei_retarget = value;
-
-       return 1;
-}
-
-__setup("force_cpei=", cmdl_force_cpei);
-
 static int __init
 nointroute (char *str)
 {
@@ -187,27 +161,6 @@ nointroute (char *str)
 
 __setup("nointroute", nointroute);
 
-static void fix_b0_for_bsp(void)
-{
-#ifdef CONFIG_HOTPLUG_CPU
-       int cpuid;
-       static int fix_bsp_b0 = 1;
-
-       cpuid = smp_processor_id();
-
-       /*
-        * Cache the b0 value on the first AP that comes up
-        */
-       if (!(fix_bsp_b0 && cpuid))
-               return;
-
-       sal_boot_rendez_state[0].br[0] = sal_boot_rendez_state[cpuid].br[0];
-       printk ("Fixed BSP b0 value from CPU %d\n", cpuid);
-
-       fix_bsp_b0 = 0;
-#endif
-}
-
 void
 sync_master (void *arg)
 {
@@ -374,9 +327,8 @@ smp_setup_percpu_timer (void)
 static void __devinit
 smp_callin (void)
 {
-       int cpuid, phys_id, itc_master;
+       int cpuid, phys_id;
        extern void ia64_init_itm(void);
-       extern volatile int time_keeper_id;
 
 #ifdef CONFIG_PERFMON
        extern void pfm_init_percpu(void);
@@ -384,7 +336,6 @@ smp_callin (void)
 
        cpuid = smp_processor_id();
        phys_id = hard_smp_processor_id();
-       itc_master = time_keeper_id;
 
        if (cpu_online(cpuid)) {
                printk(KERN_ERR "huh, phys CPU#0x%x, CPU#0x%x already present??\n",
@@ -392,8 +343,6 @@ smp_callin (void)
                BUG();
        }
 
-       fix_b0_for_bsp();
-
        lock_ipi_calllock();
        cpu_set(cpuid, cpu_online_map);
        unlock_ipi_calllock();
@@ -416,8 +365,8 @@ smp_callin (void)
                 * calls spin_unlock_bh(), which calls spin_unlock_bh(), which calls
                 * local_bh_enable(), which bugs out if irqs are not enabled...
                 */
-               Dprintk("Going to syncup ITC with ITC Master.\n");
-               ia64_sync_itc(itc_master);
+               Dprintk("Going to syncup ITC with BP.\n");
+               ia64_sync_itc(0);
        }
 
        /*
@@ -623,7 +572,31 @@ void __devinit smp_prepare_boot_cpu(void)
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 }
 
+/*
+ * mt_info[] is a temporary store for all info returned by
+ * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the
+ * specific cpu comes.
+ */
+static struct {
+       __u32   socket_id;
+       __u16   core_id;
+       __u16   thread_id;
+       __u16   proc_fixed_addr;
+       __u8    valid;
+} mt_info[NR_CPUS] __devinitdata;
+
 #ifdef CONFIG_HOTPLUG_CPU
+static inline void
+remove_from_mtinfo(int cpu)
+{
+       int i;
+
+       for_each_cpu(i)
+               if (mt_info[i].valid &&  mt_info[i].socket_id ==
+                                               cpu_data(cpu)->socket_id)
+                       mt_info[i].valid = 0;
+}
+
 static inline void
 clear_cpu_sibling_map(int cpu)
 {
@@ -653,50 +626,15 @@ remove_siblinginfo(int cpu)
 
        /* remove it from all sibling map's */
        clear_cpu_sibling_map(cpu);
-}
-
-extern void fixup_irqs(void);
 
-int migrate_platform_irqs(unsigned int cpu)
-{
-       int new_cpei_cpu;
-       irq_desc_t *desc = NULL;
-       cpumask_t       mask;
-       int             retval = 0;
-
-       /*
-        * dont permit CPEI target to removed.
+       /* if this cpu is the last in the core group, remove all its info 
+        * from mt_info structure
         */
-       if (cpe_vector > 0 && is_cpu_cpei_target(cpu)) {
-               printk ("CPU (%d) is CPEI Target\n", cpu);
-               if (can_cpei_retarget()) {
-                       /*
-                        * Now re-target the CPEI to a different processor
-                        */
-                       new_cpei_cpu = any_online_cpu(cpu_online_map);
-                       mask = cpumask_of_cpu(new_cpei_cpu);
-                       set_cpei_target_cpu(new_cpei_cpu);
-                       desc = irq_desc + ia64_cpe_irq;
-                       /*
-                        * Switch for now, immediatly, we need to do fake intr
-                        * as other interrupts, but need to study CPEI behaviour with
-                        * polling before making changes.
-                        */
-                       if (desc) {
-                               desc->chip->disable(ia64_cpe_irq);
-                               desc->chip->set_affinity(ia64_cpe_irq, mask);
-                               desc->chip->enable(ia64_cpe_irq);
-                               printk ("Re-targetting CPEI to cpu %d\n", new_cpei_cpu);
-                       }
-               }
-               if (!desc) {
-                       printk ("Unable to retarget CPEI, offline cpu [%d] failed\n", cpu);
-                       retval = -EBUSY;
-               }
-       }
-       return retval;
+       if (last)
+               remove_from_mtinfo(cpu);
 }
 
+extern void fixup_irqs(void);
 /* must be called with cpucontrol mutex held */
 int __cpu_disable(void)
 {
@@ -705,17 +643,8 @@ int __cpu_disable(void)
        /*
         * dont permit boot processor for now
         */
-       if (cpu == 0 && !bsp_remove_ok) {
-               printk ("Your platform does not support removal of BSP\n");
-               return (-EBUSY);
-       }
-
-       cpu_clear(cpu, cpu_online_map);
-
-       if (migrate_platform_irqs(cpu)) {
-               cpu_set(cpu, cpu_online_map);
-               return (-EBUSY);
-       }
+       if (cpu == 0)
+               return -EBUSY;
 
        remove_siblinginfo(cpu);
        cpu_clear(cpu, cpu_online_map);
@@ -847,6 +776,40 @@ init_smp_config(void)
                       ia64_sal_strerror(sal_ret));
 }
 
+static inline int __devinit
+check_for_mtinfo_index(void)
+{
+       int i;
+       
+       for_each_cpu(i)
+               if (!mt_info[i].valid)
+                       return i;
+
+       return -1;
+}
+
+/*
+ * Search the mt_info to find out if this socket's cid/tid information is
+ * cached or not. If the socket exists, fill in the core_id and thread_id 
+ * in cpuinfo
+ */
+static int __devinit
+check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c)
+{
+       int i;
+       __u32 sid = c->socket_id;
+
+       for_each_cpu(i) {
+               if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address
+                   && mt_info[i].socket_id == sid) {
+                       c->core_id = mt_info[i].core_id;
+                       c->thread_id = mt_info[i].thread_id;
+                       return 1; /* not a new socket */
+               }
+       }
+       return 0;
+}
+
 /*
  * identify_siblings(cpu) gets called from identify_cpu. This populates the 
  * information related to logical execution units in per_cpu_data structure.
@@ -856,12 +819,14 @@ identify_siblings(struct cpuinfo_ia64 *c)
 {
        s64 status;
        u16 pltid;
+       u64 proc_fixed_addr;
+       int count, i;
        pal_logical_to_physical_t info;
 
        if (smp_num_cpucores == 1 && smp_num_siblings == 1)
                return;
 
-       if ((status = ia64_pal_logical_to_phys(-1, &info)) != PAL_STATUS_SUCCESS) {
+       if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) {
                printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
                       status);
                return;
@@ -870,12 +835,47 @@ identify_siblings(struct cpuinfo_ia64 *c)
                printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status);
                return;
        }
+       if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) {
+               printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status);
+               return;
+       }
 
        c->socket_id =  (pltid << 8) | info.overview_ppid;
        c->cores_per_socket = info.overview_cpp;
        c->threads_per_core = info.overview_tpc;
-       c->num_log = info.overview_num_log;
+       count = c->num_log = info.overview_num_log;
+
+       /* If the thread and core id information is already cached, then
+        * we will simply update cpu_info and return. Otherwise, we will
+        * do the PAL calls and cache core and thread id's of all the siblings.
+        */
+       if (check_for_new_socket(proc_fixed_addr, c))
+               return;
+
+       for (i = 0; i < count; i++) {
+               int index;
+
+               if (i && (status = ia64_pal_logical_to_phys(i, &info))
+                         != PAL_STATUS_SUCCESS) {
+                       printk(KERN_ERR "ia64_pal_logical_to_phys failed"
+                                       " with %ld\n", status);
+                       return;
+               }
+               if (info.log2_la == proc_fixed_addr) {
+                       c->core_id = info.log1_cid;
+                       c->thread_id = info.log1_tid;
+               }
 
-       c->core_id = info.log1_cid;
-       c->thread_id = info.log1_tid;
+               index = check_for_mtinfo_index();
+               /* We will not do the mt_info caching optimization in this case.
+                */
+               if (index < 0)
+                       continue;
+
+               mt_info[index].valid = 1;
+               mt_info[index].socket_id = c->socket_id;
+               mt_info[index].core_id = info.log1_cid;
+               mt_info[index].thread_id = info.log1_tid;
+               mt_info[index].proc_fixed_addr = info.log2_la;
+       }
 }