linux/arch/mips/powertv/asic/asic_int.c
<<
>>
Prefs
   1/*
   2 * Carsten Langgaard, carstenl@mips.com
   3 * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
   4 * Copyright (C) 2001 Ralf Baechle
   5 * Portions copyright (C) 2009  Cisco Systems, Inc.
   6 *
   7 *  This program is free software; you can distribute it and/or modify it
   8 *  under the terms of the GNU General Public License (Version 2) as
   9 *  published by the Free Software Foundation.
  10 *
  11 *  This program is distributed in the hope it will be useful, but WITHOUT
  12 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14 *  for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License along
  17 *  with this program; if not, write to the Free Software Foundation, Inc.,
  18 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  19 *
  20 * Routines for generic manipulation of the interrupts found on the PowerTV
  21 * platform.
  22 *
  23 * The interrupt controller is located in the South Bridge a PIIX4 device
  24 * with two internal 82C95 interrupt controllers.
  25 */
  26#include <linux/init.h>
  27#include <linux/irq.h>
  28#include <linux/sched.h>
  29#include <linux/interrupt.h>
  30#include <linux/kernel_stat.h>
  31#include <linux/kernel.h>
  32#include <linux/random.h>
  33
  34#include <asm/irq_cpu.h>
  35#include <linux/io.h>
  36#include <asm/irq_regs.h>
  37#include <asm/mips-boards/generic.h>
  38
  39#include <asm/mach-powertv/asic_regs.h>
  40
  41static DEFINE_RAW_SPINLOCK(asic_irq_lock);
  42
  43static inline int get_int(void)
  44{
  45        unsigned long flags;
  46        int irq;
  47
  48        raw_spin_lock_irqsave(&asic_irq_lock, flags);
  49
  50        irq = (asic_read(int_int_scan) >> 4) - 1;
  51
  52        if (irq == 0 || irq >= NR_IRQS)
  53                irq = -1;
  54
  55        raw_spin_unlock_irqrestore(&asic_irq_lock, flags);
  56
  57        return irq;
  58}
  59
  60static void asic_irqdispatch(void)
  61{
  62        int irq;
  63
  64        irq = get_int();
  65        if (irq < 0)
  66                return;  /* interrupt has already been cleared */
  67
  68        do_IRQ(irq);
  69}
  70
  71static inline int clz(unsigned long x)
  72{
  73        __asm__(
  74        "       .set    push                                    \n"
  75        "       .set    mips32                                  \n"
  76        "       clz     %0, %1                                  \n"
  77        "       .set    pop                                     \n"
  78        : "=r" (x)
  79        : "r" (x));
  80
  81        return x;
  82}
  83
  84/*
  85 * Version of ffs that only looks at bits 12..15.
  86 */
  87static inline unsigned int irq_ffs(unsigned int pending)
  88{
  89        return fls(pending) - 1 + CAUSEB_IP;
  90}
  91
  92/*
  93 * TODO: check how it works under EIC mode.
  94 */
  95asmlinkage void plat_irq_dispatch(void)
  96{
  97        unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
  98        int irq;
  99
 100        irq = irq_ffs(pending);
 101
 102        if (irq == CAUSEF_IP3)
 103                asic_irqdispatch();
 104        else if (irq >= 0)
 105                do_IRQ(irq);
 106        else
 107                spurious_interrupt();
 108}
 109
 110void __init arch_init_irq(void)
 111{
 112        int i;
 113
 114        asic_irq_init();
 115
 116        /*
 117         * Initialize interrupt exception vectors.
 118         */
 119        if (cpu_has_veic || cpu_has_vint) {
 120                int nvec = cpu_has_veic ? 64 : 8;
 121                for (i = 0; i < nvec; i++)
 122                        set_vi_handler(i, asic_irqdispatch);
 123        }
 124}
 125