]>
Commit | Line | Data |
---|---|---|
8f69975d BS |
1 | From: Dean Nelson <dcn@sgi.com> |
2 | Date: Thu, 2 Oct 2008 17:18:21 +0000 (-0500) | |
3 | Subject: x86, UV: add uv_setup_irq() and uv_teardown_irq() functions, v3 | |
4 | X-Git-Tag: v2.6.28-rc1~80^2~27 | |
5 | X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=4173a0e7371ece227559b44943c6fd456ee470d1 | |
6 | References: bnc#442461 | |
7 | ||
8 | x86, UV: add uv_setup_irq() and uv_teardown_irq() functions, v3 | |
9 | ||
10 | Provide a means for UV interrupt MMRs to be setup with the message to be sent | |
11 | when an MSI is raised. | |
12 | ||
13 | Signed-off-by: Dean Nelson <dcn@sgi.com> | |
14 | Signed-off-by: Ingo Molnar <mingo@elte.hu> | |
15 | Acked-by: Bernhard Walle <bwalle@suse.de> | |
16 | ||
17 | --- | |
18 | arch/x86/kernel/Makefile | 2 - | |
19 | arch/x86/kernel/io_apic_64.c | 68 +++++++++++++++++++++++++++++++++++++ | |
20 | arch/x86/kernel/uv_irq.c | 79 +++++++++++++++++++++++++++++++++++++++++++ | |
21 | include/asm-x86/uv/uv_irq.h | 36 +++++++++++++++++++ | |
22 | 4 files changed, 184 insertions(+), 1 deletion(-) | |
23 | ||
24 | --- a/arch/x86/kernel/Makefile | |
25 | +++ b/arch/x86/kernel/Makefile | |
26 | @@ -106,7 +106,7 @@ ifeq ($(CONFIG_X86_64),y) | |
27 | obj-y += uv_sysfs.o | |
28 | obj-y += genx2apic_cluster.o | |
29 | obj-y += genx2apic_phys.o | |
30 | - obj-y += bios_uv.o | |
31 | + obj-y += bios_uv.o uv_irq.o | |
32 | obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o | |
33 | obj-$(CONFIG_AUDIT) += audit_64.o | |
34 | ||
35 | --- a/arch/x86/kernel/io_apic_64.c | |
36 | +++ b/arch/x86/kernel/io_apic_64.c | |
37 | @@ -51,6 +51,8 @@ | |
38 | #include <asm/msidef.h> | |
39 | #include <asm/hypertransport.h> | |
40 | #include <asm/irq_remapping.h> | |
41 | +#include <asm/uv/uv_hub.h> | |
42 | +#include <asm/uv/uv_irq.h> | |
43 | ||
44 | #include <mach_ipi.h> | |
45 | #include <mach_apic.h> | |
46 | @@ -2787,6 +2789,72 @@ int arch_setup_ht_irq(unsigned int irq, | |
47 | } | |
48 | #endif /* CONFIG_HT_IRQ */ | |
49 | ||
50 | +#ifdef CONFIG_X86_64 | |
51 | +/* | |
52 | + * Re-target the irq to the specified CPU and enable the specified MMR located | |
53 | + * on the specified blade to allow the sending of MSIs to the specified CPU. | |
54 | + */ | |
55 | +int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, | |
56 | + unsigned long mmr_offset) | |
57 | +{ | |
58 | + const cpumask_t *eligible_cpu = get_cpu_mask(cpu); | |
59 | + struct irq_cfg *cfg; | |
60 | + int mmr_pnode; | |
61 | + unsigned long mmr_value; | |
62 | + struct uv_IO_APIC_route_entry *entry; | |
63 | + unsigned long flags; | |
64 | + int err; | |
65 | + | |
66 | + err = assign_irq_vector(irq, eligible_cpu); | |
67 | + if (err != 0) | |
68 | + return err; | |
69 | + | |
70 | + spin_lock_irqsave(&vector_lock, flags); | |
71 | + set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq, | |
72 | + irq_name); | |
73 | + spin_unlock_irqrestore(&vector_lock, flags); | |
74 | + | |
75 | + cfg = &irq_cfg[irq]; | |
76 | + | |
77 | + mmr_value = 0; | |
78 | + entry = (struct uv_IO_APIC_route_entry *)&mmr_value; | |
79 | + BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); | |
80 | + | |
81 | + entry->vector = cfg->vector; | |
82 | + entry->delivery_mode = INT_DELIVERY_MODE; | |
83 | + entry->dest_mode = INT_DEST_MODE; | |
84 | + entry->polarity = 0; | |
85 | + entry->trigger = 0; | |
86 | + entry->mask = 0; | |
87 | + entry->dest = cpu_mask_to_apicid(eligible_cpu); | |
88 | + | |
89 | + mmr_pnode = uv_blade_to_pnode(mmr_blade); | |
90 | + uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value); | |
91 | + | |
92 | + return irq; | |
93 | +} | |
94 | + | |
95 | +/* | |
96 | + * Disable the specified MMR located on the specified blade so that MSIs are | |
97 | + * longer allowed to be sent. | |
98 | + */ | |
99 | +void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset) | |
100 | +{ | |
101 | + unsigned long mmr_value; | |
102 | + struct uv_IO_APIC_route_entry *entry; | |
103 | + int mmr_pnode; | |
104 | + | |
105 | + mmr_value = 0; | |
106 | + entry = (struct uv_IO_APIC_route_entry *)&mmr_value; | |
107 | + BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); | |
108 | + | |
109 | + entry->mask = 1; | |
110 | + | |
111 | + mmr_pnode = uv_blade_to_pnode(mmr_blade); | |
112 | + uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value); | |
113 | +} | |
114 | +#endif /* CONFIG_X86_64 */ | |
115 | + | |
116 | /* -------------------------------------------------------------------------- | |
117 | ACPI-based IOAPIC Configuration | |
118 | -------------------------------------------------------------------------- */ | |
119 | --- /dev/null | |
120 | +++ b/arch/x86/kernel/uv_irq.c | |
121 | @@ -0,0 +1,79 @@ | |
122 | +/* | |
123 | + * This file is subject to the terms and conditions of the GNU General Public | |
124 | + * License. See the file "COPYING" in the main directory of this archive | |
125 | + * for more details. | |
126 | + * | |
127 | + * SGI UV IRQ functions | |
128 | + * | |
129 | + * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved. | |
130 | + */ | |
131 | + | |
132 | +#include <linux/module.h> | |
133 | +#include <linux/irq.h> | |
134 | + | |
135 | +#include <asm/apic.h> | |
136 | +#include <asm/uv/uv_irq.h> | |
137 | + | |
138 | +static void uv_noop(unsigned int irq) | |
139 | +{ | |
140 | +} | |
141 | + | |
142 | +static unsigned int uv_noop_ret(unsigned int irq) | |
143 | +{ | |
144 | + return 0; | |
145 | +} | |
146 | + | |
147 | +static void uv_ack_apic(unsigned int irq) | |
148 | +{ | |
149 | + ack_APIC_irq(); | |
150 | +} | |
151 | + | |
152 | +struct irq_chip uv_irq_chip = { | |
153 | + .name = "UV-CORE", | |
154 | + .startup = uv_noop_ret, | |
155 | + .shutdown = uv_noop, | |
156 | + .enable = uv_noop, | |
157 | + .disable = uv_noop, | |
158 | + .ack = uv_noop, | |
159 | + .mask = uv_noop, | |
160 | + .unmask = uv_noop, | |
161 | + .eoi = uv_ack_apic, | |
162 | + .end = uv_noop, | |
163 | +}; | |
164 | + | |
165 | +/* | |
166 | + * Set up a mapping of an available irq and vector, and enable the specified | |
167 | + * MMR that defines the MSI that is to be sent to the specified CPU when an | |
168 | + * interrupt is raised. | |
169 | + */ | |
170 | +int uv_setup_irq(char *irq_name, int cpu, int mmr_blade, | |
171 | + unsigned long mmr_offset) | |
172 | +{ | |
173 | + int irq; | |
174 | + int ret; | |
175 | + | |
176 | + irq = create_irq(); | |
177 | + if (irq < 0) | |
178 | + return -EBUSY; | |
179 | + | |
180 | + ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset); | |
181 | + if (ret != irq) | |
182 | + destroy_irq(irq); | |
183 | + | |
184 | + return ret; | |
185 | +} | |
186 | +EXPORT_SYMBOL_GPL(uv_setup_irq); | |
187 | + | |
188 | +/* | |
189 | + * Tear down a mapping of an irq and vector, and disable the specified MMR that | |
190 | + * defined the MSI that was to be sent to the specified CPU when an interrupt | |
191 | + * was raised. | |
192 | + * | |
193 | + * Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq(). | |
194 | + */ | |
195 | +void uv_teardown_irq(unsigned int irq, int mmr_blade, unsigned long mmr_offset) | |
196 | +{ | |
197 | + arch_disable_uv_irq(mmr_blade, mmr_offset); | |
198 | + destroy_irq(irq); | |
199 | +} | |
200 | +EXPORT_SYMBOL_GPL(uv_teardown_irq); | |
201 | --- /dev/null | |
202 | +++ b/include/asm-x86/uv/uv_irq.h | |
203 | @@ -0,0 +1,36 @@ | |
204 | +/* | |
205 | + * This file is subject to the terms and conditions of the GNU General Public | |
206 | + * License. See the file "COPYING" in the main directory of this archive | |
207 | + * for more details. | |
208 | + * | |
209 | + * SGI UV IRQ definitions | |
210 | + * | |
211 | + * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved. | |
212 | + */ | |
213 | + | |
214 | +#ifndef _ASM_X86_UV_UV_IRQ_H | |
215 | +#define _ASM_X86_UV_UV_IRQ_H | |
216 | + | |
217 | +/* If a generic version of this structure gets defined, eliminate this one. */ | |
218 | +struct uv_IO_APIC_route_entry { | |
219 | + __u64 vector : 8, | |
220 | + delivery_mode : 3, | |
221 | + dest_mode : 1, | |
222 | + delivery_status : 1, | |
223 | + polarity : 1, | |
224 | + __reserved_1 : 1, | |
225 | + trigger : 1, | |
226 | + mask : 1, | |
227 | + __reserved_2 : 15, | |
228 | + dest : 32; | |
229 | +}; | |
230 | + | |
231 | +extern struct irq_chip uv_irq_chip; | |
232 | + | |
233 | +extern int arch_enable_uv_irq(char *, unsigned int, int, int, unsigned long); | |
234 | +extern void arch_disable_uv_irq(int, unsigned long); | |
235 | + | |
236 | +extern int uv_setup_irq(char *, int, int, unsigned long); | |
237 | +extern void uv_teardown_irq(unsigned int, int, unsigned long); | |
238 | + | |
239 | +#endif /* _ASM_X86_UV_UV_IRQ_H */ |