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/setup.h>
  38#include <asm/mips-boards/generic.h>
  39
  40#include <asm/mach-powertv/asic_regs.h>
  41
  42static DEFINE_RAW_SPINLOCK(asic_irq_lock);
  43
  44static inline int get_int(void)
  45{
  46        unsigned long flags;
  47        int irq;
  48
  49        raw_spin_lock_irqsave(&asic_irq_lock, flags);
  50
  51        irq = (asic_read(int_int_scan) >> 4) - 1;
  52
  53        if (irq == 0 || irq >= NR_IRQS)
  54                irq = -1;
  55
  56        raw_spin_unlock_irqrestore(&asic_irq_lock, flags);
  57
  58        return irq;
  59}
  60
  61static void asic_irqdispatch(void)
  62{
  63        int irq;
  64
  65        irq = get_int();
  66        if (irq < 0)
  67                return;  /* interrupt has already been cleared */
  68
  69        do_IRQ(irq);
  70}
  71
  72static inline int clz(unsigned long x)
  73{
  74        __asm__(
  75        "       .set    push                                    \n"
  76        "       .set    mips32                                  \n"
  77        "       clz     %0, %1                                  \n"
  78        "       .set    pop                                     \n"
  79        : "=r" (x)
  80        : "r" (x));
  81
  82        return x;
  83}
  84
  85/*
  86 * Version of ffs that only looks at bits 12..15.
  87 */
  88static inline unsigned int irq_ffs(unsigned int pending)
  89{
  90        return fls(pending) - 1 + CAUSEB_IP;
  91}
  92
  93/*
  94 * TODO: check how it works under EIC mode.
  95 */
  96asmlinkage void plat_irq_dispatch(void)
  97{
  98        unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
  99        int irq;
 100
 101        irq = irq_ffs(pending);
 102
 103        if (irq == CAUSEF_IP3)
 104                asic_irqdispatch();
 105        else if (irq >= 0)
 106                do_IRQ(irq);
 107        else
 108                spurious_interrupt();
 109}
 110
 111void __init arch_init_irq(void)
 112{
 113        int i;
 114
 115        asic_irq_init();
 116
 117        /*
 118         * Initialize interrupt exception vectors.
 119         */
 120        if (cpu_has_veic || cpu_has_vint) {
 121                int nvec = cpu_has_veic ? 64 : 8;
 122                for (i = 0; i < nvec; i++)
 123                        set_vi_handler(i, asic_irqdispatch);
 124        }
 125}
 126