1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17215990Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22215990Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27215990Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38210284Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett/** 41210284Sjmallett * @file 42210284Sjmallett * 43210284Sjmallett * Interface to the Mips interrupts. 44210284Sjmallett * 45232812Sjmallett * <hr>$Revision: 70030 $<hr> 46210284Sjmallett */ 47215990Sjmallett#ifndef __U_BOOT__ 48210284Sjmallett#if __GNUC__ >= 4 49210284Sjmallett/* Backtrace is only available with the new toolchain. */ 50210284Sjmallett#include <execinfo.h> 51210284Sjmallett#endif 52215990Sjmallett#endif /* __U_BOOT__ */ 53210284Sjmallett#include "cvmx-config.h" 54210284Sjmallett#include "cvmx.h" 55210284Sjmallett#include "cvmx-interrupt.h" 56210284Sjmallett#include "cvmx-sysinfo.h" 57210284Sjmallett#include "cvmx-uart.h" 58210284Sjmallett#include "cvmx-pow.h" 59210284Sjmallett#include "cvmx-ebt3000.h" 60210284Sjmallett#include "cvmx-coremask.h" 61210284Sjmallett#include "cvmx-spinlock.h" 62232812Sjmallett#include "cvmx-atomic.h" 63210284Sjmallett#include "cvmx-app-init.h" 64215990Sjmallett#include "cvmx-error.h" 65232812Sjmallett#include "cvmx-app-hotplug.h" 66232812Sjmallett#include "cvmx-profiler.h" 67232812Sjmallett#ifndef __U_BOOT__ 68232812Sjmallett# include <octeon_mem_map.h> 69232812Sjmallett#else 70232812Sjmallett# include <asm/arch/octeon_mem_map.h> 71232812Sjmallett#endif 72210284SjmallettEXTERN_ASM void cvmx_interrupt_stage1(void); 73215990SjmallettEXTERN_ASM void cvmx_debug_handler_stage1(void); 74210284SjmallettEXTERN_ASM void cvmx_interrupt_cache_error(void); 75210284Sjmallett 76215990Sjmallettint cvmx_interrupt_in_isr = 0; 77215990Sjmallett 78232812Sjmallettstruct __cvmx_interrupt_handler { 79232812Sjmallett cvmx_interrupt_func_t handler; /**< One function to call per interrupt */ 80232812Sjmallett void *data; /**< User data per interrupt */ 81232812Sjmallett int handler_data; /**< Used internally */ 82232812Sjmallett}; 83232812Sjmallett 84210284Sjmallett/** 85210284Sjmallett * Internal status the interrupt registration 86210284Sjmallett */ 87210284Sjmalletttypedef struct 88210284Sjmallett{ 89232812Sjmallett struct __cvmx_interrupt_handler handlers[CVMX_IRQ_MAX]; 90210284Sjmallett cvmx_interrupt_exception_t exception_handler; 91210284Sjmallett} cvmx_interrupt_state_t; 92210284Sjmallett 93210284Sjmallett/** 94210284Sjmallett * Internal state the interrupt registration 95210284Sjmallett */ 96215990Sjmallett#ifndef __U_BOOT__ 97210284Sjmallettstatic CVMX_SHARED cvmx_interrupt_state_t cvmx_interrupt_state; 98210284Sjmallettstatic CVMX_SHARED cvmx_spinlock_t cvmx_interrupt_default_lock; 99232812Sjmallett/* Incremented once first core processing is finished. */ 100232812Sjmallettstatic CVMX_SHARED int32_t cvmx_interrupt_initialize_flag; 101215990Sjmallett#endif /* __U_BOOT__ */ 102210284Sjmallett 103210284Sjmallett#define ULL unsigned long long 104210284Sjmallett 105232812Sjmallett#define HI32(data64) ((uint32_t)(data64 >> 32)) 106232812Sjmallett#define LO32(data64) ((uint32_t)(data64 & 0xFFFFFFFF)) 107210284Sjmallett 108215990Sjmallettstatic const char reg_names[][32] = { "r0","at","v0","v1","a0","a1","a2","a3", 109215990Sjmallett "t0","t1","t2","t3","t4","t5","t6","t7", 110215990Sjmallett "s0","s1","s2","s3","s4","s5", "s6","s7", 111215990Sjmallett "t8","t9", "k0","k1","gp","sp","s8","ra" }; 112210284Sjmallett 113210284Sjmallett/** 114215990Sjmallett * version of printf that works better in exception context. 115215990Sjmallett * 116215990Sjmallett * @param format 117215990Sjmallett */ 118215990Sjmallettvoid cvmx_safe_printf(const char *format, ...) 119215990Sjmallett{ 120215990Sjmallett char buffer[256]; 121215990Sjmallett char *ptr = buffer; 122215990Sjmallett int count; 123215990Sjmallett va_list args; 124215990Sjmallett 125215990Sjmallett va_start(args, format); 126215990Sjmallett#ifndef __U_BOOT__ 127215990Sjmallett count = vsnprintf(buffer, sizeof(buffer), format, args); 128215990Sjmallett#else 129215990Sjmallett count = vsprintf(buffer, format, args); 130215990Sjmallett#endif 131215990Sjmallett va_end(args); 132215990Sjmallett 133215990Sjmallett while (count-- > 0) 134215990Sjmallett { 135215990Sjmallett cvmx_uart_lsr_t lsrval; 136215990Sjmallett 137215990Sjmallett /* Spin until there is room */ 138215990Sjmallett do 139215990Sjmallett { 140215990Sjmallett lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0)); 141215990Sjmallett#if !defined(CONFIG_OCTEON_SIM_SPEED) 142215990Sjmallett if (lsrval.s.temt == 0) 143215990Sjmallett cvmx_wait(10000); /* Just to reduce the load on the system */ 144215990Sjmallett#endif 145215990Sjmallett } 146215990Sjmallett while (lsrval.s.temt == 0); 147215990Sjmallett 148215990Sjmallett if (*ptr == '\n') 149215990Sjmallett cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r'); 150215990Sjmallett cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++); 151215990Sjmallett } 152215990Sjmallett} 153215990Sjmallett 154215990Sjmallett/* Textual descriptions of cause codes */ 155215990Sjmallettstatic const char cause_names[][128] = { 156215990Sjmallett /* 0 */ "Interrupt", 157215990Sjmallett /* 1 */ "TLB modification", 158215990Sjmallett /* 2 */ "tlb load/fetch", 159215990Sjmallett /* 3 */ "tlb store", 160215990Sjmallett /* 4 */ "address exc, load/fetch", 161215990Sjmallett /* 5 */ "address exc, store", 162215990Sjmallett /* 6 */ "bus error, instruction fetch", 163215990Sjmallett /* 7 */ "bus error, load/store", 164215990Sjmallett /* 8 */ "syscall", 165215990Sjmallett /* 9 */ "breakpoint", 166215990Sjmallett /* 10 */ "reserved instruction", 167215990Sjmallett /* 11 */ "cop unusable", 168215990Sjmallett /* 12 */ "arithmetic overflow", 169215990Sjmallett /* 13 */ "trap", 170215990Sjmallett /* 14 */ "", 171215990Sjmallett /* 15 */ "floating point exc", 172215990Sjmallett /* 16 */ "", 173215990Sjmallett /* 17 */ "", 174215990Sjmallett /* 18 */ "cop2 exception", 175215990Sjmallett /* 19 */ "", 176215990Sjmallett /* 20 */ "", 177215990Sjmallett /* 21 */ "", 178215990Sjmallett /* 22 */ "mdmx unusable", 179215990Sjmallett /* 23 */ "watch", 180215990Sjmallett /* 24 */ "machine check", 181215990Sjmallett /* 25 */ "", 182215990Sjmallett /* 26 */ "", 183215990Sjmallett /* 27 */ "", 184215990Sjmallett /* 28 */ "", 185215990Sjmallett /* 29 */ "", 186215990Sjmallett /* 30 */ "cache error", 187215990Sjmallett /* 31 */ "" 188215990Sjmallett}; 189215990Sjmallett 190215990Sjmallett/** 191210284Sjmallett * @INTERNAL 192215990Sjmallett * print_reg64 193215990Sjmallett * @param name Name of the value to print 194215990Sjmallett * @param reg Value to print 195215990Sjmallett */ 196215990Sjmallettstatic inline void print_reg64(const char *name, uint64_t reg) 197215990Sjmallett{ 198215990Sjmallett cvmx_safe_printf("%16s: 0x%08x%08x\n", name, (unsigned int)HI32(reg),(unsigned int)LO32(reg)); 199215990Sjmallett} 200215990Sjmallett 201215990Sjmallett/** 202215990Sjmallett * @INTERNAL 203210284Sjmallett * Dump all useful registers to the console 204210284Sjmallett * 205210284Sjmallett * @param registers CPU register to dump 206210284Sjmallett */ 207232812Sjmallettstatic void __cvmx_interrupt_dump_registers(uint64_t *registers) 208210284Sjmallett{ 209215990Sjmallett uint64_t r1, r2; 210215990Sjmallett int reg; 211210284Sjmallett for (reg=0; reg<16; reg++) 212210284Sjmallett { 213215990Sjmallett r1 = registers[reg]; r2 = registers[reg+16]; 214215990Sjmallett cvmx_safe_printf("%3s ($%02d): 0x%08x%08x \t %3s ($%02d): 0x%08x%08x\n", 215215990Sjmallett reg_names[reg], reg, (unsigned int)HI32(r1), (unsigned int)LO32(r1), 216215990Sjmallett reg_names[reg+16], reg+16, (unsigned int)HI32(r2), (unsigned int)LO32(r2)); 217210284Sjmallett } 218215990Sjmallett CVMX_MF_COP0 (r1, COP0_CAUSE); 219215990Sjmallett print_reg64 ("COP0_CAUSE", r1); 220215990Sjmallett CVMX_MF_COP0 (r2, COP0_STATUS); 221215990Sjmallett print_reg64 ("COP0_STATUS", r2); 222215990Sjmallett CVMX_MF_COP0 (r1, COP0_BADVADDR); 223215990Sjmallett print_reg64 ("COP0_BADVADDR", r1); 224215990Sjmallett CVMX_MF_COP0 (r2, COP0_EPC); 225215990Sjmallett print_reg64 ("COP0_EPC", r2); 226210284Sjmallett} 227210284Sjmallett 228210284Sjmallett/** 229210284Sjmallett * @INTERNAL 230210284Sjmallett * Default exception handler. Prints out the exception 231210284Sjmallett * cause decode and all relevant registers. 232210284Sjmallett * 233210284Sjmallett * @param registers Registers at time of the exception 234210284Sjmallett */ 235215990Sjmallett#ifndef __U_BOOT__ 236215990Sjmallettstatic 237215990Sjmallett#endif /* __U_BOOT__ */ 238232812Sjmallettvoid __cvmx_interrupt_default_exception_handler(uint64_t *registers) 239210284Sjmallett{ 240210284Sjmallett uint64_t trap_print_cause; 241215990Sjmallett const char *str; 242232812Sjmallett#ifndef __U_BOOT__ 243232812Sjmallett int modified_zero_pc = 0; 244210284Sjmallett 245210284Sjmallett ebt3000_str_write("Trap"); 246210284Sjmallett cvmx_spinlock_lock(&cvmx_interrupt_default_lock); 247215990Sjmallett#endif 248215990Sjmallett CVMX_MF_COP0 (trap_print_cause, COP0_CAUSE); 249215990Sjmallett str = cause_names [(trap_print_cause >> 2) & 0x1f]; 250215990Sjmallett 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"); 251210284Sjmallett cvmx_safe_printf("******************************************************************\n"); 252215990Sjmallett __cvmx_interrupt_dump_registers(registers); 253210284Sjmallett 254215990Sjmallett#ifndef __U_BOOT__ 255210284Sjmallett 256210284Sjmallett cvmx_safe_printf("******************************************************************\n"); 257210284Sjmallett#if __GNUC__ >= 4 && !defined(OCTEON_DISABLE_BACKTRACE) 258210284Sjmallett cvmx_safe_printf("Backtrace:\n\n"); 259232812Sjmallett if (registers[35] == 0) { 260232812Sjmallett modified_zero_pc = 1; 261232812Sjmallett /* If PC is zero we probably did jalr $zero, in which case $31 - 8 is the call site. */ 262232812Sjmallett registers[35] = registers[31] - 8; 263232812Sjmallett } 264210284Sjmallett __octeon_print_backtrace_func ((__octeon_backtrace_printf_t)cvmx_safe_printf); 265232812Sjmallett if (modified_zero_pc) 266232812Sjmallett registers[35] = 0; 267210284Sjmallett cvmx_safe_printf("******************************************************************\n"); 268210284Sjmallett#endif 269210284Sjmallett 270210284Sjmallett cvmx_spinlock_unlock(&cvmx_interrupt_default_lock); 271210284Sjmallett 272210284Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 273232812Sjmallett CVMX_BREAK; 274210284Sjmallett 275210284Sjmallett while (1) 276210284Sjmallett { 277232812Sjmallett /* Interrupts are suppressed when we are in the exception 278232812Sjmallett handler (because of SR[EXL]). Spin and poll the uart 279232812Sjmallett status and see if the debugger is trying to stop us. */ 280232812Sjmallett cvmx_uart_lsr_t lsrval; 281232812Sjmallett lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(cvmx_debug_uart)); 282232812Sjmallett if (lsrval.s.dr) 283232812Sjmallett { 284232812Sjmallett uint64_t tmp; 285232812Sjmallett /* Pulse the MCD0 signal. */ 286232812Sjmallett asm volatile ( 287232812Sjmallett ".set push\n" 288232812Sjmallett ".set noreorder\n" 289232812Sjmallett ".set mips64\n" 290232812Sjmallett "dmfc0 %0, $22\n" 291232812Sjmallett "ori %0, %0, 0x10\n" 292232812Sjmallett "dmtc0 %0, $22\n" 293232812Sjmallett ".set pop\n" 294232812Sjmallett : "=r" (tmp)); 295232812Sjmallett } 296210284Sjmallett } 297215990Sjmallett#endif /* __U_BOOT__ */ 298210284Sjmallett} 299210284Sjmallett 300215990Sjmallett#ifndef __U_BOOT__ 301210284Sjmallett/** 302210284Sjmallett * @INTERNAL 303210284Sjmallett * Default interrupt handler if the user doesn't register one. 304210284Sjmallett * 305210284Sjmallett * @param irq_number IRQ that caused this interrupt 306210284Sjmallett * @param registers Register at the time of the interrupt 307210284Sjmallett * @param user_arg Unused optional user data 308210284Sjmallett */ 309232812Sjmallettstatic void __cvmx_interrupt_default(int irq_number, uint64_t *registers, void *user_arg) 310210284Sjmallett{ 311210284Sjmallett cvmx_safe_printf("cvmx_interrupt_default: Received interrupt %d\n", irq_number); 312210284Sjmallett __cvmx_interrupt_dump_registers(registers); 313210284Sjmallett} 314210284Sjmallett 315232812Sjmallett/** 316232812Sjmallett * Map a ciu bit to an irq number. 0xff for invalid. 317232812Sjmallett * 0-63 for en0. 318232812Sjmallett * 64-127 for en1. 319232812Sjmallett */ 320210284Sjmallett 321232812Sjmallettstatic CVMX_SHARED uint8_t cvmx_ciu_to_irq[8][64]; 322232812Sjmallett#define cvmx_ciu_en0_to_irq cvmx_ciu_to_irq[0] 323232812Sjmallett#define cvmx_ciu_en1_to_irq cvmx_ciu_to_irq[1] 324232812Sjmallett#define cvmx_ciu2_wrkq_to_irq cvmx_ciu_to_irq[0] 325232812Sjmallett#define cvmx_ciu2_wdog_to_irq cvmx_ciu_to_irq[1] 326232812Sjmallett#define cvmx_ciu2_rml_to_irq cvmx_ciu_to_irq[2] 327232812Sjmallett#define cvmx_ciu2_mio_to_irq cvmx_ciu_to_irq[3] 328232812Sjmallett#define cvmx_ciu2_io_to_irq cvmx_ciu_to_irq[4] 329232812Sjmallett#define cvmx_ciu2_mem_to_irq cvmx_ciu_to_irq[5] 330232812Sjmallett#define cvmx_ciu2_eth_to_irq cvmx_ciu_to_irq[6] 331232812Sjmallett#define cvmx_ciu2_gpio_to_irq cvmx_ciu_to_irq[7] 332232812Sjmallett 333232812Sjmallettstatic CVMX_SHARED uint8_t cvmx_ciu2_mbox_to_irq[64]; 334232812Sjmallettstatic CVMX_SHARED uint8_t cvmx_ciu_61xx_timer_to_irq[64]; 335232812Sjmallett 336232812Sjmallettstatic void __cvmx_interrupt_set_mapping(int irq, unsigned int en, unsigned int bit) 337232812Sjmallett{ 338232812Sjmallett cvmx_interrupt_state.handlers[irq].handler_data = (en << 6) | bit; 339232812Sjmallett if (en <= 7) 340232812Sjmallett cvmx_ciu_to_irq[en][bit] = irq; 341232812Sjmallett else if (en == 8) 342232812Sjmallett cvmx_ciu_61xx_timer_to_irq[bit] = irq; 343232812Sjmallett else 344232812Sjmallett cvmx_ciu2_mbox_to_irq[bit] = irq; 345232812Sjmallett} 346232812Sjmallett 347232812Sjmallettstatic uint64_t cvmx_interrupt_ciu_en0_mirror; 348232812Sjmallettstatic uint64_t cvmx_interrupt_ciu_en1_mirror; 349232812Sjmallettstatic uint64_t cvmx_interrupt_ciu_61xx_timer_mirror; 350232812Sjmallett 351210284Sjmallett/** 352210284Sjmallett * @INTERNAL 353232812Sjmallett * Called for all Performance Counter interrupts. Handler for 354232812Sjmallett * interrupt line 6 355232812Sjmallett * 356232812Sjmallett * @param irq_number Interrupt number that we're being called for 357232812Sjmallett * @param registers Registers at the time of the interrupt 358232812Sjmallett * @param user_arg Unused user argument* 359232812Sjmallett */ 360232812Sjmallettstatic void __cvmx_interrupt_perf(int irq_number, uint64_t *registers, void *user_arg) 361232812Sjmallett{ 362232812Sjmallett uint64_t perf_counter; 363232812Sjmallett CVMX_MF_COP0(perf_counter, COP0_PERFVALUE0); 364232812Sjmallett if (perf_counter & (1ull << 63)) 365232812Sjmallett cvmx_collect_sample(); 366232812Sjmallett} 367232812Sjmallett 368232812Sjmallett/** 369232812Sjmallett * @INTERNAL 370210284Sjmallett * Handler for interrupt lines 2 and 3. These are directly tied 371232812Sjmallett * to the CIU. The handler queries the status of the CIU and 372210284Sjmallett * calls the secondary handler for the CIU interrupt that 373210284Sjmallett * occurred. 374210284Sjmallett * 375210284Sjmallett * @param irq_number Interrupt number that fired (2 or 3) 376210284Sjmallett * @param registers Registers at the time of the interrupt 377210284Sjmallett * @param user_arg Unused user argument 378210284Sjmallett */ 379232812Sjmallettstatic void __cvmx_interrupt_ciu(int irq_number, uint64_t *registers, void *user_arg) 380210284Sjmallett{ 381232812Sjmallett int ciu_offset; 382232812Sjmallett uint64_t irq_mask; 383232812Sjmallett uint64_t irq; 384232812Sjmallett int bit; 385232812Sjmallett int core = cvmx_get_core_num(); 386210284Sjmallett 387232812Sjmallett if (irq_number == CVMX_IRQ_MIPS2) { 388232812Sjmallett /* Handle EN0 sources */ 389232812Sjmallett ciu_offset = core * 2; 390232812Sjmallett irq_mask = cvmx_read_csr(CVMX_CIU_INTX_SUM0(ciu_offset)) & cvmx_interrupt_ciu_en0_mirror; 391232812Sjmallett CVMX_DCLZ(bit, irq_mask); 392232812Sjmallett bit = 63 - bit; 393232812Sjmallett /* If ciu_int_sum1<sum2> is set, means its a timer interrupt */ 394232812Sjmallett if (bit == 51 && (OCTEON_IS_MODEL(OCTEON_CN61XX) || OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_2))) { 395232812Sjmallett uint64_t irq_mask; 396232812Sjmallett int bit; 397232812Sjmallett irq_mask = cvmx_read_csr(CVMX_CIU_SUM2_PPX_IP2(core)) & cvmx_interrupt_ciu_61xx_timer_mirror; 398232812Sjmallett CVMX_DCLZ(bit, irq_mask); 399232812Sjmallett bit = 63 - bit; 400232812Sjmallett /* Handle TIMER(4..9) interrupts */ 401232812Sjmallett if (bit <= 9 && bit >= 4) { 402232812Sjmallett uint64_t irq = cvmx_ciu_61xx_timer_to_irq[bit]; 403232812Sjmallett if (cvmx_unlikely(irq == 0xff)) { 404232812Sjmallett /* No mapping */ 405232812Sjmallett cvmx_interrupt_ciu_61xx_timer_mirror &= ~(1ull << bit); 406232812Sjmallett cvmx_write_csr(CVMX_CIU_EN2_PPX_IP2(core), cvmx_interrupt_ciu_61xx_timer_mirror); 407232812Sjmallett return; 408232812Sjmallett } 409232812Sjmallett struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + irq; 410232812Sjmallett h->handler(irq, registers, h->data); 411232812Sjmallett return; 412232812Sjmallett } 413232812Sjmallett } 414232812Sjmallett 415232812Sjmallett if (bit >= 0) { 416232812Sjmallett irq = cvmx_ciu_en0_to_irq[bit]; 417232812Sjmallett if (cvmx_unlikely(irq == 0xff)) { 418232812Sjmallett /* No mapping. */ 419232812Sjmallett cvmx_interrupt_ciu_en0_mirror &= ~(1ull << bit); 420232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(ciu_offset), cvmx_interrupt_ciu_en0_mirror); 421232812Sjmallett return; 422232812Sjmallett } 423232812Sjmallett struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + irq; 424232812Sjmallett h->handler(irq, registers, h->data); 425210284Sjmallett return; 426210284Sjmallett } 427232812Sjmallett } else { 428232812Sjmallett /* Handle EN1 sources */ 429232812Sjmallett ciu_offset = cvmx_get_core_num() * 2 + 1; 430232812Sjmallett irq_mask = cvmx_read_csr(CVMX_CIU_INT_SUM1) & cvmx_interrupt_ciu_en1_mirror; 431232812Sjmallett CVMX_DCLZ(bit, irq_mask); 432232812Sjmallett bit = 63 - bit; 433232812Sjmallett if (bit >= 0) { 434232812Sjmallett irq = cvmx_ciu_en1_to_irq[bit]; 435232812Sjmallett if (cvmx_unlikely(irq == 0xff)) { 436232812Sjmallett /* No mapping. */ 437232812Sjmallett cvmx_interrupt_ciu_en1_mirror &= ~(1ull << bit); 438232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN1(ciu_offset), cvmx_interrupt_ciu_en1_mirror); 439232812Sjmallett return; 440232812Sjmallett } 441232812Sjmallett struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + irq; 442232812Sjmallett h->handler(irq, registers, h->data); 443232812Sjmallett return; 444232812Sjmallett } 445210284Sjmallett } 446232812Sjmallett} 447210284Sjmallett 448232812Sjmallett/** 449232812Sjmallett * @INTERNAL 450232812Sjmallett * Handler for interrupt line 3, the DPI_DMA will have different value 451232812Sjmallett * per core, all other fields values are identical for different cores. 452232812Sjmallett * These are directly tied to the CIU. The handler queries the status of 453232812Sjmallett * the CIU and calls the secondary handler for the CIU interrupt that 454232812Sjmallett * occurred. 455232812Sjmallett * 456232812Sjmallett * @param irq_number Interrupt number that fired (2 or 3) 457232812Sjmallett * @param registers Registers at the time of the interrupt 458232812Sjmallett * @param user_arg Unused user argument 459232812Sjmallett */ 460232812Sjmallettstatic void __cvmx_interrupt_ciu_cn61xx(int irq_number, uint64_t *registers, void *user_arg) 461232812Sjmallett{ 462210284Sjmallett /* Handle EN1 sources */ 463232812Sjmallett int core = cvmx_get_core_num(); 464232812Sjmallett int ciu_offset; 465232812Sjmallett uint64_t irq_mask; 466232812Sjmallett uint64_t irq; 467232812Sjmallett int bit; 468232812Sjmallett 469232812Sjmallett ciu_offset = core * 2 + 1; 470232812Sjmallett irq_mask = cvmx_read_csr(CVMX_CIU_SUM1_PPX_IP3(core)) & cvmx_interrupt_ciu_en1_mirror; 471232812Sjmallett CVMX_DCLZ(bit, irq_mask); 472232812Sjmallett bit = 63 - bit; 473232812Sjmallett if (bit >= 0) { 474232812Sjmallett irq = cvmx_ciu_en1_to_irq[bit]; 475232812Sjmallett if (cvmx_unlikely(irq == 0xff)) { 476232812Sjmallett /* No mapping. */ 477232812Sjmallett cvmx_interrupt_ciu_en1_mirror &= ~(1ull << bit); 478232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN1(ciu_offset), cvmx_interrupt_ciu_en1_mirror); 479210284Sjmallett return; 480210284Sjmallett } 481232812Sjmallett struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + irq; 482232812Sjmallett h->handler(irq, registers, h->data); 483232812Sjmallett return; 484210284Sjmallett } 485210284Sjmallett} 486210284Sjmallett 487232812Sjmallett/** 488232812Sjmallett * @INTERNAL 489232812Sjmallett * Handler for interrupt line 2 on 68XX. These are directly tied 490232812Sjmallett * to the CIU2. The handler queries the status of the CIU and 491232812Sjmallett * calls the secondary handler for the CIU interrupt that 492232812Sjmallett * occurred. 493232812Sjmallett * 494232812Sjmallett * @param irq_number Interrupt number that fired (2 or 3) 495232812Sjmallett * @param registers Registers at the time of the interrupt 496232812Sjmallett * @param user_arg Unused user argument 497232812Sjmallett */ 498232812Sjmallettstatic void __cvmx_interrupt_ciu2(int irq_number, uint64_t *registers, void *user_arg) 499232812Sjmallett{ 500232812Sjmallett int sum_bit, src_bit; 501232812Sjmallett uint64_t irq; 502232812Sjmallett uint64_t src_reg, src_val; 503232812Sjmallett struct __cvmx_interrupt_handler *h; 504232812Sjmallett int core = cvmx_get_core_num(); 505232812Sjmallett uint64_t sum = cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP2(core)); 506210284Sjmallett 507232812Sjmallett CVMX_DCLZ(sum_bit, sum); 508232812Sjmallett sum_bit = 63 - sum_bit; 509232812Sjmallett 510232812Sjmallett if (sum_bit >= 0) { 511232812Sjmallett switch (sum_bit) { 512232812Sjmallett case 63: 513232812Sjmallett case 62: 514232812Sjmallett case 61: 515232812Sjmallett case 60: 516232812Sjmallett irq = cvmx_ciu2_mbox_to_irq[sum_bit - 60]; 517232812Sjmallett if (cvmx_unlikely(irq == 0xff)) { 518232812Sjmallett /* No mapping. */ 519232812Sjmallett uint64_t mask_reg = CVMX_CIU2_EN_PPX_IP2_MBOX_W1C(core); 520232812Sjmallett cvmx_write_csr(mask_reg, 1ull << (sum_bit - 60)); 521232812Sjmallett break; 522232812Sjmallett } 523232812Sjmallett h = cvmx_interrupt_state.handlers + irq; 524232812Sjmallett h->handler(irq, registers, h->data); 525232812Sjmallett break; 526232812Sjmallett 527232812Sjmallett case 7: 528232812Sjmallett case 6: 529232812Sjmallett case 5: 530232812Sjmallett case 4: 531232812Sjmallett case 3: 532232812Sjmallett case 2: 533232812Sjmallett case 1: 534232812Sjmallett case 0: 535232812Sjmallett src_reg = CVMX_CIU2_SRC_PPX_IP2_WRKQ(core) + (0x1000 * sum_bit); 536232812Sjmallett src_val = cvmx_read_csr(src_reg); 537232812Sjmallett if (!src_val) 538232812Sjmallett break; 539232812Sjmallett CVMX_DCLZ(src_bit, src_val); 540232812Sjmallett src_bit = 63 - src_bit; 541232812Sjmallett irq = cvmx_ciu_to_irq[sum_bit][src_bit]; 542232812Sjmallett if (cvmx_unlikely(irq == 0xff)) { 543232812Sjmallett /* No mapping. */ 544232812Sjmallett uint64_t mask_reg = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(core) + (0x1000 * sum_bit); 545232812Sjmallett cvmx_write_csr(mask_reg, 1ull << src_bit); 546232812Sjmallett break; 547232812Sjmallett } 548232812Sjmallett h = cvmx_interrupt_state.handlers + irq; 549232812Sjmallett h->handler(irq, registers, h->data); 550232812Sjmallett break; 551232812Sjmallett 552232812Sjmallett default: 553232812Sjmallett cvmx_safe_printf("Unknown CIU2 bit: %d\n", sum_bit); 554232812Sjmallett break; 555232812Sjmallett } 556232812Sjmallett } 557232812Sjmallett /* Clear the source to reduce the chance for spurious interrupts. */ 558232812Sjmallett 559232812Sjmallett /* CN68XX has an CIU-15786 errata that accessing the ACK registers 560232812Sjmallett * can stop interrupts from propagating 561232812Sjmallett */ 562232812Sjmallett 563232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 564232812Sjmallett cvmx_read_csr(CVMX_CIU2_INTR_CIU_READY); 565232812Sjmallett else 566232812Sjmallett cvmx_read_csr(CVMX_CIU2_ACK_PPX_IP2(core)); 567232812Sjmallett} 568232812Sjmallett 569232812Sjmallett 570210284Sjmallett/** 571210284Sjmallett * @INTERNAL 572210284Sjmallett * Called for all RML interrupts. This is usually an ECC error 573210284Sjmallett * 574210284Sjmallett * @param irq_number Interrupt number that we're being called for 575210284Sjmallett * @param registers Registers at the time of the interrupt 576210284Sjmallett * @param user_arg Unused user argument 577210284Sjmallett */ 578232812Sjmallettstatic void __cvmx_interrupt_ecc(int irq_number, uint64_t *registers, void *user_arg) 579210284Sjmallett{ 580215990Sjmallett cvmx_error_poll(); 581210284Sjmallett} 582210284Sjmallett 583210284Sjmallett 584210284Sjmallett/** 585210284Sjmallett * Process an interrupt request 586210284Sjmallett * 587210284Sjmallett * @param registers Registers at time of interrupt / exception 588210284Sjmallett * Registers 0-31 are standard MIPS, others specific to this routine 589210284Sjmallett * @return 590210284Sjmallett */ 591232812Sjmallettvoid cvmx_interrupt_do_irq(uint64_t *registers); 592232812Sjmallettvoid cvmx_interrupt_do_irq(uint64_t *registers) 593210284Sjmallett{ 594210284Sjmallett uint64_t mask; 595210284Sjmallett uint64_t cause; 596210284Sjmallett uint64_t status; 597210284Sjmallett uint64_t cache_err; 598210284Sjmallett int i; 599210284Sjmallett uint32_t exc_vec; 600210284Sjmallett /* Determine the cause of the interrupt */ 601210284Sjmallett asm volatile ("dmfc0 %0,$13,0" : "=r" (cause)); 602210284Sjmallett asm volatile ("dmfc0 %0,$12,0" : "=r" (status)); 603215990Sjmallett /* In case of exception, clear all interrupts to avoid recursive interrupts. 604215990Sjmallett Also clear EXL bit to display the correct PC value. */ 605215990Sjmallett if ((cause & 0x7c) == 0) 606215990Sjmallett { 607215990Sjmallett asm volatile ("dmtc0 %0, $12, 0" : : "r" (status & ~(0xff02))); 608215990Sjmallett } 609210284Sjmallett /* The assembly stub at each exception vector saves its address in k1 when 610210284Sjmallett ** it calls the stage 2 handler. We use this to compute the exception vector 611210284Sjmallett ** that brought us here */ 612210284Sjmallett exc_vec = (uint32_t)(registers[27] & 0x780); /* Mask off bits we need to ignore */ 613210284Sjmallett 614210284Sjmallett /* Check for cache errors. The cache errors go to a separate exception vector, 615210284Sjmallett ** so we will only check these if we got here from a cache error exception, and 616210284Sjmallett ** the ERL (error level) bit is set. */ 617232812Sjmallett i = cvmx_get_core_num(); 618210284Sjmallett if (exc_vec == 0x100 && (status & 0x4)) 619210284Sjmallett { 620210284Sjmallett CVMX_MF_CACHE_ERR(cache_err); 621210284Sjmallett 622210284Sjmallett /* Use copy of DCACHE_ERR register that early exception stub read */ 623232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)) 624210284Sjmallett { 625232812Sjmallett if (registers[34] & 0x1) 626232812Sjmallett 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); 627232812Sjmallett else if (cache_err & 0x1) 628232812Sjmallett 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); 629232812Sjmallett else 630232812Sjmallett cvmx_safe_printf("Cache error exception: core %d\n", i); 631210284Sjmallett } 632232812Sjmallett else 633210284Sjmallett { 634232812Sjmallett if (registers[34] & 0x1) 635232812Sjmallett 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); 636232812Sjmallett else if (cache_err & 0x1) 637232812Sjmallett 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); 638232812Sjmallett else 639232812Sjmallett cvmx_safe_printf("Cache error exception: core %d\n", i); 640210284Sjmallett } 641232812Sjmallett CVMX_MT_DCACHE_ERR(1); 642232812Sjmallett CVMX_MT_CACHE_ERR(0); 643210284Sjmallett } 644210284Sjmallett 645232812Sjmallett /* The bus error exceptions can occur due to DID timeout or write buffer, 646232812Sjmallett check by reading COP0_CACHEERRD */ 647232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) 648232812Sjmallett { 649232812Sjmallett i = cvmx_get_core_num(); 650232812Sjmallett if (registers[34] & 0x4) 651232812Sjmallett { 652232812Sjmallett cvmx_safe_printf("Bus error detected due to DID timeout: core: %d\n", i); 653232812Sjmallett CVMX_MT_DCACHE_ERR(4); 654232812Sjmallett } 655232812Sjmallett else if (registers[34] & 0x2) 656232812Sjmallett { 657232812Sjmallett cvmx_safe_printf("Bus error detected due to write buffer parity: core: %d\n", i); 658232812Sjmallett CVMX_MT_DCACHE_ERR(2); 659232812Sjmallett } 660232812Sjmallett } 661232812Sjmallett 662210284Sjmallett if ((cause & 0x7c) != 0) 663210284Sjmallett { 664210284Sjmallett cvmx_interrupt_state.exception_handler(registers); 665215990Sjmallett goto return_from_interrupt; 666210284Sjmallett } 667210284Sjmallett 668210284Sjmallett /* Convert the cause into an active mask */ 669210284Sjmallett mask = ((cause & status) >> 8) & 0xff; 670210284Sjmallett if (mask == 0) 671215990Sjmallett { 672215990Sjmallett goto return_from_interrupt; /* Spurious interrupt */ 673215990Sjmallett } 674210284Sjmallett 675210284Sjmallett for (i=0; i<8; i++) 676210284Sjmallett { 677210284Sjmallett if (mask & (1<<i)) 678210284Sjmallett { 679232812Sjmallett struct __cvmx_interrupt_handler *h = cvmx_interrupt_state.handlers + i; 680232812Sjmallett h->handler(i, registers, h->data); 681215990Sjmallett goto return_from_interrupt; 682210284Sjmallett } 683210284Sjmallett } 684210284Sjmallett 685210284Sjmallett /* We should never get here */ 686210284Sjmallett __cvmx_interrupt_default_exception_handler(registers); 687215990Sjmallett 688215990Sjmallettreturn_from_interrupt: 689215990Sjmallett /* Restore Status register before returning from exception. */ 690215990Sjmallett asm volatile ("dmtc0 %0, $12, 0" : : "r" (status)); 691210284Sjmallett} 692210284Sjmallett 693232812Sjmallettvoid (*cvmx_interrupt_mask_irq)(int irq_number); 694232812Sjmallettvoid (*cvmx_interrupt_unmask_irq)(int irq_number); 695210284Sjmallett 696232812Sjmallett#define CLEAR_OR_MASK(V,M,O) ({\ 697232812Sjmallett if (O) \ 698232812Sjmallett (V) &= ~(M); \ 699232812Sjmallett else \ 700232812Sjmallett (V) |= (M); \ 701232812Sjmallett }) 702232812Sjmallett 703232812Sjmallettstatic void __cvmx_interrupt_ciu2_mask_unmask_irq(int irq_number, int op) 704232812Sjmallett{ 705232812Sjmallett 706232812Sjmallett if (irq_number < 0 || irq_number >= CVMX_IRQ_MAX) 707232812Sjmallett return; 708232812Sjmallett 709232812Sjmallett if (irq_number <= CVMX_IRQ_MIPS7) { 710232812Sjmallett uint32_t flags, mask; 711232812Sjmallett 712232812Sjmallett flags = cvmx_interrupt_disable_save(); 713232812Sjmallett asm volatile ("mfc0 %0,$12,0" : "=r" (mask)); 714232812Sjmallett CLEAR_OR_MASK(mask, 1 << (8 + irq_number), op); 715232812Sjmallett asm volatile ("mtc0 %0,$12,0" : : "r" (mask)); 716232812Sjmallett cvmx_interrupt_restore(flags); 717232812Sjmallett } else { 718232812Sjmallett int idx; 719232812Sjmallett uint64_t reg; 720232812Sjmallett int core = cvmx_get_core_num(); 721232812Sjmallett 722232812Sjmallett int bit = cvmx_interrupt_state.handlers[irq_number].handler_data; 723232812Sjmallett 724232812Sjmallett if (bit < 0) 725232812Sjmallett return; 726232812Sjmallett 727232812Sjmallett idx = bit >> 6; 728232812Sjmallett bit &= 0x3f; 729232812Sjmallett if (idx > 7) { 730232812Sjmallett /* MBOX */ 731232812Sjmallett if (op) 732232812Sjmallett reg = CVMX_CIU2_EN_PPX_IP2_MBOX_W1C(core); 733232812Sjmallett else 734232812Sjmallett reg = CVMX_CIU2_EN_PPX_IP2_MBOX_W1S(core); 735232812Sjmallett } else { 736232812Sjmallett if (op) 737232812Sjmallett reg = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(core) + (0x1000 * idx); 738232812Sjmallett else 739232812Sjmallett reg = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(core) + (0x1000 * idx); 740232812Sjmallett } 741232812Sjmallett cvmx_write_csr(reg, 1ull << bit); 742232812Sjmallett } 743232812Sjmallett} 744232812Sjmallett 745232812Sjmallettstatic void __cvmx_interrupt_ciu2_mask_irq(int irq_number) 746232812Sjmallett{ 747232812Sjmallett __cvmx_interrupt_ciu2_mask_unmask_irq(irq_number, 1); 748232812Sjmallett} 749232812Sjmallett 750232812Sjmallettstatic void __cvmx_interrupt_ciu2_unmask_irq(int irq_number) 751232812Sjmallett{ 752232812Sjmallett __cvmx_interrupt_ciu2_mask_unmask_irq(irq_number, 0); 753232812Sjmallett} 754232812Sjmallett 755232812Sjmallettstatic void __cvmx_interrupt_ciu_mask_unmask_irq(int irq_number, int op) 756232812Sjmallett{ 757232812Sjmallett uint32_t flags; 758232812Sjmallett 759232812Sjmallett if (irq_number < 0 || irq_number >= CVMX_IRQ_MAX) 760232812Sjmallett return; 761232812Sjmallett 762232812Sjmallett flags = cvmx_interrupt_disable_save(); 763232812Sjmallett if (irq_number <= CVMX_IRQ_MIPS7) { 764232812Sjmallett uint32_t mask; 765232812Sjmallett asm volatile ("mfc0 %0,$12,0" : "=r" (mask)); 766232812Sjmallett CLEAR_OR_MASK(mask, 1 << (8 + irq_number), op); 767232812Sjmallett asm volatile ("mtc0 %0,$12,0" : : "r" (mask)); 768232812Sjmallett } else { 769232812Sjmallett int ciu_bit, ciu_offset; 770232812Sjmallett int bit = cvmx_interrupt_state.handlers[irq_number].handler_data; 771232812Sjmallett int is_timer_intr = bit >> 6; 772232812Sjmallett int core = cvmx_get_core_num(); 773232812Sjmallett 774232812Sjmallett if (bit < 0) 775232812Sjmallett goto out; 776232812Sjmallett 777232812Sjmallett ciu_bit = bit & 0x3f; 778232812Sjmallett ciu_offset = core * 2; 779232812Sjmallett 780232812Sjmallett if (is_timer_intr == 8) 781232812Sjmallett { 782232812Sjmallett CLEAR_OR_MASK(cvmx_interrupt_ciu_61xx_timer_mirror, 1ull << ciu_bit, op); 783232812Sjmallett CLEAR_OR_MASK(cvmx_interrupt_ciu_en0_mirror, 1ull << 51, op); // SUM2 bit 784232812Sjmallett cvmx_write_csr(CVMX_CIU_EN2_PPX_IP2(core), cvmx_interrupt_ciu_61xx_timer_mirror); 785232812Sjmallett } 786232812Sjmallett else if (bit & 0x40) { 787232812Sjmallett /* EN1 */ 788232812Sjmallett ciu_offset += 1; 789232812Sjmallett CLEAR_OR_MASK(cvmx_interrupt_ciu_en1_mirror, 1ull << ciu_bit, op); 790232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN1(ciu_offset), cvmx_interrupt_ciu_en1_mirror); 791232812Sjmallett } else { 792232812Sjmallett /* EN0 */ 793232812Sjmallett CLEAR_OR_MASK(cvmx_interrupt_ciu_en0_mirror, 1ull << ciu_bit, op); 794232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(ciu_offset), cvmx_interrupt_ciu_en0_mirror); 795232812Sjmallett } 796232812Sjmallett } 797232812Sjmallettout: 798232812Sjmallett cvmx_interrupt_restore(flags); 799232812Sjmallett} 800232812Sjmallett 801232812Sjmallettstatic void __cvmx_interrupt_ciu_mask_irq(int irq_number) 802232812Sjmallett{ 803232812Sjmallett __cvmx_interrupt_ciu_mask_unmask_irq(irq_number, 1); 804232812Sjmallett} 805232812Sjmallett 806232812Sjmallettstatic void __cvmx_interrupt_ciu_unmask_irq(int irq_number) 807232812Sjmallett{ 808232812Sjmallett __cvmx_interrupt_ciu_mask_unmask_irq(irq_number, 0); 809232812Sjmallett} 810232812Sjmallett 811210284Sjmallett/** 812232812Sjmallett * Register an interrupt handler for the specified interrupt number. 813232812Sjmallett * 814232812Sjmallett * @param irq_number Interrupt number to register for See 815232812Sjmallett * cvmx-interrupt.h for enumeration and description of sources. 816232812Sjmallett * @param func Function to call on interrupt. 817232812Sjmallett * @param user_arg User data to pass to the interrupt handler 818232812Sjmallett */ 819232812Sjmallettvoid cvmx_interrupt_register(int irq_number, cvmx_interrupt_func_t func, void *user_arg) 820232812Sjmallett{ 821232812Sjmallett if (irq_number >= CVMX_IRQ_MAX || irq_number < 0) { 822232812Sjmallett cvmx_warn("cvmx_interrupt_register: Illegal irq_number %d\n", irq_number); 823232812Sjmallett return; 824232812Sjmallett } 825232812Sjmallett cvmx_interrupt_state.handlers[irq_number].handler = func; 826232812Sjmallett cvmx_interrupt_state.handlers[irq_number].data = user_arg; 827232812Sjmallett CVMX_SYNCWS; 828232812Sjmallett} 829232812Sjmallett 830232812Sjmallett 831232812Sjmallettstatic void cvmx_interrupt_ciu_initialize(cvmx_sysinfo_t *sys_info_ptr) 832232812Sjmallett{ 833232812Sjmallett int i; 834232812Sjmallett int core = cvmx_get_core_num(); 835232812Sjmallett 836232812Sjmallett /* Disable all CIU interrupts by default */ 837232812Sjmallett cvmx_interrupt_ciu_en0_mirror = 0; 838232812Sjmallett cvmx_interrupt_ciu_en1_mirror = 0; 839232812Sjmallett cvmx_interrupt_ciu_61xx_timer_mirror = 0; 840232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(core * 2), cvmx_interrupt_ciu_en0_mirror); 841232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0((core * 2)+1), cvmx_interrupt_ciu_en0_mirror); 842232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN1(core * 2), cvmx_interrupt_ciu_en1_mirror); 843232812Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN1((core * 2)+1), cvmx_interrupt_ciu_en1_mirror); 844232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN61XX) || OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_2)) 845232812Sjmallett cvmx_write_csr(CVMX_CIU_EN2_PPX_IP2(cvmx_get_core_num()), cvmx_interrupt_ciu_61xx_timer_mirror); 846232812Sjmallett 847232812Sjmallett if (!cvmx_coremask_first_core(sys_info_ptr->core_mask)|| is_core_being_hot_plugged()) 848232812Sjmallett return; 849232812Sjmallett 850232812Sjmallett /* On the first core, set up the maps */ 851232812Sjmallett for (i = 0; i < 64; i++) { 852232812Sjmallett cvmx_ciu_en0_to_irq[i] = 0xff; 853232812Sjmallett cvmx_ciu_en1_to_irq[i] = 0xff; 854232812Sjmallett cvmx_ciu_61xx_timer_to_irq[i] = 0xff; 855232812Sjmallett } 856232812Sjmallett 857232812Sjmallett /* WORKQ */ 858232812Sjmallett for (i = 0; i < 16; i++) 859232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_WORKQ0 + i, 0, i); 860232812Sjmallett /* GPIO */ 861232812Sjmallett for (i = 0; i < 16; i++) 862232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_GPIO0 + i, 0, i + 16); 863232812Sjmallett 864232812Sjmallett /* MBOX */ 865232812Sjmallett for (i = 0; i < 2; i++) 866232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_MBOX0 + i, 0, i + 32); 867232812Sjmallett 868232812Sjmallett /* UART */ 869232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_UART0 + 0, 0, 34); 870232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_UART0 + 1, 0, 35); 871232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_UART0 + 2, 1, 16); 872232812Sjmallett 873232812Sjmallett /* PCI */ 874232812Sjmallett for (i = 0; i < 4; i++) 875232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PCI_INT0 + i, 0, i + 36); 876232812Sjmallett 877232812Sjmallett /* MSI */ 878232812Sjmallett for (i = 0; i < 4; i++) 879232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PCI_MSI0 + i, 0, i + 40); 880232812Sjmallett 881232812Sjmallett /* TWSI */ 882232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TWSI0 + 0, 0, 45); 883232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TWSI0 + 1, 0, 59); 884232812Sjmallett 885232812Sjmallett /* other */ 886232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_RML, 0, 46); 887232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TRACE0, 0, 47); 888232812Sjmallett 889232812Sjmallett /* GMX_DRP */ 890232812Sjmallett for (i = 0; i < 2; i++) 891232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_GMX_DRP0 + i, 0, i + 48); 892232812Sjmallett 893232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_IPD_DRP, 0, 50); 894232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_KEY_ZERO, 0, 51); 895232812Sjmallett 896232812Sjmallett /* TIMER0 */ 897232812Sjmallett for (i = 0; i < 4; i++) 898232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TIMER0 + i, 0, i + 52); 899232812Sjmallett 900232812Sjmallett /* TIMER4..9 */ 901232812Sjmallett for(i = 0; i < 6; i++) 902232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TIMER4 + i, 8, i + 4); 903232812Sjmallett 904232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_USB0 + 0, 0, 56); 905232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_USB0 + 1, 1, 17); 906232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PCM, 0, 57); 907232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_MPI, 0, 58); 908232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_POWIQ, 0, 60); 909232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_IPDPPTHR, 0, 61); 910232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_MII0 + 0, 0, 62); 911232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_MII0 + 1, 1, 18); 912232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_BOOTDMA, 0, 63); 913232812Sjmallett 914232812Sjmallett /* WDOG */ 915232812Sjmallett for (i = 0; i < 16; i++) 916232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_WDOG0 + i, 1, i); 917232812Sjmallett 918232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_NAND, 1, 19); 919232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_MIO, 1, 20); 920232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_IOB, 1, 21); 921232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_FPA, 1, 22); 922232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_POW, 1, 23); 923232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_L2C, 1, 24); 924232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_IPD, 1, 25); 925232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PIP, 1, 26); 926232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PKO, 1, 27); 927232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_ZIP, 1, 28); 928232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TIM, 1, 29); 929232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_RAD, 1, 30); 930232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_KEY, 1, 31); 931232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_DFA, 1, 32); 932232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_USBCTL, 1, 33); 933232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_SLI, 1, 34); 934232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_DPI, 1, 35); 935232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_AGX0, 1, 36); 936232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_AGX0 + 1, 1, 37); 937232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_DPI_DMA, 1, 40); 938232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_AGL, 1, 46); 939232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PTP, 1, 47); 940232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PEM0, 1, 48); 941232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PEM1, 1, 49); 942232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_SRIO0, 1, 50); 943232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_SRIO1, 1, 51); 944232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_LMC0, 1, 52); 945232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_DFM, 1, 56); 946232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_SRIO2, 1, 60); 947232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_RST, 1, 63); 948232812Sjmallett} 949232812Sjmallett 950232812Sjmallettstatic void cvmx_interrupt_ciu2_initialize(cvmx_sysinfo_t *sys_info_ptr) 951232812Sjmallett{ 952232812Sjmallett int i; 953232812Sjmallett 954232812Sjmallett /* Disable all CIU2 interrupts by default */ 955232812Sjmallett 956232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_WRKQ(cvmx_get_core_num()), 0); 957232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_WRKQ(cvmx_get_core_num()), 0); 958232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_WRKQ(cvmx_get_core_num()), 0); 959232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_WDOG(cvmx_get_core_num()), 0); 960232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_WDOG(cvmx_get_core_num()), 0); 961232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_WDOG(cvmx_get_core_num()), 0); 962232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_RML(cvmx_get_core_num()), 0); 963232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_RML(cvmx_get_core_num()), 0); 964232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_RML(cvmx_get_core_num()), 0); 965232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_MIO(cvmx_get_core_num()), 0); 966232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_MIO(cvmx_get_core_num()), 0); 967232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_MIO(cvmx_get_core_num()), 0); 968232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_IO(cvmx_get_core_num()), 0); 969232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_IO(cvmx_get_core_num()), 0); 970232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_IO(cvmx_get_core_num()), 0); 971232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_MEM(cvmx_get_core_num()), 0); 972232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_MEM(cvmx_get_core_num()), 0); 973232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_MEM(cvmx_get_core_num()), 0); 974232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_PKT(cvmx_get_core_num()), 0); 975232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_PKT(cvmx_get_core_num()), 0); 976232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_PKT(cvmx_get_core_num()), 0); 977232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_GPIO(cvmx_get_core_num()), 0); 978232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_GPIO(cvmx_get_core_num()), 0); 979232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_GPIO(cvmx_get_core_num()), 0); 980232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP2_MBOX(cvmx_get_core_num()), 0); 981232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP3_MBOX(cvmx_get_core_num()), 0); 982232812Sjmallett cvmx_write_csr(CVMX_CIU2_EN_PPX_IP4_MBOX(cvmx_get_core_num()), 0); 983232812Sjmallett 984232812Sjmallett if (!cvmx_coremask_first_core(sys_info_ptr->core_mask) || is_core_being_hot_plugged()) 985232812Sjmallett return; 986232812Sjmallett 987232812Sjmallett /* On the first core, set up the maps */ 988232812Sjmallett for (i = 0; i < 64; i++) { 989232812Sjmallett cvmx_ciu2_wrkq_to_irq[i] = 0xff; 990232812Sjmallett cvmx_ciu2_wdog_to_irq[i] = 0xff; 991232812Sjmallett cvmx_ciu2_rml_to_irq[i] = 0xff; 992232812Sjmallett cvmx_ciu2_mio_to_irq[i] = 0xff; 993232812Sjmallett cvmx_ciu2_io_to_irq[i] = 0xff; 994232812Sjmallett cvmx_ciu2_mem_to_irq[i] = 0xff; 995232812Sjmallett cvmx_ciu2_eth_to_irq[i] = 0xff; 996232812Sjmallett cvmx_ciu2_gpio_to_irq[i] = 0xff; 997232812Sjmallett cvmx_ciu2_mbox_to_irq[i] = 0xff; 998232812Sjmallett } 999232812Sjmallett 1000232812Sjmallett /* WORKQ */ 1001232812Sjmallett for (i = 0; i < 64; i++) 1002232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_WORKQ0 + i, 0, i); 1003232812Sjmallett 1004232812Sjmallett /* GPIO */ 1005232812Sjmallett for (i = 0; i < 16; i++) 1006232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_GPIO0 + i, 7, i); 1007232812Sjmallett 1008232812Sjmallett /* MBOX */ 1009232812Sjmallett for (i = 0; i < 4; i++) 1010232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_MBOX0 + i, 60, i); 1011232812Sjmallett 1012232812Sjmallett /* UART */ 1013232812Sjmallett for (i = 0; i < 2; i++) 1014232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_UART0 + i, 3, 36 + i); 1015232812Sjmallett 1016232812Sjmallett /* PCI */ 1017232812Sjmallett for (i = 0; i < 4; i++) 1018232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PCI_INT0 + i, 4, 16 + i); 1019232812Sjmallett 1020232812Sjmallett /* MSI */ 1021232812Sjmallett for (i = 0; i < 4; i++) 1022232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PCI_MSI0 + i, 4, 8 + i); 1023232812Sjmallett 1024232812Sjmallett /* TWSI */ 1025232812Sjmallett for (i = 0; i < 2; i++) 1026232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TWSI0 + i, 3, 32 + i); 1027232812Sjmallett 1028232812Sjmallett /* TRACE */ 1029232812Sjmallett for (i = 0; i < 4; i++) 1030232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TRACE0 + i, 2, 52 + i); 1031232812Sjmallett 1032232812Sjmallett /* GMX_DRP */ 1033232812Sjmallett for (i = 0; i < 5; i++) 1034232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_GMX_DRP0 + i, 6, 8 + i); 1035232812Sjmallett 1036232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_IPD_DRP, 3, 2); 1037232812Sjmallett 1038232812Sjmallett /* TIMER0 */ 1039232812Sjmallett for (i = 0; i < 4; i++) 1040232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TIMER0 + i, 3, 8 + i); 1041232812Sjmallett 1042232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_USB0, 3, 44); 1043232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_IPDPPTHR, 3, 0); 1044232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_MII0, 6, 40); 1045232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_BOOTDMA, 3, 18); 1046232812Sjmallett 1047232812Sjmallett /* WDOG */ 1048232812Sjmallett for (i = 0; i < 32; i++) 1049232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_WDOG0 + i, 1, i); 1050232812Sjmallett 1051232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_NAND, 3, 16); 1052232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_MIO, 3, 17); 1053232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_IOB, 2, 0); 1054232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_FPA, 2, 4); 1055232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_POW, 2, 16); 1056232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_L2C, 2, 48); 1057232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_IPD, 2, 5); 1058232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PIP, 2, 6); 1059232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PKO, 2, 7); 1060232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_ZIP, 2, 24); 1061232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_TIM, 2, 28); 1062232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_RAD, 2, 29); 1063232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_KEY, 2, 30); 1064232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_DFA, 2, 40); 1065232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_USBCTL, 3, 40); 1066232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_SLI, 2, 32); 1067232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_DPI, 2, 33); 1068232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_DPI_DMA, 2, 36); 1069232812Sjmallett 1070232812Sjmallett /* AGX */ 1071232812Sjmallett for (i = 0; i < 5; i++) 1072232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_AGX0 + i, 6, i); 1073232812Sjmallett 1074232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_AGL, 6, 32); 1075232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PTP, 3, 48); 1076232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PEM0, 4, 32); 1077232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_PEM1, 4, 32); 1078232812Sjmallett 1079232812Sjmallett /* LMC */ 1080232812Sjmallett for (i = 0; i < 4; i++) 1081232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_LMC0 + i, 5, i); 1082232812Sjmallett 1083232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_RST, 3, 63); 1084232812Sjmallett __cvmx_interrupt_set_mapping(CVMX_IRQ_ILK, 6, 48); 1085232812Sjmallett} 1086232812Sjmallett 1087232812Sjmallett/** 1088210284Sjmallett * Initialize the interrupt routine and copy the low level 1089210284Sjmallett * stub into the correct interrupt vector. This is called 1090210284Sjmallett * automatically during application startup. 1091210284Sjmallett */ 1092210284Sjmallettvoid cvmx_interrupt_initialize(void) 1093210284Sjmallett{ 1094210284Sjmallett void *low_level_loc; 1095210284Sjmallett cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); 1096210284Sjmallett int i; 1097210284Sjmallett 1098232812Sjmallett if (cvmx_coremask_first_core(sys_info_ptr->core_mask) && !is_core_being_hot_plugged()) { 1099232812Sjmallett#ifndef CVMX_ENABLE_CSR_ADDRESS_CHECKING 1100232812Sjmallett /* We assume this relationship between the registers. */ 1101232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x1000 == CVMX_CIU2_SRC_PPX_IP2_WDOG(0)); 1102232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x2000 == CVMX_CIU2_SRC_PPX_IP2_RML(0)); 1103232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x3000 == CVMX_CIU2_SRC_PPX_IP2_MIO(0)); 1104232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x4000 == CVMX_CIU2_SRC_PPX_IP2_IO(0)); 1105232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x5000 == CVMX_CIU2_SRC_PPX_IP2_MEM(0)); 1106232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x6000 == CVMX_CIU2_SRC_PPX_IP2_PKT(0)); 1107232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_SRC_PPX_IP2_WRKQ(0) + 0x7000 == CVMX_CIU2_SRC_PPX_IP2_GPIO(0)); 1108232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x1000 == CVMX_CIU2_EN_PPX_IP2_WDOG_W1C(0)); 1109232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x2000 == CVMX_CIU2_EN_PPX_IP2_RML_W1C(0)); 1110232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x3000 == CVMX_CIU2_EN_PPX_IP2_MIO_W1C(0)); 1111232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x4000 == CVMX_CIU2_EN_PPX_IP2_IO_W1C(0)); 1112232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x5000 == CVMX_CIU2_EN_PPX_IP2_MEM_W1C(0)); 1113232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x6000 == CVMX_CIU2_EN_PPX_IP2_PKT_W1C(0)); 1114232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(0) + 0x7000 == CVMX_CIU2_EN_PPX_IP2_GPIO_W1C(0)); 1115232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x1000 == CVMX_CIU2_EN_PPX_IP2_WDOG_W1S(0)); 1116232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x2000 == CVMX_CIU2_EN_PPX_IP2_RML_W1S(0)); 1117232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x3000 == CVMX_CIU2_EN_PPX_IP2_MIO_W1S(0)); 1118232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x4000 == CVMX_CIU2_EN_PPX_IP2_IO_W1S(0)); 1119232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x5000 == CVMX_CIU2_EN_PPX_IP2_MEM_W1S(0)); 1120232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x6000 == CVMX_CIU2_EN_PPX_IP2_PKT_W1S(0)); 1121232812Sjmallett CVMX_BUILD_ASSERT(CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(0) + 0x7000 == CVMX_CIU2_EN_PPX_IP2_GPIO_W1S(0)); 1122232812Sjmallett#endif /* !CVMX_ENABLE_CSR_ADDRESS_CHECKING */ 1123210284Sjmallett 1124232812Sjmallett for (i = 0; i < CVMX_IRQ_MAX; i++) { 1125232812Sjmallett cvmx_interrupt_state.handlers[i].handler = __cvmx_interrupt_default; 1126232812Sjmallett cvmx_interrupt_state.handlers[i].data = NULL; 1127232812Sjmallett cvmx_interrupt_state.handlers[i].handler_data = -1; 1128232812Sjmallett } 1129232812Sjmallett } 1130232812Sjmallett 1131232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 1132210284Sjmallett { 1133232812Sjmallett cvmx_interrupt_mask_irq = __cvmx_interrupt_ciu2_mask_irq; 1134232812Sjmallett cvmx_interrupt_unmask_irq = __cvmx_interrupt_ciu2_unmask_irq; 1135232812Sjmallett cvmx_interrupt_ciu2_initialize(sys_info_ptr); 1136232812Sjmallett /* Add an interrupt handlers for chained CIU interrupt */ 1137232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_MIPS2, __cvmx_interrupt_ciu2, NULL); 1138232812Sjmallett } 1139232812Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN61XX) || OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_2)) 1140232812Sjmallett { 1141232812Sjmallett cvmx_interrupt_mask_irq = __cvmx_interrupt_ciu_mask_irq; 1142232812Sjmallett cvmx_interrupt_unmask_irq = __cvmx_interrupt_ciu_unmask_irq; 1143232812Sjmallett cvmx_interrupt_ciu_initialize(sys_info_ptr); 1144232812Sjmallett 1145232812Sjmallett /* Add an interrupt handlers for chained CIU interrupts */ 1146232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_MIPS2, __cvmx_interrupt_ciu, NULL); 1147232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_MIPS3, __cvmx_interrupt_ciu_cn61xx, NULL); 1148232812Sjmallett } 1149232812Sjmallett else 1150232812Sjmallett { 1151232812Sjmallett cvmx_interrupt_mask_irq = __cvmx_interrupt_ciu_mask_irq; 1152232812Sjmallett cvmx_interrupt_unmask_irq = __cvmx_interrupt_ciu_unmask_irq; 1153232812Sjmallett cvmx_interrupt_ciu_initialize(sys_info_ptr); 1154232812Sjmallett 1155232812Sjmallett /* Add an interrupt handlers for chained CIU interrupts */ 1156232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_MIPS2, __cvmx_interrupt_ciu, NULL); 1157232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_MIPS3, __cvmx_interrupt_ciu, NULL); 1158232812Sjmallett } 1159232812Sjmallett 1160232812Sjmallett /* Move performance counter interrupts to IRQ 6*/ 1161232812Sjmallett cvmx_update_perfcnt_irq(); 1162232812Sjmallett 1163232812Sjmallett /* Add an interrupt handler for Perf counter interrupts */ 1164232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_MIPS6, __cvmx_interrupt_perf, NULL); 1165232812Sjmallett 1166232812Sjmallett if (cvmx_coremask_first_core(sys_info_ptr->core_mask) && !is_core_being_hot_plugged()) 1167232812Sjmallett { 1168210284Sjmallett cvmx_interrupt_state.exception_handler = __cvmx_interrupt_default_exception_handler; 1169210284Sjmallett 1170210284Sjmallett low_level_loc = CASTPTR(void, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0,sys_info_ptr->exception_base_addr)); 1171210284Sjmallett memcpy(low_level_loc + 0x80, (void*)cvmx_interrupt_stage1, 0x80); 1172210284Sjmallett memcpy(low_level_loc + 0x100, (void*)cvmx_interrupt_cache_error, 0x80); 1173210284Sjmallett memcpy(low_level_loc + 0x180, (void*)cvmx_interrupt_stage1, 0x80); 1174210284Sjmallett memcpy(low_level_loc + 0x200, (void*)cvmx_interrupt_stage1, 0x80); 1175215990Sjmallett 1176210284Sjmallett /* Make sure the locations used to count Icache and Dcache exceptions 1177210284Sjmallett starts out as zero */ 1178210284Sjmallett cvmx_write64_uint64(CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, 8), 0); 1179210284Sjmallett cvmx_write64_uint64(CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, 16), 0); 1180210284Sjmallett cvmx_write64_uint64(CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, 24), 0); 1181210284Sjmallett CVMX_SYNC; 1182210284Sjmallett 1183210284Sjmallett /* Add an interrupt handler for ECC failures */ 1184215990Sjmallett if (cvmx_error_initialize(0 /* || CVMX_ERROR_FLAGS_ECC_SINGLE_BIT */)) 1185215990Sjmallett cvmx_warn("cvmx_error_initialize() failed\n"); 1186232812Sjmallett 1187232812Sjmallett /* Enable PIP/IPD, POW, PKO, FPA, NAND, KEY, RAD, L2C, LMC, GMX, AGL, 1188232812Sjmallett DFM, DFA, error handling interrupts. */ 1189232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 1190232812Sjmallett { 1191232812Sjmallett int i; 1192232812Sjmallett 1193232812Sjmallett for (i = 0; i < 5; i++) 1194232812Sjmallett { 1195232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_AGX0+i, __cvmx_interrupt_ecc, NULL); 1196232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_AGX0+i); 1197232812Sjmallett } 1198232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_NAND, __cvmx_interrupt_ecc, NULL); 1199232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_NAND); 1200232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_MIO, __cvmx_interrupt_ecc, NULL); 1201232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_MIO); 1202232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_FPA, __cvmx_interrupt_ecc, NULL); 1203232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_FPA); 1204232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_IPD, __cvmx_interrupt_ecc, NULL); 1205232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_IPD); 1206232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_PIP, __cvmx_interrupt_ecc, NULL); 1207232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_PIP); 1208232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_POW, __cvmx_interrupt_ecc, NULL); 1209232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_POW); 1210232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_L2C, __cvmx_interrupt_ecc, NULL); 1211232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_L2C); 1212232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_PKO, __cvmx_interrupt_ecc, NULL); 1213232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_PKO); 1214232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_ZIP, __cvmx_interrupt_ecc, NULL); 1215232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_ZIP); 1216232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_RAD, __cvmx_interrupt_ecc, NULL); 1217232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_RAD); 1218232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_KEY, __cvmx_interrupt_ecc, NULL); 1219232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_KEY); 1220232812Sjmallett /* Before enabling SLI interrupt clear any RML_TO interrupt */ 1221232812Sjmallett if (cvmx_read_csr(CVMX_PEXP_SLI_INT_SUM) & 0x1) 1222232812Sjmallett { 1223232812Sjmallett cvmx_safe_printf("clearing pending SLI_INT_SUM[RML_TO] interrupt (ignore)\n"); 1224232812Sjmallett cvmx_write_csr(CVMX_PEXP_SLI_INT_SUM, 1); 1225232812Sjmallett } 1226232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_SLI, __cvmx_interrupt_ecc, NULL); 1227232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_SLI); 1228232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_DPI, __cvmx_interrupt_ecc, NULL); 1229232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_DPI); 1230232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_DFA, __cvmx_interrupt_ecc, NULL); 1231232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_DFA); 1232232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_AGL, __cvmx_interrupt_ecc, NULL); 1233232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_AGL); 1234232812Sjmallett for (i = 0; i < 4; i++) 1235232812Sjmallett { 1236232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_LMC0+i, __cvmx_interrupt_ecc, NULL); 1237232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_LMC0+i); 1238232812Sjmallett } 1239232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_DFM, __cvmx_interrupt_ecc, NULL); 1240232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_DFM); 1241232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_RST, __cvmx_interrupt_ecc, NULL); 1242232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_RST); 1243232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_ILK, __cvmx_interrupt_ecc, NULL); 1244232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_ILK); 1245232812Sjmallett } 1246232812Sjmallett else 1247232812Sjmallett { 1248232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_RML, __cvmx_interrupt_ecc, NULL); 1249232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_RML); 1250232812Sjmallett } 1251232812Sjmallett 1252232812Sjmallett cvmx_atomic_set32(&cvmx_interrupt_initialize_flag, 1); 1253210284Sjmallett } 1254210284Sjmallett 1255232812Sjmallett while (!cvmx_atomic_get32(&cvmx_interrupt_initialize_flag)) 1256232812Sjmallett ; /* Wait for first core to finish above. */ 1257232812Sjmallett 1258232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { 1259232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_MIPS2); 1260232812Sjmallett } else { 1261232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_MIPS2); 1262232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_MIPS3); 1263232812Sjmallett } 1264232812Sjmallett 1265210284Sjmallett CVMX_ICACHE_INVALIDATE; 1266210284Sjmallett 1267210284Sjmallett /* Enable interrupts for each core (bit0 of COP0 Status) */ 1268232812Sjmallett cvmx_interrupt_restore(1); 1269210284Sjmallett} 1270210284Sjmallett 1271210284Sjmallett 1272210284Sjmallett 1273210284Sjmallett/** 1274210284Sjmallett * Set the exception handler for all non interrupt sources. 1275210284Sjmallett * 1276210284Sjmallett * @param handler New exception handler 1277210284Sjmallett * @return Old exception handler 1278210284Sjmallett */ 1279210284Sjmallettcvmx_interrupt_exception_t cvmx_interrupt_set_exception(cvmx_interrupt_exception_t handler) 1280210284Sjmallett{ 1281210284Sjmallett cvmx_interrupt_exception_t result = cvmx_interrupt_state.exception_handler; 1282210284Sjmallett cvmx_interrupt_state.exception_handler = handler; 1283210284Sjmallett CVMX_SYNCWS; 1284210284Sjmallett return result; 1285210284Sjmallett} 1286215990Sjmallett#endif /* !__U_BOOT__ */ 1287210284Sjmallett 1288210284Sjmallett 1289