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