]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kernel/irq.c
[PATCH] powerpc: enable PPC_PTRACE_[GS]ETREGS on ppc32
[karo-tx-linux.git] / arch / powerpc / kernel / irq.c
index 5a71ed9612fec6e90ff3f81bad91e2b501e16ecf..57d560c68897b08bcd85003eaefbf1c4442ad0ac 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/irq.c
- *
  *  Derived from arch/i386/kernel/irq.c
  *    Copyright (C) 1992 Linus Torvalds
  *  Adapted from arch/i386 by Gary Thomas
@@ -31,7 +29,6 @@
  * to reduce code space and undefined function references.
  */
 
-#include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/threads.h>
 #include <linux/kernel_stat.h>
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/proc_fs.h>
-#include <linux/random.h>
 #include <linux/seq_file.h>
 #include <linux/cpumask.h>
 #include <linux/profile.h>
 #include <linux/bitops.h>
-#ifdef CONFIG_PPC64
-#include <linux/kallsyms.h>
-#endif
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -66,8 +57,7 @@
 #include <asm/prom.h>
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
-#ifdef CONFIG_PPC64
-#include <asm/iseries/it_lp_queue.h>
+#ifdef CONFIG_PPC_ISERIES
 #include <asm/paca.h>
 #endif
 
@@ -78,10 +68,6 @@ EXPORT_SYMBOL(__irq_offset_value);
 
 static int ppc_spurious_interrupts;
 
-#if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP)
-extern void iSeries_smp_message_recv(struct pt_regs *);
-#endif
-
 #ifdef CONFIG_PPC32
 #define NR_MASK_WORDS  ((NR_IRQS + 31) / 32)
 
@@ -149,9 +135,8 @@ skip:
 #ifdef CONFIG_TAU_INT
                if (tau_initialized){
                        seq_puts(p, "TAU: ");
-                       for (j = 0; j < NR_CPUS; j++)
-                               if (cpu_online(j))
-                                       seq_printf(p, "%10u ", tau_interrupts(j));
+                       for_each_online_cpu(j)
+                               seq_printf(p, "%10u ", tau_interrupts(j));
                        seq_puts(p, "  PowerPC             Thermal Assist (cpu temp)\n");
                }
 #endif
@@ -195,49 +180,6 @@ void fixup_irqs(cpumask_t map)
 }
 #endif
 
-#ifdef CONFIG_PPC_ISERIES
-void do_IRQ(struct pt_regs *regs)
-{
-       struct paca_struct *lpaca;
-
-       irq_enter();
-
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
-       /* Debugging check for stack overflow: is there less than 2KB free? */
-       {
-               long sp;
-
-               sp = __get_SP() & (THREAD_SIZE-1);
-
-               if (unlikely(sp < (sizeof(struct thread_info) + 2048))) {
-                       printk("do_IRQ: stack overflow: %ld\n",
-                               sp - sizeof(struct thread_info));
-                       dump_stack();
-               }
-       }
-#endif
-
-       lpaca = get_paca();
-#ifdef CONFIG_SMP
-       if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
-               lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
-               iSeries_smp_message_recv(regs);
-       }
-#endif /* CONFIG_SMP */
-       if (hvlpevent_is_pending())
-               process_hvlpevents(regs);
-
-       irq_exit();
-
-       if (lpaca->lppaca.int_dword.fields.decr_int) {
-               lpaca->lppaca.int_dword.fields.decr_int = 0;
-               /* Signal a fake decrementer interrupt */
-               timer_interrupt(regs);
-       }
-}
-
-#else  /* CONFIG_PPC_ISERIES */
-
 void do_IRQ(struct pt_regs *regs)
 {
        int irq;
@@ -286,16 +228,20 @@ void do_IRQ(struct pt_regs *regs)
                } else
 #endif
                        __do_IRQ(irq, regs);
-       } else
-#ifdef CONFIG_PPC32
-               if (irq != -2)
-#endif
-                       /* That's not SMP safe ... but who cares ? */
-                       ppc_spurious_interrupts++;
+       } else if (irq != -2)
+               /* That's not SMP safe ... but who cares ? */
+               ppc_spurious_interrupts++;
+
         irq_exit();
-}
 
