cvmx-interrupt.c revision 232812
11556Srgrimes/***********************license start***************
21556Srgrimes * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
31556Srgrimes * reserved.
41556Srgrimes *
51556Srgrimes *
61556Srgrimes * Redistribution and use in source and binary forms, with or without
71556Srgrimes * modification, are permitted provided that the following conditions are
81556Srgrimes * met:
91556Srgrimes *
101556Srgrimes *   * Redistributions of source code must retain the above copyright
111556Srgrimes *     notice, this list of conditions and the following disclaimer.
121556Srgrimes *
131556Srgrimes *   * Redistributions in binary form must reproduce the above
141556Srgrimes *     copyright notice, this list of conditions and the following
151556Srgrimes *     disclaimer in the documentation and/or other materials provided
161556Srgrimes *     with the distribution.
171556Srgrimes
181556Srgrimes *   * Neither the name of Cavium Inc. nor the names of
191556Srgrimes *     its contributors may be used to endorse or promote products
201556Srgrimes *     derived from this software without specific prior written
211556Srgrimes *     permission.
221556Srgrimes
231556Srgrimes * This Software, including technical data, may be subject to U.S. export  control
241556Srgrimes * laws, including the U.S. Export Administration Act and its  associated
251556Srgrimes * regulations, and may be subject to export or import  regulations in other
261556Srgrimes * countries.
271556Srgrimes
28127499Sgad * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29127499Sgad * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30127499Sgad * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31127499Sgad * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32127499Sgad * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33127499Sgad * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34127499Sgad * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
351556Srgrimes * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
361556Srgrimes * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
371556Srgrimes * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
3890143Smarkm ***********************license end**************************************/
391556Srgrimes
401556Srgrimes/**
411556Srgrimes * @file
421556Srgrimes *
4390143Smarkm * Interface to the Mips interrupts.
441556Srgrimes *
4536049Scharnier * <hr>$Revision: 70030 $<hr>
4690143Smarkm */
4736049Scharnier#ifndef __U_BOOT__
48110391Scharnier#if __GNUC__ >= 4
4999110Sobrien/* Backtrace is only available with the new toolchain.  */
5099110Sobrien#include <execinfo.h>
511556Srgrimes#endif
521556Srgrimes#endif  /* __U_BOOT__ */
53127546Sgad#include "cvmx-config.h"
543296Sdg#include "cvmx.h"
551556Srgrimes#include "cvmx-interrupt.h"
561556Srgrimes#include "cvmx-sysinfo.h"
571556Srgrimes#include "cvmx-uart.h"
58137696Scsjp#include "cvmx-pow.h"
591556Srgrimes#include "cvmx-ebt3000.h"
601556Srgrimes#include "cvmx-coremask.h"
611556Srgrimes#include "cvmx-spinlock.h"
62127149Sgad#include "cvmx-atomic.h"
631556Srgrimes#include "cvmx-app-init.h"
64127499Sgad#include "cvmx-error.h"
651556Srgrimes#include "cvmx-app-hotplug.h"
6613514Smpp#include "cvmx-profiler.h"
6773367Sache#ifndef __U_BOOT__
681556Srgrimes# include <octeon_mem_map.h>
6990143Smarkm#else
701556Srgrimes# include <asm/arch/octeon_mem_map.h>
711556Srgrimes#endif
721556SrgrimesEXTERN_ASM void cvmx_interrupt_stage1(void);
731556SrgrimesEXTERN_ASM void cvmx_debug_handler_stage1(void);
741556SrgrimesEXTERN_ASM void cvmx_interrupt_cache_error(void);
751556Srgrimes
761556Srgrimesint cvmx_interrupt_in_isr = 0;
77127499Sgad
78127499Sgadstruct __cvmx_interrupt_handler {
7966377Sbrian    cvmx_interrupt_func_t handler;      /**< One function to call per interrupt */
80127537Sgad    void *data;                         /**< User data per interrupt */
81127555Sgad    int handler_data;                   /**< Used internally */
82127537Sgad};
83127537Sgad
84127555Sgad/**
85127537Sgad * Internal status the interrupt registration
86127537Sgad */
87127537Sgadtypedef struct
88129914Sgad{
89129971Sgad    struct __cvmx_interrupt_handler handlers[CVMX_IRQ_MAX];
90129971Sgad    cvmx_interrupt_exception_t exception_handler;
91129914Sgad} cvmx_interrupt_state_t;
92129971Sgad
93129914Sgad/**
94127537Sgad * Internal state the interrupt registration
95127537Sgad */
96127537Sgad#ifndef __U_BOOT__
97127537Sgadstatic CVMX_SHARED cvmx_interrupt_state_t cvmx_interrupt_state;
98127537Sgadstatic CVMX_SHARED cvmx_spinlock_t cvmx_interrupt_default_lock;
99127537Sgad/* Incremented once first core processing is finished. */
100127537Sgadstatic CVMX_SHARED int32_t cvmx_interrupt_initialize_flag;
101127537Sgad#endif  /* __U_BOOT__ */
102130999Sgad
1031556Srgrimes#define ULL unsigned long long
104127537Sgad
105127537Sgad#define HI32(data64)    ((uint32_t)(data64 >> 32))
106127537Sgad#define LO32(data64)    ((uint32_t)(data64 & 0xFFFFFFFF))
107127537Sgad
108127537Sgadstatic const char reg_names[][32] = { "r0","at","v0","v1","a0","a1","a2","a3",
109127537Sgad                                      "t0","t1","t2","t3","t4","t5","t6","t7",
110127537Sgad                                      "s0","s1","s2","s3","s4","s5", "s6","s7",
1111556Srgrimes                                      "t8","t9", "k0","k1","gp","sp","s8","ra" };
112127537Sgad
11397966Sjmallett/**
114127499Sgad * version of printf that works better in exception context.
115127537Sgad *
116127499Sgad * @param format
117127499Sgad */
118127499Sgadvoid cvmx_safe_printf(const char *format, ...)
119127499Sgad{
120127499Sgad    char buffer[256];
121127499Sgad    char *ptr = buffer;
122127499Sgad    int count;
123127499Sgad    va_list args;
124127499Sgad
125127499Sgad    va_start(args, format);
126127499Sgad#ifndef __U_BOOT__
127127499Sgad    count = vsnprintf(buffer, sizeof(buffer), format, args);
128127499Sgad#else
129127823Sgad    count = vsprintf(buffer, format, args);
130127499Sgad#endif
131127499Sgad    va_end(args);
132137696Scsjp
133127499Sgad    while (count-- > 0)
134127499Sgad    {
135127499Sgad        cvmx_uart_lsr_t lsrval;
136127499Sgad
137127499Sgad        /* Spin until there is room */
138127536Sgad        do
139127499Sgad        {
140127598Sgad            lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0));
141127598Sgad#if !defined(CONFIG_OCTEON_SIM_SPEED)
142127536Sgad            if (lsrval.s.temt == 0)
143127499Sgad                cvmx_wait(10000);   /* Just to reduce the load on the system */
144127499Sgad#endif
145129952Sgad        }
146127536Sgad        while (lsrval.s.temt == 0);
147127536Sgad
148127536Sgad        if (*ptr == '\n')
149127536Sgad            cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r');
150127536Sgad        cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++);
151127499Sgad    }
15297875Sjmallett}
153129635Sgad
154127538Sgad/* Textual descriptions of cause codes */
155127538Sgadstatic const char cause_names[][128] = {
15690143Smarkm        /*  0 */ "Interrupt",
15797875Sjmallett        /*  1 */ "TLB modification",
15897875Sjmallett        /*  2 */ "tlb load/fetch",
159127538Sgad        /*  3 */ "tlb store",
160127538Sgad        /*  4 */ "address exc, load/fetch",
161105831Srwatson        /*  5 */ "address exc, store",
1621556Srgrimes        /*  6 */ "bus error, instruction fetch",
163127843Sgad        /*  7 */ "bus error, load/store",
16498494Ssobomax        /*  8 */ "syscall",
1651556Srgrimes        /*  9 */ "breakpoint",
16690110Simp        /* 10 */ "reserved instruction",
1671556Srgrimes        /* 11 */ "cop unusable",
168127499Sgad        /* 12 */ "arithmetic overflow",
169127499Sgad        /* 13 */ "trap",
1701556Srgrimes        /* 14 */ "",
171130816Sgad        /* 15 */ "floating point exc",
1721556Srgrimes        /* 16 */ "",
1731556Srgrimes        /* 17 */ "",
174129914Sgad        /* 18 */ "cop2 exception",
175127539Sgad        /* 19 */ "",
176137670Sru        /* 20 */ "",
177129914Sgad        /* 21 */ "",
178127499Sgad        /* 22 */ "mdmx unusable",
17990143Smarkm        /* 23 */ "watch",
1801556Srgrimes        /* 24 */ "machine check",
18111809Sache        /* 25 */ "",
182127542Sgad        /* 26 */ "",
18311809Sache        /* 27 */ "",
18497804Stjr        /* 28 */ "",
18597804Stjr        /* 29 */ "",
18697804Stjr        /* 30 */ "cache error",
1871556Srgrimes        /* 31 */ ""
1881556Srgrimes};
1891556Srgrimes
1901556Srgrimes/**
1911556Srgrimes * @INTERNAL
1921556Srgrimes * print_reg64
1931556Srgrimes * @param name   Name of the value to print
19498494Ssobomax * @param reg    Value to print
195129914Sgad */
196129914Sgadstatic inline void print_reg64(const char *name, uint64_t reg)
19798494Ssobomax{
198129914Sgad    cvmx_safe_printf("%16s: 0x%08x%08x\n", name, (unsigned int)HI32(reg),(unsigned int)LO32(reg));
199129915Sgad}
2001556Srgrimes
201137670Sru/**
202127542Sgad * @INTERNAL
203127542Sgad * Dump all useful registers to the console
204127499Sgad *
205127499Sgad * @param registers CPU register to dump
206127499Sgad */
207127499Sgadstatic void __cvmx_interrupt_dump_registers(uint64_t *registers)
208127499Sgad{
209127499Sgad    uint64_t r1, r2;
210127499Sgad    int reg;
21189909Sru    for (reg=0; reg<16; reg++)
21298494Ssobomax    {
213129967Sgad        r1 = registers[reg]; r2 = registers[reg+16];
214127499Sgad        cvmx_safe_printf("%3s ($%02d): 0x%08x%08x \t %3s ($%02d): 0x%08x%08x\n",
215127499Sgad                           reg_names[reg], reg, (unsigned int)HI32(r1), (unsigned int)LO32(r1),
216127499Sgad                           reg_names[reg+16], reg+16, (unsigned int)HI32(r2), (unsigned int)LO32(r2));
217127499Sgad    }
218127499Sgad    CVMX_MF_COP0 (r1, COP0_CAUSE);
219127499Sgad    print_reg64 ("COP0_CAUSE", r1);
220127499Sgad    CVMX_MF_COP0 (r2, COP0_STATUS);
221127499Sgad    print_reg64 ("COP0_STATUS", r2);
222127499Sgad    CVMX_MF_COP0 (r1, COP0_BADVADDR);
2231556Srgrimes    print_reg64 ("COP0_BADVADDR", r1);
224127499Sgad    CVMX_MF_COP0 (r2, COP0_EPC);
2251556Srgrimes    print_reg64 ("COP0_EPC", r2);
2261556Srgrimes}
22719068Speter
22819068Speter/**
22919068Speter * @INTERNAL
23019068Speter * Default exception handler. Prints out the exception
23119068Speter * cause decode and all relevant registers.
23219068Speter *
2331556Srgrimes * @param registers Registers at time of the exception
2341556Srgrimes */
2351556Srgrimes#ifndef __U_BOOT__
236127506Sgadstatic
237127506Sgad#endif  /* __U_BOOT__ */
238127506Sgadvoid __cvmx_interrupt_default_exception_handler(uint64_t *registers)
239127542Sgad{
240127506Sgad    uint64_t trap_print_cause;
241127506Sgad    const char *str;
242127499Sgad#ifndef __U_BOOT__
243127499Sgad    int modified_zero_pc = 0;
244127499Sgad
245127499Sgad    ebt3000_str_write("Trap");
246127499Sgad    cvmx_spinlock_lock(&cvmx_interrupt_default_lock);
247127542Sgad#endif
248127499Sgad    CVMX_MF_COP0 (trap_print_cause, COP0_CAUSE);
249127597Sgad    str = cause_names [(trap_print_cause >> 2) & 0x1f];
250127542Sgad    cvmx_safe_printf("Core %d: Unhandled Exception. Cause register decodes to:\n%s\n", (int)cvmx_get_core_num(), str && *str ? str : "Reserved exception cause");
251127542Sgad    cvmx_safe_printf("******************************************************************\n");
252127542Sgad    __cvmx_interrupt_dump_registers(registers);
253127542Sgad
254127499Sgad#ifndef __U_BOOT__
255127499Sgad
256127499Sgad    cvmx_safe_printf("******************************************************************\n");
257127499Sgad#if __GNUC__ >= 4 && !defined(OCTEON_DISABLE_BACKTRACE)
258127499Sgad    cvmx_safe_printf("Backtrace:\n\n");
259127542Sgad    if (registers[35] == 0) {
2601556Srgrimes	modified_zero_pc = 1;
261127499Sgad	/* If PC is zero we probably did jalr $zero, in which case $31 - 8 is the call site. */
262116265Sscottl	registers[35] = registers[31] - 8;
263126127Sdeischen    }
264116265Sscottl    __octeon_print_backtrace_func ((__octeon_backtrace_printf_t)cvmx_safe_printf);
2651556Srgrimes    if (modified_zero_pc)
2661556Srgrimes	registers[35] = 0;
2671556Srgrimes    cvmx_safe_printf("******************************************************************\n");
2681556Srgrimes#endif
269109502Sjmallett
27090143Smarkm    cvmx_spinlock_unlock(&cvmx_interrupt_default_lock);
2711556Srgrimes
2721556Srgrimes    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
2731556Srgrimes        CVMX_BREAK;
2741556Srgrimes
2751556Srgrimes    while (1)
2761556Srgrimes    {
277109502Sjmallett        /* Interrupts are suppressed when we are in the exception
27890143Smarkm           handler (because of SR[EXL]).  Spin and poll the uart
2791556Srgrimes           status and see if the debugger is trying to stop us. */
2801556Srgrimes        cvmx_uart_lsr_t lsrval;
2811556Srgrimes        lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(cvmx_debug_uart));
2821556Srgrimes        if (lsrval.s.dr)
2831556Srgrimes        {
2841556Srgrimes            uint64_t tmp;
2851556Srgrimes            /* Pulse the MCD0 signal. */
2861556Srgrimes            asm volatile (
2871556Srgrimes            ".set push\n"
2881556Srgrimes            ".set noreorder\n"
2891556Srgrimes            ".set mips64\n"
2901556Srgrimes            "dmfc0 %0, $22\n"
291109502Sjmallett            "ori   %0, %0, 0x10\n"
292109502Sjmallett            "dmtc0 %0, $22\n"
293109502Sjmallett            ".set pop\n"
2941556Srgrimes            : "=r" (tmp));
29590143Smarkm        }
2961556Srgrimes    }
2971556Srgrimes#endif /* __U_BOOT__ */
298109502Sjmallett}
29990143Smarkm
3001556Srgrimes#ifndef __U_BOOT__
3011556Srgrimes/**
302127499Sgad * @INTERNAL
303127499Sgad * Default interrupt handler if the user doesn't register one.
304127499Sgad *
305127499Sgad * @param irq_number IRQ that caused this interrupt
306127499Sgad * @param registers  Register at the time of the interrupt
307127499Sgad * @param user_arg   Unused optional user data
308127499Sgad */
309127499Sgadstatic void __cvmx_interrupt_default(int irq_number, uint64_t *registers, void *user_arg)
3101556Srgrimes{
311127499Sgad    cvmx_safe_printf("cvmx_interrupt_default: Received interrupt %d\n", irq_number);
312127499Sgad    __cvmx_interrupt_dump_registers(registers);
313127597Sgad}
314127542Sgad
315127542Sgad/**
316127542Sgad * Map a ciu bit to an irq number.  0xff for invalid.
317127542Sgad * 0-63 for en0.
318127542Sgad * 64-127 for en1.
319127542Sgad */
320127499Sgad
321127499Sgadstatic CVMX_SHARED uint8_t cvmx_ciu_to_irq[8][64];
322127499Sgad#define cvmx_ciu_en0_to_irq cvmx_ciu_to_irq[0]
323127499Sgad#define cvmx_ciu_en1_to_irq cvmx_ciu_to_irq[1]
324127499Sgad#define cvmx_ciu2_wrkq_to_irq cvmx_ciu_to_irq[0]
3251556Srgrimes#define cvmx_ciu2_wdog_to_irq cvmx_ciu_to_irq[1]
3261556Srgrimes#define cvmx_ciu2_rml_to_irq cvmx_ciu_to_irq[2]
3271556Srgrimes#define cvmx_ciu2_mio_to_irq cvmx_ciu_to_irq[3]
3281556Srgrimes#define cvmx_ciu2_io_to_irq cvmx_ciu_to_irq[4]
3291556Srgrimes#define cvmx_ciu2_mem_to_irq cvmx_ciu_to_irq[5]
3301556Srgrimes#define cvmx_ciu2_eth_to_irq cvmx_ciu_to_irq[6]
331127499Sgad#define cvmx_ciu2_gpio_to_irq cvmx_ciu_to_irq[7]
332127499Sgad
333127597Sgadstatic CVMX_SHARED uint8_t cvmx_ciu2_mbox_to_irq[64];
334127542Sgadstatic CVMX_SHARED uint8_t cvmx_ciu_61xx_timer_to_irq[64];
335127542Sgad
336127542Sgadstatic void __cvmx_interrupt_set_mapping(int irq, unsigned int en, unsigned int bit)
337127542Sgad{
338127542Sgad    cvmx_interrupt_state.handlers[irq].handler_data = (en << 6) | bit;
339127499Sgad    if (en <= 7)
340127499Sgad        cvmx_ciu_to_irq[en][bit] = irq;
341127499Sgad    else if (en == 8)
342127499Sgad        cvmx_ciu_61xx_timer_to_irq[bit] = irq;
343127499Sgad    else
3441556Srgrimes        cvmx_ciu2_mbox_to_irq[bit] = irq;
3451556Srgrimes}
3461556Srgrimes
3471556Srgrimesstatic uint64_t cvmx_interrupt_ciu_en0_mirror;
348127499Sgadstatic uint64_t cvmx_interrupt_ciu_en1_mirror;
349127499Sgadstatic uint64_t cvmx_interrupt_ciu_61xx_timer_mirror;
350127499Sgad
351127499Sgad/**
3521556Srgrimes * @INTERNAL
35313020Speter * Called for all Performance Counter interrupts. Handler for
354127499Sgad * interrupt line 6
355127499Sgad *
356127499Sgad * @param irq_number Interrupt number that we're being called for
357127499Sgad * @param registers  Registers at the time of the interrupt
35813020Speter * @param user_arg   Unused user argument*
3591556Srgrimes */
360109502Sjmallettstatic void __cvmx_interrupt_perf(int irq_number, uint64_t *registers, void *user_arg)
3611556Srgrimes{
36290143Smarkm    uint64_t perf_counter;
3631556Srgrimes    CVMX_MF_COP0(perf_counter, COP0_PERFVALUE0);
3641556Srgrimes    if (perf_counter & (1ull << 63))
3651556Srgrimes        cvmx_collect_sample();
366109502Sjmallett}
3671556Srgrimes
36890143Smarkm/**
3691556Srgrimes * @INTERNAL
3701556Srgrimes * Handler for interrupt lines 2 and 3. These are directly tied
3711556Srgrimes * to the CIU. The handler queries the status of the CIU and
3721556Srgrimes * calls the secondary handler for the CIU interrupt that
3731556Srgrimes * occurred.
3741556Srgrimes *
3751556Srgrimes * @param irq_number Interrupt number that fired (2 or 3)
3761556Srgrimes * @param registers  Registers at the time of the interrupt
3771556Srgrimes * @param user_arg   Unused user argument
378127499Sgad */
379127499Sgadstatic void __cvmx_interrupt_ciu(int irq_number, uint64_t *registers, void *user_arg)
380127499Sgad{
381127499Sgad    int ciu_offset;
382127499Sgad    uint64_t irq_mask;
383127499Sgad    uint64_t irq;
384127499Sgad    int bit;
385127499Sgad    int core = cvmx_get_core_num();
386127499Sgad
387127499Sgad    if (irq_number == CVMX_IRQ_MIPS2) {
388127499Sgad        /* Handle EN0 sources */
389127499Sgad        ciu_offset = core * 2;
390127499Sgad        irq_mask = cvmx_read_csr(CVMX_CIU_INTX_SUM0(ciu_offset)) & cvmx_interrupt_ciu_en0_mirror;
391127499Sgad        CVMX_DCLZ(bit, irq_mask);
3921556Srgrimes        bit = 63 - bit;
393127499Sgad        /* If ciu_int_sum1<sum2> is set, means its a timer interrupt */
3941556Srgrimes        if (bit == 51 && (OCTEON_IS_MODEL(OCTEON_CN61XX) || OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_2))) {
39586922Sgreen            uint64_t irq_mask;
396109502Sjmallett            int bit;
39786922Sgreen            irq_mask = cvmx_read_csr(CVMX_CIU_SUM2_PPX_IP2(core)) & cvmx_interrupt_ciu_61xx_timer_mirror;
39886922Sgreen            CVMX_DCLZ(bit, irq_mask);
3991556Srgrimes            bit = 63 - bit;
4001556Srgrimes            /* Handle TIMER(4..9) interrupts */
4011556Srgrimes            if (bit <= 9 && bit >= 4) {
4021556Srgrimes                uint64_t irq = cvmx_ciu_61xx_timer_to_irq[bit];
4031556Srgrimes                if (cvmx_unlikely(irq == 0xff)) {
4041556Srgrimes                    /* No mapping */
405129914Sgad                    cvmx_interrupt_ciu_61xx_timer_mirror &= ~(1ull << bit);
406129914Sgad                    cvmx_write_csr(CVMX_CIU_EN2_PPX_IP2(core), cvmx_interrupt_ciu_61xx_timer_mirror);
407137696Scsjp                    return;
408137696Scsjp                }
409137696Scsjp                struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + irq;
410137696Scsjp                h->handler(irq, registers, h->data);
411137696Scsjp                return;
412137696Scsjp            }
413137696Scsjp        }
414137696Scsjp
415129914Sgad        if (bit >= 0) {
416129914Sgad            irq = cvmx_ciu_en0_to_irq[bit];
417129914Sgad            if (cvmx_unlikely(irq == 0xff)) {
418129914Sgad                /* No mapping. */
419129914Sgad                cvmx_interrupt_ciu_en0_mirror &= ~(1ull << bit);
420129914Sgad                cvmx_write_csr(CVMX_CIU_INTX_EN0(ciu_offset), cvmx_interrupt_ciu_en0_mirror);
421129914Sgad                return;
422129914Sgad            }
423129914Sgad            struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + irq;
424129914Sgad            h->handler(irq, registers, h->data);
425129914Sgad            return;
426129914Sgad        }
427129914Sgad    } else {
428129914Sgad        /* Handle EN1 sources */
429127499Sgad        ciu_offset = cvmx_get_core_num() * 2 + 1;
430127542Sgad        irq_mask = cvmx_read_csr(CVMX_CIU_INT_SUM1) & cvmx_interrupt_ciu_en1_mirror;
431127542Sgad        CVMX_DCLZ(bit, irq_mask);
432127499Sgad        bit = 63 - bit;
433127499Sgad        if (bit >= 0) {
43489909Sru            irq = cvmx_ciu_en1_to_irq[bit];
4351556Srgrimes            if (cvmx_unlikely(irq == 0xff)) {
4361556Srgrimes                /* No mapping. */
4371556Srgrimes                cvmx_interrupt_ciu_en1_mirror &= ~(1ull << bit);
43890143Smarkm                cvmx_write_csr(CVMX_CIU_INTX_EN1(ciu_offset), cvmx_interrupt_ciu_en1_mirror);
439109502Sjmallett                return;
4401556Srgrimes            }
441127499Sgad            struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + irq;
442127823Sgad            h->handler(irq, registers, h->data);
443127823Sgad            return;
44497877Sjmallett        }
445127499Sgad    }
446127499Sgad}
447127823Sgad
44866377Sbrian/**
4491556Srgrimes * @INTERNAL
4501556Srgrimes * Handler for interrupt line 3, the DPI_DMA will have different value
4511556Srgrimes * per core, all other fields values are identical for different cores.
45253170Skris *  These are directly tied to the CIU. The handler queries the status of
4531556Srgrimes * the CIU and calls the secondary handler for the CIU interrupt that
4541556Srgrimes * occurred.
455127499Sgad *
4561556Srgrimes * @param irq_number Interrupt number that fired (2 or 3)
457127499Sgad * @param registers  Registers at the time of the interrupt
458127499Sgad * @param user_arg   Unused user argument
459127499Sgad */
460127499Sgadstatic void __cvmx_interrupt_ciu_cn61xx(int irq_number, uint64_t *registers, void *user_arg)
461127499Sgad{
4621556Srgrimes    /* Handle EN1 sources */
463127499Sgad    int core = cvmx_get_core_num();
464127499Sgad    int ciu_offset;
465127499Sgad    uint64_t irq_mask;
466129600Sgad    uint64_t irq;
467129600Sgad    int bit;
468129600Sgad
469129600Sgad    ciu_offset = core * 2 + 1;
470129600Sgad    irq_mask = cvmx_read_csr(CVMX_CIU_SUM1_PPX_IP3(core)) & cvmx_interrupt_ciu_en1_mirror;
471127499Sgad    CVMX_DCLZ(bit, irq_mask);
472127823Sgad    bit = 63 - bit;
473127499Sgad    if (bit >= 0) {
474127499Sgad        irq = cvmx_ciu_en1_to_irq[bit];
475127499Sgad        if (cvmx_unlikely(irq == 0xff)) {
476127823Sgad            /* No mapping. */
477127499Sgad            cvmx_interrupt_ciu_en1_mirror &= ~(1ull << bit);
478127499Sgad            cvmx_write_csr(CVMX_CIU_INTX_EN1(ciu_offset), cvmx_interrupt_ciu_en1_mirror);
479127499Sgad            return;
480127823Sgad        }
481127499Sgad        struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + irq;
482127499Sgad        h->handler(irq, registers, h->data);
483127499Sgad        return;
484127823Sgad    }
485127499Sgad}
486127499Sgad
487127499Sgad/**
488127823Sgad * @INTERNAL
489127499Sgad * Handler for interrupt line 2 on 68XX. These are directly tied
490127499Sgad * to the CIU2. The handler queries the status of the CIU and
491127499Sgad * calls the secondary handler for the CIU interrupt that
492127823Sgad * occurred.
493127499Sgad *
494127499Sgad * @param irq_number Interrupt number that fired (2 or 3)
495127499Sgad * @param registers  Registers at the time of the interrupt
496127499Sgad * @param user_arg   Unused user argument
497127499Sgad */
4981556Srgrimesstatic void __cvmx_interrupt_ciu2(int irq_number, uint64_t *registers, void *user_arg)
499126127Sdeischen{
5001556Srgrimes    int sum_bit, src_bit;
5011556Srgrimes    uint64_t irq;
5021556Srgrimes    uint64_t src_reg, src_val;
503127499Sgad    struct __cvmx_interrupt_handler *h;
504127149Sgad    int core = cvmx_get_core_num();
505127544Sgad    uint64_t sum = cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP2(core));
5061556Srgrimes
507127499Sgad    CVMX_DCLZ(sum_bit, sum);
508127149Sgad    sum_bit = 63 - sum_bit;
509127149Sgad
510127149Sgad    if (sum_bit >= 0) {
511127149Sgad        switch (sum_bit) {
512127499Sgad        case 63:
513127499Sgad        case 62:
514127499Sgad        case 61:
515127499Sgad        case 60:
516127499Sgad            irq = cvmx_ciu2_mbox_to_irq[sum_bit - 60];
517127499Sgad            if (cvmx_unlikely(irq == 0xff)) {
518127499Sgad                /* No mapping. */
519127823Sgad                uint64_t mask_reg = CVMX_CIU2_EN_PPX_IP2_MBOX_W1C(core);
520127499Sgad                cvmx_write_csr(mask_reg, 1ull << (sum_bit - 60));
521127499Sgad                break;
522127499Sgad            }
523127499Sgad            h = cvmx_interrupt_state.handlers + irq;
524127499Sgad            h->handler(irq, registers, h->data);
525127499Sgad            break;
526127499Sgad
527127499Sgad        case 7:
528127499Sgad        case 6:
529127499Sgad        case 5:
530127499Sgad        case 4:
531127499Sgad        case 3:
532127499Sgad        case 2:
533127499Sgad        case 1:
534127499Sgad        case 0:
535127499Sgad            src_reg = CVMX_CIU2_SRC_PPX_IP2_WRKQ(core) + (0x1000 * sum_bit);
536127823Sgad            src_val = cvmx_read_csr(src_reg);
537127499Sgad            if (!src_val)
538127499Sgad                break;
539127499Sgad            CVMX_DCLZ(src_bit, src_val);
540127499Sgad            src_bit = 63 - src_bit;
541127823Sgad            irq = cvmx_ciu_to_irq[sum_bit][src_bit];
542127823Sgad            if (cvmx_unlikely(irq == 0xff)) {
543127499Sgad                /* No mapping. */
544127499Sgad                uint64_t mask_reg = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(core) + (0x1000 * sum_bit);
545127499Sgad                cvmx_write_csr(mask_reg, 1ull << src_bit);
546127499Sgad                break;
547127823Sgad            }
548127823Sgad            h = cvmx_interrupt_state.handlers + irq;
549127499Sgad            h->handler(irq, registers, h->data);
550127499Sgad            break;
551127499Sgad
552127499Sgad        default:
553127823Sgad            cvmx_safe_printf("Unknown CIU2 bit: %d\n", sum_bit);
554127499Sgad            break;
555127499Sgad        }
556127499Sgad    }
557127499Sgad    /* Clear the source to reduce the chance for spurious interrupts.  */
558127823Sgad
559127499Sgad    /* CN68XX has an CIU-15786 errata that accessing the ACK registers
560127499Sgad     * can stop interrupts from propagating
561127499Sgad     */
562127499Sgad
563127823Sgad    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
564127499Sgad        cvmx_read_csr(CVMX_CIU2_INTR_CIU_READY);
565127499Sgad    else
566127499Sgad        cvmx_read_csr(CVMX_CIU2_ACK_PPX_IP2(core));
567127499Sgad}
568127499Sgad
569127499Sgad
570127499Sgad/**
571127499Sgad * @INTERNAL
572127499Sgad * Called for all RML interrupts. This is usually an ECC error
573130816Sgad *
574130816Sgad * @param irq_number Interrupt number that we're being called for
575130816Sgad * @param registers  Registers at the time of the interrupt
576130816Sgad * @param user_arg   Unused user argument
577130816Sgad */
578130816Sgadstatic void __cvmx_interrupt_ecc(int irq_number, uint64_t *registers, void *user_arg)
579127149Sgad{
580130816Sgad    cvmx_error_poll();
581130816Sgad}
582127499Sgad
583127149Sgad
5841556Srgrimes/**
58525271Sjkh * Process an interrupt request
58625271Sjkh *
58725271Sjkh * @param registers Registers at time of interrupt / exception
5881556Srgrimes * Registers 0-31 are standard MIPS, others specific to this routine
5891556Srgrimes * @return
5901556Srgrimes */
5911556Srgrimesvoid cvmx_interrupt_do_irq(uint64_t *registers);
592127499Sgadvoid cvmx_interrupt_do_irq(uint64_t *registers)
59362803Swill{
594127499Sgad    uint64_t        mask;
5951556Srgrimes    uint64_t        cause;
5961556Srgrimes    uint64_t        status;
5971556Srgrimes    uint64_t        cache_err;
598127499Sgad    int             i;
5991556Srgrimes    uint32_t exc_vec;
600127499Sgad    /* Determine the cause of the interrupt */
6011556Srgrimes    asm volatile ("dmfc0 %0,$13,0" : "=r" (cause));
602127499Sgad    asm volatile ("dmfc0 %0,$12,0" : "=r" (status));
603130999Sgad    /* In case of exception, clear all interrupts to avoid recursive interrupts.
6041556Srgrimes       Also clear EXL bit to display the correct PC value. */
605130999Sgad    if ((cause & 0x7c) == 0)
6061556Srgrimes    {
6071556Srgrimes        asm volatile ("dmtc0 %0, $12, 0" : : "r" (status & ~(0xff02)));
6081556Srgrimes    }
6091556Srgrimes    /* The assembly stub at each exception vector saves its address in k1 when
6101556Srgrimes    ** it calls the stage 2 handler.  We use this to compute the exception vector
6111556Srgrimes    ** that brought us here */
6121556Srgrimes    exc_vec = (uint32_t)(registers[27] & 0x780);  /* Mask off bits we need to ignore */
6131556Srgrimes
6141556Srgrimes    /* Check for cache errors.  The cache errors go to a separate exception vector,
615127499Sgad    ** so we will only check these if we got here from a cache error exception, and
616127499Sgad    ** the ERL (error level) bit is set. */
617127499Sgad    i = cvmx_get_core_num();
618127499Sgad    if (exc_vec == 0x100 && (status & 0x4))
619127499Sgad    {
620127499Sgad        CVMX_MF_CACHE_ERR(cache_err);
621127499Sgad
62266377Sbrian        /* Use copy of DCACHE_ERR register that early exception stub read */
6231556Srgrimes        if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX))
6241556Srgrimes        {
6251556Srgrimes            if (registers[34] & 0x1)
626127499Sgad                cvmx_safe_printf("Dcache error detected: core: %d, way: %d, va 7:3: 0x%x\n", i, (int)(registers[34] >> 8) & 0x3f, (int)(registers[34] >> 3) & 0x1f);
627127499Sgad            else if (cache_err & 0x1)
628127499Sgad                cvmx_safe_printf("Icache error detected: core: %d, set: %d, way : %d, va 6:3 = 0x%x\n", i, (int)(cache_err >> 5) & 0x3f, (int)(cache_err >> 3) & 0x3, (int)(cache_err >> 11) & 0xf);
629127499Sgad            else
630127499Sgad                cvmx_safe_printf("Cache error exception: core %d\n", i);
631127499Sgad        }
632127602Sgad        else
633127499Sgad        {
634127499Sgad            if (registers[34] & 0x1)
635127499Sgad                cvmx_safe_printf("Dcache error detected: core: %d, way: %d, va 9:7: 0x%x\n", i, (int)(registers[34] >> 10) & 0x1f, (int)(registers[34] >> 7) & 0x3);
636127499Sgad            else if (cache_err & 0x1)
637127499Sgad                cvmx_safe_printf("Icache error detected: core: %d, way : %d, va 9:3 = 0x%x\n", i, (int)(cache_err >> 10) & 0x3f, (int)(cache_err >> 3) & 0x7f);
638127499Sgad            else
639127499Sgad                cvmx_safe_printf("Cache error exception: core %d\n", i);
640127542Sgad        }
641127499Sgad        CVMX_MT_DCACHE_ERR(1);
642127499Sgad        CVMX_MT_CACHE_ERR(0);
643127499Sgad    }
644127499Sgad
645127499Sgad    /* The bus error exceptions can occur due to DID timeout or write buffer,
646127499Sgad       check by reading COP0_CACHEERRD */
647127499Sgad    if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
648127499Sgad    {
649127499Sgad        i = cvmx_get_core_num();
650127499Sgad        if (registers[34] & 0x4)
651127499Sgad        {
652127499Sgad            cvmx_safe_printf("Bus error detected due to DID timeout: core: %d\n", i);
653127499Sgad            CVMX_MT_DCACHE_ERR(4);
654127499Sgad        }
655127602Sgad        else if (registers[34] & 0x2)
656127602Sgad        {
657127499Sgad            cvmx_safe_printf("Bus error detected due to write buffer parity: core: %d\n", i);
658127602Sgad            CVMX_MT_DCACHE_ERR(2);
659127499Sgad        }
660127499Sgad    }
661127499Sgad
662127499Sgad    if ((cause & 0x7c) != 0)
663127499Sgad    {
664127499Sgad        cvmx_interrupt_state.exception_handler(registers);
665129967Sgad        goto return_from_interrupt;
666127499Sgad    }
667127499Sgad
668127499Sgad    /* Convert the cause into an active mask */
669127823Sgad    mask = ((cause & status) >> 8) & 0xff;
670127499Sgad    if (mask == 0)
671127499Sgad    {
672127499Sgad        goto return_from_interrupt; /* Spurious interrupt */
673127597Sgad    }
674127499Sgad
675127499Sgad    for (i=0; i<8; i++)
676127149Sgad    {
677127539Sgad        if (mask & (1<<i))
678127149Sgad        {
679127149Sgad            struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + i;
680129917Sgad            h->handler(i, registers, h->data);
681129917Sgad            goto return_from_interrupt;
682129917Sgad        }
683129917Sgad    }
684127149Sgad
685127149Sgad    /* We should never get here */
686129952Sgad    __cvmx_interrupt_default_exception_handler(registers);
687129952Sgad
688129952Sgadreturn_from_interrupt:
689129952Sgad    /* Restore Status register before returning from exception. */
690129952Sgad    asm volatile ("dmtc0 %0, $12, 0" : : "r" (status));
691129952Sgad}
692129952Sgad
693129952Sgadvoid (*cvmx_interrupt_mask_irq)(int irq_number);
694129952Sgadvoid (*cvmx_interrupt_unmask_irq)(int irq_number);
695129952Sgad
696129952Sgad#define CLEAR_OR_MASK(V,M,O) ({\
697129967Sgad            if (O)             \
698129952Sgad                (V) &= ~(M);   \
699127499Sgad            else               \
700127499Sgad                (V) |= (M);    \
701127823Sgad        })
702127499Sgad
703127499Sgadstatic void __cvmx_interrupt_ciu2_mask_unmask_irq(int irq_number, int op)
704127499Sgad{
705127149Sgad
706131010Sgad    if (irq_number < 0 || irq_number >= CVMX_IRQ_MAX)
707131010Sgad        return;
708131010Sgad
709131010Sgad    if (irq_number <=  CVMX_IRQ_MIPS7) {
710131010Sgad        uint32_t flags, mask;
711131010Sgad
712131010Sgad        flags = cvmx_interrupt_disable_save();
713127499Sgad        asm volatile ("mfc0 %0,$12,0" : "=r" (mask));
714127499Sgad        CLEAR_OR_MASK(mask, 1 << (8 + irq_number), op);
715127499Sgad        asm volatile ("mtc0 %0,$12,0" : : "r" (mask));
716127539Sgad        cvmx_interrupt_restore(flags);
717127539Sgad    } else {
718131209Sgad        int idx;
719127499Sgad        uint64_t reg;
720131010Sgad        int core = cvmx_get_core_num();
721131209Sgad
722131010Sgad        int bit = cvmx_interrupt_state.handlers[irq_number].handler_data;
723131010Sgad
724127499Sgad        if (bit < 0)
725131010Sgad            return;
726131010Sgad
727131010Sgad        idx = bit >> 6;
728131010Sgad        bit &= 0x3f;
729131010Sgad        if (idx > 7) {
730131010Sgad            /* MBOX */
731131010Sgad            if (op)
732131010Sgad                reg = CVMX_CIU2_EN_PPX_IP2_MBOX_W1C(core);
733131010Sgad            else
734131010Sgad                reg = CVMX_CIU2_EN_PPX_IP2_MBOX_W1S(core);
735131010Sgad        } else {
736131209Sgad            if (op)
737131010Sgad                reg = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(core) + (0x1000 * idx);
738131010Sgad            else
739131010Sgad                reg = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(core) + (0x1000 * idx);
740131209Sgad        }
741131209Sgad        cvmx_write_csr(reg, 1ull << bit);
742131209Sgad    }
743131209Sgad}
744131010Sgad
745131010Sgadstatic void __cvmx_interrupt_ciu2_mask_irq(int irq_number)
746131010Sgad{
747131010Sgad    __cvmx_interrupt_ciu2_mask_unmask_irq(irq_number, 1);
748131010Sgad}
749127499Sgad
750131010Sgadstatic void __cvmx_interrupt_ciu2_unmask_irq(int irq_number)
751131010Sgad{
752131209Sgad    __cvmx_interrupt_ciu2_mask_unmask_irq(irq_number, 0);
753131209Sgad}
754131209Sgad
755131209Sgadstatic void __cvmx_interrupt_ciu_mask_unmask_irq(int irq_number, int op)
756131010Sgad{
757131010Sgad    uint32_t flags;
758131010Sgad
759131010Sgad    if (irq_number < 0 || irq_number >= CVMX_IRQ_MAX)
760131209Sgad        return;
761131209Sgad
762131209Sgad    flags = cvmx_interrupt_disable_save();
763131209Sgad    if (irq_number <=  CVMX_IRQ_MIPS7) {
764131209Sgad        uint32_t mask;
765131010Sgad        asm volatile ("mfc0 %0,$12,0" : "=r" (mask));
766131010Sgad        CLEAR_OR_MASK(mask, 1 << (8 + irq_number), op);
767131010Sgad        asm volatile ("mtc0 %0,$12,0" : : "r" (mask));
768127499Sgad    } else {
769127499Sgad        int ciu_bit, ciu_offset;
770127499Sgad        int bit = cvmx_interrupt_state.handlers[irq_number].handler_data;
771127823Sgad        int is_timer_intr = bit >> 6;
772127499Sgad        int core = cvmx_get_core_num();
773127149Sgad
774127149Sgad        if (bit < 0)
775127499Sgad            goto out;
776127499Sgad
77766377Sbrian        ciu_bit = bit & 0x3f;
77866377Sbrian        ciu_offset = core * 2;
779127539Sgad
780127602Sgad        if (is_timer_intr == 8)
78166377Sbrian        {
782127499Sgad            CLEAR_OR_MASK(cvmx_interrupt_ciu_61xx_timer_mirror, 1ull << ciu_bit, op);
783127499Sgad            CLEAR_OR_MASK(cvmx_interrupt_ciu_en0_mirror, 1ull << 51, op); // SUM2 bit
784127499Sgad            cvmx_write_csr(CVMX_CIU_EN2_PPX_IP2(core), cvmx_interrupt_ciu_61xx_timer_mirror);
785127499Sgad        }
786127499Sgad        else if (bit & 0x40) {
787127499Sgad            /* EN1 */
788127542Sgad            ciu_offset += 1;
789127499Sgad            CLEAR_OR_MASK(cvmx_interrupt_ciu_en1_mirror, 1ull << ciu_bit, op);
79066377Sbrian            cvmx_write_csr(CVMX_CIU_INTX_EN1(ciu_offset), cvmx_interrupt_ciu_en1_mirror);
791127499Sgad        } else {
792127499Sgad            /* EN0 */
793127499Sgad            CLEAR_OR_MASK(cvmx_interrupt_ciu_en0_mirror, 1ull << ciu_bit, op);
794127602Sgad            cvmx_write_csr(CVMX_CIU_INTX_EN0(ciu_offset), cvmx_interrupt_ciu_en0_mirror);
795127602Sgad        }
796127499Sgad    }
797127499Sgadout:
798127499Sgad    cvmx_interrupt_restore(flags);
799127602Sgad}
800127499Sgad
801127499Sgadstatic void __cvmx_interrupt_ciu_mask_irq(int irq_number)
802127499Sgad{
80366377Sbrian    __cvmx_interrupt_ciu_mask_unmask_irq(irq_number, 1);
804127499Sgad}
805127499Sgad
806127509Sgadstatic void __cvmx_interrupt_ciu_unmask_irq(int irq_number)
807127509Sgad{
808127509Sgad    __cvmx_interrupt_ciu_mask_unmask_irq(irq_number, 0);
809127509Sgad}
810127509Sgad
811127509Sgad/**
812129967Sgad * Register an interrupt handler for the specified interrupt number.
813127499Sgad *
814127499Sgad * @param irq_number Interrupt number to register for See
815127499Sgad *                   cvmx-interrupt.h for enumeration and description of sources.
816127823Sgad * @param func       Function to call on interrupt.
817127499Sgad * @param user_arg   User data to pass to the interrupt handler
818127499Sgad */
819127499Sgadvoid cvmx_interrupt_register(int irq_number, cvmx_interrupt_func_t func, void *user_arg)
820127499Sgad{
821127499Sgad    if (irq_number >= CVMX_IRQ_MAX || irq_number < 0) {
822127499Sgad        cvmx_warn("cvmx_interrupt_register: Illegal irq_number %d\n", irq_number);
823127499Sgad        return;
824127499Sgad    }
825127499Sgad    cvmx_interrupt_state.handlers[irq_number].handler = func;
826127539Sgad    cvmx_interrupt_state.handlers[irq_number].data = user_arg;
827127499Sgad    CVMX_SYNCWS;
828129917Sgad}
829129967Sgad
830127499Sgad
831127499Sgadstatic void cvmx_interrupt_ciu_initialize(cvmx_sysinfo_t *sys_info_ptr)
832127499Sgad{
833127499Sgad    int i;
834127499Sgad    int core = cvmx_get_core_num();
835127499Sgad
836127499Sgad    /* Disable all CIU interrupts by default */
837127499Sgad    cvmx_interrupt_ciu_en0_mirror = 0;
838127499Sgad    cvmx_interrupt_ciu_en1_mirror = 0;
839127499Sgad    cvmx_interrupt_ciu_61xx_timer_mirror = 0;
840127499Sgad    cvmx_write_csr(CVMX_CIU_INTX_EN0(core * 2), cvmx_interrupt_ciu_en0_mirror);
841127499Sgad    cvmx_write_csr(CVMX_CIU_INTX_EN0((core * 2)+1), cvmx_interrupt_ciu_en0_mirror);
842127499Sgad    cvmx_write_csr(CVMX_CIU_INTX_EN1(core * 2), cvmx_interrupt_ciu_en1_mirror);
84366377Sbrian    cvmx_write_csr(CVMX_CIU_INTX_EN1((core * 2)+1), cvmx_interrupt_ciu_en1_mirror);
844127499Sgad    if (OCTEON_IS_MODEL(OCTEON_CN61XX) || OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_2))
845127499Sgad        cvmx_write_csr(CVMX_CIU_EN2_PPX_IP2(cvmx_get_core_num()), cvmx_interrupt_ciu_61xx_timer_mirror);
846127542Sgad
847129953Sgad    if (!cvmx_coremask_first_core(sys_info_ptr->core_mask)|| is_core_being_hot_plugged())
848127542Sgad        return;
849127499Sgad
850127499Sgad    /* On the first core, set up the maps */
851127499Sgad    for (i = 0; i < 64; i++) {
852127499Sgad        cvmx_ciu_en0_to_irq[i] = 0xff;
853127499Sgad        cvmx_ciu_en1_to_irq[i] = 0xff;
854127499Sgad        cvmx_ciu_61xx_timer_to_irq[i] = 0xff;
855127499Sgad    }
856127499Sgad
857127499Sgad    /* WORKQ */
858127499Sgad    for (i = 0; i < 16; i++)
859127499Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_WORKQ0 + i, 0, i);
860127499Sgad    /* GPIO */
86166377Sbrian    for (i = 0; i < 16; i++)
862127499Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_GPIO0 + i, 0, i + 16);
863127499Sgad
864127499Sgad    /* MBOX */
865127499Sgad    for (i = 0; i < 2; i++)
866127499Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_MBOX0 + i, 0, i + 32);
867127499Sgad
868127499Sgad    /* UART */
869127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_UART0 + 0, 0, 34);
870127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_UART0 + 1, 0, 35);
871127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_UART0 + 2, 1, 16);
872127499Sgad
873127499Sgad    /* PCI */
874127499Sgad    for (i = 0; i < 4; i++)
87566377Sbrian        __cvmx_interrupt_set_mapping(CVMX_IRQ_PCI_INT0 + i, 0, i + 36);
876127499Sgad
87766377Sbrian    /* MSI */
878127499Sgad    for (i = 0; i < 4; i++)
879127499Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_PCI_MSI0 + i, 0, i + 40);
880127499Sgad
881127539Sgad    /* TWSI */
882127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_TWSI0 + 0, 0, 45);
88366377Sbrian    __cvmx_interrupt_set_mapping(CVMX_IRQ_TWSI0 + 1, 0, 59);
884127499Sgad
885127823Sgad    /* other */
886127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_RML, 0, 46);
887127823Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_TRACE0, 0, 47);
888129967Sgad
889127499Sgad    /* GMX_DRP */
890127499Sgad    for (i = 0; i < 2; i++)
891127823Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_GMX_DRP0 + i, 0, i + 48);
892127499Sgad
893127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_IPD_DRP, 0, 50);
89466377Sbrian    __cvmx_interrupt_set_mapping(CVMX_IRQ_KEY_ZERO, 0, 51);
89566377Sbrian
896127499Sgad    /* TIMER0 */
897127499Sgad    for (i = 0; i < 4; i++)
898127499Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_TIMER0 + i, 0, i + 52);
899127499Sgad
900127499Sgad    /* TIMER4..9 */
901127823Sgad    for(i = 0; i < 6; i++)
902127823Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_TIMER4 + i, 8, i + 4);
903127499Sgad
904127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_USB0 + 0, 0, 56);
905127823Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_USB0 + 1, 1, 17);
906127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_PCM, 0, 57);
907127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_MPI, 0, 58);
908127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_POWIQ, 0, 60);
909127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_IPDPPTHR, 0, 61);
910127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_MII0 + 0, 0, 62);
911127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_MII0 + 1, 1, 18);
912127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_BOOTDMA, 0, 63);
913127499Sgad
914127499Sgad    /* WDOG */
915127499Sgad    for (i = 0; i < 16; i++)
916127499Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_WDOG0 + i, 1, i);
917127823Sgad
918127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_NAND, 1, 19);
919127499Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_MIO, 1, 20);
920109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_IOB, 1, 21);
921109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_FPA, 1, 22);
922109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_POW, 1, 23);
923109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_L2C, 1, 24);
924109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_IPD, 1, 25);
925130999Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_PIP, 1, 26);
926109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_PKO, 1, 27);
927109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_ZIP, 1, 28);
928109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_TIM, 1, 29);
929109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_RAD, 1, 30);
930109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_KEY, 1, 31);
931109502Sjmallett    __cvmx_interrupt_set_mapping(CVMX_IRQ_DFA, 1, 32);
9321556Srgrimes    __cvmx_interrupt_set_mapping(CVMX_IRQ_USBCTL, 1, 33);
93390110Simp    __cvmx_interrupt_set_mapping(CVMX_IRQ_SLI, 1, 34);
9341556Srgrimes    __cvmx_interrupt_set_mapping(CVMX_IRQ_DPI, 1, 35);
9351556Srgrimes    __cvmx_interrupt_set_mapping(CVMX_IRQ_AGX0, 1, 36);
9361556Srgrimes    __cvmx_interrupt_set_mapping(CVMX_IRQ_AGX0 + 1, 1, 37);
93725271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_DPI_DMA, 1, 40);
938130999Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_AGL, 1, 46);
93925271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_PTP, 1, 47);
94025271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_PEM0, 1, 48);
94125271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_PEM1, 1, 49);
94225271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_SRIO0, 1, 50);
94325271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_SRIO1, 1, 51);
94425271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_LMC0, 1, 52);
94525271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_DFM, 1, 56);
94625271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_SRIO2, 1, 60);
94725271Sjkh    __cvmx_interrupt_set_mapping(CVMX_IRQ_RST, 1, 63);
94825271Sjkh}
94925271Sjkh
95025271Sjkhstatic void cvmx_interrupt_ciu2_initialize(cvmx_sysinfo_t *sys_info_ptr)
95125271Sjkh{
95290110Simp    int i;
95325271Sjkh
95425271Sjkh    /* Disable all CIU2 interrupts by default */
95525271Sjkh
9561556Srgrimes    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_WRKQ(cvmx_get_core_num()), 0);
9571556Srgrimes    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_WRKQ(cvmx_get_core_num()), 0);
958130999Sgad    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_WRKQ(cvmx_get_core_num()), 0);
9591556Srgrimes    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_WDOG(cvmx_get_core_num()), 0);
96025271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_WDOG(cvmx_get_core_num()), 0);
96125271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_WDOG(cvmx_get_core_num()), 0);
96225271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_RML(cvmx_get_core_num()), 0);
96325271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_RML(cvmx_get_core_num()), 0);
96425271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_RML(cvmx_get_core_num()), 0);
96525271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_MIO(cvmx_get_core_num()), 0);
96625271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_MIO(cvmx_get_core_num()), 0);
96725271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_MIO(cvmx_get_core_num()), 0);
96825271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_IO(cvmx_get_core_num()), 0);
96925271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_IO(cvmx_get_core_num()), 0);
97025271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_IO(cvmx_get_core_num()), 0);
97190110Simp    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_MEM(cvmx_get_core_num()), 0);
97225271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_MEM(cvmx_get_core_num()), 0);
97325271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_MEM(cvmx_get_core_num()), 0);
97425271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_PKT(cvmx_get_core_num()), 0);
97525271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_PKT(cvmx_get_core_num()), 0);
97625271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_PKT(cvmx_get_core_num()), 0);
977130999Sgad    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_GPIO(cvmx_get_core_num()), 0);
97825271Sjkh    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_GPIO(cvmx_get_core_num()), 0);
979109504Sjmallett    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_GPIO(cvmx_get_core_num()), 0);
9801556Srgrimes    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_MBOX(cvmx_get_core_num()), 0);
9811556Srgrimes    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_MBOX(cvmx_get_core_num()), 0);
9821556Srgrimes    cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_MBOX(cvmx_get_core_num()), 0);
9831556Srgrimes
9841556Srgrimes    if (!cvmx_coremask_first_core(sys_info_ptr->core_mask) || is_core_being_hot_plugged())
9851556Srgrimes        return;
9861556Srgrimes
98790143Smarkm    /* On the first core, set up the maps */
98890110Simp    for (i = 0; i < 64; i++) {
989127542Sgad        cvmx_ciu2_wrkq_to_irq[i] = 0xff;
9901556Srgrimes        cvmx_ciu2_wdog_to_irq[i] = 0xff;
99190143Smarkm        cvmx_ciu2_rml_to_irq[i] = 0xff;
9921556Srgrimes        cvmx_ciu2_mio_to_irq[i] = 0xff;
99390143Smarkm        cvmx_ciu2_io_to_irq[i] = 0xff;
9941556Srgrimes        cvmx_ciu2_mem_to_irq[i] = 0xff;
9951556Srgrimes        cvmx_ciu2_eth_to_irq[i] = 0xff;
9961556Srgrimes        cvmx_ciu2_gpio_to_irq[i] = 0xff;
99771578Sjhb        cvmx_ciu2_mbox_to_irq[i] = 0xff;
99831552Sdyson    }
9991556Srgrimes
100090110Simp    /* WORKQ */
10011556Srgrimes    for (i = 0; i < 64; i++)
10021556Srgrimes        __cvmx_interrupt_set_mapping(CVMX_IRQ_WORKQ0 + i, 0, i);
100371578Sjhb
10041556Srgrimes    /* GPIO */
10051556Srgrimes    for (i = 0; i < 16; i++)
10061556Srgrimes        __cvmx_interrupt_set_mapping(CVMX_IRQ_GPIO0 + i, 7, i);
10071556Srgrimes
10081556Srgrimes    /* MBOX */
10091556Srgrimes    for (i = 0; i < 4; i++)
101069896Smckusick        __cvmx_interrupt_set_mapping(CVMX_IRQ_MBOX0 + i, 60, i);
10111556Srgrimes
101269896Smckusick    /* UART */
10131556Srgrimes    for (i = 0; i < 2; i++)
10141556Srgrimes        __cvmx_interrupt_set_mapping(CVMX_IRQ_UART0 + i, 3, 36 + i);
10151556Srgrimes
1016130991Sgad    /* PCI */
1017130991Sgad    for (i = 0; i < 4; i++)
1018130991Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_PCI_INT0 + i, 4, 16 + i);
1019130991Sgad
1020130991Sgad    /* MSI */
1021130991Sgad    for (i = 0; i < 4; i++)
1022130991Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_PCI_MSI0 + i, 4, 8 + i);
1023130991Sgad
1024131024Sgad    /* TWSI */
1025130991Sgad    for (i = 0; i < 2; i++)
102653276Speter        __cvmx_interrupt_set_mapping(CVMX_IRQ_TWSI0 + i, 3, 32 + i);
102753276Speter
102853276Speter    /* TRACE */
1029130991Sgad    for (i = 0; i < 4; i++)
1030130991Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_TRACE0 + i, 2, 52 + i);
1031130991Sgad
1032130991Sgad    /* GMX_DRP */
1033130991Sgad    for (i = 0; i < 5; i++)
1034130991Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_GMX_DRP0 + i, 6, 8 + i);
1035130991Sgad
1036130991Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_IPD_DRP, 3, 2);
103753276Speter
103853276Speter    /* TIMER0 */
103953276Speter    for (i = 0; i < 4; i++)
10401556Srgrimes        __cvmx_interrupt_set_mapping(CVMX_IRQ_TIMER0 + i, 3, 8 + i);
10411556Srgrimes
1042130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_USB0, 3, 44);
1043130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_IPDPPTHR, 3, 0);
1044130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_MII0, 6, 40);
1045130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_BOOTDMA, 3, 18);
1046130816Sgad
1047130816Sgad    /* WDOG */
10481556Srgrimes    for (i = 0; i < 32; i++)
104990110Simp        __cvmx_interrupt_set_mapping(CVMX_IRQ_WDOG0 + i, 1, i);
10501556Srgrimes
1051127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_NAND, 3, 16);
10521556Srgrimes    __cvmx_interrupt_set_mapping(CVMX_IRQ_MIO, 3, 17);
1053127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_IOB, 2, 0);
1054127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_FPA, 2, 4);
1055127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_POW, 2, 16);
1056130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_L2C, 2, 48);
1057130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_IPD, 2, 5);
1058130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_PIP, 2, 6);
1059130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_PKO, 2, 7);
1060127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_ZIP, 2, 24);
1061127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_TIM, 2, 28);
1062127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_RAD, 2, 29);
1063127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_KEY, 2, 30);
1064130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_DFA, 2, 40);
1065130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_USBCTL, 3, 40);
1066130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_SLI, 2, 32);
1067130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_DPI, 2, 33);
1068130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_DPI_DMA, 2, 36);
1069130816Sgad
1070130816Sgad    /* AGX */
1071130816Sgad    for (i = 0; i < 5; i++)
1072130972Sgad        __cvmx_interrupt_set_mapping(CVMX_IRQ_AGX0 + i, 6, i);
1073130816Sgad
1074130972Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_AGL, 6, 32);
1075127596Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_PTP, 3, 48);
10761556Srgrimes    __cvmx_interrupt_set_mapping(CVMX_IRQ_PEM0, 4, 32);
1077130816Sgad    __cvmx_interrupt_set_mapping(CVMX_IRQ_PEM1, 4, 32);
10781556Srgrimes
10791556Srgrimes    /* LMC */
10801556Srgrimes    for (i = 0; i < 4; i++)
10811556Srgrimes        __cvmx_interrupt_set_mapping(CVMX_IRQ_LMC0 + i, 5, i);
10821556Srgrimes
10831556Srgrimes    __cvmx_interrupt_set_mapping(CVMX_IRQ_RST, 3, 63);
10841556Srgrimes    __cvmx_interrupt_set_mapping(CVMX_IRQ_ILK, 6, 48);
10851556Srgrimes}
10861556Srgrimes
10871556Srgrimes/**
10881556Srgrimes * Initialize the interrupt routine and copy the low level
10891556Srgrimes * stub into the correct interrupt vector. This is called
10901556Srgrimes * automatically during application startup.
1091129915Sgad */
10921556Srgrimesvoid cvmx_interrupt_initialize(void)
10931556Srgrimes{
1094129914Sgad    void *low_level_loc;
10951556Srgrimes    cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
1096102886Sjmallett    int i;
1097129914Sgad
1098129914Sgad    if (cvmx_coremask_first_core(sys_info_ptr->core_mask) && !is_core_being_hot_plugged()) {
1099102886Sjmallett#ifndef CVMX_ENABLE_CSR_ADDRESS_CHECKING
1100129914Sgad        /* We assume this relationship between the registers. */
1101129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x1000 == CVMX_CIU2_SRC_PPX_IP2_WDOG(0));
1102129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x2000 == CVMX_CIU2_SRC_PPX_IP2_RML(0));
1103129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x3000 == CVMX_CIU2_SRC_PPX_IP2_MIO(0));
1104129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x4000 == CVMX_CIU2_SRC_PPX_IP2_IO(0));
1105129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x5000 == CVMX_CIU2_SRC_PPX_IP2_MEM(0));
1106129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x6000 == CVMX_CIU2_SRC_PPX_IP2_PKT(0));
1107129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x7000 == CVMX_CIU2_SRC_PPX_IP2_GPIO(0));
1108129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x1000 == CVMX_CIU2_EN_PPX_IP2_WDOG_W1C(0));
1109129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x2000 == CVMX_CIU2_EN_PPX_IP2_RML_W1C(0));
1110129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x3000 == CVMX_CIU2_EN_PPX_IP2_MIO_W1C(0));
1111129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x4000 == CVMX_CIU2_EN_PPX_IP2_IO_W1C(0));
1112102886Sjmallett        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x5000 == CVMX_CIU2_EN_PPX_IP2_MEM_W1C(0));
11131556Srgrimes        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x6000 == CVMX_CIU2_EN_PPX_IP2_PKT_W1C(0));
11141556Srgrimes        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x7000 == CVMX_CIU2_EN_PPX_IP2_GPIO_W1C(0));
11151556Srgrimes        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x1000 == CVMX_CIU2_EN_PPX_IP2_WDOG_W1S(0));
11161556Srgrimes        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x2000 == CVMX_CIU2_EN_PPX_IP2_RML_W1S(0));
111781743Sbrian        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x3000 == CVMX_CIU2_EN_PPX_IP2_MIO_W1S(0));
1118129634Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x4000 == CVMX_CIU2_EN_PPX_IP2_IO_W1S(0));
1119129634Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x5000 == CVMX_CIU2_EN_PPX_IP2_MEM_W1S(0));
1120129634Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x6000 == CVMX_CIU2_EN_PPX_IP2_PKT_W1S(0));
1121129914Sgad        CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x7000 == CVMX_CIU2_EN_PPX_IP2_GPIO_W1S(0));
1122129914Sgad#endif /* !CVMX_ENABLE_CSR_ADDRESS_CHECKING */
1123129914Sgad
11241556Srgrimes        for (i = 0; i < CVMX_IRQ_MAX; i++) {
1125129914Sgad            cvmx_interrupt_state.handlers[i].handler = __cvmx_interrupt_default;
1126129914Sgad            cvmx_interrupt_state.handlers[i].data = NULL;
1127129914Sgad            cvmx_interrupt_state.handlers[i].handler_data = -1;
1128129915Sgad        }
1129129915Sgad    }
1130129915Sgad
1131129915Sgad    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
11321556Srgrimes    {
1133129914Sgad        cvmx_interrupt_mask_irq = __cvmx_interrupt_ciu2_mask_irq;
1134129914Sgad        cvmx_interrupt_unmask_irq = __cvmx_interrupt_ciu2_unmask_irq;
1135129914Sgad        cvmx_interrupt_ciu2_initialize(sys_info_ptr);
1136129914Sgad        /* Add an interrupt handlers for chained CIU interrupt */
11371556Srgrimes        cvmx_interrupt_register(CVMX_IRQ_MIPS2, __cvmx_interrupt_ciu2, NULL);
1138129914Sgad    }
1139129914Sgad    else if (OCTEON_IS_MODEL(OCTEON_CN61XX) || OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_2))
1140129914Sgad    {
1141129914Sgad        cvmx_interrupt_mask_irq = __cvmx_interrupt_ciu_mask_irq;
1142129914Sgad        cvmx_interrupt_unmask_irq = __cvmx_interrupt_ciu_unmask_irq;
11431556Srgrimes        cvmx_interrupt_ciu_initialize(sys_info_ptr);
1144129914Sgad
11451556Srgrimes        /* Add an interrupt handlers for chained CIU interrupts */
1146129914Sgad        cvmx_interrupt_register(CVMX_IRQ_MIPS2, __cvmx_interrupt_ciu, NULL);
1147129914Sgad        cvmx_interrupt_register(CVMX_IRQ_MIPS3, __cvmx_interrupt_ciu_cn61xx, NULL);
11481556Srgrimes    }
1149129914Sgad    else
1150129914Sgad    {
1151129914Sgad        cvmx_interrupt_mask_irq = __cvmx_interrupt_ciu_mask_irq;
1152129914Sgad        cvmx_interrupt_unmask_irq = __cvmx_interrupt_ciu_unmask_irq;
1153129914Sgad        cvmx_interrupt_ciu_initialize(sys_info_ptr);
1154129914Sgad
1155129914Sgad        /* Add an interrupt handlers for chained CIU interrupts */
1156129914Sgad        cvmx_interrupt_register(CVMX_IRQ_MIPS2, __cvmx_interrupt_ciu, NULL);
1157129914Sgad        cvmx_interrupt_register(CVMX_IRQ_MIPS3, __cvmx_interrupt_ciu, NULL);
1158129914Sgad    }
1159129914Sgad
1160129914Sgad    /* Move performance counter interrupts to IRQ 6*/
1161129914Sgad    cvmx_update_perfcnt_irq();
1162129914Sgad
1163129914Sgad    /* Add an interrupt handler for Perf counter interrupts */
1164129914Sgad    cvmx_interrupt_register(CVMX_IRQ_MIPS6, __cvmx_interrupt_perf, NULL);
1165129914Sgad
1166129914Sgad    if (cvmx_coremask_first_core(sys_info_ptr->core_mask) && !is_core_being_hot_plugged())
1167129914Sgad    {
1168129914Sgad        cvmx_interrupt_state.exception_handler = __cvmx_interrupt_default_exception_handler;
1169129914Sgad
1170129914Sgad        low_level_loc = CASTPTR(void, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0,sys_info_ptr->exception_base_addr));
1171129914Sgad        memcpy(low_level_loc + 0x80, (void*)cvmx_interrupt_stage1, 0x80);
11721556Srgrimes        memcpy(low_level_loc + 0x100, (void*)cvmx_interrupt_cache_error, 0x80);
1173129914Sgad        memcpy(low_level_loc + 0x180, (void*)cvmx_interrupt_stage1, 0x80);
1174129914Sgad        memcpy(low_level_loc + 0x200, (void*)cvmx_interrupt_stage1, 0x80);
11751556Srgrimes
11761556Srgrimes        /* Make sure the locations used to count Icache and Dcache exceptions
11771556Srgrimes            starts out as zero */
11781556Srgrimes        cvmx_write64_uint64(CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, 8), 0);
1179137696Scsjp        cvmx_write64_uint64(CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, 16), 0);
1180137696Scsjp        cvmx_write64_uint64(CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, 24), 0);
1181137696Scsjp        CVMX_SYNC;
1182137890Scsjp
1183137696Scsjp        /* Add an interrupt handler for ECC failures */
1184137890Scsjp        if (cvmx_error_initialize(0 /* || CVMX_ERROR_FLAGS_ECC_SINGLE_BIT */))
1185137890Scsjp            cvmx_warn("cvmx_error_initialize() failed\n");
1186137890Scsjp
1187137890Scsjp        /* Enable PIP/IPD, POW, PKO, FPA, NAND, KEY, RAD, L2C, LMC, GMX, AGL,
1188137890Scsjp           DFM, DFA, error handling interrupts. */
1189137696Scsjp        if (OCTEON_IS_MODEL(OCTEON_CN68XX))
1190137696Scsjp        {
11911556Srgrimes            int i;
119290110Simp
11931556Srgrimes            for (i = 0; i < 5; i++)
1194141578Sru            {
11951556Srgrimes                cvmx_interrupt_register(CVMX_IRQ_AGX0+i, __cvmx_interrupt_ecc, NULL);
1196127499Sgad                cvmx_interrupt_unmask_irq(CVMX_IRQ_AGX0+i);
1197141578Sru            }
1198127499Sgad            cvmx_interrupt_register(CVMX_IRQ_NAND, __cvmx_interrupt_ecc, NULL);
1199141578Sru            cvmx_interrupt_unmask_irq(CVMX_IRQ_NAND);
120026465Scharnier            cvmx_interrupt_register(CVMX_IRQ_MIO, __cvmx_interrupt_ecc, NULL);
12011556Srgrimes            cvmx_interrupt_unmask_irq(CVMX_IRQ_MIO);
12021556Srgrimes            cvmx_interrupt_register(CVMX_IRQ_FPA, __cvmx_interrupt_ecc, NULL);
1203            cvmx_interrupt_unmask_irq(CVMX_IRQ_FPA);
1204            cvmx_interrupt_register(CVMX_IRQ_IPD, __cvmx_interrupt_ecc, NULL);
1205            cvmx_interrupt_unmask_irq(CVMX_IRQ_IPD);
1206            cvmx_interrupt_register(CVMX_IRQ_PIP, __cvmx_interrupt_ecc, NULL);
1207            cvmx_interrupt_unmask_irq(CVMX_IRQ_PIP);
1208            cvmx_interrupt_register(CVMX_IRQ_POW, __cvmx_interrupt_ecc, NULL);
1209            cvmx_interrupt_unmask_irq(CVMX_IRQ_POW);
1210            cvmx_interrupt_register(CVMX_IRQ_L2C, __cvmx_interrupt_ecc, NULL);
1211            cvmx_interrupt_unmask_irq(CVMX_IRQ_L2C);
1212            cvmx_interrupt_register(CVMX_IRQ_PKO, __cvmx_interrupt_ecc, NULL);
1213            cvmx_interrupt_unmask_irq(CVMX_IRQ_PKO);
1214            cvmx_interrupt_register(CVMX_IRQ_ZIP, __cvmx_interrupt_ecc, NULL);
1215            cvmx_interrupt_unmask_irq(CVMX_IRQ_ZIP);
1216            cvmx_interrupt_register(CVMX_IRQ_RAD, __cvmx_interrupt_ecc, NULL);
1217            cvmx_interrupt_unmask_irq(CVMX_IRQ_RAD);
1218            cvmx_interrupt_register(CVMX_IRQ_KEY, __cvmx_interrupt_ecc, NULL);
1219            cvmx_interrupt_unmask_irq(CVMX_IRQ_KEY);
1220            /* Before enabling SLI interrupt clear any RML_TO interrupt */
1221            if (cvmx_read_csr(CVMX_PEXP_SLI_INT_SUM) & 0x1)
1222            {
1223                cvmx_safe_printf("clearing pending SLI_INT_SUM[RML_TO] interrupt (ignore)\n");
1224                cvmx_write_csr(CVMX_PEXP_SLI_INT_SUM, 1);
1225            }
1226            cvmx_interrupt_register(CVMX_IRQ_SLI, __cvmx_interrupt_ecc, NULL);
1227            cvmx_interrupt_unmask_irq(CVMX_IRQ_SLI);
1228            cvmx_interrupt_register(CVMX_IRQ_DPI, __cvmx_interrupt_ecc, NULL);
1229            cvmx_interrupt_unmask_irq(CVMX_IRQ_DPI);
1230            cvmx_interrupt_register(CVMX_IRQ_DFA, __cvmx_interrupt_ecc, NULL);
1231            cvmx_interrupt_unmask_irq(CVMX_IRQ_DFA);
1232            cvmx_interrupt_register(CVMX_IRQ_AGL, __cvmx_interrupt_ecc, NULL);
1233            cvmx_interrupt_unmask_irq(CVMX_IRQ_AGL);
1234            for (i = 0; i < 4; i++)
1235            {
1236                cvmx_interrupt_register(CVMX_IRQ_LMC0+i, __cvmx_interrupt_ecc, NULL);
1237                cvmx_interrupt_unmask_irq(CVMX_IRQ_LMC0+i);
1238            }
1239            cvmx_interrupt_register(CVMX_IRQ_DFM, __cvmx_interrupt_ecc, NULL);
1240            cvmx_interrupt_unmask_irq(CVMX_IRQ_DFM);
1241            cvmx_interrupt_register(CVMX_IRQ_RST, __cvmx_interrupt_ecc, NULL);
1242            cvmx_interrupt_unmask_irq(CVMX_IRQ_RST);
1243            cvmx_interrupt_register(CVMX_IRQ_ILK, __cvmx_interrupt_ecc, NULL);
1244            cvmx_interrupt_unmask_irq(CVMX_IRQ_ILK);
1245        }
1246        else
1247        {
1248            cvmx_interrupt_register(CVMX_IRQ_RML, __cvmx_interrupt_ecc, NULL);
1249            cvmx_interrupt_unmask_irq(CVMX_IRQ_RML);
1250        }
1251
1252        cvmx_atomic_set32(&cvmx_interrupt_initialize_flag, 1);
1253    }
1254
1255    while (!cvmx_atomic_get32(&cvmx_interrupt_initialize_flag))
1256        ; /* Wait for first core to finish above. */
1257
1258    if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
1259        cvmx_interrupt_unmask_irq(CVMX_IRQ_MIPS2);
1260    } else {
1261        cvmx_interrupt_unmask_irq(CVMX_IRQ_MIPS2);
1262        cvmx_interrupt_unmask_irq(CVMX_IRQ_MIPS3);
1263    }
1264
1265    CVMX_ICACHE_INVALIDATE;
1266
1267    /* Enable interrupts for each core (bit0 of COP0 Status) */
1268    cvmx_interrupt_restore(1);
1269}
1270
1271
1272
1273/**
1274 * Set the exception handler for all non interrupt sources.
1275 *
1276 * @param handler New exception handler
1277 * @return Old exception handler
1278 */
1279cvmx_interrupt_exception_t cvmx_interrupt_set_exception(cvmx_interrupt_exception_t handler)
1280{
1281    cvmx_interrupt_exception_t result = cvmx_interrupt_state.exception_handler;
1282    cvmx_interrupt_state.exception_handler = handler;
1283    CVMX_SYNCWS;
1284    return result;
1285}
1286#endif /* !__U_BOOT__ */
1287
1288
1289