MIPS: Move GIC to drivers/irqchip/
authorAndrew Bresticker <abrestic@chromium.org>
Thu, 18 Sep 2014 21:47:19 +0000 (14:47 -0700)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 24 Nov 2014 06:44:54 +0000 (07:44 +0100)
Move GIC irqchip support to drivers/irqchip/ and rename the Kconfig
option from IRQ_GIC to MIPS_GIC to avoid confusion with the ARM GIC.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Acked-by: Jason Cooper <jason@lakedaemon.net>
Reviewed-by: Qais Yousef <qais.yousef@imgtec.com>
Tested-by: Qais Yousef <qais.yousef@imgtec.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jeffrey Deans <jeffrey.deans@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: Jonas Gorski <jogo@openwrt.org>
Cc: John Crispin <blogic@openwrt.org>
Cc: David Daney <ddaney.cavm@gmail.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7812/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/Kconfig
arch/mips/kernel/Makefile
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/irq-gic.c [deleted file]
arch/mips/kernel/smp-mt.c
arch/mips/mti-malta/malta-time.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-mips-gic.c [new file with mode: 0644]

index e08aeec7d916fa54d2defc49eee6db28e0089de4..e0b7c2006900b277bdc78ae9388b3540d1a888e8 100644 (file)
@@ -320,7 +320,7 @@ config MIPS_MALTA
        select GENERIC_ISA_DMA
        select HAVE_PCSPKR_PLATFORM
        select IRQ_CPU
-       select IRQ_GIC
+       select MIPS_GIC
        select HW_HAS_PCI
        select I8253
        select I8259
@@ -362,7 +362,7 @@ config MIPS_SEAD3
        select CPU_MIPSR2_IRQ_EI
        select DMA_NONCOHERENT
        select IRQ_CPU
-       select IRQ_GIC
+       select MIPS_GIC
        select LIBFDT
        select MIPS_MSC
        select SYS_HAS_CPU_MIPS32_R1
@@ -1073,10 +1073,6 @@ config IRQ_TXX9
 config IRQ_GT641XX
        bool
 
-config IRQ_GIC
-       select MIPS_CM
-       bool
-
 config PCI_GT64XXX_PCI0
        bool
 
@@ -1890,7 +1886,7 @@ config FORCE_MAX_ZONEORDER
 
 config CEVT_GIC
        bool "Use GIC global counter for clock events"
-       depends on IRQ_GIC && !MIPS_SEAD3
+       depends on MIPS_GIC && !MIPS_SEAD3
        help
          Use the GIC global counter for the clock events. The R4K clock
          event driver is always present, so if the platform ends up not
index 008a2fed058413ab2eea98109e22016712890b23..3982e5138f61e5aa868f2a1f69ae292f312cf919 100644 (file)
@@ -68,7 +68,6 @@ obj-$(CONFIG_IRQ_CPU_RM7K)    += irq-rm7000.o
 obj-$(CONFIG_MIPS_MSC)         += irq-msc01.o
 obj-$(CONFIG_IRQ_TXX9)         += irq_txx9.o
 obj-$(CONFIG_IRQ_GT641XX)      += irq-gt641xx.o
