linux/arch/blackfin/kernel/irqchip.c
<<
>>
Prefs
   1/*
   2 * File:         arch/blackfin/kernel/irqchip.c
   3 * Based on:
   4 * Author:
   5 *
   6 * Created:
   7 * Description:  This file contains the simple DMA Implementation for Blackfin
   8 *
   9 * Modified:
  10 *               Copyright 2004-2006 Analog Devices Inc.
  11 *
  12 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License as published by
  16 * the Free Software Foundation; either version 2 of the License, or
  17 * (at your option) any later version.
  18 *
  19 * This program is distributed in the hope that it will be useful,
  20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22 * GNU General Public License for more details.
  23 *
  24 * You should have received a copy of the GNU General Public License
  25 * along with this program; if not, see the file COPYING, or write
  26 * to the Free Software Foundation, Inc.,
  27 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  28 */
  29
  30#include <linux/kernel_stat.h>
  31#include <linux/module.h>
  32#include <linux/random.h>
  33#include <linux/seq_file.h>
  34#include <linux/kallsyms.h>
  35#include <linux/interrupt.h>
  36#include <linux/irq.h>
  37#include <asm/trace.h>
  38
  39static unsigned long irq_err_count;
  40static spinlock_t irq_controller_lock;
  41
  42/*
  43 * Dummy mask/unmask handler
  44 */
  45void dummy_mask_unmask_irq(unsigned int irq)
  46{
  47}
  48
  49void ack_bad_irq(unsigned int irq)
  50{
  51        irq_err_count += 1;
  52        printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
  53}
  54EXPORT_SYMBOL(ack_bad_irq);
  55
  56static struct irq_chip bad_chip = {
  57        .ack = dummy_mask_unmask_irq,
  58        .mask = dummy_mask_unmask_irq,
  59        .unmask = dummy_mask_unmask_irq,
  60};
  61
  62static struct irq_desc bad_irq_desc = {
  63        .status = IRQ_DISABLED,
  64        .chip = &bad_chip,
  65        .handle_irq = handle_bad_irq,
  66        .depth = 1,
  67        .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
  68#ifdef CONFIG_SMP
  69        .affinity = CPU_MASK_ALL
  70#endif
  71};
  72
  73int show_interrupts(struct seq_file *p, void *v)
  74{
  75        int i = *(loff_t *) v;
  76        struct irqaction *action;
  77        unsigned long flags;
  78
  79        if (i < NR_IRQS) {
  80                spin_lock_irqsave(&irq_desc[i].lock, flags);
  81                action = irq_desc[i].action;
  82                if (!action)
  83                        goto unlock;
  84
  85                seq_printf(p, "%3d: %10u ", i, kstat_irqs(i));
  86                seq_printf(p, "  %s", action->name);
  87                for (action = action->next; action; action = action->next)
  88                        seq_printf(p, ", %s", action->name);
  89
  90                seq_putc(p, '\n');
  91 unlock:
  92                spin_unlock_irqrestore(&irq_desc[i].lock, flags);
  93        } else if (i == NR_IRQS) {
  94                seq_printf(p, "Err: %10lu\n", irq_err_count);
  95        }
  96        return 0;
  97}
  98
  99/*
 100 * do_IRQ handles all hardware IRQs.  Decoded IRQs should not
 101 * come via this function.  Instead, they should provide their
 102 * own 'handler'
 103 */
 104
 105#ifdef CONFIG_DO_IRQ_L1
 106__attribute__((l1_text))
 107#endif
 108asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
 109{
 110        struct pt_regs *old_regs;
 111        struct irq_desc *desc = irq_desc + irq;
 112        unsigned short pending, other_ints;
 113
 114        old_regs = set_irq_regs(regs);
 115
 116        /*
 117         * Some hardware gives randomly wrong interrupts.  Rather
 118         * than crashing, do something sensible.
 119         */
 120        if (irq >= NR_IRQS)
 121                desc = &bad_irq_desc;
 122
 123        irq_enter();
 124
 125        generic_handle_irq(irq);
 126
 127        /* If we're the only interrupt running (ignoring IRQ15 which is for
 128           syscalls), lower our priority to IRQ14 so that softirqs run at
 129           that level.  If there's another, lower-level interrupt, irq_exit
 130           will defer softirqs to that.  */
 131        CSYNC();
 132        pending = bfin_read_IPEND() & ~0x8000;
 133        other_ints = pending & (pending - 1);
 134        if (other_ints == 0)
 135                lower_to_irq14();
 136        irq_exit();
 137
 138        set_irq_regs(old_regs);
 139}
 140
 141void __init init_IRQ(void)
 142{
 143        struct irq_desc *desc;
 144        int irq;
 145
 146        spin_lock_init(&irq_controller_lock);
 147        for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
 148                *desc = bad_irq_desc;
 149        }
 150
 151        init_arch_irq();
 152
 153#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
 154        /* Now that evt_ivhw is set up, turn this on */
 155        trace_buff_offset = 0;
 156        bfin_write_TBUFCTL(BFIN_TRACE_ON);
 157        printk(KERN_INFO "Hardware Trace expanded to %ik\n",
 158          1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN);
 159#endif
 160}
 161
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.