This patch is essentially a rewrite of the irq handling code to make proper use
of the genirq framework.

Based on patch by Michael Walle.

Signed-off-by: Lars-Peter Clausen <[email protected]>
---
 arch/lm32/Kconfig                   |   10 +--
 arch/lm32/include/asm/hardirq.h     |   35 ++-----
 arch/lm32/include/asm/irq.h         |   37 ++----
 arch/lm32/include/asm/thread_info.h |    2 -
 arch/lm32/kernel/entry.S            |   49 ++++++--
 arch/lm32/kernel/init_task.c        |    1 +
 arch/lm32/kernel/irq.c              |  213 +++++++++--------------------------
 drivers/input/keyboard/softusb.c    |    2 -
 drivers/net/milkymist_minimac.c     |   12 +--
 drivers/serial/milkymist_uart.c     |   12 ++-
 10 files changed, 125 insertions(+), 248 deletions(-)

diff --git a/arch/lm32/Kconfig b/arch/lm32/Kconfig
index 66c789b..0563647 100644
--- a/arch/lm32/Kconfig
+++ b/arch/lm32/Kconfig
@@ -2,6 +2,8 @@ config LM32
        bool
        default y
        select CPU_MICO32
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_HARDIRQS_NO_DEPRECATED
 
 config MMU
        bool
@@ -43,10 +45,6 @@ config GENERIC_BUG
        bool
        default y
 
-config GENERIC_HARDIRQS
-       bool
-       default y
-
 config GENERIC_CLOCKEVENTS
        bool
        default y
@@ -67,10 +65,6 @@ config NO_IOPORT
        bool
        default y
 
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       bool
-       default y
-
 config APM_EMULATION
        bool
        default n
diff --git a/arch/lm32/include/asm/hardirq.h b/arch/lm32/include/asm/hardirq.h
index fb3b938..05abd08 100644
--- a/arch/lm32/include/asm/hardirq.h
+++ b/arch/lm32/include/asm/hardirq.h
@@ -1,30 +1,13 @@
-/*
- * Based on:
- * include/asm-m68knommu/hardirq.h
- */
+#ifndef _ASM_HARDIRQ_H_
+#define _ASM_HARDIRQ_H_
 
-#ifndef _LM32_ASM_HARDIRQ_H
-#define _LM32_ASM_HARDIRQ_H
+#define ack_bad_irq ack_bad_irq
+#include <asm-generic/hardirq.h>
 
-#include <linux/cache.h>
-#include <linux/threads.h>
-#include <asm/irq.h>
+extern atomic_t irq_err_count;
+static inline void ack_bad_irq(int irq)
+{
+       atomic_inc(&irq_err_count);
+}
 