-obj-$(CONFIG_IRQ_GIC)          += irq-gic.o
 
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_32BIT)            += scall32-o32.o
index bc127e22fdab011bfd1d224a396a00672b4e5ca4..5b8f8e32b47dd92f94769eadaf4a184f04637b34 100644 (file)
@@ -85,7 +85,7 @@ void mips_event_handler(struct clock_event_device *dev)
  */
 static int c0_compare_int_pending(void)
 {
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
        if (cpu_has_veic)
                return gic_get_timer_pending();
 #endif
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
deleted file mode 100644 (file)
index 5828830..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org)
- * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
- */
-#include <linux/bitmap.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/irq.h>
-#include <linux/clocksource.h>
-
-#include <asm/io.h>
-#include <asm/gic.h>
-#include <asm/setup.h>
-#include <asm/traps.h>
-#include <linux/hardirq.h>
-#include <asm-generic/bitops/find.h>
-
-unsigned int gic_frequency;
-unsigned int gic_present;
-unsigned long _gic_base;
-unsigned int gic_irq_base;
-unsigned int gic_irq_flags[GIC_NUM_INTRS];
-
-/* The index into this array is the vector # of the interrupt. */
-struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS];
-
-struct gic_pcpu_mask {
-       DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS);
-};
-
-struct gic_pending_regs {
-       DECLARE_BITMAP(pending, GIC_NUM_INTRS);
-};
-
-struct gic_intrmask_regs {
-       DECLARE_BITMAP(intrmask, GIC_NUM_INTRS);
-};
-
-static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
-static struct gic_pending_regs pending_regs[NR_CPUS];
-static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
-
-#if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
-cycle_t gic_read_count(void)
-{
-       unsigned int hi, hi2, lo;
-
-       do {
-               GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi);
-               GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo);
-               GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2);
-       } while (hi2 != hi);
-
-       return (((cycle_t) hi) << 32) + lo;
-}
-
-void gic_write_compare(cycle_t cnt)
-{
-       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI),
-                               (int)(cnt >> 32));
-       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO),
-                               (int)(cnt & 0xffffffff));
-}
-
-void gic_write_cpu_compare(cycle_t cnt, int cpu)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu);
-       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI),
-                               (int)(cnt >> 32));
-       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO),
-                               (int)(cnt & 0xffffffff));
-
-       local_irq_restore(flags);
-}
-
-cycle_t gic_read_compare(void)
-{
-       unsigned int hi, lo;
-
-       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), hi);
-       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), lo);
-
-       return (((cycle_t) hi) << 32) + lo;
-}
-#endif
-
-unsigned int gic_get_timer_pending(void)
-{
-       unsigned int vpe_pending;
-
-       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
-       GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending);
-       return vpe_pending & GIC_VPE_PEND_TIMER_MSK;
-}
-
-void gic_bind_eic_interrupt(int irq, int set)
-{
-       /* Convert irq vector # to hw int # */
-       irq -= GIC_PIN_TO_VEC_OFFSET;
-
-       /* Set irq to use shadow set */
-       GICWRITE(GIC_REG_ADDR(VPE_LOCAL, GIC_VPE_EIC_SS(irq)), set);
-}
-
-void gic_send_ipi(unsigned int intr)
-{
-       GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
-}
-
-static void gic_eic_irq_dispatch(void)
-{
-       unsigned int cause = read_c0_cause();
-       int irq;
-
-       irq = (cause & ST0_IM) >> STATUSB_IP2;
-       if (irq == 0)
-               irq = -1;
-
-       if (irq >= 0)
-               do_IRQ(gic_irq_base + irq);
-       else
-               spurious_interrupt();
-}
-
-static void __init vpe_local_setup(unsigned int numvpes)
-{
-       unsigned long timer_intr = GIC_INT_TMR;
-       unsigned long perf_intr = GIC_INT_PERFCTR;
-       unsigned int vpe_ctl;
-       int i;
-
-       if (cpu_has_veic) {
-               /*
-                * GIC timer interrupt -> CPU HW Int X (vector X+2) ->
-                * map to pin X+2-1 (since GIC adds 1)
-                */
-               timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
-               /*
-                * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) ->
-                * map to pin X+2-1 (since GIC adds 1)
-                */
-               perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
-       }
-
-       /*
-        * Setup the default performance counter timer interrupts
-        * for all VPEs
-        */
-       for (i = 0; i < numvpes; i++) {
-               GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
-
-               /* Are Interrupts locally routable? */
-               GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
-               if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
-                       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
-                                GIC_MAP_TO_PIN_MSK | timer_intr);
-               if (cpu_has_veic) {
-                       set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
-                               gic_eic_irq_dispatch);
-                       gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK;
-               }
-
-               if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
-                       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
-                                GIC_MAP_TO_PIN_MSK | perf_intr);
-               if (cpu_has_veic) {
-                       set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch);
-                       gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK;
-               }
-       }
-}
-
-unsigned int gic_compare_int(void)
-{
-       unsigned int pending;
-
-       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
-       if (pending & GIC_VPE_PEND_CMP_MSK)
-               return 1;
-       else
-               return 0;
-}
-
-void gic_get_int_mask(unsigned long *dst, const unsigned long *src)
-{
-       unsigned int i;
-       unsigned long *pending, *intrmask, *pcpu_mask;
-       unsigned long *pending_abs, *intrmask_abs;
-
-       /* Get per-cpu bitmaps */
-       pending = pending_regs[smp_processor_id()].pending;
-       intrmask = intrmask_regs[smp_processor_id()].intrmask;
-       pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
-
-       pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
-                                                        GIC_SH_PEND_31_0_OFS);
-       intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
-                                                         GIC_SH_MASK_31_0_OFS);
-
-       for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) {
-               GICREAD(*pending_abs, pending[i]);
-               GICREAD(*intrmask_abs, intrmask[i]);
-               pending_abs++;
-               intrmask_abs++;
-       }
-
-       bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
-       bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
-       bitmap_and(dst, src, pending, GIC_NUM_INTRS);
-}
-
-unsigned int gic_get_int(void)
-{
-       DECLARE_BITMAP(interrupts, GIC_NUM_INTRS);
-
-       bitmap_fill(interrupts, GIC_NUM_INTRS);
-       gic_get_int_mask(interrupts, interrupts);
-
-       return find_first_bit(interrupts, GIC_NUM_INTRS);
-}
-
-static void gic_mask_irq(struct irq_data *d)
-{
-       GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
-}
-
-static void gic_unmask_irq(struct irq_data *d)
-{
-       GIC_SET_INTR_MASK(d->irq - gic_irq_base);
-}
-
-#ifdef CONFIG_SMP
-static DEFINE_SPINLOCK(gic_lock);
-
-static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
-                           bool force)
-{
-       unsigned int irq = (d->irq - gic_irq_base);
-       cpumask_t       tmp = CPU_MASK_NONE;
-       unsigned long   flags;
-       int             i;
-
-       cpumask_and(&tmp, cpumask, cpu_online_mask);
-       if (cpus_empty(tmp))
-               return -1;
-
-       /* Assumption : cpumask refers to a single CPU */
-       spin_lock_irqsave(&gic_lock, flags);
-
-       /* Re-route this IRQ */
-       GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
-
-       /* Update the pcpu_masks */
-       for (i = 0; i < NR_CPUS; i++)
-               clear_bit(irq, pcpu_masks[i].pcpu_mask);
-       set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
-
-       cpumask_copy(d->affinity, cpumask);
-       spin_unlock_irqrestore(&gic_lock, flags);
-
-       return IRQ_SET_MASK_OK_NOCOPY;
-}
-#endif
-
-static struct irq_chip gic_irq_controller = {
-       .name                   =       "MIPS GIC",
-       .irq_ack                =       gic_irq_ack,
-       .irq_mask               =       gic_mask_irq,
-       .irq_mask_ack           =       gic_mask_irq,
-       .irq_unmask             =       gic_unmask_irq,
-       .irq_eoi                =       gic_finish_irq,
-#ifdef CONFIG_SMP
-       .irq_set_affinity       =       gic_set_affinity,
-#endif
-};
-
-static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
-       unsigned int pin, unsigned int polarity, unsigned int trigtype,
-       unsigned int flags)
-{
-       struct gic_shared_intr_map *map_ptr;
-
-       /* Setup Intr to Pin mapping */
-       if (pin & GIC_MAP_TO_NMI_MSK) {
-               int i;
-
-               GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
-               /* FIXME: hack to route NMI to all cpu's */
-               for (i = 0; i < NR_CPUS; i += 32) {
-                       GICWRITE(GIC_REG_ADDR(SHARED,
-                                         GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)),
-                                0xffffffff);
-               }
-       } else {
-               GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
-                        GIC_MAP_TO_PIN_MSK | pin);
-               /* Setup Intr to CPU mapping */
-               GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
-               if (cpu_has_veic) {
-                       set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET,
-                               gic_eic_irq_dispatch);
-                       map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET];
-                       if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR)
-                               BUG();
-                       map_ptr->intr_list[map_ptr->num_shared_intr++] = intr;
-               }
-       }
-
-       /* Setup Intr Polarity */
-       GIC_SET_POLARITY(intr, polarity);
-
-       /* Setup Intr Trigger Type */
-       GIC_SET_TRIGGER(intr, trigtype);
-
-       /* Init Intr Masks */
-       GIC_CLR_INTR_MASK(intr);
-
-       /* Initialise per-cpu Interrupt software masks */
-       set_bit(intr, pcpu_masks[cpu].pcpu_mask);
-
-       if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0))
-               GIC_SET_INTR_MASK(intr);
-       if (trigtype == GIC_TRIG_EDGE)
-               gic_irq_flags[intr] |= GIC_TRIG_EDGE;
-}
-
-static void __init gic_basic_init(int numintrs, int numvpes,
-                       struct gic_intr_map *intrmap, int mapsize)
-{
-       unsigned int i, cpu;
-       unsigned int pin_offset = 0;
-
-       board_bind_eic_interrupt = &gic_bind_eic_interrupt;
-
-       /* Setup defaults */
-       for (i = 0; i < numintrs; i++) {
-               GIC_SET_POLARITY(i, GIC_POL_POS);
-               GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
-               GIC_CLR_INTR_MASK(i);
-               if (i < GIC_NUM_INTRS) {
-                       gic_irq_flags[i] = 0;
-                       gic_shared_intr_map[i].num_shared_intr = 0;
-                       gic_shared_intr_map[i].local_intr_mask = 0;
-               }
-       }
-
-       /*
-        * In EIC mode, the HW_INT# is offset by (2-1). Need to subtract
-        * one because the GIC will add one (since 0=no intr).
-        */
-       if (cpu_has_veic)
-               pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
-
-       /* Setup specifics */
-       for (i = 0; i < mapsize; i++) {
-               cpu = intrmap[i].cpunum;
-               if (cpu == GIC_UNUSED)
-                       continue;
-               gic_setup_intr(i,
-                       intrmap[i].cpunum,
-                       intrmap[i].pin + pin_offset,
-                       intrmap[i].polarity,
-                       intrmap[i].trigtype,
-                       intrmap[i].flags);
-       }
-
-       vpe_local_setup(numvpes);
-}
-
-void __init gic_init(unsigned long gic_base_addr,
-                    unsigned long gic_addrspace_size,
-                    struct gic_intr_map *intr_map, unsigned int intr_map_size,
-                    unsigned int irqbase)
-{
-       unsigned int gicconfig;
-       int numvpes, numintrs;
-
-       _gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
-                                                   gic_addrspace_size);
-       gic_irq_base = irqbase;
-
-       GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
-       numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
-                  GIC_SH_CONFIG_NUMINTRS_SHF;
-       numintrs = ((numintrs + 1) * 8);
-
-       numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
-                 GIC_SH_CONFIG_NUMVPES_SHF;
-       numvpes = numvpes + 1;
-
-       gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
-
-       gic_platform_init(numintrs, &gic_irq_controller);
-}
index 21f23add04f4f775f80a37223ceb8bd87d1b7ef2..d60475fe595700a9e1a0ad81dd380d81c4dd129b 100644 (file)
@@ -119,7 +119,7 @@ static void vsmp_send_ipi_single(int cpu, unsigned int action)
        unsigned long flags;
        int vpflags;
 
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
        if (gic_present) {
                gic_send_ipi_single(cpu, action);
                return;
@@ -158,7 +158,7 @@ static void vsmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
 
 static void vsmp_init_secondary(void)
 {
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
        /* This is Malta specific: IPI,performance and timer interrupts */
        if (gic_present)
                change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
index a4e035c8acf6543a9200ff90efd275856aaba36c..17cfc8a379a6ee17906233b101209d690b9bcf36 100644 (file)
@@ -70,7 +70,7 @@ static void __init estimate_frequencies(void)
 {
        unsigned long flags;
        unsigned int count, start;
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
        unsigned int giccount = 0, gicstart = 0;
 #endif
 
@@ -87,7 +87,7 @@ static void __init estimate_frequencies(void)
 
        /* Initialize counters. */
        start = read_c0_count();
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
        if (gic_present)
                GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart);
 #endif
@@ -97,7 +97,7 @@ static void __init estimate_frequencies(void)
        while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
 
        count = read_c0_count();
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
        if (gic_present)
                GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount);
 #endif
@@ -107,7 +107,7 @@ static void __init estimate_frequencies(void)
        count -= start;
        mips_hpt_frequency = count;
 
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
        if (gic_present) {
                giccount -= gicstart;
                gic_frequency = giccount;
@@ -189,7 +189,7 @@ void __init plat_time_init(void)
        setup_pit_timer();
 #endif
 
-#ifdef CONFIG_IRQ_GIC
+#ifdef CONFIG_MIPS_GIC
        if (gic_present) {
                freq = freqround(gic_frequency, 5000);
                printk("GIC frequency %d.%02d MHz\n", freq/1000000,
index b21f12f1766dea301c7b6749d0e77bc6bfaa3ebd..f2dde146bbdb49f2de339c663cf14e55ef40a0d4 100644 (file)
@@ -125,3 +125,7 @@ config KEYSTONE_IRQ
        help
                Support for Texas Instruments Keystone 2 IRQ controller IP which
                is part of the Keystone 2 IPC mechanism
+
+config MIPS_GIC
+       bool
+       select MIPS_CM
index 173bb5fa2cc945f6a5c60e7532754519b377ae17..021833079c911d80489911ff829eb2b419946b26 100644 (file)
@@ -38,3 +38,4 @@ obj-$(CONFIG_IRQ_CROSSBAR)            += irq-crossbar.o
 obj-$(CONFIG_BRCMSTB_L2_IRQ)           += irq-brcmstb-l2.o \
                                           irq-bcm7120-l2.o
 obj-$(CONFIG_KEYSTONE_IRQ)             += irq-keystone.o
+obj-$(CONFIG_MIPS_GIC)                 += irq-mips-gic.o
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
new file mode 100644 (file)
index 0000000..5828830
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
+ */
+#include <linux/bitmap.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <linux/clocksource.h>
+
+#include <asm/io.h>
+#include <asm/gic.h>
+#include <asm/setup.h>
+#include <asm/traps.h>
+#include <linux/hardirq.h>
+#include <asm-generic/bitops/find.h>
+
+unsigned int gic_frequency;
+unsigned int gic_present;
+unsigned long _gic_base;
+unsigned int gic_irq_base;
+unsigned int gic_irq_flags[GIC_NUM_INTRS];
+
+/* The index into this array is the vector # of the interrupt. */
+struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS];
+
+struct gic_pcpu_mask {
+       DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS);
+};
+
+struct gic_pending_regs {
+       DECLARE_BITMAP(pending, GIC_NUM_INTRS);
+};
+
+struct gic_intrmask_regs {
+       DECLARE_BITMAP(intrmask, GIC_NUM_INTRS);
+};
+
+static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
+static struct gic_pending_regs pending_regs[NR_CPUS];
+static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
+
+#if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
+cycle_t gic_read_count(void)
+{
+       unsigned int hi, hi2, lo;
+
+       do {
+               GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi);
+               GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo);
+               GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2);
+       } while (hi2 != hi);
+
+       return (((cycle_t) hi) << 32) + lo;
+}
+
+void gic_write_compare(cycle_t cnt)
+{
+       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI),
+                               (int)(cnt >> 32));
+       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO),
+                               (int)(cnt & 0xffffffff));
+}
+
+void gic_write_cpu_compare(cycle_t cnt, int cpu)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu);
+       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI),
+                               (int)(cnt >> 32));
+       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO),
+                               (int)(cnt & 0xffffffff));
+
+       local_irq_restore(flags);
+}
+
+cycle_t gic_read_compare(void)
+{
+       unsigned int hi, lo;
+
+       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), hi);
+       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), lo);
+
+       return (((cycle_t) hi) << 32) + lo;
+}
+#endif
+
+unsigned int gic_get_timer_pending(void)
+{
+       unsigned int vpe_pending;
+
+       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
+       GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending);
+       return vpe_pending & GIC_VPE_PEND_TIMER_MSK;
+}
+
+void gic_bind_eic_interrupt(int irq, int set)
+{
+       /* Convert irq vector # to hw int # */
+       irq -= GIC_PIN_TO_VEC_OFFSET;
+
+       /* Set irq to use shadow set */
+       GICWRITE(GIC_REG_ADDR(VPE_LOCAL, GIC_VPE_EIC_SS(irq)), set);
+}
+
+void gic_send_ipi(unsigned int intr)
+{
+       GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
+}
+
+static void gic_eic_irq_dispatch(void)
+{
+       unsigned int cause = read_c0_cause();
+       int irq;
+
+       irq = (cause & ST0_IM) >> STATUSB_IP2;
+       if (irq == 0)
+               irq = -1;
+
+       if (irq >= 0)
+               do_IRQ(gic_irq_base + irq);
+       else
+               spurious_interrupt();
+}
+
+static void __init vpe_local_setup(unsigned int numvpes)
+{
+       unsigned long timer_intr = GIC_INT_TMR;
+       unsigned long perf_intr = GIC_INT_PERFCTR;
+       unsigned int vpe_ctl;
+       int i;
+
+       if (cpu_has_veic) {
+               /*
+                * GIC timer interrupt -> CPU HW Int X (vector X+2) ->
+                * map to pin X+2-1 (since GIC adds 1)
+                */
+               timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
+               /*
+                * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) ->
+                * map to pin X+2-1 (since GIC adds 1)
+                */
+               perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
+       }
+
+       /*
+        * Setup the default performance counter timer interrupts
+        * for all VPEs
+        */
+       for (i = 0; i < numvpes; i++) {
+               GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
+
+               /* Are Interrupts locally routable? */
+               GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
+               if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
+                       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
+                                GIC_MAP_TO_PIN_MSK | timer_intr);
+               if (cpu_has_veic) {
+                       set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
+                               gic_eic_irq_dispatch);
+                       gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK;
+               }
+
+               if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
+                       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
+                                GIC_MAP_TO_PIN_MSK | perf_intr);
+               if (cpu_has_veic) {
+                       set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch);
+                       gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK;
+               }
+       }
+}
+
+unsigned int gic_compare_int(void)
+{
+       unsigned int pending;
+
+       GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
+       if (pending & GIC_VPE_PEND_CMP_MSK)
+               return 1;
+       else
+               return 0;
+}
+
+void gic_get_int_mask(unsigned long *dst, const unsigned long *src)
+{
+       unsigned int i;
+       unsigned long *pending, *intrmask, *pcpu_mask;
+       unsigned long *pending_abs, *intrmask_abs;
+
+       /* Get per-cpu bitmaps */
+       pending = pending_regs[smp_processor_id()].pending;
+       intrmask = intrmask_regs[smp_processor_id()].intrmask;
+       pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
+
+       pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
+                                                        GIC_SH_PEND_31_0_OFS);
+       intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
+                                                         GIC_SH_MASK_31_0_OFS);
+
+       for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) {
+               GICREAD(*pending_abs, pending[i]);
+               GICREAD(*intrmask_abs, intrmask[i]);
+               pending_abs++;
+               intrmask_abs++;
+       }
+
+       bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
+       bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
+       bitmap_and(dst, src, pending, GIC_NUM_INTRS);
+}
+
+unsigned int gic_get_int(void)
+{
+       DECLARE_BITMAP(interrupts, GIC_NUM_INTRS);
+
+       bitmap_fill(interrupts, GIC_NUM_INTRS);
+       gic_get_int_mask(interrupts, interrupts);
+
+       return find_first_bit(interrupts, GIC_NUM_INTRS);
+}
+
+static void gic_mask_irq(struct irq_data *d)
+{
+       GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
+}
+
+static void gic_unmask_irq(struct irq_data *d)
+{
+       GIC_SET_INTR_MASK(d->irq - gic_irq_base);
+}
+
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(gic_lock);
+
+static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
+                           bool force)
+{
+       unsigned int irq = (d->irq - gic_irq_base);
+       cpumask_t       tmp = CPU_MASK_NONE;
+       unsigned long   flags;
+       int             i;
+
+       cpumask_and(&tmp, cpumask, cpu_online_mask);
+       if (cpus_empty(tmp))
+               return -1;
+
+       /* Assumption : cpumask refers to a single CPU */
+       spin_lock_irqsave(&gic_lock, flags);
+
+       /* Re-route this IRQ */
+       GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
+
+       /* Update the pcpu_masks */
+       for (i = 0; i < NR_CPUS; i++)
+               clear_bit(irq, pcpu_masks[i].pcpu_mask);
+       set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
+
+       cpumask_copy(d->affinity, cpumask);
+       spin_unlock_irqrestore(&gic_lock, flags);
+
+       return IRQ_SET_MASK_OK_NOCOPY;
+}
+#endif
+
+static struct irq_chip gic_irq_controller = {
+       .name                   =       "MIPS GIC",
+       .irq_ack                =       gic_irq_ack,
+       .irq_mask               =       gic_mask_irq,
+       .irq_mask_ack           =       gic_mask_irq,
+       .irq_unmask             =       gic_unmask_irq,
+       .irq_eoi                =       gic_finish_irq,
+#ifdef CONFIG_SMP
+       .irq_set_affinity       =       gic_set_affinity,
+#endif
+};
+
+static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
+       unsigned int pin, unsigned int polarity, unsigned int trigtype,
+       unsigned int flags)
+{
+       struct gic_shared_intr_map *map_ptr;
+
+       /* Setup Intr to Pin mapping */
+       if (pin & GIC_MAP_TO_NMI_MSK) {
+               int i;
+
+               GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
+               /* FIXME: hack to route NMI to all cpu's */
+               for (i = 0; i < NR_CPUS; i += 32) {
+                       GICWRITE(GIC_REG_ADDR(SHARED,
+                                         GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)),
+                                0xffffffff);
+               }
+       } else {
+               GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
+                        GIC_MAP_TO_PIN_MSK | pin);
+               /* Setup Intr to CPU mapping */
+               GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
+               if (cpu_has_veic) {
+                       set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET,
+                               gic_eic_irq_dispatch);
+                       map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET];
+                       if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR)
+                               BUG();
+                       map_ptr->intr_list[map_ptr->num_shared_intr++] = intr;
+               }
+       }
+
+       /* Setup Intr Polarity */
+       GIC_SET_POLARITY(intr, polarity);
+
+       /* Setup Intr Trigger Type */
+       GIC_SET_TRIGGER(intr, trigtype);
+
+       /* Init Intr Masks */
+       GIC_CLR_INTR_MASK(intr);
+
+       /* Initialise per-cpu Interrupt software masks */
+       set_bit(intr, pcpu_masks[cpu].pcpu_mask);
+
+       if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0))
+               GIC_SET_INTR_MASK(intr);
+       if (trigtype == GIC_TRIG_EDGE)
+               gic_irq_flags[intr] |= GIC_TRIG_EDGE;
+}
+
+static void __init gic_basic_init(int numintrs, int numvpes,
+                       struct gic_intr_map *intrmap, int mapsize)
+{
+       unsigned int i, cpu;
+       unsigned int pin_offset = 0;
+
+       board_bind_eic_interrupt = &gic_bind_eic_interrupt;
+
+       /* Setup defaults */
+       for (i = 0; i < numintrs; i++) {
+               GIC_SET_POLARITY(i, GIC_POL_POS);
+               GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
+               GIC_CLR_INTR_MASK(i);
+               if (i < GIC_NUM_INTRS) {
+                       gic_irq_flags[i] = 0;
+                       gic_shared_intr_map[i].num_shared_intr = 0;
+                       gic_shared_intr_map[i].local_intr_mask = 0;
+               }
+       }
+
+       /*
+        * In EIC mode, the HW_INT# is offset by (2-1). Need to subtract
+        * one because the GIC will add one (since 0=no intr).
+        */
+       if (cpu_has_veic)
+               pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
+
+       /* Setup specifics */
+       for (i = 0; i < mapsize; i++) {
+               cpu = intrmap[i].cpunum;
+               if (cpu == GIC_UNUSED)
+                       continue;
+               gic_setup_intr(i,
+                       intrmap[i].cpunum,
+                       intrmap[i].pin + pin_offset,
+                       intrmap[i].polarity,
+                       intrmap[i].trigtype,
+                       intrmap[i].flags);
+       }
+
+       vpe_local_setup(numvpes);
+}
+
+void __init gic_init(unsigned long gic_base_addr,
+                    unsigned long gic_addrspace_size,
+                    struct gic_intr_map *intr_map, unsigned int intr_map_size,
+                    unsigned int irqbase)
+{
+       unsigned int gicconfig;
+       int numvpes, numintrs;
+
+       _gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
+                                                   gic_addrspace_size);
+       gic_irq_base = irqbase;
+
+       GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
+       numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
+                  GIC_SH_CONFIG_NUMINTRS_SHF;
+       numintrs = ((numintrs + 1) * 8);
+
+       numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
+                 GIC_SH_CONFIG_NUMVPES_SHF;
+       numvpes = numvpes + 1;
+
+       gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
+
+       gic_platform_init(numintrs, &gic_irq_controller);
+}