[POWERPC] Lazy interrupt disabling for 64-bit machines
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / powerpc / kernel / irq.c
index b4432332341fc6a695b87e0cf4f6b3de1ac520ba..67b21a008f6e3e71593c2145a54847869d57d5ff 100644 (file)
@@ -64,8 +64,9 @@
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
 #include <asm/udbg.h>
-#ifdef CONFIG_PPC_ISERIES
+#ifdef CONFIG_PPC64
 #include <asm/paca.h>
+#include <asm/firmware.h>
 #endif
 
 int __irq_offset_value;
@@ -95,6 +96,27 @@ extern atomic_t ipi_sent;
 EXPORT_SYMBOL(irq_desc);
 
 int distribute_irqs = 1;
+
+void local_irq_restore(unsigned long en)
+{
+       get_paca()->soft_enabled = en;
+       if (!en)
+               return;
+
+       if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+               if (get_paca()->lppaca_ptr->int_dword.any_int)
+                       iseries_handle_interrupts();
+               return;
+       }
+
+       if (get_paca()->hard_enabled)
+               return;
+       /* need to hard-enable interrupts here */
+       get_paca()->hard_enabled = en;
+       if ((int)mfspr(SPRN_DEC) < 0)
+               mtspr(SPRN_DEC, 1);
+       hard_irq_enable();
+}
 #endif /* CONFIG_PPC64 */
 
 int show_interrupts(struct seq_file *p, void *v)
@@ -187,6 +209,7 @@ void fixup_irqs(cpumask_t map)
 
 void do_IRQ(struct pt_regs *regs)
 {
+       struct pt_regs *old_regs = set_irq_regs(regs);
        unsigned int irq;
 #ifdef CONFIG_IRQSTACKS
        struct thread_info *curtp, *irqtp;
@@ -216,7 +239,7 @@ void do_IRQ(struct pt_regs *regs)
         * The value -2 is for buggy hardware and means that this IRQ
         * has already been handled. -- Tom
         */
-       irq = ppc_md.get_irq(regs);
+       irq = ppc_md.get_irq();
 
        if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
 #ifdef CONFIG_IRQSTACKS
@@ -230,18 +253,19 @@ void do_IRQ(struct pt_regs *regs)
                                handler = &__do_IRQ;
                        irqtp->task = curtp->task;
                        irqtp->flags = 0;
-                       call_handle_irq(irq, desc, regs, irqtp, handler);
+                       call_handle_irq(irq, desc, irqtp, handler);
                        irqtp->task = NULL;
                        if (irqtp->flags)
                                set_bits(irqtp->flags, &curtp->flags);
                } else
 #endif
-                       generic_handle_irq(irq, regs);
+                       generic_handle_irq(irq);
        } else if (irq != NO_IRQ_IGNORE)
                /* That's not SMP safe ... but who cares ? */
                ppc_spurious_interrupts++;
 
         irq_exit();
+       set_irq_regs(old_regs);
 
 #ifdef CONFIG_PPC_ISERIES
        if (get_lppaca()->int_dword.fields.decr_int) {
@@ -570,8 +594,8 @@ unsigned int irq_create_mapping(struct irq_host *host,
 }
 EXPORT_SYMBOL_GPL(irq_create_mapping);
 
-extern unsigned int irq_create_of_mapping(struct device_node *controller,
-                                         u32 *intspec, unsigned int intsize)
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                  u32 *intspec, unsigned int intsize)
 {
        struct irq_host *host;
        irq_hw_number_t hwirq;
@@ -777,7 +801,6 @@ unsigned int irq_alloc_virt(struct irq_host *host,
 {
        unsigned long flags;
        unsigned int i, j, found = NO_IRQ;
-       unsigned int limit = irq_virq_count - count;
 
        if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
                return NO_IRQ;
@@ -794,14 +817,16 @@ unsigned int irq_alloc_virt(struct irq_host *host,
        /* Look for count consecutive numbers in the allocatable
         * (non-legacy) space
         */
-       for (i = NUM_ISA_INTERRUPTS; i <= limit; ) {
-               for (j = i; j < (i + count); j++)
-                       if (irq_map[j].host != NULL) {
-                               i = j + 1;
-                               continue;
-                       }
-               found = i;
-               break;
+       for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {
+               if (irq_map[i].host != NULL)
+                       j = 0;
+               else
+                       j++;
+
+               if (j == count) {
+                       found = i - count + 1;
+                       break;
+               }
        }
        if (found == NO_IRQ) {
                spin_unlock_irqrestore(&irq_big_lock, flags);