-typedef struct {
-       unsigned int __softirq_pending;
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
-
-#define HARDIRQ_BITS   8
-
-/*
- * The hardirq mask has to be large enough to have
- * space for potentially all IRQ sources in the system
- * nesting on a single CPU:
- */
-#if (1 << HARDIRQ_BITS) < NR_IRQS
-# error HARDIRQ_BITS is too low!
 #endif
-
-#endif /* _LM32_ASM_HARDIRQ_H */
diff --git a/arch/lm32/include/asm/irq.h b/arch/lm32/include/asm/irq.h
index b8161dc..32b8d8c 100644
--- a/arch/lm32/include/asm/irq.h
+++ b/arch/lm32/include/asm/irq.h
@@ -24,35 +24,24 @@
 #ifndef _LM32_ASM_IRQ_H
 #define _LM32_ASM_IRQ_H
 
-#include <asm/hw/interrupts.h>
+#include <asm/atomic.h>
 
-/* # of lm32 interrupts */
-#define NR_IRQS (32)
+#define NR_IRQS 32
+#include <asm-generic/irq.h>
 
-/* # of lm32 irq levels */
-#define NR_IRQLVL      1
+#define        NO_IRQ 0
 
-#define        NO_IRQ          (-1)
-
-#define IRQ_SYSTMR     (IRQ_TIMER0)
-
-#include <linux/irq.h>
-
-#define irq_canonicalize(i) (i)
-
-extern unsigned long irq_err_count;
-static inline void ack_bad_irq(int irq)
+static inline uint32_t lm32_irq_pending(void)
 {
-       irq_err_count++;
+       uint32_t ip;
+       __asm__ __volatile__("rcsr %0, IP" : "=r"(ip) : );
+       return ip;
 }
 
-/* in arch/lm32/kernel/irq.c */
-void lm32_irq_mask(unsigned int irq);
-void lm32_irq_multimask(unsigned long mask);
-void lm32_irq_unmask(unsigned int irq);
-void lm32_irq_ack(unsigned int irq);
-unsigned long lm32_irq_pending(void);
-void lm32_irq_disable(unsigned int irq);
-void lm32_irq_enable(unsigned int irq);
+static inline void lm32_irq_ack(unsigned int irq)
+{
+       uint32_t mask = (1 << irq);
+       __asm__ __volatile__("wcsr IP, %0" : : "r"(mask) );
+}
 
 #endif /* _LM32_ASM_IRQ_H_ */
diff --git a/arch/lm32/include/asm/thread_info.h 
b/arch/lm32/include/asm/thread_info.h
index 221f603..9cbfe45 100644
--- a/arch/lm32/include/asm/thread_info.h
+++ b/arch/lm32/include/asm/thread_info.h
@@ -77,8 +77,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TI_CPU         12
 #define TI_PRE_COUNT   16
 
-#define        PREEMPT_ACTIVE  0x4000000
-
 /*
  * thread information flag bit numbers
  */
diff --git a/arch/lm32/kernel/entry.S b/arch/lm32/kernel/entry.S
index aec9e65..24c1740 100644
--- a/arch/lm32/kernel/entry.S
+++ b/arch/lm32/kernel/entry.S
@@ -363,22 +363,49 @@ _long_interrupt_handler:
        sw      (sp+120), ra
        calli   _save_irq_frame
 
-       rcsr    r2, IP
-       rcsr    r3, IM
+       /* Workaround hardware hazard. Sometimes the interrupt handler is 
entered
+        * although interrupts are disabled */
+       rcsr    r1, IE
+       andi    r1, r1, 0x2
+       be              r1, r0, 5f
+
+       rcsr    r3, IP
+       rcsr    r4, IM
        mvi     r1, 0
-       and     r2, r2, r3
-       mvi     r3, 1
-       be      r2, r0, 3f
+       and     r3, r3, r4
+       be      r3, r0, 5f
+
+       andi    r4, r3, 0xffff
+       bne             r4, r0, 1f
+       sri             r3, r3, 16
+       addi    r1, r1, 16
 1:
-       and     r4, r2, r3
-       bne     r4, r0, 2f
-       sli     r3, r3, 1
-       addi    r1, r1, 1
-       bi      1b
+       andi    r4, r3, 0xff
+       bne             r4, r0, 2f
+       sri             r3, r3, 8
+       addi    r1, r1, 8
 2:
+       andi    r4, r3, 0xf
+       bne             r4, r0, 3f
+       sri             r3, r3, 4
+       addi    r1, r1, 4
+3:
+       andi    r4, r3, 0x3
+       bne             r4, r0, 4f
+       sri             r3, r3, 2
+       addi    r1, r1, 2
+4:
+       andi    r4, r3, 0x1
+       bne             r4, r0, 5f
+       sri             r3, r3, 1
+       addi    r1, r1, 1
+5:
+
        addi    r2, sp, 4
        calli   asm_do_IRQ
-3:
+       addi    r1, sp, 4
+       calli   manage_signals_irq
+5:
        bi      _restore_irq_frame_and_return
 
 _save_irq_frame:
diff --git a/arch/lm32/kernel/init_task.c b/arch/lm32/kernel/init_task.c
index 6f8c357..c46a26a 100644
--- a/arch/lm32/kernel/init_task.c
+++ b/arch/lm32/kernel/init_task.c
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/mqueue.h>
+#include <linux/hardirq.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff --git a/arch/lm32/kernel/irq.c b/arch/lm32/kernel/irq.c
index 08d0524..2a695a3 100644
--- a/arch/lm32/kernel/irq.c
+++ b/arch/lm32/kernel/irq.c
@@ -1,183 +1,85 @@
-/*
- * (C) Copyright 2007
- *     Theobroma Systems <www.theobroma-systems.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
+#include <linux/atomic.h>
 #include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kernel_stat.h>
-#include <linux/errno.h>
 #include <linux/seq_file.h>
+#include <linux/types.h>
 
-unsigned long irq_err_count;
-/* this is the current mask in IM */
-static unsigned long lm32_current_irq_mask = 0;
-static unsigned long lm32_current_irq_disable = 0;
-
-/*
- * NOP IRQ functions
- */
-static void noop(unsigned int irq)
-{
-}
-
-static unsigned int noop_ret(unsigned int irq)
-{
-       return 0;
-}
-
-void lm32_irq_mask(unsigned int irq)
-{
-       unsigned long flags;
-       unsigned long mask = ~(1 << irq);
-
-       local_irq_save(flags);
-
-       mask &= lm32_current_irq_mask;
-       lm32_current_irq_mask = mask;
-
-       asm volatile ("wcsr IM, %0" : : "r"(mask));
-
-       local_irq_restore(flags);
-}
-
-void lm32_irq_multimask(unsigned long mask)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       lm32_current_irq_mask &= ~mask;
-
-       asm volatile ("wcsr IM, %0" : : "r"(lm32_current_irq_mask));
-
-       local_irq_restore(flags);
-}
-
-void lm32_irq_unmask(unsigned int irq)
-{
-       unsigned long flags;
-       unsigned long mask = (1 << irq);
-
-       if( !(lm32_current_irq_mask & mask) && !(lm32_current_irq_disable & 
mask)) {
-               local_irq_save(flags);
-
-               mask |= lm32_current_irq_mask;
-               lm32_current_irq_mask = mask;
-
-               asm volatile ("wcsr IM, %0" : : "r"(mask));
-
-               local_irq_restore(flags);
-       }
-}
+atomic_t irq_err_count;
 
