linux/arch/mips/mti-malta/malta-int.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Carsten Langgaard, carstenl@mips.com
   7 * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
   8 * Copyright (C) 2001 Ralf Baechle
   9 * Copyright (C) 2013 Imagination Technologies Ltd.
  10 *
  11 * Routines for generic manipulation of the interrupts found on the MIPS
  12 * Malta board. The interrupt controller is located in the South Bridge
  13 * a PIIX4 device with two internal 82C95 interrupt controllers.
  14 */
  15#include <linux/init.h>
  16#include <linux/irq.h>
  17#include <linux/irqchip.h>
  18#include <linux/sched.h>
  19#include <linux/smp.h>
  20#include <linux/interrupt.h>
  21#include <linux/io.h>
  22#include <linux/of_irq.h>
  23#include <linux/kernel_stat.h>
  24#include <linux/kernel.h>
  25#include <linux/random.h>
  26
  27#include <asm/traps.h>
  28#include <asm/i8259.h>
  29#include <asm/irq_cpu.h>
  30#include <asm/irq_regs.h>
  31#include <asm/mips-boards/malta.h>
  32#include <asm/mips-boards/maltaint.h>
  33#include <asm/mips-cps.h>
  34#include <asm/gt64120.h>
  35#include <asm/mips-boards/generic.h>
  36#include <asm/mips-boards/msc01_pci.h>
  37#include <asm/msc01_ic.h>
  38#include <asm/setup.h>
  39#include <asm/rtlx.h>
  40
  41static inline int mips_pcibios_iack(void)
  42{
  43        int irq;
  44
  45        /*
  46         * Determine highest priority pending interrupt by performing
  47         * a PCI Interrupt Acknowledge cycle.
  48         */
  49        switch (mips_revision_sconid) {
  50        case MIPS_REVISION_SCON_SOCIT:
  51        case MIPS_REVISION_SCON_ROCIT:
  52        case MIPS_REVISION_SCON_SOCITSC:
  53        case MIPS_REVISION_SCON_SOCITSCP:
  54                MSC_READ(MSC01_PCI_IACK, irq);
  55                irq &= 0xff;
  56                break;
  57        case MIPS_REVISION_SCON_GT64120:
  58                irq = GT_READ(GT_PCI0_IACK_OFS);
  59                irq &= 0xff;
  60                break;
  61        case MIPS_REVISION_SCON_BONITO:
  62                /* The following will generate a PCI IACK cycle on the
  63                 * Bonito controller. It's a little bit kludgy, but it
  64                 * was the easiest way to implement it in hardware at
  65                 * the given time.
  66                 */
  67                BONITO_PCIMAP_CFG = 0x20000;
  68
  69                /* Flush Bonito register block */
  70                (void) BONITO_PCIMAP_CFG;
  71                iob();    /* sync */
  72
  73                irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg);
  74                iob();    /* sync */
  75                irq &= 0xff;
  76                BONITO_PCIMAP_CFG = 0;
  77                break;
  78        default:
  79                pr_emerg("Unknown system controller.\n");
  80                return -1;
  81        }
  82        return irq;
  83}
  84
  85static void corehi_irqdispatch(void)
  86{
  87        unsigned int intedge, intsteer, pcicmd, pcibadaddr;
  88        unsigned int pcimstat, intisr, inten, intpol;
  89        unsigned int intrcause, datalo, datahi;
  90        struct pt_regs *regs = get_irq_regs();
  91
  92        pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n");
  93        pr_emerg("epc    : %08lx\nStatus: %08lx\n"
  94                 "Cause : %08lx\nbadVaddr : %08lx\n",
  95                 regs->cp0_epc, regs->cp0_status,
  96                 regs->cp0_cause, regs->cp0_badvaddr);
  97
  98        /* Read all the registers and then print them as there is a
  99           problem with interspersed printk's upsetting the Bonito controller.
 100           Do it for the others too.
 101        */
 102
 103        switch (mips_revision_sconid) {
 104        case MIPS_REVISION_SCON_SOCIT:
 105        case MIPS_REVISION_SCON_ROCIT:
 106        case MIPS_REVISION_SCON_SOCITSC:
 107        case MIPS_REVISION_SCON_SOCITSCP:
 108                ll_msc_irq();
 109                break;
 110        case MIPS_REVISION_SCON_GT64120:
 111                intrcause = GT_READ(GT_INTRCAUSE_OFS);
 112                datalo = GT_READ(GT_CPUERR_ADDRLO_OFS);
 113                datahi = GT_READ(GT_CPUERR_ADDRHI_OFS);
 114                pr_emerg("GT_INTRCAUSE = %08x\n", intrcause);
 115                pr_emerg("GT_CPUERR_ADDR = %02x%08x\n",
 116                                datahi, datalo);
 117                break;
 118        case MIPS_REVISION_SCON_BONITO:
 119                pcibadaddr = BONITO_PCIBADADDR;
 120                pcimstat = BONITO_PCIMSTAT;
 121                intisr = BONITO_INTISR;
 122                inten = BONITO_INTEN;
 123                intpol = BONITO_INTPOL;
 124                intedge = BONITO_INTEDGE;
 125                intsteer = BONITO_INTSTEER;
 126                pcicmd = BONITO_PCICMD;
 127                pr_emerg("BONITO_INTISR = %08x\n", intisr);
 128                pr_emerg("BONITO_INTEN = %08x\n", inten);
 129                pr_emerg("BONITO_INTPOL = %08x\n", intpol);
 130                pr_emerg("BONITO_INTEDGE = %08x\n", intedge);
 131                pr_emerg("BONITO_INTSTEER = %08x\n", intsteer);
 132                pr_emerg("BONITO_PCICMD = %08x\n", pcicmd);
 133                pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr);
 134                pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat);
 135                break;
 136        }
 137
 138        die("CoreHi interrupt", regs);
 139}
 140
 141static irqreturn_t corehi_handler(int irq, void *dev_id)
 142{
 143        corehi_irqdispatch();
 144        return IRQ_HANDLED;
 145}
 146
 147static struct irqaction corehi_irqaction = {
 148        .handler = corehi_handler,
 149        .name = "CoreHi",
 150        .flags = IRQF_NO_THREAD,
 151};
 152
 153static msc_irqmap_t msc_irqmap[] __initdata = {
 154        {MSC01C_INT_TMR,                MSC01_IRQ_EDGE, 0},
 155        {MSC01C_INT_PCI,                MSC01_IRQ_LEVEL, 0},
 156};
 157static int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap);
 158
 159static msc_irqmap_t msc_eicirqmap[] __initdata = {
 160        {MSC01E_INT_SW0,                MSC01_IRQ_LEVEL, 0},
 161        {MSC01E_INT_SW1,                MSC01_IRQ_LEVEL, 0},
 162        {MSC01E_INT_I8259A,             MSC01_IRQ_LEVEL, 0},
 163        {MSC01E_INT_SMI,                MSC01_IRQ_LEVEL, 0},
 164        {MSC01E_INT_COREHI,             MSC01_IRQ_LEVEL, 0},
 165        {MSC01E_INT_CORELO,             MSC01_IRQ_LEVEL, 0},
 166        {MSC01E_INT_TMR,                MSC01_IRQ_EDGE, 0},
 167        {MSC01E_INT_PCI,                MSC01_IRQ_LEVEL, 0},
 168        {MSC01E_INT_PERFCTR,            MSC01_IRQ_LEVEL, 0},
 169        {MSC01E_INT_CPUCTR,             MSC01_IRQ_LEVEL, 0}
 170};
 171
 172static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap);
 173
 174void __init arch_init_irq(void)
 175{
 176        int corehi_irq;
 177
 178        /*
 179         * Preallocate the i8259's expected virq's here. Since irqchip_init()
 180         * will probe the irqchips in hierarchial order, i8259 is probed last.
 181         * If anything allocates a virq before the i8259 is probed, it will
 182         * be given one of the i8259's expected range and consequently setup
 183         * of the i8259 will fail.
 184         */
 185        WARN(irq_alloc_descs(I8259A_IRQ_BASE, I8259A_IRQ_BASE,
 186                            16, numa_node_id()) < 0,
 187                "Cannot reserve i8259 virqs at IRQ%d\n", I8259A_IRQ_BASE);
 188
 189        i8259_set_poll(mips_pcibios_iack);
 190        irqchip_init();
 191
 192        switch (mips_revision_sconid) {
 193        case MIPS_REVISION_SCON_SOCIT:
 194        case MIPS_REVISION_SCON_ROCIT:
 195                if (cpu_has_veic)
 196                        init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
 197                                        MSC01E_INT_BASE, msc_eicirqmap,
 198                                        msc_nr_eicirqs);
 199                else
 200                        init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
 201                                        MSC01C_INT_BASE, msc_irqmap,
 202                                        msc_nr_irqs);
 203                break;
 204
 205        case MIPS_REVISION_SCON_SOCITSC:
 206        case MIPS_REVISION_SCON_SOCITSCP:
 207                if (cpu_has_veic)
 208                        init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
 209                                        MSC01E_INT_BASE, msc_eicirqmap,
 210                                        msc_nr_eicirqs);
 211                else
 212                        init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
 213                                        MSC01C_INT_BASE, msc_irqmap,
 214                                        msc_nr_irqs);
 215        }
 216
 217        if (mips_gic_present()) {
 218                corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
 219        } else if (cpu_has_veic) {
 220                set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch);
 221                corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI;
 222        } else {
 223                corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
 224        }
 225
 226        setup_irq(corehi_irq, &corehi_irqaction);
 227}
 228