include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / arch / x86 / kernel / apic / x2apic_uv_x.c
index b684bb3..c085d52 100644 (file)
@@ -5,7 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
 #include <linux/ctype.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
+#include <linux/slab.h>
 #include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/kdebug.h>
 
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
 
 DEFINE_PER_CPU(int, x2apic_extra_bits);
 
+#define PR_DEVEL(fmt, args...) pr_devel("%s: " fmt, __func__, args)
+
 static enum uv_system_type uv_system_type;
 static u64 gru_start_paddr, gru_end_paddr;
+int uv_min_hub_revision_id;
+EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
+static DEFINE_SPINLOCK(uv_nmi_lock);
 
 static inline bool is_GRU_range(u64 start, u64 end)
 {
@@ -55,20 +63,28 @@ static int early_get_nodeid(void)
        mmr = early_ioremap(UV_LOCAL_MMR_BASE | UVH_NODE_ID, sizeof(*mmr));
        node_id.v = *mmr;
        early_iounmap(mmr, sizeof(*mmr));
+
+       /* Currently, all blades have same revision number */
+       uv_min_hub_revision_id = node_id.s.revision;
+
        return node_id.s.node_id;
 }
 
 static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
+       int nodeid;
+
        if (!strcmp(oem_id, "SGI")) {
+               nodeid = early_get_nodeid();
                x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
+               x86_platform.nmi_init = uv_nmi_init;
                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);
+                               nodeid << (UV_APIC_PNODE_SHIFT - 1);
                        uv_system_type = UV_NON_UNIQUE_APIC;
                        return 1;
                }
@@ -105,11 +121,9 @@ EXPORT_SYMBOL_GPL(uv_possible_blades);
 unsigned long sn_rtc_cycles_per_second;
 EXPORT_SYMBOL(sn_rtc_cycles_per_second);
 
-/* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */
-
 static const struct cpumask *uv_target_cpus(void)
 {
-       return cpumask_of(0);
+       return cpu_online_mask;
 }
 
 static void uv_vector_allocation_domain(int cpu, struct cpumask *retmask)
@@ -225,10 +239,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)
@@ -377,13 +388,13 @@ static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
 
 enum map_type {map_wb, map_uc};
 
-static __init void map_high(char *id, unsigned long base, int shift,
-                           int max_pnode, enum map_type map_type)
+static __init void map_high(char *id, unsigned long base, int pshift,
+                       int bshift, int max_pnode, enum map_type map_type)
 {
        unsigned long bytes, paddr;
 
-       paddr = base << shift;
-       bytes = (1UL << shift) * (max_pnode + 1);
+       paddr = base << pshift;
+       bytes = (1UL << bshift) * (max_pnode + 1);
        printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
                                                paddr + bytes);
        if (map_type == map_uc)
@@ -399,7 +410,7 @@ static __init void map_gru_high(int max_pnode)
 
        gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
        if (gru.s.enable) {
-               map_high("GRU", gru.s.base, shift, max_pnode, map_wb);
+               map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb);
                gru_start_paddr = ((u64)gru.s.base << shift);
                gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
 
@@ -413,7 +424,7 @@ static __init void map_mmr_high(int max_pnode)
 
        mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
        if (mmr.s.enable)
-               map_high("MMR", mmr.s.base, shift, max_pnode, map_uc);
+               map_high("MMR", mmr.s.base, shift, shift, max_pnode, map_uc);
 }
 
 static __init void map_mmioh_high(int max_pnode)
@@ -423,7 +434,8 @@ static __init void map_mmioh_high(int max_pnode)
 
        mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
        if (mmioh.s.enable)
-               map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc);
+               map_high("MMIOH", mmioh.s.base, shift, mmioh.s.m_io,
+                       max_pnode, map_uc);
 }
 
 static __init void map_low_mmrs(void)
@@ -475,7 +487,7 @@ static void uv_heartbeat(unsigned long ignored)
 
 static void __cpuinit uv_heartbeat_enable(int cpu)
 {
-       if (!uv_cpu_hub_info(cpu)->scir.enabled) {
+       while (!uv_cpu_hub_info(cpu)->scir.enabled) {
                struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer;
 
                uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY);
@@ -483,11 +495,10 @@ static void __cpuinit uv_heartbeat_enable(int cpu)
                timer->expires = jiffies + SCIR_CPU_HB_INTERVAL;
                add_timer_on(timer, cpu);
                uv_cpu_hub_info(cpu)->scir.enabled = 1;
-       }
 
-       /* check boot cpu */
-       if (!uv_cpu_hub_info(0)->scir.enabled)
-               uv_heartbeat_enable(0);
+               /* also ensure that boot cpu is enabled */
+               cpu = 0;
+       }
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -546,6 +557,30 @@ late_initcall(uv_init_heartbeat);
 
 #endif /* !CONFIG_HOTPLUG_CPU */
 