-void lm32_irq_disable(unsigned int irq)
+static inline uint32_t lm32_pic_get_irq_mask(struct irq_data *data)
 {
-       unsigned long mask = (1 << irq);
-
-       mask |= lm32_current_irq_disable;
-       lm32_current_irq_disable = mask;
-
-       lm32_irq_mask(irq);
+       return (uint32_t)irq_data_get_irq_chip_data(data);
 }
 
-void lm32_irq_enable(unsigned int irq)
+static void lm32_pic_irq_mask(struct irq_data *data)
 {
-       unsigned long mask = ~(1 << irq);
-
-       mask &= lm32_current_irq_disable;
-       lm32_current_irq_disable = mask;
-
-       lm32_irq_unmask(irq);
+       uint32_t mask = lm32_pic_get_irq_mask(data);
+       uint32_t im;
+
+       __asm__ __volatile__("rcsr %0, IM\n"
+                            "not %0, %0\n"
+                            "nor %0, %0, %1\n"
+                            "wcsr IM, %0"
+                             : "=&r"(im) : "r"(mask));
 }
 
-void lm32_irq_ack(unsigned int irq)
+static void lm32_pic_irq_unmask(struct irq_data *data)
 {
-       unsigned long mask = 1 << irq;
+       uint32_t mask = lm32_pic_get_irq_mask(data);
+       uint32_t im;
 
-       asm volatile ("wcsr IP, %0" : : "r"(mask));
+       __asm__ __volatile__("rcsr %0, IM\n"
+                            "or %0, %0, %1\n"
+                            "wcsr IM, %0\n"
+                            : "=&r"(im) : "r"(mask));
 }
 
-void lm32_irq_mask_ack(unsigned int irq)
+static void lm32_pic_irq_ack(struct irq_data *data)
 {
-       unsigned long flags;
-       unsigned long mask = ~(1 << irq);
-       unsigned long ack = 1 << irq;
-
-       local_irq_save(flags);
-
-       mask &= lm32_current_irq_mask;
-       lm32_current_irq_mask = mask;
-
-       asm volatile ("wcsr IM, %0" : : "r"(mask));
-
-       asm volatile ("wcsr IP, %0" : : "r"(ack));
+       uint32_t mask = lm32_pic_get_irq_mask(data);
 
-       local_irq_restore(flags);
+       __asm__ __volatile__("wcsr IP, %0" : : "r"(mask));
 }
 
