Merge branch 'classmate' into release
[safe/jmp/linux-2.6] / arch / x86 / kernel / apic / x2apic_uv_x.c
index 20b4ad0..d56b0ef 100644 (file)
@@ -7,41 +7,68 @@
  *
  * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
  */
-
-#include <linux/kernel.h>
-#include <linux/threads.h>
-#include <linux/cpu.h>
 #include <linux/cpumask.h>
+#include <linux/hardirq.h>
+#include <linux/proc_fs.h>
+#include <linux/threads.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
-#include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/hardirq.h>
 #include <linux/timer.h>
-#include <linux/proc_fs.h>
-#include <asm/current.h>
-#include <asm/smp.h>
-#include <asm/apic.h>
-#include <asm/ipi.h>
-#include <asm/pgtable.h>
-#include <asm/uv/uv.h>
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
 #include <asm/uv/bios.h>
+#include <asm/uv/uv.h>
+#include <asm/apic.h>
+#include <asm/ipi.h>
+#include <asm/smp.h>
+#include <asm/x86_init.h>
 
 DEFINE_PER_CPU(int, x2apic_extra_bits);
 
 static enum uv_system_type uv_system_type;
+static u64 gru_start_paddr, gru_end_paddr;
+
+static inline bool is_GRU_range(u64 start, u64 end)
+{
+       return start >= gru_start_paddr && end <= gru_end_paddr;
+}
+
+static bool uv_is_untracked_pat_range(u64 start, u64 end)
+{
+       return is_ISA_range(start, end) || is_GRU_range(start, end);
+}
+
+static int early_get_nodeid(void)
+{
+       union uvh_node_id_u node_id;
+       unsigned long *mmr;
 
-static int uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+       mmr = early_ioremap(UV_LOCAL_MMR_BASE | UVH_NODE_ID, sizeof(*mmr));
+       node_id.v = *mmr;
+       early_iounmap(mmr, sizeof(*mmr));
+       return node_id.s.node_id;
+}
+
+static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
        if (!strcmp(oem_id, "SGI")) {
+               x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
                if (!strcmp(oem_table_id, "UVL"))
                        uv_system_type = UV_LEGACY_APIC;
                else if (!strcmp(oem_table_id, "UVX"))
                        uv_system_type = UV_X2APIC;
                else if (!strcmp(oem_table_id, "UVH")) {
+                       __get_cpu_var(x2apic_extra_bits) =
+                               early_get_nodeid() << (UV_APIC_PNODE_SHIFT - 1);
                        uv_system_type = UV_NON_UNIQUE_APIC;
                        return 1;
                }
@@ -91,40 +118,39 @@ static void uv_vector_allocation_domain(int cpu, struct cpumask *retmask)
        cpumask_set_cpu(cpu, retmask);
 }
 
