ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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-2003 Silicon Graphics, Inc.  All Rights Reserved.
9  */
10
11 #include <linux/init.h>
12 #include <linux/sched.h>
13 #include <linux/vmalloc.h>
14 #include <linux/irq.h>
15 #include <linux/interrupt.h>
16 #include <linux/slab.h>
17 #include <linux/bootmem.h>
18 #include <linux/cpumask.h>
19 #include <asm/page.h>
20 #include <asm/pgtable.h>
21 #include <asm/sn/sgi.h>
22 #include <asm/sn/hcl.h>
23 #include <asm/sn/types.h>
24 #include <asm/sn/pci/pciio.h>
25 #include <asm/sn/pci/pciio_private.h>
26 #include <asm/sn/pci/pcibr.h>
27 #include <asm/sn/pci/pcibr_private.h>
28 #include <asm/sn/sn_cpuid.h>
29 #include <asm/sn/io.h>
30 #include <asm/sn/intr.h>
31 #include <asm/sn/addrs.h>
32 #include <asm/sn/driver.h>
33 #include <asm/sn/arch.h>
34 #include <asm/sn/pda.h>
35 #include <asm/processor.h>
36 #include <asm/system.h>
37 #include <asm/bitops.h>
38 #include <asm/sn/sn2/shub_mmr.h>
39
40 static void force_interrupt(int irq);
41 extern void pcibr_force_interrupt(pcibr_intr_t intr);
42 extern int sn_force_interrupt_flag;
43 struct irq_desc * sn_irq_desc(unsigned int irq);
44
45 struct sn_intr_list_t {
46         struct sn_intr_list_t *next;
47         pcibr_intr_t intr;
48 };
49
50 static struct sn_intr_list_t *sn_intr_list[NR_IRQS];
51
52
53 static unsigned int
54 sn_startup_irq(unsigned int irq)
55 {
56         return(0);
57 }
58
59 static void
60 sn_shutdown_irq(unsigned int irq)
61 {
62 }
63
64 static void
65 sn_disable_irq(unsigned int irq)
66 {
67 }
68
69 static void
70 sn_enable_irq(unsigned int irq)
71 {
72 }
73
74 static void
75 sn_ack_irq(unsigned int irq)
76 {
77         unsigned long event_occurred, mask = 0;
78         int nasid;
79
80         irq = irq & 0xff;
81         nasid = smp_physical_node_id();
82         event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) );
83         if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
84                 mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT);
85         }
86         if (event_occurred & SH_EVENT_OCCURRED_IPI_INT_MASK) {
87                 mask |= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT);
88         }
89         if (event_occurred & SH_EVENT_OCCURRED_II_INT0_MASK) {
90                 mask |= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT);
91         }
92         if (event_occurred & SH_EVENT_OCCURRED_II_INT1_MASK) {
93                 mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT);
94         }
95         HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), mask );
96         __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
97 }
98
99 static void
100 sn_end_irq(unsigned int irq)
101 {
102         int nasid;
103         int ivec;
104         unsigned long event_occurred;
105         irq_desc_t *desc = sn_irq_desc(irq);
106         unsigned int status = desc->status;
107
108         ivec = irq & 0xff;
109         if (ivec == SGI_UART_VECTOR) {
110                 nasid = smp_physical_node_id();
111                 event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) );
112                 // If the UART bit is set here, we may have received an interrupt from the
113                 // UART that the driver missed.  To make sure, we IPI ourselves to force us
114                 // to look again.
115                 if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
116                                 platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR, IA64_IPI_DM_INT, 0);
117                 }
118         }
119         __clear_bit(ivec, (volatile void *)pda->sn_in_service_ivecs);
120         if (sn_force_interrupt_flag)
121                 if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
122                         force_interrupt(irq);
123 }
124
125 static void
126 sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
127 {
128 #ifdef CONFIG_SMP
129         int redir = 0;
130         int cpu;
131         struct sn_intr_list_t *p = sn_intr_list[irq];
132         pcibr_intr_t intr;
133         extern void sn_shub_redirect_intr(pcibr_intr_t intr, unsigned long cpu);
134         extern void sn_tio_redirect_intr(pcibr_intr_t intr, unsigned long cpu);
135
136         if (p == NULL)
137                 return; 
138         
139         intr = p->intr;
140
141         if (intr == NULL)
142                 return; 
143
144         cpu = first_cpu(mask);
145         sn_shub_redirect_intr(intr, cpu);
146         irq = irq & 0xff;  /* strip off redirect bit, if someone stuck it on. */
147         (void) set_irq_affinity_info(irq, cpu_physical_id(intr->bi_cpu), redir);
148 #endif /* CONFIG_SMP */
149 }
150
151
152 struct hw_interrupt_type irq_type_sn = {
153         "SN hub",
154         sn_startup_irq,
155         sn_shutdown_irq,
156         sn_enable_irq,
157         sn_disable_irq,
158         sn_ack_irq, 
159         sn_end_irq,
160         sn_set_affinity_irq
161 };
162
163
164 struct irq_desc *
165 sn_irq_desc(unsigned int irq)
166 {
167
168         irq = SN_IVEC_FROM_IRQ(irq);
169
170         return(_irq_desc + irq);
171 }
172
173 u8
174 sn_irq_to_vector(u8 irq)
175 {
176         return(irq);
177 }
178
179 unsigned int
180 sn_local_vector_to_irq(u8 vector)
181 {
182         return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector));
183 }
184
185 void
186 sn_irq_init (void)
187 {
188         int i;
189         irq_desc_t *base_desc = _irq_desc;
190
191         for (i=0; i<NR_IRQS; i++) {
192                 if (base_desc[i].handler == &no_irq_type) {
193                         base_desc[i].handler = &irq_type_sn;
194                 }
195         }
196 }
197
198 void
199 register_pcibr_intr(int irq, pcibr_intr_t intr)
200 {
201         struct sn_intr_list_t *p = kmalloc(sizeof(struct sn_intr_list_t), GFP_KERNEL);
202         struct sn_intr_list_t *list;
203         int cpu = intr->bi_cpu;
204
205         if (pdacpu(cpu)->sn_last_irq < irq) {
206                 pdacpu(cpu)->sn_last_irq = irq;
207         }
208         if (pdacpu(cpu)->sn_first_irq == 0 || pdacpu(cpu)->sn_first_irq > irq) pdacpu(cpu)->sn_first_irq = irq;
209         if (!p) panic("Could not allocate memory for sn_intr_list_t\n");
210         if ((list = sn_intr_list[irq])) {
211                 while (list->next) list = list->next;
212                 list->next = p;
213                 p->next = NULL;
214                 p->intr = intr;
215         } else {
216                 sn_intr_list[irq] = p;
217                 p->next = NULL;
218                 p->intr = intr;
219         }
220 }
221
222 void
223 unregister_pcibr_intr(int irq, pcibr_intr_t intr)
224 {
225
226         struct sn_intr_list_t **prev, *curr;
227         int cpu = intr->bi_cpu;
228         int i;
229
230         if (sn_intr_list[irq] == NULL)
231                 return;
232
233         prev = &sn_intr_list[irq];
234         curr = sn_intr_list[irq];
235         while (curr) {
236                 if (curr->intr == intr)  {
237                         *prev = curr->next;
238                         break;
239                 }
240                 prev = &curr->next;
241                 curr = curr->next;
242         }
243
244         if (curr)
245                 kfree(curr);
246
247         if (!sn_intr_list[irq]) {
248                 if (pdacpu(cpu)->sn_last_irq == irq) {
249                         for (i = pdacpu(cpu)->sn_last_irq - 1; i; i--)
250                                 if (sn_intr_list[i])
251                                         break;
252                         pdacpu(cpu)->sn_last_irq = i;
253                 }
254
255                 if (pdacpu(cpu)->sn_first_irq == irq) {
256                         pdacpu(cpu)->sn_first_irq = 0;
257                         for (i = pdacpu(cpu)->sn_first_irq + 1; i < NR_IRQS; i++)
258                                 if (sn_intr_list[i])
259                                         pdacpu(cpu)->sn_first_irq = i;
260                 }
261         }
262
263 }
264
265 void
266 force_polled_int(void)
267 {
268         int i;
269         struct sn_intr_list_t *p;
270
271         for (i=0; i<NR_IRQS;i++) {
272                 p = sn_intr_list[i];
273                 while (p) {
274                         if (p->intr){
275                                 pcibr_force_interrupt(p->intr);
276                         }
277                         p = p->next;
278                 }
279         }
280 }
281
282 static void
283 force_interrupt(int irq)
284 {
285         struct sn_intr_list_t *p = sn_intr_list[irq];
286
287         while (p) {
288                 if (p->intr) {
289                         pcibr_force_interrupt(p->intr);
290                 }
291                 p = p->next;
292         }
293 }
294
295 /*
296 Check for lost interrupts.  If the PIC int_status reg. says that
297 an interrupt has been sent, but not handled, and the interrupt
298 is not pending in either the cpu irr regs or in the soft irr regs,
299 and the interrupt is not in service, then the interrupt may have
300 been lost.  Force an interrupt on that pin.  It is possible that
301 the interrupt is in flight, so we may generate a spurious interrupt,
302 but we should never miss a real lost interrupt.
303 */
304
305 static void
306 sn_check_intr(int irq, pcibr_intr_t intr)
307 {
308         unsigned long regval;
309         int irr_reg_num;
310         int irr_bit;
311         unsigned long irr_reg;
312
313
314         regval = pcireg_intr_status_get(intr->bi_soft);
315         irr_reg_num = irq_to_vector(irq) / 64;
316         irr_bit = irq_to_vector(irq) % 64;
317         switch (irr_reg_num) {
318                 case 0:
319                         irr_reg = ia64_getreg(_IA64_REG_CR_IRR0);
320                         break;
321                 case 1:
322                         irr_reg = ia64_getreg(_IA64_REG_CR_IRR1);
323                         break;
324                 case 2:
325                         irr_reg = ia64_getreg(_IA64_REG_CR_IRR2);
326                         break;
327                 case 3:
328                         irr_reg = ia64_getreg(_IA64_REG_CR_IRR3);
329                         break;
330         }
331         if (!test_bit(irr_bit, &irr_reg) ) {
332                 if (!test_bit(irq, pda->sn_soft_irr) ) {
333                         if (!test_bit(irq, pda->sn_in_service_ivecs) ) {
334                                 regval &= 0xff;
335                                 if (intr->bi_ibits & regval & intr->bi_last_intr) {
336                                         regval &= ~(intr->bi_ibits & regval);
337                                         pcibr_force_interrupt(intr);
338                                 }
339                         }
340                 }
341         }
342         intr->bi_last_intr = regval;
343 }
344
345 void
346 sn_lb_int_war_check(void)
347 {
348         int i;
349
350         if (pda->sn_first_irq == 0) return;
351         for (i=pda->sn_first_irq;
352                 i <= pda->sn_last_irq; i++) {
353                         struct sn_intr_list_t *p = sn_intr_list[i];
354                         if (p == NULL) {
355                                 continue;
356                         }
357                         while (p) {
358                                 sn_check_intr(i, p->intr);
359                                 p = p->next;
360                         }
361         }
362 }