--- /dev/null
+From: Dean Nelson <dcn@sgi.com>
+Date: Thu, 2 Oct 2008 17:18:21 +0000 (-0500)
+Subject: x86, UV: add uv_setup_irq() and uv_teardown_irq() functions, v3
+X-Git-Tag: v2.6.28-rc1~80^2~27
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=4173a0e7371ece227559b44943c6fd456ee470d1
+References: bnc#442461
+
+x86, UV: add uv_setup_irq() and uv_teardown_irq() functions, v3
+
+Provide a means for UV interrupt MMRs to be setup with the message to be sent
+when an MSI is raised.
+
+Signed-off-by: Dean Nelson <dcn@sgi.com>
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+Acked-by: Bernhard Walle <bwalle@suse.de>
+
+---
+ arch/x86/kernel/Makefile | 2 -
+ arch/x86/kernel/io_apic_64.c | 68 +++++++++++++++++++++++++++++++++++++
+ arch/x86/kernel/uv_irq.c | 79 +++++++++++++++++++++++++++++++++++++++++++
+ include/asm-x86/uv/uv_irq.h | 36 +++++++++++++++++++
+ 4 files changed, 184 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/kernel/Makefile
++++ b/arch/x86/kernel/Makefile
+@@ -106,7 +106,7 @@ ifeq ($(CONFIG_X86_64),y)
+ obj-y += uv_sysfs.o
+ obj-y += genx2apic_cluster.o
+ obj-y += genx2apic_phys.o
+- obj-y += bios_uv.o
++ obj-y += bios_uv.o uv_irq.o
+ obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o
+ obj-$(CONFIG_AUDIT) += audit_64.o
+
+--- a/arch/x86/kernel/io_apic_64.c
++++ b/arch/x86/kernel/io_apic_64.c
+@@ -51,6 +51,8 @@
+ #include <asm/msidef.h>
+ #include <asm/hypertransport.h>
+ #include <asm/irq_remapping.h>
++#include <asm/uv/uv_hub.h>
++#include <asm/uv/uv_irq.h>
+
+ #include <mach_ipi.h>
+ #include <mach_apic.h>
+@@ -2787,6 +2789,72 @@ int arch_setup_ht_irq(unsigned int irq,
+ }
+ #endif /* CONFIG_HT_IRQ */
+
++#ifdef CONFIG_X86_64
++/*
++ * Re-target the irq to the specified CPU and enable the specified MMR located
++ * on the specified blade to allow the sending of MSIs to the specified CPU.
++ */
++int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
++ unsigned long mmr_offset)
++{
++ const cpumask_t *eligible_cpu = get_cpu_mask(cpu);
++ struct irq_cfg *cfg;
++ int mmr_pnode;
++ unsigned long mmr_value;
++ struct uv_IO_APIC_route_entry *entry;
++ unsigned long flags;
++ int err;
++
++ err = assign_irq_vector(irq, eligible_cpu);
++ if (err != 0)
++ return err;
++
++ spin_lock_irqsave(&vector_lock, flags);
++ set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
++ irq_name);
++ spin_unlock_irqrestore(&vector_lock, flags);
++
++ cfg = &irq_cfg[irq];
++
++ mmr_value = 0;
++ entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
++ BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
++
++ entry->vector = cfg->vector;
++ entry->delivery_mode = INT_DELIVERY_MODE;
++ entry->dest_mode = INT_DEST_MODE;
++ entry->polarity = 0;
++ entry->trigger = 0;
++ entry->mask = 0;
++ entry->dest = cpu_mask_to_apicid(eligible_cpu);
++
++ mmr_pnode = uv_blade_to_pnode(mmr_blade);
++ uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
++
++ return irq;
++}
++
++/*
++ * Disable the specified MMR located on the specified blade so that MSIs are
++ * longer allowed to be sent.
++ */
++void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset)
++{
++ unsigned long mmr_value;
++ struct uv_IO_APIC_route_entry *entry;
++ int mmr_pnode;
++
++ mmr_value = 0;
++ entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
++ BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
++
++ entry->mask = 1;
++
++ mmr_pnode = uv_blade_to_pnode(mmr_blade);
++ uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
++}
++#endif /* CONFIG_X86_64 */
++
+ /* --------------------------------------------------------------------------
+ ACPI-based IOAPIC Configuration
+ -------------------------------------------------------------------------- */
+--- /dev/null
++++ b/arch/x86/kernel/uv_irq.c
+@@ -0,0 +1,79 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * SGI UV IRQ functions
++ *
++ * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
++ */
++
++#include <linux/module.h>
++#include <linux/irq.h>
++
++#include <asm/apic.h>
++#include <asm/uv/uv_irq.h>
++
++static void uv_noop(unsigned int irq)
++{
++}
++
++static unsigned int uv_noop_ret(unsigned int irq)
++{
++ return 0;
++}
++
++static void uv_ack_apic(unsigned int irq)
++{
++ ack_APIC_irq();
++}
++
++struct irq_chip uv_irq_chip = {
++ .name = "UV-CORE",
++ .startup = uv_noop_ret,
++ .shutdown = uv_noop,
++ .enable = uv_noop,
++ .disable = uv_noop,
++ .ack = uv_noop,
++ .mask = uv_noop,
++ .unmask = uv_noop,
++ .eoi = uv_ack_apic,
++ .end = uv_noop,
++};
++
++/*
++ * Set up a mapping of an available irq and vector, and enable the specified
++ * MMR that defines the MSI that is to be sent to the specified CPU when an
++ * interrupt is raised.
++ */
++int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
++ unsigned long mmr_offset)
++{
++ int irq;
++ int ret;
++
++ irq = create_irq();
++ if (irq < 0)
++ return -EBUSY;
++
++ ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset);
++ if (ret != irq)
++ destroy_irq(irq);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(uv_setup_irq);
++
++/*
++ * Tear down a mapping of an irq and vector, and disable the specified MMR that
++ * defined the MSI that was to be sent to the specified CPU when an interrupt
++ * was raised.
++ *
++ * Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq().
++ */
++void uv_teardown_irq(unsigned int irq, int mmr_blade, unsigned long mmr_offset)
++{
++ arch_disable_uv_irq(mmr_blade, mmr_offset);
++ destroy_irq(irq);
++}
++EXPORT_SYMBOL_GPL(uv_teardown_irq);
+--- /dev/null
++++ b/include/asm-x86/uv/uv_irq.h
+@@ -0,0 +1,36 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * SGI UV IRQ definitions
++ *
++ * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
++ */
++
++#ifndef _ASM_X86_UV_UV_IRQ_H
++#define _ASM_X86_UV_UV_IRQ_H
++
++/* If a generic version of this structure gets defined, eliminate this one. */
++struct uv_IO_APIC_route_entry {
++ __u64 vector : 8,
++ delivery_mode : 3,
++ dest_mode : 1,
++ delivery_status : 1,
++ polarity : 1,
++ __reserved_1 : 1,
++ trigger : 1,
++ mask : 1,
++ __reserved_2 : 15,
++ dest : 32;
++};
++
++extern struct irq_chip uv_irq_chip;
++
++extern int arch_enable_uv_irq(char *, unsigned int, int, int, unsigned long);
++extern void arch_disable_uv_irq(int, unsigned long);
++
++extern int uv_setup_irq(char *, int, int, unsigned long);
++extern void uv_teardown_irq(unsigned int, int, unsigned long);
++
++#endif /* _ASM_X86_UV_UV_IRQ_H */