]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - arch/x86/kernel/apic/x2apic_uv_x.c
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mv-sheeva.git] / arch / x86 / kernel / apic / x2apic_uv_x.c
index af0ca80e38a9967662dc595b6aa1bca4b8ce2e07..49dbeaef2a27b03f092b2eb267d26b6028b9c382 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>
@@ -20,6 +20,8 @@
 #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)
 {
@@ -71,6 +76,7 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
        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"))
@@ -480,7 +486,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);
@@ -488,11 +494,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
@@ -551,6 +556,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
@@ -567,6 +596,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)
 {
@@ -632,8 +701,8 @@ 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) {
@@ -688,5 +757,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);
 }