+/* Direct Legacy VGA I/O traffic to designated IOH */
+int uv_set_vga_state(struct pci_dev *pdev, bool decode,
+                     unsigned int command_bits, bool change_bridge)
+{
+       int domain, bus, rc;
+
+       PR_DEVEL("devfn %x decode %d cmd %x chg_brdg %d\n",
+                       pdev->devfn, decode, command_bits, change_bridge);
+
+       if (!change_bridge)
+               return 0;
+
+       if ((command_bits & PCI_COMMAND_IO) == 0)
+               return 0;
+
+       domain = pci_domain_nr(pdev->bus);
+       bus = pdev->bus->number;
+
+       rc = uv_bios_set_legacy_vga_target(decode, domain, bus);
+       PR_DEVEL("vga decode %d %x:%x, rc: %d\n", decode, domain, bus, rc);
+
+       return rc;
+}
+
 /*
  * Called on each cpu to initialize the per_cpu UV data area.
  * FIXME: hotplug not supported yet
@@ -562,6 +597,46 @@ void __cpuinit uv_cpu_init(void)
                set_x2apic_extra_bits(uv_hub_info->pnode);
 }
 
+/*
+ * When NMI is received, print a stack trace.
+ */
+int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data)
+{
+       if (reason != DIE_NMI_IPI)
+               return NOTIFY_OK;
+       /*
+        * Use a lock so only one cpu prints at a time
+        * to prevent intermixed output.
+        */
+       spin_lock(&uv_nmi_lock);
+       pr_info("NMI stack dump cpu %u:\n", smp_processor_id());
+       dump_stack();
+       spin_unlock(&uv_nmi_lock);
+
+       return NOTIFY_STOP;
+}
+
+static struct notifier_block uv_dump_stack_nmi_nb = {
+       .notifier_call  = uv_handle_nmi
+};
+
+void uv_register_nmi_notifier(void)
+{
+       if (register_die_notifier(&uv_dump_stack_nmi_nb))
+               printk(KERN_WARNING "UV NMI handler failed to register\n");
+}
+
+void uv_nmi_init(void)
+{
+       unsigned int value;
+
+       /*
+        * Unmask NMI on all cpus
+        */
+       value = apic_read(APIC_LVT1) | APIC_DM_NMI;
+       value &= ~APIC_LVT_MASKED;
+       apic_write(APIC_LVT1, value);
+}
 
 void __init uv_system_init(void)
 {
@@ -627,13 +702,15 @@ void __init uv_system_init(void)
        }
 
        uv_bios_init();
-       uv_bios_get_sn_info(0, &uv_type, &sn_partition_id,
-                           &sn_coherency_id, &sn_region_size);
+       uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, &sn_coherency_id,
+                           &sn_region_size, &system_serial_number);
        uv_rtc_init();
 
        for_each_present_cpu(cpu) {
+               int apicid = per_cpu(x86_cpu_to_apicid, cpu);
+
                nid = cpu_to_node(cpu);
-               pnode = uv_apicid_to_pnode(per_cpu(x86_cpu_to_apicid, cpu));
+               pnode = uv_apicid_to_pnode(apicid);
                blade = boot_pnode_to_blade(pnode);
                lcpu = uv_blade_info[blade].nr_possible_cpus;
                uv_blade_info[blade].nr_possible_cpus++;
@@ -654,15 +731,13 @@ void __init uv_system_init(void)
                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;
+               uv_cpu_hub_info(cpu)->scir.offset = uv_scir_offset(apicid);
                uv_node_to_blade[nid] = blade;
                uv_cpu_to_blade[cpu] = blade;
                max_pnode = max(pnode, max_pnode);
 
-               printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, "
-                       "lcpu %d, blade %d\n",
-                       cpu, per_cpu(x86_cpu_to_apicid, cpu), pnode, nid,
-                       lcpu, blade);
+               printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, lcpu %d, blade %d\n",
+                       cpu, apicid, pnode, nid, lcpu, blade);
        }
 
        /* Add blade/pnode info for nodes without cpus */
@@ -683,5 +758,9 @@ void __init uv_system_init(void)
 
        uv_cpu_init();
        uv_scir_register_cpu_notifier();
+       uv_register_nmi_notifier();
        proc_mkdir("sgi_uv", NULL);
+
+       /* register Legacy VGA I/O redirection handler */
+       pci_register_set_vga_state(uv_set_vga_state);
 }