-unsigned long lm32_irq_pending()
+static void lm32_pic_irq_mask_ack(struct irq_data *data)
 {
-       unsigned long ret;
-
-       asm volatile ("rcsr %0, IP" : "=r"(ret) : );
-
-       return ret;
+       uint32_t mask = lm32_pic_get_irq_mask(data);
+       uint32_t im;
+
+       __asm__ __volatile__("rcsr %0, IM\n"
+                            "not %0, %0\n"
+                            "nor %0, %0, %1\n"
+                            "wcsr IM, %0\n"
+                            "wcsr IP, %1\n"
+                            : "=&r"(im) : "r"(mask) );
 }
 
-/*
- * LM32 IRQs implementation
- */
-struct irq_chip lm32_internal_irq_chip = {
-       .name           = "LM32",
-       .startup        = noop_ret,
-       .shutdown       = noop,
-       .enable         = noop,
-       .disable        = lm32_irq_mask,
-       .ack            = lm32_irq_ack,
-       .mask           = lm32_irq_mask,
-       .unmask         = lm32_irq_unmask,
-       .mask_ack       = lm32_irq_mask_ack,
-       .end            = noop,
+static struct irq_chip lm32_irq_chip = {
+       .name           = "LM32 PIC",
+       .irq_ack        = lm32_pic_irq_ack,
+       .irq_mask       = lm32_pic_irq_mask,
+       .irq_mask_ack   = lm32_pic_irq_mask_ack,
+       .irq_unmask     = lm32_pic_irq_unmask,
 };
 
 void __init init_IRQ(void)
 {
-       int irq;
+       unsigned int irq;
 
        local_irq_disable();
+       __asm__ __volatile__("wcsr IM, r0");
 
        for (irq = 0; irq < NR_IRQS; irq++) {
-               set_irq_chip(irq, &lm32_internal_irq_chip);
-               set_irq_handler(irq, handle_simple_irq);
+               set_irq_chip(irq, &lm32_irq_chip);
+               set_irq_chip_data(irq, (void *)(1 << irq));
+               set_irq_handler(irq, handle_level_irq);
        }
 }
 
 int show_interrupts(struct seq_file *p, void *v)
 {
-       int i = *(loff_t *) v;
+       int i = *(loff_t *)v;
        struct irqaction * action;
        unsigned long flags;
 
@@ -185,10 +87,11 @@ int show_interrupts(struct seq_file *p, void *v)
        {
                raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
                action = irq_desc[i].action;
-               if( action )
+               if (action)
                {
                        seq_printf(p, "%3d: ", i);
-                       seq_printf(p, "%10s ", irq_desc[i].chip->name ? : "-");
+                       seq_printf(p, "%10u", kstat_irqs(i));
+                       seq_printf(p, "%14s ", get_irq_chip(i)->name ? : "-");
                        seq_printf(p, " %s", action->name);
                        for (action = action->next; action; action = 
action->next)
                                seq_printf(p, ", %s", action->name);
@@ -196,33 +99,19 @@ int show_interrupts(struct seq_file *p, void *v)
                }
                raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
        } else if (i == NR_IRQS) {
-               seq_printf(p, "Errors: %lu\n", irq_err_count);
+               seq_printf(p, "\nErrors: %u\n", atomic_read(&irq_err_count));
        }
 
        return 0;
 }
 
-asmlinkage void manage_signals_irq(struct pt_regs* regs);
-
-/*
- * do_IRQ handles all hardware IRQ's.  Decoded IRQs should not
- * come via this function.  Instead, they should provide their
- * own 'handler'
- */
 asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
 
        irq_enter();
-
-       lm32_irq_mask(irq);
-       generic_handle_irq(irq); /* < this (re)enables interrupts globally */
-       lm32_irq_ack(irq);
-       lm32_irq_unmask(irq);
-
+       generic_handle_irq(irq);
        irq_exit();
 
        set_irq_regs(old_regs);
-
-       manage_signals_irq(regs);
 }
diff --git a/drivers/input/keyboard/softusb.c b/drivers/input/keyboard/softusb.c
index 3c6abfc..523a8f31 100644
--- a/drivers/input/keyboard/softusb.c
+++ b/drivers/input/keyboard/softusb.c
@@ -178,8 +178,6 @@ static int __devinit softusb_probe(struct platform_device 
*pdev)
                return -EBUSY;
        }
 
