diff options
author | Dean Nelson <dcn@sgi.com> | 2008-10-02 13:18:21 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:53:12 -0400 |
commit | 4173a0e7371ece227559b44943c6fd456ee470d1 (patch) | |
tree | e9a6dd475bfc72b373c1db13c21c8d82591636ec /arch/x86 | |
parent | 5f79f2f2ad39b5177c52ed08ffd066ea0c1da924 (diff) |
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>
Diffstat (limited to 'arch/x86')
-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 |
3 files changed, 146 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); | ||