linux/arch/c6x/kernel/irq.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2011-2012 Texas Instruments Incorporated
   3 *
   4 *  This borrows heavily from powerpc version, which is:
   5 *
   6 *  Derived from arch/i386/kernel/irq.c
   7 *    Copyright (C) 1992 Linus Torvalds
   8 *  Adapted from arch/i386 by Gary Thomas
   9 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  10 *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
  11 *    Copyright (C) 1996-2001 Cort Dougan
  12 *  Adapted for Power Macintosh by Paul Mackerras
  13 *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
  14 *
  15 * This program is free software; you can redistribute it and/or
  16 * modify it under the terms of the GNU General Public License
  17 * as published by the Free Software Foundation; either version
  18 * 2 of the License, or (at your option) any later version.
  19 */
  20#include <linux/slab.h>
  21#include <linux/seq_file.h>
  22#include <linux/radix-tree.h>
  23#include <linux/module.h>
  24#include <linux/of.h>
  25#include <linux/of_irq.h>
  26#include <linux/interrupt.h>
  27#include <linux/kernel_stat.h>
  28
  29#include <asm/megamod-pic.h>
  30#include <asm/special_insns.h>
  31
  32unsigned long irq_err_count;
  33
  34static DEFINE_RAW_SPINLOCK(core_irq_lock);
  35
  36static void mask_core_irq(struct irq_data *data)
  37{
  38        unsigned int prio = data->hwirq;
  39
  40        raw_spin_lock(&core_irq_lock);
  41        and_creg(IER, ~(1 << prio));
  42        raw_spin_unlock(&core_irq_lock);
  43}
  44
  45static void unmask_core_irq(struct irq_data *data)
  46{
  47        unsigned int prio = data->hwirq;
  48
  49        raw_spin_lock(&core_irq_lock);
  50        or_creg(IER, 1 << prio);
  51        raw_spin_unlock(&core_irq_lock);
  52}
  53
  54static struct irq_chip core_chip = {
  55        .name           = "core",
  56        .irq_mask       = mask_core_irq,
  57        .irq_unmask     = unmask_core_irq,
  58};
  59
  60static int prio_to_virq[NR_PRIORITY_IRQS];
  61
  62asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs)
  63{
  64        struct pt_regs *old_regs = set_irq_regs(regs);
  65
  66        irq_enter();
  67
  68        generic_handle_irq(prio_to_virq[prio]);
  69
  70        irq_exit();
  71
  72        set_irq_regs(old_regs);
  73}
  74
  75static struct irq_domain *core_domain;
  76
  77static int core_domain_map(struct irq_domain *h, unsigned int virq,
  78                           irq_hw_number_t hw)
  79{
  80        if (hw < 4 || hw >= NR_PRIORITY_IRQS)
  81                return -EINVAL;
  82
  83        prio_to_virq[hw] = virq;
  84
  85        irq_set_status_flags(virq, IRQ_LEVEL);
  86        irq_set_chip_and_handler(virq, &core_chip, handle_level_irq);
  87        return 0;
  88}
  89
  90static const struct irq_domain_ops core_domain_ops = {
  91        .map = core_domain_map,
  92        .xlate = irq_domain_xlate_onecell,
  93};
  94
  95void __init init_IRQ(void)
  96{
  97        struct device_node *np;
  98
  99        /* Mask all priority IRQs */
 100        and_creg(IER, ~0xfff0);
 101
 102        np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic");
 103        if (np != NULL) {
 104                /* create the core host */
 105                core_domain = irq_domain_add_linear(np, NR_PRIORITY_IRQS,
 106                                                    &core_domain_ops, NULL);
 107                if (core_domain)
 108                        irq_set_default_host(core_domain);
 109                of_node_put(np);
 110        }
 111
 112        printk(KERN_INFO "Core interrupt controller initialized\n");
 113
 114        /* now we're ready for other SoC controllers */
 115        megamod_pic_init();
 116
 117        /* Clear all general IRQ flags */
 118        set_creg(ICR, 0xfff0);
 119}
 120
 121void ack_bad_irq(int irq)
 122{
 123        printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
 124        irq_err_count++;
 125}
 126
 127int arch_show_interrupts(struct seq_file *p, int prec)
 128{
 129        seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
 130        return 0;
 131}
 132