]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - arch/ia64/sn/kernel/irq.c
merge by hand - fix up rejections in Documentation/DocBook/Makefile
[mirror_ubuntu-artful-kernel.git] / arch / ia64 / sn / kernel / irq.c
1 /*
2 * Platform dependent support for SGI SN
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
9 */
10
11 #include <linux/irq.h>
12 #include <asm/sn/intr.h>
13 #include <asm/sn/addrs.h>
14 #include <asm/sn/arch.h>
15 #include "xtalk/xwidgetdev.h"
16 #include <asm/sn/pcibus_provider_defs.h>
17 #include <asm/sn/pcidev.h>
18 #include "pci/pcibr_provider.h"
19 #include <asm/sn/shub_mmr.h>
20 #include <asm/sn/sn_sal.h>
21
22 static void force_interrupt(int irq);
23 static void register_intr_pda(struct sn_irq_info *sn_irq_info);
24 static void unregister_intr_pda(struct sn_irq_info *sn_irq_info);
25
26 extern int sn_force_interrupt_flag;
27 extern int sn_ioif_inited;
28 struct sn_irq_info **sn_irq;
29
30 static inline uint64_t sn_intr_alloc(nasid_t local_nasid, int local_widget,
31 u64 sn_irq_info,
32 int req_irq, nasid_t req_nasid,
33 int req_slice)
34 {
35 struct ia64_sal_retval ret_stuff;
36 ret_stuff.status = 0;
37 ret_stuff.v0 = 0;
38
39 SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
40 (u64) SAL_INTR_ALLOC, (u64) local_nasid,
41 (u64) local_widget, (u64) sn_irq_info, (u64) req_irq,
42 (u64) req_nasid, (u64) req_slice);
43 return ret_stuff.status;
44 }
45
46 static inline void sn_intr_free(nasid_t local_nasid, int local_widget,
47 struct sn_irq_info *sn_irq_info)
48 {
49 struct ia64_sal_retval ret_stuff;
50 ret_stuff.status = 0;
51 ret_stuff.v0 = 0;
52
53 SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
54 (u64) SAL_INTR_FREE, (u64) local_nasid,
55 (u64) local_widget, (u64) sn_irq_info->irq_irq,
56 (u64) sn_irq_info->irq_cookie, 0, 0);
57 }
58
59 static unsigned int sn_startup_irq(unsigned int irq)
60 {
61 return 0;
62 }
63
64 static void sn_shutdown_irq(unsigned int irq)
65 {
66 }
67
68 static void sn_disable_irq(unsigned int irq)
69 {
70 }
71
72 static void sn_enable_irq(unsigned int irq)
73 {
74 }
75
76 static void sn_ack_irq(unsigned int irq)
77 {
78 uint64_t event_occurred, mask = 0;
79 int nasid;
80
81 irq = irq & 0xff;
82 nasid = get_nasid();
83 event_occurred =
84 HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED));
85 mask = event_occurred & SH_ALL_INT_MASK;
86 HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS),
87 mask);
88 __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
89
90 move_irq(irq);
91 }
92
93 static void sn_end_irq(unsigned int irq)
94 {
95 int nasid;
96 int ivec;
97 uint64_t event_occurred;
98
99 ivec = irq & 0xff;
100 if (ivec == SGI_UART_VECTOR) {
101 nasid = get_nasid();
102 event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR
103 (nasid, SH_EVENT_OCCURRED));
104 /* If the UART bit is set here, we may have received an
105 * interrupt from the UART that the driver missed. To
106 * make sure, we IPI ourselves to force us to look again.
107 */
108 if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
109 platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR,
110 IA64_IPI_DM_INT, 0);
111 }
112 }
113 __clear_bit(ivec, (volatile void *)pda->sn_in_service_ivecs);
114 if (sn_force_interrupt_flag)
115 force_interrupt(irq);
116 }
117
118 static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
119 {
120 struct sn_irq_info *sn_irq_info = sn_irq[irq];
121 struct sn_irq_info *tmp_sn_irq_info;
122 int cpuid, cpuphys;
123 nasid_t t_nasid; /* nasid to target */
124 int t_slice; /* slice to target */
125
126 /* allocate a temp sn_irq_info struct to get new target info */
127 tmp_sn_irq_info = kmalloc(sizeof(*tmp_sn_irq_info), GFP_KERNEL);
128 if (!tmp_sn_irq_info)
129 return;
130
131 cpuid = first_cpu(mask);
132 cpuphys = cpu_physical_id(cpuid);
133 t_nasid = cpuid_to_nasid(cpuid);
134 t_slice = cpuid_to_slice(cpuid);
135
136 while (sn_irq_info) {
137 int status;
138 int local_widget;
139 uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
140 nasid_t local_nasid = NASID_GET(bridge);
141
142 if (!bridge)
143 break; /* irq is not a device interrupt */
144
145 if (local_nasid & 1)
146 local_widget = TIO_SWIN_WIDGETNUM(bridge);
147 else
148 local_widget = SWIN_WIDGETNUM(bridge);
149
150 /* Free the old PROM sn_irq_info structure */
151 sn_intr_free(local_nasid, local_widget, sn_irq_info);
152
153 /* allocate a new PROM sn_irq_info struct */
154 status = sn_intr_alloc(local_nasid, local_widget,
155 __pa(tmp_sn_irq_info), irq, t_nasid,
156 t_slice);
157
158 if (status == 0) {
159 /* Update kernels sn_irq_info with new target info */
160 unregister_intr_pda(sn_irq_info);
161 sn_irq_info->irq_cpuid = cpuid;
162 sn_irq_info->irq_nasid = t_nasid;
163 sn_irq_info->irq_slice = t_slice;
164 sn_irq_info->irq_xtalkaddr =
165 tmp_sn_irq_info->irq_xtalkaddr;
166 sn_irq_info->irq_cookie = tmp_sn_irq_info->irq_cookie;
167 register_intr_pda(sn_irq_info);
168
169 if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type)) {
170 pcibr_change_devices_irq(sn_irq_info);
171 }
172
173 sn_irq_info = sn_irq_info->irq_next;
174
175 #ifdef CONFIG_SMP
176 set_irq_affinity_info((irq & 0xff), cpuphys, 0);
177 #endif
178 } else {
179 break; /* snp_affinity failed the intr_alloc */
180 }
181 }
182 kfree(tmp_sn_irq_info);
183 }
184
185 struct hw_interrupt_type irq_type_sn = {
186 "SN hub",
187 sn_startup_irq,
188 sn_shutdown_irq,
189 sn_enable_irq,
190 sn_disable_irq,
191 sn_ack_irq,
192 sn_end_irq,
193 sn_set_affinity_irq
194 };
195
196 unsigned int sn_local_vector_to_irq(u8 vector)
197 {
198 return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector));
199 }
200
201 void sn_irq_init(void)
202 {
203 int i;
204 irq_desc_t *base_desc = irq_desc;
205
206 for (i = 0; i < NR_IRQS; i++) {
207 if (base_desc[i].handler == &no_irq_type) {
208 base_desc[i].handler = &irq_type_sn;
209 }
210 }
211 }
212
213 static void register_intr_pda(struct sn_irq_info *sn_irq_info)
214 {
215 int irq = sn_irq_info->irq_irq;
216 int cpu = sn_irq_info->irq_cpuid;
217
218 if (pdacpu(cpu)->sn_last_irq < irq) {
219 pdacpu(cpu)->sn_last_irq = irq;
220 }
221
222 if (pdacpu(cpu)->sn_first_irq == 0 || pdacpu(cpu)->sn_first_irq > irq) {
223 pdacpu(cpu)->sn_first_irq = irq;
224 }
225 }
226
227 static void unregister_intr_pda(struct sn_irq_info *sn_irq_info)
228 {
229 int irq = sn_irq_info->irq_irq;
230 int cpu = sn_irq_info->irq_cpuid;
231 struct sn_irq_info *tmp_irq_info;
232 int i, foundmatch;
233
234 if (pdacpu(cpu)->sn_last_irq == irq) {
235 foundmatch = 0;
236 for (i = pdacpu(cpu)->sn_last_irq - 1; i; i--) {
237 tmp_irq_info = sn_irq[i];
238 while (tmp_irq_info) {
239 if (tmp_irq_info->irq_cpuid == cpu) {
240 foundmatch++;
241 break;
242 }
243 tmp_irq_info = tmp_irq_info->irq_next;
244 }
245 if (foundmatch) {
246 break;
247 }
248 }
249 pdacpu(cpu)->sn_last_irq = i;
250 }
251
252 if (pdacpu(cpu)->sn_first_irq == irq) {
253 foundmatch = 0;
254 for (i = pdacpu(cpu)->sn_first_irq + 1; i < NR_IRQS; i++) {
255 tmp_irq_info = sn_irq[i];
256 while (tmp_irq_info) {
257 if (tmp_irq_info->irq_cpuid == cpu) {
258 foundmatch++;
259 break;
260 }
261 tmp_irq_info = tmp_irq_info->irq_next;
262 }
263 if (foundmatch) {
264 break;
265 }
266 }
267 pdacpu(cpu)->sn_first_irq = ((i == NR_IRQS) ? 0 : i);
268 }
269 }
270
271 struct sn_irq_info *sn_irq_alloc(nasid_t local_nasid, int local_widget, int irq,
272 nasid_t nasid, int slice)
273 {
274 struct sn_irq_info *sn_irq_info;
275 int status;
276
277 sn_irq_info = kmalloc(sizeof(*sn_irq_info), GFP_KERNEL);
278 if (sn_irq_info == NULL)
279 return NULL;
280
281 memset(sn_irq_info, 0x0, sizeof(*sn_irq_info));
282
283 status =
284 sn_intr_alloc(local_nasid, local_widget, __pa(sn_irq_info), irq,
285 nasid, slice);
286
287 if (status) {
288 kfree(sn_irq_info);
289 return NULL;
290 } else {
291 return sn_irq_info;
292 }
293 }
294
295 void sn_irq_free(struct sn_irq_info *sn_irq_info)
296 {
297 uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
298 nasid_t local_nasid = NASID_GET(bridge);
299 int local_widget;
300
301 if (local_nasid & 1) /* tio check */
302 local_widget = TIO_SWIN_WIDGETNUM(bridge);
303 else
304 local_widget = SWIN_WIDGETNUM(bridge);
305
306 sn_intr_free(local_nasid, local_widget, sn_irq_info);
307
308 kfree(sn_irq_info);
309 }
310
311 void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info)
312 {
313 nasid_t nasid = sn_irq_info->irq_nasid;
314 int slice = sn_irq_info->irq_slice;
315 int cpu = nasid_slice_to_cpuid(nasid, slice);
316
317 sn_irq_info->irq_cpuid = cpu;
318 sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev);
319
320 /* link it into the sn_irq[irq] list */
321 sn_irq_info->irq_next = sn_irq[sn_irq_info->irq_irq];
322 sn_irq[sn_irq_info->irq_irq] = sn_irq_info;
323
324 (void)register_intr_pda(sn_irq_info);
325 }
326
327 static void force_interrupt(int irq)
328 {
329 struct sn_irq_info *sn_irq_info;
330
331 if (!sn_ioif_inited)
332 return;
333 sn_irq_info = sn_irq[irq];
334 while (sn_irq_info) {
335 if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
336 (sn_irq_info->irq_bridge != NULL)) {
337 pcibr_force_interrupt(sn_irq_info);
338 }
339 sn_irq_info = sn_irq_info->irq_next;
340 }
341 }
342
343 /*
344 * Check for lost interrupts. If the PIC int_status reg. says that
345 * an interrupt has been sent, but not handled, and the interrupt
346 * is not pending in either the cpu irr regs or in the soft irr regs,
347 * and the interrupt is not in service, then the interrupt may have
348 * been lost. Force an interrupt on that pin. It is possible that
349 * the interrupt is in flight, so we may generate a spurious interrupt,
350 * but we should never miss a real lost interrupt.
351 */
352 static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
353 {
354 uint64_t regval;
355 int irr_reg_num;
356 int irr_bit;
357 uint64_t irr_reg;
358 struct pcidev_info *pcidev_info;
359 struct pcibus_info *pcibus_info;
360
361 pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
362 if (!pcidev_info)
363 return;
364
365 pcibus_info =
366 (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->
367 pdi_pcibus_info;
368 regval = pcireg_intr_status_get(pcibus_info);
369
370 irr_reg_num = irq_to_vector(irq) / 64;
371 irr_bit = irq_to_vector(irq) % 64;
372 switch (irr_reg_num) {
373 case 0:
374 irr_reg = ia64_getreg(_IA64_REG_CR_IRR0);
375 break;
376 case 1:
377 irr_reg = ia64_getreg(_IA64_REG_CR_IRR1);
378 break;
379 case 2:
380 irr_reg = ia64_getreg(_IA64_REG_CR_IRR2);
381 break;
382 case 3:
383 irr_reg = ia64_getreg(_IA64_REG_CR_IRR3);
384 break;
385 }
386 if (!test_bit(irr_bit, &irr_reg)) {
387 if (!test_bit(irq, pda->sn_soft_irr)) {
388 if (!test_bit(irq, pda->sn_in_service_ivecs)) {
389 regval &= 0xff;
390 if (sn_irq_info->irq_int_bit & regval &
391 sn_irq_info->irq_last_intr) {
392 regval &=
393 ~(sn_irq_info->
394 irq_int_bit & regval);
395 pcibr_force_interrupt(sn_irq_info);
396 }
397 }
398 }
399 }
400 sn_irq_info->irq_last_intr = regval;
401 }
402
403 void sn_lb_int_war_check(void)
404 {
405 int i;
406
407 if (!sn_ioif_inited || pda->sn_first_irq == 0)
408 return;
409 for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
410 struct sn_irq_info *sn_irq_info = sn_irq[i];
411 while (sn_irq_info) {
412 /* Only call for PCI bridges that are fully initialized. */
413 if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
414 (sn_irq_info->irq_bridge != NULL)) {
415 sn_check_intr(i, sn_irq_info);
416 }
417 sn_irq_info = sn_irq_info->irq_next;
418 }
419 }
420 }