-       lm32_irq_unmask(IRQ_USB);
-
        printk(KERN_INFO "milkymist_softusb: softusb at 0x%08x irq %d\n",
                SOFTUSB_PMEM_BASE,
                IRQ_USB);
diff --git a/drivers/net/milkymist_minimac.c b/drivers/net/milkymist_minimac.c
index d037026..06b5d61 100644
--- a/drivers/net/milkymist_minimac.c
+++ b/drivers/net/milkymist_minimac.c
@@ -257,7 +257,7 @@ static irqreturn_t minimac_interrupt_rx(int irq, void 
*dev_id)
                out_be32(CSR_MINIMAC_SETUP, 0);
        }
 
-       lm32_irq_disable(dev->irq);
+       disable_irq(dev->irq);
 
        napi_schedule(&tp->napi);
 
@@ -291,7 +291,7 @@ static int minimac_poll(struct napi_struct *napi, int 
budget)
 
        if (work_done < budget) {
                napi_complete(napi);
-               lm32_irq_enable(dev->irq);
+               enable_irq(dev->irq);
        }
 
        return work_done;
@@ -302,7 +302,7 @@ static int minimac_open(struct net_device *dev)
        struct minimac *tp = netdev_priv(dev);
        int ret;
 
-       ret = request_irq(dev->irq, minimac_interrupt_rx, IRQF_DISABLED, 
"milkymist_minimac RX", dev);
+       ret = request_irq(dev->irq, minimac_interrupt_rx, 0, "milkymist_minimac 
RX", dev);
        if (ret)
                return -1;
 
@@ -314,9 +314,6 @@ static int minimac_open(struct net_device *dev)
        netif_start_queue(dev);
        napi_enable(&tp->napi);
 
-       lm32_irq_unmask(dev->irq);
-       lm32_irq_unmask((dev->irq)+1);
-
        return 0;
 }
 
@@ -329,9 +326,6 @@ static int minimac_stop(struct net_device *dev)
 
        netif_stop_queue(dev);
 
-       lm32_irq_mask(dev->irq);
-       lm32_irq_mask(dev->irq+1);
-
        free_irq(dev->irq, dev);
        free_irq(dev->irq+1, dev);
 
diff --git a/drivers/serial/milkymist_uart.c b/drivers/serial/milkymist_uart.c
index ec505db..f7bc945 100644
--- a/drivers/serial/milkymist_uart.c
+++ b/drivers/serial/milkymist_uart.c
@@ -44,6 +44,7 @@
 #define MILKYMISTUART_MINOR 64
 
 static volatile int tx_cts;
+static bool milkymist_uart_irqs_enabled;
 
 /* these two will be initialized by milkymistuart_init */
 static struct uart_port milkymistuart_ports[1];
@@ -240,16 +241,15 @@ static int milkymistuart_startup(struct uart_port *port)
                return -EBUSY;
        }
 
-       lm32_irq_unmask(IRQ_UARTRX);
-       lm32_irq_unmask(IRQ_UARTTX);
+       milkymist_uart_irqs_enabled = true;
 
        return 0;
 }
 
 static void milkymistuart_shutdown(struct uart_port *port)
 {
-       lm32_irq_mask(IRQ_UARTRX);
-       lm32_irq_mask(IRQ_UARTTX);
+       milkymist_uart_irqs_enabled = false;
+
        free_irq(IRQ_UARTRX, port);
        free_irq(IRQ_UARTTX, port);
 }
@@ -309,9 +309,13 @@ static int milkymistuart_verify_port(struct uart_port 
*port, struct serial_struc
 #ifdef CONFIG_SERIAL_MILKYMIST_CONSOLE
 static void milkymist_console_putchar(struct uart_port *port, int ch)
 {
+       if (milkymist_uart_irqs_enabled)
+               disable_irq(IRQ_UARTTX);
        out_be32(CSR_UART_RXTX,ch);
        while(!(lm32_irq_pending() & (1 << IRQ_UARTTX)));
        lm32_irq_ack(IRQ_UARTTX);
+       if (milkymist_uart_irqs_enabled)
+               enable_irq(IRQ_UARTTX);
 }
 
 /*
-- 
1.7.2.3

_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode
Twitter: www.twitter.com/milkymistvj
Ideas? http://milkymist.uservoice.com

Reply via email to