diff options
-rw-r--r-- | arch/x86/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/kernel/io_apic.c | 68 | ||||
-rw-r--r-- | arch/x86/kernel/uv_irq.c | 77 | ||||
-rw-r--r-- | include/asm-x86/uv/uv_irq.h | 36 |
4 files changed, 182 insertions, 1 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 45cecc59d894..acc0e8bf043e 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -108,7 +108,7 @@ obj-$(CONFIG_MICROCODE) += microcode.o | |||
108 | # 64 bit specific files | 108 | # 64 bit specific files |
109 | ifeq ($(CONFIG_X86_64),y) | 109 | ifeq ($(CONFIG_X86_64),y) |
110 | obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o | 110 | obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o |
111 | obj-y += bios_uv.o | 111 | obj-y += bios_uv.o uv_irq.o |
112 | obj-y += genx2apic_cluster.o | 112 | obj-y += genx2apic_cluster.o |
113 | obj-y += genx2apic_phys.o | 113 | obj-y += genx2apic_phys.o |
114 | obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o | 114 | obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o |
diff --git a/arch/x86/kernel/io_apic.c b/arch/x86/kernel/io_apic.c index 4ee270d30358..260c95a5e6dc 100644 --- a/arch/x86/kernel/io_apic.c +++ b/arch/x86/kernel/io_apic.c | |||
@@ -58,6 +58,8 @@ | |||
58 | #include <asm/setup.h> | 58 | #include <asm/setup.h> |
59 | #include <asm/irq_remapping.h> | 59 | #include <asm/irq_remapping.h> |
60 | #include <asm/hpet.h> | 60 | #include <asm/hpet.h> |
61 | #include <asm/uv/uv_hub.h> | ||
62 | #include <asm/uv/uv_irq.h> | ||
61 | 63 | ||
62 | #include <mach_ipi.h> | 64 | #include <mach_ipi.h> |
63 | #include <mach_apic.h> | 65 | #include <mach_apic.h> |
@@ -3692,6 +3694,72 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) | |||
3692 | } | 3694 | } |
3693 | #endif /* CONFIG_HT_IRQ */ | 3695 | #endif /* CONFIG_HT_IRQ */ |
3694 | 3696 | ||
3697 | #ifdef CONFIG_X86_64 | ||
3698 | /* | ||
3699 | * Re-target the irq to the specified CPU and enable the specified MMR located | ||
3700 | * on the specified blade to allow the sending of MSIs to the specified CPU. | ||
3701 | */ | ||
3702 | int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, | ||
3703 | unsigned long mmr_offset) | ||
3704 | { | ||
3705 | const cpumask_t *eligible_cpu = get_cpu_mask(cpu); | ||
3706 | struct irq_cfg *cfg; | ||
3707 | int mmr_pnode; | ||
3708 | unsigned long mmr_value; | ||
3709 | struct uv_IO_APIC_route_entry *entry; | ||
3710 | unsigned long flags; | ||
3711 | int err; | ||
3712 | |||
3713 | err = assign_irq_vector(irq, *eligible_cpu); | ||
3714 | if (err != 0) | ||
3715 | return err; | ||
3716 | |||
3717 | spin_lock_irqsave(&vector_lock, flags); | ||
3718 | set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq, | ||
3719 | irq_name); | ||
3720 | spin_unlock_irqrestore(&vector_lock, flags); | ||
3721 | |||
3722 | cfg = irq_cfg(irq); | ||
3723 | |||
3724 | mmr_value = 0; | ||
3725 | entry = (struct uv_IO_APIC_route_entry *)&mmr_value; | ||
3726 | BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); | ||
3727 | |||
3728 | entry->vector = cfg->vector; | ||
3729 | entry->delivery_mode = INT_DELIVERY_MODE; | ||
3730 | entry->dest_mode = INT_DEST_MODE; | ||
3731 | entry->polarity = 0; | ||
3732 | entry->trigger = 0; | ||
3733 | entry->mask = 0; | ||
3734 | entry->dest = cpu_mask_to_apicid(*eligible_cpu); | ||
3735 | |||
3736 | mmr_pnode = uv_blade_to_pnode(mmr_blade); | ||
3737 | uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value); | ||
3738 | |||
3739 | return irq; | ||
3740 | } | ||
3741 | |||
3742 | /* | ||
3743 | * Disable the specified MMR located on the specified blade so that MSIs are | ||
3744 | * longer allowed to be sent. | ||
3745 | */ | ||
3746 | void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset) | ||
3747 | { | ||
3748 | unsigned long mmr_value; | ||
3749 | struct uv_IO_APIC_route_entry *entry; | ||
3750 | int mmr_pnode; | ||
3751 | |||
3752 | mmr_value = 0; | ||
3753 | entry = (struct uv_IO_APIC_route_entry *)&mmr_value; | ||
3754 | BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); | ||
3755 | |||
3756 | entry->mask = 1; | ||
3757 | |||
3758 | mmr_pnode = uv_blade_to_pnode(mmr_blade); | ||
3759 | uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value); | ||
3760 | } | ||
3761 | #endif /* CONFIG_X86_64 */ | ||
3762 | |||
3695 | int __init io_apic_get_redir_entries (int ioapic) | 3763 | int __init io_apic_get_redir_entries (int ioapic) |
3696 | { | 3764 | { |
3697 | union IO_APIC_reg_01 reg_01; | 3765 | union IO_APIC_reg_01 reg_01; |
diff --git a/arch/x86/kernel/uv_irq.c b/arch/x86/kernel/uv_irq.c new file mode 100644 index 000000000000..6bd26c91c30b --- /dev/null +++ b/arch/x86/kernel/uv_irq.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * SGI UV IRQ functions | ||
7 | * | ||
8 | * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/irq.h> | ||
13 | #include <asm/uv/uv_irq.h> | ||
14 | |||
15 | static void uv_noop(unsigned int irq) | ||
16 | { | ||
17 | } | ||
18 | |||
19 | static unsigned int uv_noop_ret(unsigned int irq) | ||
20 | { | ||
21 | return 0; | ||
22 | } | ||
23 | |||
24 | static void uv_ack_apic(unsigned int irq) | ||
25 | { | ||
26 | ack_APIC_irq(); | ||
27 | } | ||
28 | |||
29 | struct irq_chip uv_irq_chip = { | ||
30 | .name = "UV-CORE", | ||
31 | .startup = uv_noop_ret, | ||
32 | .shutdown = uv_noop, | ||
33 | .enable = uv_noop, | ||
34 | .disable = uv_noop, | ||
35 | .ack = uv_noop, | ||
36 | .mask = uv_noop, | ||
37 | .unmask = uv_noop, | ||
38 | .eoi = uv_ack_apic, | ||
39 | .end = uv_noop, | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * Set up a mapping of an available irq and vector, and enable the specified | ||
44 | * MMR that defines the MSI that is to be sent to the specified CPU when an | ||
45 | * interrupt is raised. | ||
46 | */ | ||
47 | int uv_setup_irq(char *irq_name, int cpu, int mmr_blade, | ||
48 | unsigned long mmr_offset) | ||
49 | { | ||
50 | int irq; | ||
51 | int ret; | ||
52 | |||
53 | irq = create_irq(); | ||
54 | if (irq <= 0) | ||
55 | return -EBUSY; | ||
56 | |||
57 | ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset); | ||
58 | if (ret != irq) | ||
59 | destroy_irq(irq); | ||
60 | |||
61 | return ret; | ||
62 | } | ||
63 | EXPORT_SYMBOL_GPL(uv_setup_irq); | ||
64 | |||
65 | /* | ||
66 | * Tear down a mapping of an irq and vector, and disable the specified MMR that | ||
67 | * defined the MSI that was to be sent to the specified CPU when an interrupt | ||
68 | * was raised. | ||
69 | * | ||
70 | * Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq(). | ||
71 | */ | ||
72 | void uv_teardown_irq(unsigned int irq, int mmr_blade, unsigned long mmr_offset) | ||
73 | { | ||
74 | arch_disable_uv_irq(mmr_blade, mmr_offset); | ||
75 | destroy_irq(irq); | ||
76 | } | ||
77 | EXPORT_SYMBOL_GPL(uv_teardown_irq); | ||
diff --git a/include/asm-x86/uv/uv_irq.h b/include/asm-x86/uv/uv_irq.h new file mode 100644 index 000000000000..8bf5f32da9c6 --- /dev/null +++ b/include/asm-x86/uv/uv_irq.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * SGI UV IRQ definitions | ||
7 | * | ||
8 | * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved. | ||
9 | */ | ||
10 | |||
11 | #ifndef ASM_X86__UV__UV_IRQ_H | ||
12 | #define ASM_X86__UV__UV_IRQ_H | ||
13 | |||
14 | /* If a generic version of this structure gets defined, eliminate this one. */ | ||
15 | struct uv_IO_APIC_route_entry { | ||
16 | __u64 vector : 8, | ||
17 | delivery_mode : 3, | ||
18 | dest_mode : 1, | ||
19 | delivery_status : 1, | ||
20 | polarity : 1, | ||
21 | __reserved_1 : 1, | ||
22 | trigger : 1, | ||
23 | mask : 1, | ||
24 | __reserved_2 : 15, | ||
25 | dest : 32; | ||
26 | }; | ||
27 | |||
28 | extern struct irq_chip uv_irq_chip; | ||
29 | |||
30 | extern int arch_enable_uv_irq(char *, unsigned int, int, int, unsigned long); | ||
31 | extern void arch_disable_uv_irq(int, unsigned long); | ||
32 | |||
33 | extern int uv_setup_irq(char *, int, int, unsigned long); | ||
34 | extern void uv_teardown_irq(unsigned int, int, unsigned long); | ||
35 | |||
36 | #endif /* ASM_X86__UV__UV_IRQ_H */ | ||