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