upgrade to linux 2.6.9-1.11_FC2
[linux-2.6.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 "pci/pcibus_provider_defs.h"
17 #include "pci/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         if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
86                 mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT);
87         }
88         if (event_occurred & SH_EVENT_OCCURRED_IPI_INT_MASK) {
89                 mask |= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT);
90         }
91         if (event_occurred & SH_EVENT_OCCURRED_II_INT0_MASK) {
92                 mask |= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT);
93         }
94         if (event_occurred & SH_EVENT_OCCURRED_II_INT1_MASK) {
95                 mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT);
96         }
97         HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS),
98               mask);
99         __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
100
101         move_irq(irq);
102 }
103
104 static void sn_end_irq(unsigned int irq)
105 {
106         int nasid;
107         int ivec;
108         uint64_t event_occurred;
109
110         ivec = irq & 0xff;
111         if (ivec == SGI_UART_VECTOR) {
112                 nasid = get_nasid();
113                 event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR
114                                        (nasid, SH_EVENT_OCCURRED));
115                 /* If the UART bit is set here, we may have received an 
116                  * interrupt from the UART that the driver missed.  To
117                  * make sure, we IPI ourselves to force us to look again.
118                  */
119                 if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
120                         platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR,
121                                           IA64_IPI_DM_INT, 0);
122                 }
123         }
124         __clear_bit(ivec, (volatile void *)pda->sn_in_service_ivecs);
125         if (sn_force_interrupt_flag)
126                 force_interrupt(irq);
127 }
128
129 static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
130 {
131         struct sn_irq_info *sn_irq_info = sn_irq[irq];
132         struct sn_irq_info *tmp_sn_irq_info;
133         int cpuid, cpuphys;
134         nasid_t t_nasid;        /* nasid to target */
135         int t_slice;            /* slice to target */
136
137         /* allocate a temp sn_irq_info struct to get new target info */
138         tmp_sn_irq_info = kmalloc(sizeof(*tmp_sn_irq_info), GFP_KERNEL);
139         if (!tmp_sn_irq_info)
140                 return;
141
142         cpuid = first_cpu(mask);
143         cpuphys = cpu_physical_id(cpuid);
144         t_nasid = cpuid_to_nasid(cpuid);
145         t_slice = cpuid_to_slice(cpuid);
146
147         while (sn_irq_info) {
148                 int status;
149                 int local_widget;
150                 uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
151                 nasid_t local_nasid = NASID_GET(bridge);
152
153                 if (!bridge)
154                         break;  /* irq is not a device interrupt */
155
156                 if (local_nasid & 1)
157                         local_widget = TIO_SWIN_WIDGETNUM(bridge);
158                 else
159                         local_widget = SWIN_WIDGETNUM(bridge);
160
161                 /* Free the old PROM sn_irq_info structure */
162                 sn_intr_free(local_nasid, local_widget, sn_irq_info);
163
164                 /* allocate a new PROM sn_irq_info struct */
165                 status = sn_intr_alloc(local_nasid, local_widget,
166                                        __pa(tmp_sn_irq_info), irq, t_nasid,
167                                        t_slice);
168
169                 if (status == 0) {
170                         /* Update kernels sn_irq_info with new target info */
171                         unregister_intr_pda(sn_irq_info);
172                         sn_irq_info->irq_cpuid = cpuid;
173                         sn_irq_info->irq_nasid = t_nasid;
174                         sn_irq_info->irq_slice = t_slice;
175                         sn_irq_info->irq_xtalkaddr =
176                             tmp_sn_irq_info->irq_xtalkaddr;
177                         sn_irq_info->irq_cookie = tmp_sn_irq_info->irq_cookie;
178                         register_intr_pda(sn_irq_info);
179
180                         if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type)) {
181                                 pcibr_change_devices_irq(sn_irq_info);
182                         }
183
184                         sn_irq_info = sn_irq_info->irq_next;
185
186                         set_irq_affinity_info((irq & 0xff), cpuphys, 0);
187                 } else {
188                         break;  /* snp_affinity failed the intr_alloc */
189                 }
190         }
191         kfree(tmp_sn_irq_info);
192 }
193
194 struct hw_interrupt_type irq_type_sn = {
195         "SN hub",
196         sn_startup_irq,
197         sn_shutdown_irq,
198         sn_enable_irq,
199         sn_disable_irq,
200         sn_ack_irq,
201         sn_end_irq,
202         sn_set_affinity_irq
203 };
204
205 struct irq_desc *sn_irq_desc(unsigned int irq)
206 {
207         return (_irq_desc + irq);
208 }
209
210 u8 sn_irq_to_vector(unsigned int irq)
211 {
212         return irq;
213 }
214
215 unsigned int sn_local_vector_to_irq(u8 vector)
216 {
217         return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector));
218 }
219
220 void sn_irq_init(void)
221 {
222         int i;
223         irq_desc_t *base_desc = _irq_desc;
224
225         for (i = 0; i < NR_IRQS; i++) {
226                 if (base_desc[i].handler == &no_irq_type) {
227                         base_desc[i].handler = &irq_type_sn;
228                 }
229         }
230 }
231
232 static void register_intr_pda(struct sn_irq_info *sn_irq_info)
233 {
234         int irq = sn_irq_info->irq_irq;
235         int cpu = sn_irq_info->irq_cpuid;
236
237         if (pdacpu(cpu)->sn_last_irq < irq) {
238                 pdacpu(cpu)->sn_last_irq = irq;
239         }
240
241         if (pdacpu(cpu)->sn_first_irq == 0 || pdacpu(cpu)->sn_first_irq > irq) {
242                 pdacpu(cpu)->sn_first_irq = irq;
243         }
244 }
245
246 static void unregister_intr_pda(struct sn_irq_info *sn_irq_info)
247 {
248         int irq = sn_irq_info->irq_irq;
249         int cpu = sn_irq_info->irq_cpuid;
250         struct sn_irq_info *tmp_irq_info;
251         int i, foundmatch;
252
253         if (pdacpu(cpu)->sn_last_irq == irq) {
254                 foundmatch = 0;
255                 for (i = pdacpu(cpu)->sn_last_irq - 1; i; i--) {
256                         tmp_irq_info = sn_irq[i];
257                         while (tmp_irq_info) {
258                                 if (tmp_irq_info->irq_cpuid == cpu) {
259                                         foundmatch++;
260                                         break;
261                                 }
262                                 tmp_irq_info = tmp_irq_info->irq_next;
263                         }
264                         if (foundmatch) {
265                                 break;
266                         }
267                 }
268                 pdacpu(cpu)->sn_last_irq = i;
269         }
270
271         if (pdacpu(cpu)->sn_first_irq == irq) {
272                 foundmatch = 0;
273                 for (i = pdacpu(cpu)->sn_first_irq + 1; i < NR_IRQS; i++) {
274                         tmp_irq_info = sn_irq[i];
275                         while (tmp_irq_info) {
276                                 if (tmp_irq_info->irq_cpuid == cpu) {
277                                         foundmatch++;
278                                         break;
279                                 }
280                                 tmp_irq_info = tmp_irq_info->irq_next;
281                         }
282                         if (foundmatch) {
283                                 break;
284                         }
285                 }
286                 pdacpu(cpu)->sn_first_irq = ((i == NR_IRQS) ? 0 : i);
287         }
288 }
289
290 struct sn_irq_info *sn_irq_alloc(nasid_t local_nasid, int local_widget, int irq,
291                                  nasid_t nasid, int slice)
292 {
293         struct sn_irq_info *sn_irq_info;
294         int status;
295
296         sn_irq_info = kmalloc(sizeof(*sn_irq_info), GFP_KERNEL);
297         if (sn_irq_info == NULL)
298                 return NULL;
299
300         memset(sn_irq_info, 0x0, sizeof(*sn_irq_info));
301
302         status =
303             sn_intr_alloc(local_nasid, local_widget, __pa(sn_irq_info), irq,
304                           nasid, slice);
305
306         if (status) {
307                 kfree(sn_irq_info);
308                 return NULL;
309         } else {
310                 return sn_irq_info;
311         }
312 }
313
314 void sn_irq_free(struct sn_irq_info *sn_irq_info)
315 {
316         uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
317         nasid_t local_nasid = NASID_GET(bridge);
318         int local_widget;
319
320         if (local_nasid & 1)    /* tio check */
321                 local_widget = TIO_SWIN_WIDGETNUM(bridge);
322         else
323                 local_widget = SWIN_WIDGETNUM(bridge);
324
325         sn_intr_free(local_nasid, local_widget, sn_irq_info);
326
327         kfree(sn_irq_info);
328 }
329
330 void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info)
331 {
332         nasid_t nasid = sn_irq_info->irq_nasid;
333         int slice = sn_irq_info->irq_slice;
334         int cpu = nasid_slice_to_cpuid(nasid, slice);
335
336         sn_irq_info->irq_cpuid = cpu;
337         sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev);
338
339         /* link it into the sn_irq[irq] list */
340         sn_irq_info->irq_next = sn_irq[sn_irq_info->irq_irq];
341         sn_irq[sn_irq_info->irq_irq] = sn_irq_info;
342
343         (void)register_intr_pda(sn_irq_info);
344 }
345
346 static void force_interrupt(int irq)
347 {
348         struct sn_irq_info *sn_irq_info;
349
350         if (!sn_ioif_inited)
351                 return;
352         sn_irq_info = sn_irq[irq];
353         while (sn_irq_info) {
354                 if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
355                     (sn_irq_info->irq_bridge != NULL)) {
356                         pcibr_force_interrupt(sn_irq_info);
357                 }
358                 sn_irq_info = sn_irq_info->irq_next;
359         }
360 }
361
362 /*
363  * Check for lost interrupts.  If the PIC int_status reg. says that
364  * an interrupt has been sent, but not handled, and the interrupt
365  * is not pending in either the cpu irr regs or in the soft irr regs,
366  * and the interrupt is not in service, then the interrupt may have
367  * been lost.  Force an interrupt on that pin.  It is possible that
368  * the interrupt is in flight, so we may generate a spurious interrupt,
369  * but we should never miss a real lost interrupt.
370  */
371 static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
372 {
373         uint64_t regval;
374         int irr_reg_num;
375         int irr_bit;
376         uint64_t irr_reg;
377         struct pcidev_info *pcidev_info;
378         struct pcibus_info *pcibus_info;
379
380         pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
381         if (!pcidev_info)
382                 return;
383
384         pcibus_info =
385             (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->
386             pdi_pcibus_info;
387         regval = pcireg_intr_status_get(pcibus_info);
388
389         irr_reg_num = irq_to_vector(irq) / 64;
390         irr_bit = irq_to_vector(irq) % 64;
391         switch (irr_reg_num) {
392         case 0:
393                 irr_reg = ia64_getreg(_IA64_REG_CR_IRR0);
394                 break;
395         case 1:
396                 irr_reg = ia64_getreg(_IA64_REG_CR_IRR1);
397                 break;
398         case 2:
399                 irr_reg = ia64_getreg(_IA64_REG_CR_IRR2);
400                 break;
401         case 3:
402                 irr_reg = ia64_getreg(_IA64_REG_CR_IRR3);
403                 break;
404         }
405         if (!test_bit(irr_bit, &irr_reg)) {
406                 if (!test_bit(irq, pda->sn_soft_irr)) {
407                         if (!test_bit(irq, pda->sn_in_service_ivecs)) {
408                                 regval &= 0xff;
409                                 if (sn_irq_info->irq_int_bit & regval &
410                                     sn_irq_info->irq_last_intr) {
411                                         regval &=
412                                             ~(sn_irq_info->
413                                               irq_int_bit & regval);
414                                         pcibr_force_interrupt(sn_irq_info);
415                                 }
416                         }
417                 }
418         }
419         sn_irq_info->irq_last_intr = regval;
420 }
421
422 void sn_lb_int_war_check(void)
423 {
424         int i;
425
426         if (!sn_ioif_inited || pda->sn_first_irq == 0)
427                 return;
428         for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
429                 struct sn_irq_info *sn_irq_info = sn_irq[i];
430                 while (sn_irq_info) {
431                         /* Only call for PCI bridges that are fully initialized. */
432                         if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
433                             (sn_irq_info->irq_bridge != NULL)) {
434                                 sn_check_intr(i, sn_irq_info);
435                         }
436                         sn_irq_info = sn_irq_info->irq_next;
437                 }
438         }
439 }