-#endif /* CONFIG_PPC_ISERIES */
+#ifdef CONFIG_PPC_ISERIES
+       if (get_lppaca()->int_dword.fields.decr_int) {
+               get_lppaca()->int_dword.fields.decr_int = 0;
+               /* Signal a fake decrementer interrupt */
+               timer_interrupt(regs);
+       }
+#endif
+}
 
 void __init init_IRQ(void)
 {
@@ -326,18 +272,26 @@ unsigned int virt_irq_to_real_map[NR_IRQS];
  * Don't use virtual irqs 0, 1, 2 for devices.
  * The pcnet32 driver considers interrupt numbers < 2 to be invalid,
  * and 2 is the XICS IPI interrupt.
- * We limit virtual irqs to 17 less than NR_IRQS so that when we
- * offset them by 16 (to reserve the first 16 for ISA interrupts)
- * we don't end up with an interrupt number >= NR_IRQS.
+ * We limit virtual irqs to __irq_offet_value less than virt_irq_max so
+ * that when we offset them we don't end up with an interrupt
+ * number >= virt_irq_max.
  */
 #define MIN_VIRT_IRQ   3
-#define MAX_VIRT_IRQ   (NR_IRQS - NUM_ISA_INTERRUPTS - 1)
-#define NR_VIRT_IRQS   (MAX_VIRT_IRQ - MIN_VIRT_IRQ + 1)
+
+unsigned int virt_irq_max;
+static unsigned int max_virt_irq;
+static unsigned int nr_virt_irqs;
 
 void
 virt_irq_init(void)
 {
        int i;
+
+       if ((virt_irq_max == 0) || (virt_irq_max > (NR_IRQS - 1)))
+               virt_irq_max = NR_IRQS - 1;
+       max_virt_irq = virt_irq_max - __irq_offset_value;
+       nr_virt_irqs = max_virt_irq - MIN_VIRT_IRQ + 1;
+
        for (i = 0; i < NR_IRQS; i++)
                virt_irq_to_real_map[i] = UNDEFINED_IRQ;
 }
@@ -362,17 +316,17 @@ int virt_irq_create_mapping(unsigned int real_irq)
                return real_irq;
        }
 
-       /* map to a number between MIN_VIRT_IRQ and MAX_VIRT_IRQ */
+       /* map to a number between MIN_VIRT_IRQ and max_virt_irq */
        virq = real_irq;
-       if (virq > MAX_VIRT_IRQ)
-               virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ;
+       if (virq > max_virt_irq)
+               virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
 
        /* search for this number or a free slot */
        first_virq = virq;
        while (virt_irq_to_real_map[virq] != UNDEFINED_IRQ) {
                if (virt_irq_to_real_map[virq] == real_irq)
                        return virq;
-               if (++virq > MAX_VIRT_IRQ)
+               if (++virq > max_virt_irq)
                        virq = MIN_VIRT_IRQ;
                if (virq == first_virq)
                        goto nospace;   /* oops, no free slots */
@@ -384,8 +338,8 @@ int virt_irq_create_mapping(unsigned int real_irq)
  nospace:
        if (!warned) {
                printk(KERN_CRIT "Interrupt table is full\n");
-               printk(KERN_CRIT "Increase NR_IRQS (currently %d) "
-                      "in your kernel sources and rebuild.\n", NR_IRQS);
+               printk(KERN_CRIT "Increase virt_irq_max (currently %d) "
+                      "in your kernel sources and rebuild.\n", virt_irq_max);
                warned = 1;
        }
        return NO_IRQ;
@@ -403,8 +357,8 @@ unsigned int real_irq_to_virt_slowpath(unsigned int real_irq)
 
        virq = real_irq;
 
-       if (virq > MAX_VIRT_IRQ)
-               virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ;
+       if (virq > max_virt_irq)
+               virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
 
        first_virq = virq;
 
@@ -414,7 +368,7 @@ unsigned int real_irq_to_virt_slowpath(unsigned int real_irq)
 
                virq++;
 
-               if (virq >= MAX_VIRT_IRQ)
+               if (virq >= max_virt_irq)
                        virq = 0;
 
        } while (first_virq != virq);
@@ -422,6 +376,7 @@ unsigned int real_irq_to_virt_slowpath(unsigned int real_irq)
        return NO_IRQ;
 
 }
+#endif /* CONFIG_PPC64 */
 
 #ifdef CONFIG_IRQSTACKS
 struct thread_info *softirq_ctx[NR_CPUS];
@@ -432,7 +387,7 @@ void irq_ctx_init(void)
        struct thread_info *tp;
        int i;
 
-       for_each_cpu(i) {
+       for_each_possible_cpu(i) {
                memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
                tp = softirq_ctx[i];
                tp->cpu = i;
@@ -445,10 +400,24 @@ void irq_ctx_init(void)
        }
 }
 
+static inline void do_softirq_onstack(void)
+{
+       struct thread_info *curtp, *irqtp;
+
+       curtp = current_thread_info();
+       irqtp = softirq_ctx[smp_processor_id()];
+       irqtp->task = curtp->task;
+       call_do_softirq(irqtp);
+       irqtp->task = NULL;
+}
+
+#else
+#define do_softirq_onstack()   __do_softirq()
+#endif /* CONFIG_IRQSTACKS */
+
 void do_softirq(void)
 {
        unsigned long flags;
-       struct thread_info *curtp, *irqtp;
 
        if (in_interrupt())
                return;
@@ -456,19 +425,18 @@ void do_softirq(void)
        local_irq_save(flags);
 
        if (local_softirq_pending()) {
-               curtp = current_thread_info();
-               irqtp = softirq_ctx[smp_processor_id()];
-               irqtp->task = curtp->task;
-               call_do_softirq(irqtp);
-               irqtp->task = NULL;
+               account_system_vtime(current);
+               local_bh_disable();
+               do_softirq_onstack();
+               account_system_vtime(current);
+               __local_bh_enable();
        }
 
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(do_softirq);
 
-#endif /* CONFIG_IRQSTACKS */
-
+#ifdef CONFIG_PPC64
 static int __init setup_noirqdistrib(char *str)
 {
        distribute_irqs = 0;