2226ec69d8a6edb0f2efa7d7f39b5de18307bc48
[linux-flexiantxendom0-3.2.10.git] / arch / ppc64 / kernel / xics.c
1 /* 
2  * arch/ppc64/kernel/xics.c
3  *
4  * Copyright 2000 IBM Corporation.
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation; either version
9  *  2 of the License, or (at your option) any later version.
10  */
11 #include <linux/config.h>
12 #include <linux/types.h>
13 #include <linux/threads.h>
14 #include <linux/kernel.h>
15 #include <linux/irq.h>
16 #include <linux/smp.h>
17 #include <linux/interrupt.h>
18 #include <linux/signal.h>
19 #include <asm/prom.h>
20 #include <asm/io.h>
21 #include <asm/pgtable.h>
22 #include <asm/smp.h>
23 #include <asm/naca.h>
24 #include <asm/rtas.h>
25 #include <asm/xics.h>
26 #include <asm/ppcdebug.h>
27 #include <asm/hvcall.h>
28 #include <asm/machdep.h>
29
30 #include "i8259.h"
31
32 void xics_enable_irq(u_int irq);
33 void xics_disable_irq(u_int irq);
34 void xics_mask_and_ack_irq(u_int irq);
35 void xics_end_irq(u_int irq);
36 void xics_set_affinity(unsigned int irq_nr, unsigned long cpumask);
37
38 struct hw_interrupt_type xics_pic = {
39         " XICS     ",
40         NULL,
41         NULL,
42         xics_enable_irq,
43         xics_disable_irq,
44         xics_mask_and_ack_irq,
45         xics_end_irq,
46         xics_set_affinity
47 };
48
49 struct hw_interrupt_type xics_8259_pic = {
50         " XICS/8259",
51         NULL,
52         NULL,
53         NULL,
54         NULL,
55         xics_mask_and_ack_irq,
56         NULL
57 };
58
59 #define XICS_IPI                2
60 #define XICS_IRQ_OFFSET         0x10
61 #define XICS_IRQ_SPURIOUS       0
62
63 /* Want a priority other than 0.  Various HW issues require this. */
64 #define DEFAULT_PRIORITY        5
65
66 /* 
67  * Mark IPIs as higher priority so we can take them inside interrupts that
68  * arent marked SA_INTERRUPT
69  */
70 #define IPI_PRIORITY            4
71
72 struct xics_ipl {
73         union {
74                 u32 word;
75                 u8 bytes[4];
76         } xirr_poll;
77         union {
78                 u32 word;
79                 u8 bytes[4];
80         } xirr;
81         u32 dummy;
82         union {
83                 u32 word;
84                 u8 bytes[4];
85         } qirr;
86 };
87
88 static struct xics_ipl *xics_per_cpu[NR_CPUS];
89
90 static int xics_irq_8259_cascade = 0;
91 static int xics_irq_8259_cascade_real = 0;
92 static unsigned int default_server = 0xFF;
93 static unsigned int default_distrib_server = 0;
94
95 /*
96  * XICS only has a single IPI, so encode the messages per CPU
97  */
98 struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
99
100 /* RTAS service tokens */
101 int ibm_get_xive;
102 int ibm_set_xive;
103 int ibm_int_on;
104 int ibm_int_off;
105
106 typedef struct {
107         int (*xirr_info_get)(int cpu);
108         void (*xirr_info_set)(int cpu, int val);
109         void (*cppr_info)(int cpu, u8 val);
110         void (*qirr_info)(int cpu, u8 val);
111 } xics_ops;
112
113
114 /* SMP */
115
116 static int pSeries_xirr_info_get(int n_cpu)
117 {
118         return xics_per_cpu[n_cpu]->xirr.word;
119 }
120
121 static void pSeries_xirr_info_set(int n_cpu, int value)
122 {
123         xics_per_cpu[n_cpu]->xirr.word = value;
124 }
125
126 static void pSeries_cppr_info(int n_cpu, u8 value)
127 {
128         xics_per_cpu[n_cpu]->xirr.bytes[0] = value;
129 }
130
131 static void pSeries_qirr_info(int n_cpu, u8 value)
132 {
133         xics_per_cpu[n_cpu]->qirr.bytes[0] = value;
134 }
135
136 static xics_ops pSeries_ops = {
137         pSeries_xirr_info_get,
138         pSeries_xirr_info_set,
139         pSeries_cppr_info,
140         pSeries_qirr_info
141 };
142
143 static xics_ops *ops = &pSeries_ops;
144
145
146 /* LPAR */
147
148 static inline long plpar_eoi(unsigned long xirr)
149 {
150         return plpar_hcall_norets(H_EOI, xirr);
151 }
152
153 static inline long plpar_cppr(unsigned long cppr)
154 {
155         return plpar_hcall_norets(H_CPPR, cppr);
156 }
157
158 static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr)
159 {
160         return plpar_hcall_norets(H_IPI, servernum, mfrr);
161 }
162
163 static inline long plpar_xirr(unsigned long *xirr_ret)
164 {
165         unsigned long dummy;
166         return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy);
167 }
168
169 static int pSeriesLP_xirr_info_get(int n_cpu)
170 {
171         unsigned long lpar_rc;
172         unsigned long return_value; 
173
174         lpar_rc = plpar_xirr(&return_value);
175         if (lpar_rc != H_Success)
176                 panic(" bad return code xirr - rc = %lx \n", lpar_rc); 
177         return (int)return_value;
178 }
179
180 static void pSeriesLP_xirr_info_set(int n_cpu, int value)
181 {
182         unsigned long lpar_rc;
183         unsigned long val64 = value & 0xffffffff;
184
185         lpar_rc = plpar_eoi(val64);
186         if (lpar_rc != H_Success)
187                 panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc,
188                       val64); 
189 }
190
191 static void pSeriesLP_cppr_info(int n_cpu, u8 value)
192 {
193         unsigned long lpar_rc;
194
195         lpar_rc = plpar_cppr(value);
196         if (lpar_rc != H_Success)
197                 panic("bad return code cppr - rc = %lx\n", lpar_rc); 
198 }
199
200 static void pSeriesLP_qirr_info(int n_cpu , u8 value)
201 {
202         unsigned long lpar_rc;
203
204         lpar_rc = plpar_ipi(n_cpu, value);
205         if (lpar_rc != H_Success)
206                 panic("bad return code qirr - rc = %lx\n", lpar_rc); 
207 }
208
209 xics_ops pSeriesLP_ops = {
210         pSeriesLP_xirr_info_get,
211         pSeriesLP_xirr_info_set,
212         pSeriesLP_cppr_info,
213         pSeriesLP_qirr_info
214 };
215
216 void xics_enable_irq(u_int virq)
217 {
218         u_int irq;
219         long call_status;
220         unsigned int server;
221
222         virq -= XICS_IRQ_OFFSET;
223         irq = virt_irq_to_real(virq);
224         if (irq == XICS_IPI)
225                 return;
226
227 #ifdef CONFIG_IRQ_ALL_CPUS
228         if (smp_threads_ready)
229                 server = default_distrib_server;
230         else
231                 server = default_server;
232 #else
233         server = default_server;
234 #endif
235
236         call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
237                                 DEFAULT_PRIORITY);
238         if (call_status != 0) {
239                 printk("xics_enable_irq: irq=%x: ibm_set_xive returned %lx\n",
240                        irq, call_status);
241                 return;
242         }
243
244         /* Now unmask the interrupt (often a no-op) */
245         call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq);
246         if (call_status != 0) {
247                 printk("xics_enable_irq: irq=%x: ibm_int_on returned %lx\n",
248                        irq, call_status);
249                 return;
250         }
251 }
252
253 void xics_disable_irq(u_int virq)
254 {
255         u_int irq;
256         long call_status;
257
258         virq -= XICS_IRQ_OFFSET;
259         irq = virt_irq_to_real(virq);
260         if (irq == XICS_IPI)
261                 return;
262
263         call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq);
264         if (call_status != 0) {
265                 printk("xics_disable_irq: irq=%x: ibm_int_off returned %lx\n",
266                        irq, call_status);
267                 return;
268         }
269 }
270
271 void xics_end_irq(u_int irq)
272 {
273         int cpu = smp_processor_id();
274
275         iosync();
276         ops->xirr_info_set(cpu, ((0xff<<24) |
277                                  (virt_irq_to_real(irq-XICS_IRQ_OFFSET))));
278 }
279
280 void xics_mask_and_ack_irq(u_int irq)
281 {
282         int cpu = smp_processor_id();
283
284         if (irq < XICS_IRQ_OFFSET) {
285                 i8259_pic.ack(irq);
286                 iosync();
287                 ops->xirr_info_set(cpu, ((0xff<<24) |
288                                          xics_irq_8259_cascade_real));
289                 iosync();
290         }
291 }
292
293 int xics_get_irq(struct pt_regs *regs)
294 {
295         u_int cpu = smp_processor_id();
296         u_int vec;
297         int irq;
298
299         vec = ops->xirr_info_get(cpu);
300         /*  (vec >> 24) == old priority */
301         vec &= 0x00ffffff;
302
303         /* for sanity, this had better be < NR_IRQS - 16 */
304         if (vec == xics_irq_8259_cascade_real) {
305                 irq = i8259_irq(cpu);
306                 if (irq == -1) {
307                         /* Spurious cascaded interrupt.  Still must ack xics */
308                         xics_end_irq(XICS_IRQ_OFFSET + xics_irq_8259_cascade);
309                         irq = -1;
310                 }
311         } else if (vec == XICS_IRQ_SPURIOUS) {
312                 irq = -1;
313         } else {
314                 irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET;
315         }
316         return irq;
317 }
318
319 #ifdef CONFIG_SMP
320
321 extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
322
323 irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
324 {
325         int cpu = smp_processor_id();
326
327         ops->qirr_info(cpu, 0xff);
328         while (xics_ipi_message[cpu].value) {
329                 if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
330                                        &xics_ipi_message[cpu].value)) {
331                         mb();
332                         smp_message_recv(PPC_MSG_CALL_FUNCTION, regs);
333                 }
334                 if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
335                                        &xics_ipi_message[cpu].value)) {
336                         mb();
337                         smp_message_recv(PPC_MSG_RESCHEDULE, regs);
338                 }
339 #if 0
340                 if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK,
341                                        &xics_ipi_message[cpu].value)) {
342                         mb();
343                         smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
344                 }
345 #endif
346 #ifdef CONFIG_XMON
347                 if (test_and_clear_bit(PPC_MSG_XMON_BREAK,
348                                        &xics_ipi_message[cpu].value)) {
349                         mb();
350                         smp_message_recv(PPC_MSG_XMON_BREAK, regs);
351                 }
352 #endif
353         }
354         return IRQ_HANDLED;
355 }
356
357 void xics_cause_IPI(int cpu)
358 {
359         ops->qirr_info(cpu, IPI_PRIORITY);
360 }
361
362 void xics_setup_cpu(void)
363 {
364         int cpu = smp_processor_id();
365
366         ops->cppr_info(cpu, 0xff);
367         iosync();
368 }
369
370 #endif /* CONFIG_SMP */
371
372 void xics_init_IRQ(void)
373 {
374         int i;
375         unsigned long intr_size = 0;
376         struct device_node *np;
377         uint *ireg, ilen, indx=0;
378         unsigned long intr_base = 0;
379         struct xics_interrupt_node {
380                 unsigned long long addr;
381                 unsigned long long size;
382         } inodes[NR_CPUS*2]; 
383
384         ppc64_boot_msg(0x20, "XICS Init");
385
386         ibm_get_xive = rtas_token("ibm,get-xive");
387         ibm_set_xive = rtas_token("ibm,set-xive");
388         ibm_int_on  = rtas_token("ibm,int-on");
389         ibm_int_off = rtas_token("ibm,int-off");
390
391         np = find_type_devices("PowerPC-External-Interrupt-Presentation");
392         if (!np) {
393                 printk(KERN_WARNING "Can't find Interrupt Presentation\n");
394                 udbg_printf("Can't find Interrupt Presentation\n");
395                 while (1);
396         }
397 nextnode:
398         ireg = (uint *)get_property(np, "ibm,interrupt-server-ranges", 0);
399         if (ireg) {
400                 /*
401                  * set node starting index for this node
402                  */
403                 indx = *ireg;
404         }
405
406         ireg = (uint *)get_property(np, "reg", &ilen);
407         if (!ireg) {
408                 printk(KERN_WARNING "Can't find Interrupt Reg Property\n");
409                 udbg_printf("Can't find Interrupt Reg Property\n");
410                 while (1);
411         }
412         
413         while (ilen) {
414                 inodes[indx].addr = (unsigned long long)*ireg++ << 32;
415                 ilen -= sizeof(uint);
416                 inodes[indx].addr |= *ireg++;
417                 ilen -= sizeof(uint);
418                 inodes[indx].size = (unsigned long long)*ireg++ << 32;
419                 ilen -= sizeof(uint);
420                 inodes[indx].size |= *ireg++;
421                 ilen -= sizeof(uint);
422                 indx++;
423                 if (indx >= NR_CPUS) break;
424         }
425
426         np = np->next;
427         if ((indx < NR_CPUS) && np) goto nextnode;
428
429         /* Find the server numbers for the boot cpu. */
430         for (np = find_type_devices("cpu"); np; np = np->next) {
431                 ireg = (uint *)get_property(np, "reg", &ilen);
432                 if (ireg && ireg[0] == smp_processor_id()) {
433                         ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
434                         i = ilen / sizeof(int);
435                         if (ireg && i > 0) {
436                                 default_server = ireg[0];
437                                 default_distrib_server = ireg[i-1]; /* take last element */
438                         }
439                         break;
440                 }
441         }
442
443         intr_base = inodes[0].addr;
444         intr_size = (ulong)inodes[0].size;
445
446         np = find_type_devices("interrupt-controller");
447         if (!np) {
448                 printk(KERN_WARNING "xics:  no ISA Interrupt Controller\n");
449                 xics_irq_8259_cascade_real = -1;
450                 xics_irq_8259_cascade = -1;
451         } else {
452                 ireg = (uint *) get_property(np, "interrupts", 0);
453                 if (!ireg) {
454                         printk(KERN_WARNING "Can't find ISA Interrupts Property\n");
455                         udbg_printf("Can't find ISA Interrupts Property\n");
456                         while (1);
457                 }
458                 xics_irq_8259_cascade_real = *ireg;
459                 xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);
460         }
461
462         if (systemcfg->platform == PLATFORM_PSERIES) {
463 #ifdef CONFIG_SMP
464                 for (i = 0; i < NR_CPUS; ++i) {
465                         if (!cpu_possible(i))
466                                 continue;
467                         xics_per_cpu[i] = __ioremap((ulong)inodes[i].addr, 
468                                                     (ulong)inodes[i].size,
469                                                     _PAGE_NO_CACHE);
470                 }
471 #else
472                 xics_per_cpu[0] = __ioremap((ulong)intr_base, intr_size,
473                                             _PAGE_NO_CACHE);
474 #endif /* CONFIG_SMP */
475 #ifdef CONFIG_PPC_PSERIES
476         /* actually iSeries does not use any of xics...but it has link dependencies
477          * for now, except this new one...
478          */
479         } else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
480                 ops = &pSeriesLP_ops;
481 #endif
482         }
483
484         xics_8259_pic.enable = i8259_pic.enable;
485         xics_8259_pic.disable = i8259_pic.disable;
486         for (i = 0; i < 16; ++i)
487                 irq_desc[i].handler = &xics_8259_pic;
488         for (; i < NR_IRQS; ++i)
489                 irq_desc[i].handler = &xics_pic;
490
491         ops->cppr_info(boot_cpuid, 0xff);
492         iosync();
493         if (xics_irq_8259_cascade != -1) {
494                 if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET,
495                                 no_action, 0, "8259 cascade", 0))
496                         printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");
497                 i8259_init();
498         }
499
500 #ifdef CONFIG_SMP
501         real_irq_to_virt_map[XICS_IPI] = virt_irq_to_real_map[XICS_IPI] =
502                 XICS_IPI;
503         /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
504         request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, SA_INTERRUPT,
505                     "IPI", 0);
506         irq_desc[XICS_IPI+XICS_IRQ_OFFSET].status |= IRQ_PER_CPU;
507 #endif
508         ppc64_boot_msg(0x21, "XICS Done");
509 }
510
511 void xics_set_affinity(unsigned int virq, unsigned long cpumask)
512 {
513         irq_desc_t *desc = irq_desc + virq;
514         unsigned int irq;
515         unsigned long flags;
516         long status;
517         unsigned long xics_status[2];
518         unsigned long newmask;
519
520         virq -= XICS_IRQ_OFFSET;
521         irq = virt_irq_to_real(virq);
522         if (irq == XICS_IPI)
523                 return;
524
525         spin_lock_irqsave(&desc->lock, flags);
526
527         status = rtas_call(ibm_get_xive, 1, 3, (void *)&xics_status, irq);
528
529         if (status) {
530                 printk("xics_set_affinity: irq=%d ibm,get-xive returns %ld\n",
531                         irq, status);
532                 goto out;
533         }
534
535         /* For the moment only implement delivery to all cpus or one cpu */
536         if (cpumask == -1UL) {
537                 newmask = default_distrib_server;
538         } else {
539                 if (!(cpumask & cpu_online_map))
540                         goto out;
541                 newmask = find_first_bit(&cpumask, 8*sizeof(unsigned long));
542         }
543
544         status = rtas_call(ibm_set_xive, 3, 1, NULL,
545                                 irq, newmask, xics_status[1]);
546
547         if (status) {
548                 printk("xics_set_affinity irq=%d ibm,set-xive returns %ld\n",
549                         irq, status);
550                 goto out;
551         }
552
553 out:
554         spin_unlock_irqrestore(&desc->lock, flags);
555 }