-int uv_wakeup_secondary(int phys_apicid, unsigned int start_rip)
+static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 {
+#ifdef CONFIG_SMP
        unsigned long val;
        int pnode;
 
        pnode = uv_apicid_to_pnode(phys_apicid);
        val = (1UL << UVH_IPI_INT_SEND_SHFT) |
            (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
-           (((long)start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
+           ((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
            APIC_DM_INIT;
        uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
        mdelay(10);
 
        val = (1UL << UVH_IPI_INT_SEND_SHFT) |
            (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
-           (((long)start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
+           ((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
            APIC_DM_STARTUP;
        uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+
+       atomic_set(&init_deasserted, 1);
+#endif
        return 0;
 }
 
 static void uv_send_IPI_one(int cpu, int vector)
 {
-       unsigned long val, apicid;
+       unsigned long apicid;
        int pnode;
 
        apicid = per_cpu(x86_cpu_to_apicid, cpu);
        pnode = uv_apicid_to_pnode(apicid);
-
-       val = (1UL << UVH_IPI_INT_SEND_SHFT) |
-             (apicid << UVH_IPI_INT_APIC_ID_SHFT) |
-             (vector << UVH_IPI_INT_VECTOR_SHFT);
-
-       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+       uv_hub_send_ipi(pnode, apicid, vector);
 }
 
 static void uv_send_IPI_mask(const struct cpumask *mask, int vector)
@@ -199,10 +225,7 @@ uv_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
                if (cpumask_test_cpu(cpu, cpu_online_mask))
                        break;
        }
-       if (cpu < nr_cpu_ids)
-               return per_cpu(x86_cpu_to_apicid, cpu);
-
-       return BAD_APICID;
+       return per_cpu(x86_cpu_to_apicid, cpu);
 }
 
 static unsigned int x2apic_get_apic_id(unsigned long x)
@@ -240,7 +263,7 @@ static void uv_send_IPI_self(int vector)
        apic_write(APIC_SELF_IPI, vector);
 }
 
-struct apic apic_x2apic_uv_x = {
+struct apic __refdata apic_x2apic_uv_x = {
 
        .name                           = "UV large system",
        .probe                          = NULL,
@@ -248,7 +271,7 @@ struct apic apic_x2apic_uv_x = {
        .apic_id_registered             = uv_apic_id_registered,
 
        .irq_delivery_mode              = dest_Fixed,
-       .irq_dest_mode                  = 1, /* logical */
+       .irq_dest_mode                  = 0, /* physical */
 
        .target_cpus                    = uv_target_cpus,
        .disable_esr                    = 0,
@@ -285,7 +308,7 @@ struct apic apic_x2apic_uv_x = {
        .send_IPI_all                   = uv_send_IPI_all,
        .send_IPI_self                  = uv_send_IPI_self,
 
-       .wakeup_cpu                     = NULL,
+       .wakeup_secondary_cpu           = uv_wakeup_secondary,
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
        .wait_for_init_deassert         = NULL,
@@ -339,20 +362,14 @@ static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
 
        for (i = 0; i < ARRAY_SIZE(redir_addrs); i++) {
                alias.v = uv_read_local_mmr(redir_addrs[i].alias);
-               if (alias.s.base == 0) {
+               if (alias.s.enable && alias.s.base == 0) {
                        *size = (1UL << alias.s.m_alias);
                        redirect.v = uv_read_local_mmr(redir_addrs[i].redirect);
                        *base = (unsigned long)redirect.s.dest_base << DEST_SHIFT;
                        return;
                }
        }
-       BUG();
-}
-
-static __init void map_low_mmrs(void)
-{
-       init_extra_mapping_uc(UV_GLOBAL_MMR32_BASE, UV_GLOBAL_MMR32_SIZE);
-       init_extra_mapping_uc(UV_LOCAL_MMR_BASE, UV_LOCAL_MMR_SIZE);
+       *base = *size = 0;
 }
 
 enum map_type {map_wb, map_uc};
@@ -365,7 +382,7 @@ static __init void map_high(char *id, unsigned long base, int shift,
        paddr = base << shift;
        bytes = (1UL << shift) * (max_pnode + 1);
        printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
-                                               paddr + bytes);
+                                               paddr + bytes);
        if (map_type == map_uc)
                init_extra_mapping_uc(paddr, bytes);
        else
@@ -378,18 +395,12 @@ static __init void map_gru_high(int max_pnode)
        int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT;
 
        gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
-       if (gru.s.enable)
+       if (gru.s.enable) {
                map_high("GRU", gru.s.base, shift, max_pnode, map_wb);
-}
-
-static __init void map_config_high(int max_pnode)
-{
-       union uvh_rh_gam_cfg_overlay_config_mmr_u cfg;
-       int shift = UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR_BASE_SHFT;
+               gru_start_paddr = ((u64)gru.s.base << shift);
+               gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
 
-       cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR);
-       if (cfg.s.enable)
-               map_high("CONFIG", cfg.s.base, shift, max_pnode, map_uc);
+       }
 }
 
 static __init void map_mmr_high(int max_pnode)
@@ -412,6 +423,12 @@ static __init void map_mmioh_high(int max_pnode)
                map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc);
 }
 
+static __init void map_low_mmrs(void)
+{
+       init_extra_mapping_uc(UV_GLOBAL_MMR32_BASE, UV_GLOBAL_MMR32_SIZE);
+       init_extra_mapping_uc(UV_LOCAL_MMR_BASE, UV_LOCAL_MMR_SIZE);
+}
+
 static __init void uv_rtc_init(void)
 {
        long status;
@@ -450,7 +467,7 @@ static void uv_heartbeat(unsigned long ignored)
        uv_set_scir_bits(bits);
 
        /* enable next timer period */
-       mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL);
+       mod_timer_pinned(timer, jiffies + SCIR_CPU_HB_INTERVAL);
 }
 
 static void __cpuinit uv_heartbeat_enable(int cpu)
@@ -528,7 +545,7 @@ late_initcall(uv_init_heartbeat);
 
 /*
  * Called on each cpu to initialize the per_cpu UV data area.
- *     ZZZ hotplug not supported yet
+ * FIXME: hotplug not supported yet
  */
 void __cpuinit uv_cpu_init(void)
 {
@@ -549,8 +566,9 @@ void __init uv_system_init(void)
        union uvh_node_id_u node_id;
        unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
        int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
-       int max_pnode = 0;
-       unsigned long mmr_base, present;
+       int gnode_extra, max_pnode = 0;
+       unsigned long mmr_base, present, paddr;
+       unsigned short pnode_mask;
 
        map_low_mmrs();
 
@@ -560,6 +578,13 @@ void __init uv_system_init(void)
        mmr_base =
            uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
            ~UV_MMR_ENABLE;
+       pnode_mask = (1 << n_val) - 1;
+       node_id.v = uv_read_local_mmr(UVH_NODE_ID);
+       gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1;
+       gnode_upper = ((unsigned long)gnode_extra  << m_val);
+       printk(KERN_DEBUG "UV: N %d, M %d, gnode_upper 0x%lx, gnode_extra 0x%x\n",
+                       n_val, m_val, gnode_upper, gnode_extra);
+
        printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base);
 
        for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++)
@@ -569,15 +594,20 @@ void __init uv_system_init(void)
 
        bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades();
        uv_blade_info = kmalloc(bytes, GFP_KERNEL);
+       BUG_ON(!uv_blade_info);
+       for (blade = 0; blade < uv_num_possible_blades(); blade++)
+               uv_blade_info[blade].memory_nid = -1;
 
        get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size);
 
        bytes = sizeof(uv_node_to_blade[0]) * num_possible_nodes();
        uv_node_to_blade = kmalloc(bytes, GFP_KERNEL);
+       BUG_ON(!uv_node_to_blade);
        memset(uv_node_to_blade, 255, bytes);
 
        bytes = sizeof(uv_cpu_to_blade[0]) * num_possible_cpus();
        uv_cpu_to_blade = kmalloc(bytes, GFP_KERNEL);
+       BUG_ON(!uv_cpu_to_blade);
        memset(uv_cpu_to_blade, 255, bytes);
 
        blade = 0;
@@ -593,10 +623,6 @@ void __init uv_system_init(void)
                }
        }
 
-       node_id.v = uv_read_local_mmr(UVH_NODE_ID);
-       gnode_upper = (((unsigned long)node_id.s.node_id) &
-                      ~((1 << n_val) - 1)) << m_val;
-
        uv_bios_init();
        uv_bios_get_sn_info(0, &uv_type, &sn_partition_id,
                            &sn_coherency_id, &sn_region_size);
@@ -609,16 +635,20 @@ void __init uv_system_init(void)
                lcpu = uv_blade_info[blade].nr_possible_cpus;
                uv_blade_info[blade].nr_possible_cpus++;
 
+               /* Any node on the blade, else will contain -1. */
+               uv_blade_info[blade].memory_nid = nid;
+
                uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base;
                uv_cpu_hub_info(cpu)->lowmem_remap_top = lowmem_redir_size;
                uv_cpu_hub_info(cpu)->m_val = m_val;
-               uv_cpu_hub_info(cpu)->n_val = m_val;
+               uv_cpu_hub_info(cpu)->n_val = n_val;
                uv_cpu_hub_info(cpu)->numa_blade_id = blade;
                uv_cpu_hub_info(cpu)->blade_processor_id = lcpu;
                uv_cpu_hub_info(cpu)->pnode = pnode;
-               uv_cpu_hub_info(cpu)->pnode_mask = (1 << n_val) - 1;
-               uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1;
+               uv_cpu_hub_info(cpu)->pnode_mask = pnode_mask;
+               uv_cpu_hub_info(cpu)->gpa_mask = (1UL << (m_val + n_val)) - 1;
                uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper;
+               uv_cpu_hub_info(cpu)->gnode_extra = gnode_extra;
                uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base;
                uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id;
                uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu;
@@ -632,9 +662,20 @@ void __init uv_system_init(void)
                        lcpu, blade);
        }
 
+       /* Add blade/pnode info for nodes without cpus */
+       for_each_online_node(nid) {
+               if (uv_node_to_blade[nid] >= 0)
+                       continue;
+               paddr = node_start_pfn(nid) << PAGE_SHIFT;
+               paddr = uv_soc_phys_ram_to_gpa(paddr);
+               pnode = (paddr >> m_val) & pnode_mask;
+               blade = boot_pnode_to_blade(pnode);
+               uv_node_to_blade[nid] = blade;
+               max_pnode = max(pnode, max_pnode);
+       }
+
        map_gru_high(max_pnode);
        map_mmr_high(max_pnode);
-       map_config_high(max_pnode);
        map_mmioh_high(max_pnode);
 
        uv_cpu_init();