|
@@ -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>
|
|
@@ -34,10 +36,13 @@
|
|
|
|
|
|
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"))
|
|
@@ -553,6 +559,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
|
|
@@ -569,6 +599,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)
|
|
|
{
|
|
@@ -690,5 +760,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);
|
|
|
}
|