linux/arch/mips/kernel/irq-gic.c
<<
>>
Prefs
   1#undef DEBUG
   2
   3#include <linux/bitmap.h>
   4#include <linux/init.h>
   5#include <linux/smp.h>
   6
   7#include <asm/io.h>
   8#include <asm/gic.h>
   9#include <asm/gcmpregs.h>
  10#include <asm/mips-boards/maltaint.h>
  11#include <asm/irq.h>
  12#include <linux/hardirq.h>
  13#include <asm-generic/bitops/find.h>
  14
  15
  16static unsigned long _gic_base;
  17static unsigned int _irqbase;
  18static unsigned int gic_irq_flags[GIC_NUM_INTRS];
  19#define GIC_IRQ_FLAG_EDGE      0x0001
  20
  21struct gic_pcpu_mask pcpu_masks[NR_CPUS];
  22static struct gic_pending_regs pending_regs[NR_CPUS];
  23static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
  24
  25void gic_send_ipi(unsigned int intr)
  26{
  27        pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__,
  28                 read_c0_status());
  29        GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
  30}
  31
  32/* This is Malta specific and needs to be exported */
  33static void __init vpe_local_setup(unsigned int numvpes)
  34{
  35        int i;
  36        unsigned long timer_interrupt = 5, perf_interrupt = 5;
  37        unsigned int vpe_ctl;
  38
  39        /*
  40         * Setup the default performance counter timer interrupts
  41         * for all VPEs
  42         */
  43        for (i = 0; i < numvpes; i++) {
  44                GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
  45
  46                /* Are Interrupts locally routable? */
  47                GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
  48                if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
  49                        GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
  50                                 GIC_MAP_TO_PIN_MSK | timer_interrupt);
  51
  52                if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
  53                        GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
  54                                 GIC_MAP_TO_PIN_MSK | perf_interrupt);
  55        }
  56}
  57
  58unsigned int gic_get_int(void)
  59{
  60        unsigned int i;
  61        unsigned long *pending, *intrmask, *pcpu_mask;
  62        unsigned long *pending_abs, *intrmask_abs;
  63
  64        /* Get per-cpu bitmaps */
  65        pending = pending_regs[smp_processor_id()].pending;
  66        intrmask = intrmask_regs[smp_processor_id()].intrmask;
  67        pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
  68
  69        pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
  70                                                         GIC_SH_PEND_31_0_OFS);
  71        intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
  72                                                          GIC_SH_MASK_31_0_OFS);
  73
  74        for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) {
  75                GICREAD(*pending_abs, pending[i]);
  76                GICREAD(*intrmask_abs, intrmask[i]);
  77                pending_abs++;
  78                intrmask_abs++;
  79        }
  80
  81        bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
  82        bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
  83
  84        i = find_first_bit(pending, GIC_NUM_INTRS);
  85
  86        pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i);
  87
  88        return i;
  89}
  90
  91static unsigned int gic_irq_startup(unsigned int irq)
  92{
  93        irq -= _irqbase;
  94        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
  95        GIC_SET_INTR_MASK(irq);
  96        return 0;
  97}
  98
  99static void gic_irq_ack(unsigned int irq)
 100{
 101        irq -= _irqbase;
 102        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
 103        GIC_CLR_INTR_MASK(irq);
 104
 105        if (gic_irq_flags[irq] & GIC_IRQ_FLAG_EDGE)
 106                GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
 107}
 108
 109static void gic_mask_irq(unsigned int irq)
 110{
 111        irq -= _irqbase;
 112        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
 113        GIC_CLR_INTR_MASK(irq);
 114}
 115
 116static void gic_unmask_irq(unsigned int irq)
 117{
 118        irq -= _irqbase;
 119        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
 120        GIC_SET_INTR_MASK(irq);
 121}
 122
 123#ifdef CONFIG_SMP
 124
 125static DEFINE_SPINLOCK(gic_lock);
 126
 127static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
 128{
 129        cpumask_t       tmp = CPU_MASK_NONE;
 130        unsigned long   flags;
 131        int             i;
 132
 133        irq -= _irqbase;
 134        pr_debug(KERN_DEBUG "%s(%d) called\n", __func__, irq);
 135        cpumask_and(&tmp, cpumask, cpu_online_mask);
 136        if (cpus_empty(tmp))
 137                return -1;
 138
 139        /* Assumption : cpumask refers to a single CPU */
 140        spin_lock_irqsave(&gic_lock, flags);
 141        for (;;) {
 142                /* Re-route this IRQ */
 143                GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
 144
 145                /* Update the pcpu_masks */
 146                for (i = 0; i < NR_CPUS; i++)
 147                        clear_bit(irq, pcpu_masks[i].pcpu_mask);
 148                set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
 149
 150        }
 151        cpumask_copy(irq_desc[irq].affinity, cpumask);
 152        spin_unlock_irqrestore(&gic_lock, flags);
 153
 154        return 0;
 155}
 156#endif
 157
 158static struct irq_chip gic_irq_controller = {
 159        .name           =       "MIPS GIC",
 160        .startup        =       gic_irq_startup,
 161        .ack            =       gic_irq_ack,
 162        .mask           =       gic_mask_irq,
 163        .mask_ack       =       gic_mask_irq,
 164        .unmask         =       gic_unmask_irq,
 165        .eoi            =       gic_unmask_irq,
 166#ifdef CONFIG_SMP
 167        .set_affinity   =       gic_set_affinity,
 168#endif
 169};
 170
 171static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
 172        unsigned int pin, unsigned int polarity, unsigned int trigtype,
 173        unsigned int flags)
 174{
 175        /* Setup Intr to Pin mapping */
 176        if (pin & GIC_MAP_TO_NMI_MSK) {
 177                GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
 178                /* FIXME: hack to route NMI to all cpu's */
 179                for (cpu = 0; cpu < NR_CPUS; cpu += 32) {
 180                        GICWRITE(GIC_REG_ADDR(SHARED,
 181                                          GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)),
 182                                 0xffffffff);
 183                }
 184        } else {
 185                GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
 186                         GIC_MAP_TO_PIN_MSK | pin);
 187                /* Setup Intr to CPU mapping */
 188                GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
 189        }
 190
 191        /* Setup Intr Polarity */
 192        GIC_SET_POLARITY(intr, polarity);
 193
 194        /* Setup Intr Trigger Type */
 195        GIC_SET_TRIGGER(intr, trigtype);
 196
 197        /* Init Intr Masks */
 198        GIC_CLR_INTR_MASK(intr);
 199        /* Initialise per-cpu Interrupt software masks */
 200        if (flags & GIC_FLAG_IPI)
 201                set_bit(intr, pcpu_masks[cpu].pcpu_mask);
 202        if (flags & GIC_FLAG_TRANSPARENT)
 203                GIC_SET_INTR_MASK(intr);
 204        if (trigtype == GIC_TRIG_EDGE)
 205                gic_irq_flags[intr] |= GIC_IRQ_FLAG_EDGE;
 206}
 207
 208static void __init gic_basic_init(int numintrs, int numvpes,
 209                        struct gic_intr_map *intrmap, int mapsize)
 210{
 211        unsigned int i, cpu;
 212
 213        /* Setup defaults */
 214        for (i = 0; i < numintrs; i++) {
 215                GIC_SET_POLARITY(i, GIC_POL_POS);
 216                GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
 217                GIC_CLR_INTR_MASK(i);
 218                if (i < GIC_NUM_INTRS)
 219                        gic_irq_flags[i] = 0;
 220        }
 221
 222        /* Setup specifics */
 223        for (i = 0; i < mapsize; i++) {
 224                cpu = intrmap[i].cpunum;
 225                if (cpu == X)
 226                        continue;
 227                if (cpu == 0 && i != 0 && intrmap[i].flags == 0)
 228                        continue;
 229                gic_setup_intr(i,
 230                        intrmap[i].cpunum,
 231                        intrmap[i].pin,
 232                        intrmap[i].polarity,
 233                        intrmap[i].trigtype,
 234                        intrmap[i].flags);
 235        }
 236
 237        vpe_local_setup(numvpes);
 238
 239        for (i = _irqbase; i < (_irqbase + numintrs); i++)
 240                set_irq_chip(i, &gic_irq_controller);
 241}
 242
 243void __init gic_init(unsigned long gic_base_addr,
 244                     unsigned long gic_addrspace_size,
 245                     struct gic_intr_map *intr_map, unsigned int intr_map_size,
 246                     unsigned int irqbase)
 247{
 248        unsigned int gicconfig;
 249        int numvpes, numintrs;
 250
 251        _gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
 252                                                    gic_addrspace_size);
 253        _irqbase = irqbase;
 254
 255        GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
 256        numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
 257                   GIC_SH_CONFIG_NUMINTRS_SHF;
 258        numintrs = ((numintrs + 1) * 8);
 259
 260        numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
 261                  GIC_SH_CONFIG_NUMVPES_SHF;
 262
 263        pr_debug("%s called\n", __func__);
 264
 265        gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
 266}
 267