1215976Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215976Sjmallett * reserved. 4215976Sjmallett * 5215976Sjmallett * 6215976Sjmallett * Redistribution and use in source and binary forms, with or without 7215976Sjmallett * modification, are permitted provided that the following conditions are 8215976Sjmallett * met: 9215976Sjmallett * 10215976Sjmallett * * Redistributions of source code must retain the above copyright 11215976Sjmallett * notice, this list of conditions and the following disclaimer. 12215976Sjmallett * 13215976Sjmallett * * Redistributions in binary form must reproduce the above 14215976Sjmallett * copyright notice, this list of conditions and the following 15215976Sjmallett * disclaimer in the documentation and/or other materials provided 16215976Sjmallett * with the distribution. 17215976Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215976Sjmallett * its contributors may be used to endorse or promote products 20215976Sjmallett * derived from this software without specific prior written 21215976Sjmallett * permission. 22215976Sjmallett 23215976Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215976Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215976Sjmallett * regulations, and may be subject to export or import regulations in other 26215976Sjmallett * countries. 27215976Sjmallett 28215976Sjmallett * 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 30215976Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215976Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215976Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215976Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215976Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215976Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215976Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215976Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38215976Sjmallett ***********************license end**************************************/ 39215976Sjmallett 40215976Sjmallett 41215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 42215976Sjmallett#include <linux/module.h> 43215976Sjmallett#include <asm/octeon/cvmx.h> 44215976Sjmallett#include <asm/octeon/cvmx-debug.h> 45215976Sjmallett#include <asm/octeon/cvmx-uart.h> 46215976Sjmallett#include <asm/octeon/octeon-boot-info.h> 47215976Sjmallett#include <asm/octeon/cvmx-spinlock.h> 48215976Sjmallett 49215976Sjmallettint cvmx_debug_uart = 1; 50215976Sjmallett 51215976Sjmallett#else 52215976Sjmallett#include <limits.h> 53215976Sjmallett#include "executive-config.h" 54215976Sjmallett#include "cvmx.h" 55215976Sjmallett#include "cvmx-debug.h" 56215976Sjmallett#include "cvmx-uart.h" 57215976Sjmallett#include "cvmx-spinlock.h" 58215976Sjmallett#include "octeon-boot-info.h" 59215976Sjmallett#endif 60215976Sjmallett 61232812Sjmallett/* 62232812Sjmallett * NOTE: CARE SHOULD BE TAKEN USING STD C LIBRARY FUNCTIONS IN 63232812Sjmallett * THIS FILE IF SOMEONE PUTS A BREAKPOINT ON THOSE FUNCTIONS 64232812Sjmallett * DEBUGGING WILL FAIL. 65232812Sjmallett */ 66215976Sjmallett 67215976Sjmallett 68232812Sjmallett#ifdef CVMX_BUILD_FOR_TOOLCHAIN 69215976Sjmallett#pragma weak cvmx_uart_enable_intr 70215976Sjmallettint cvmx_debug_uart = 1; 71215976Sjmallett#endif 72215976Sjmallett 73215976Sjmallett 74215976Sjmallett/* Default to second uart port for backward compatibility. The default (if 75215976Sjmallett -debug does not set the uart number) can now be overridden with 76215976Sjmallett CVMX_DEBUG_COMM_UART_NUM. */ 77215976Sjmallett#ifndef CVMX_DEBUG_COMM_UART_NUM 78215976Sjmallett# define CVMX_DEBUG_COMM_UART_NUM 1 79215976Sjmallett#endif 80215976Sjmallett 81215976Sjmallettstatic CVMX_SHARED cvmx_spinlock_t cvmx_debug_uart_lock; 82215976Sjmallett 83215976Sjmallett/** 84215976Sjmallett * Interrupt handler for debugger Control-C interrupts. 85215976Sjmallett * 86215976Sjmallett * @param irq_number IRQ interrupt number 87215976Sjmallett * @param registers CPU registers at the time of the interrupt 88215976Sjmallett * @param user_arg Unused user argument 89215976Sjmallett */ 90215976Sjmallettvoid cvmx_debug_uart_process_debug_interrupt(int irq_number, uint64_t registers[32], void *user_arg) 91215976Sjmallett{ 92215976Sjmallett cvmx_uart_lsr_t lsrval; 93215976Sjmallett 94215976Sjmallett /* Check for a Control-C interrupt from the debugger. This loop will eat 95215976Sjmallett all input received on the uart */ 96215976Sjmallett lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(cvmx_debug_uart)); 97215976Sjmallett while (lsrval.s.dr) 98215976Sjmallett { 99215976Sjmallett int c = cvmx_read_csr(CVMX_MIO_UARTX_RBR(cvmx_debug_uart)); 100215976Sjmallett if (c == '\003') 101215976Sjmallett { 102215976Sjmallett register uint64_t tmp; 103215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 104215976Sjmallett fflush(stderr); 105215976Sjmallett fflush(stdout); 106215976Sjmallett#endif 107215976Sjmallett /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also 108215976Sjmallett set the MCD0 to be not masked by this core so we know 109215976Sjmallett the signal is received by someone */ 110215976Sjmallett asm volatile ( 111215976Sjmallett "dmfc0 %0, $22\n" 112215976Sjmallett "ori %0, %0, 0x1110\n" 113215976Sjmallett "dmtc0 %0, $22\n" 114215976Sjmallett : "=r" (tmp)); 115215976Sjmallett } 116215976Sjmallett lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(cvmx_debug_uart)); 117215976Sjmallett } 118215976Sjmallett} 119215976Sjmallett 120215976Sjmallett 121215976Sjmallettstatic void cvmx_debug_uart_init(void) 122215976Sjmallett{ 123215976Sjmallett if (cvmx_debug_uart == -1) 124215976Sjmallett cvmx_debug_uart = CVMX_DEBUG_COMM_UART_NUM; 125215976Sjmallett} 126215976Sjmallett 127215976Sjmallettstatic void cvmx_debug_uart_install_break_handler(void) 128215976Sjmallett{ 129215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 130232812Sjmallett#ifdef CVMX_BUILD_FOR_TOOLCHAIN 131215976Sjmallett if (cvmx_uart_enable_intr) 132215976Sjmallett#endif 133215976Sjmallett cvmx_uart_enable_intr(cvmx_debug_uart, cvmx_debug_uart_process_debug_interrupt); 134215976Sjmallett#endif 135215976Sjmallett} 136215976Sjmallett 137232812Sjmallett/** 138232812Sjmallett * Routines to handle hex data 139232812Sjmallett * 140232812Sjmallett * @param ch 141232812Sjmallett * @return 142232812Sjmallett */ 143232812Sjmallettstatic inline int cvmx_debug_uart_hex(char ch) 144232812Sjmallett{ 145232812Sjmallett if ((ch >= 'a') && (ch <= 'f')) 146232812Sjmallett return(ch - 'a' + 10); 147232812Sjmallett if ((ch >= '0') && (ch <= '9')) 148232812Sjmallett return(ch - '0'); 149232812Sjmallett if ((ch >= 'A') && (ch <= 'F')) 150232812Sjmallett return(ch - 'A' + 10); 151232812Sjmallett return(-1); 152232812Sjmallett} 153232812Sjmallett 154215976Sjmallett/* Get a packet from the UART, return 0 on failure and 1 on success. */ 155215976Sjmallett 156215976Sjmallettstatic int cvmx_debug_uart_getpacket(char *buffer, size_t size) 157215976Sjmallett{ 158215976Sjmallett while (1) 159215976Sjmallett { 160215976Sjmallett unsigned char checksum; 161215976Sjmallett int timedout = 0; 162215976Sjmallett size_t count; 163215976Sjmallett char ch; 164215976Sjmallett 165215976Sjmallett ch = cvmx_uart_read_byte_with_timeout(cvmx_debug_uart, &timedout, __SHRT_MAX__); 166215976Sjmallett 167215976Sjmallett if (timedout) 168215976Sjmallett return 0; 169215976Sjmallett 170215976Sjmallett /* if this is not the start character, ignore it. */ 171215976Sjmallett if (ch != '$') 172215976Sjmallett continue; 173215976Sjmallett 174215976Sjmallett retry: 175215976Sjmallett checksum = 0; 176215976Sjmallett count = 0; 177215976Sjmallett 178215976Sjmallett /* now, read until a # or end of buffer is found */ 179215976Sjmallett while (count < size) 180215976Sjmallett { 181215976Sjmallett ch = cvmx_uart_read_byte(cvmx_debug_uart); 182215976Sjmallett if (ch == '$') 183215976Sjmallett goto retry; 184215976Sjmallett if (ch == '#') 185215976Sjmallett break; 186215976Sjmallett checksum = checksum + ch; 187215976Sjmallett buffer[count] = ch; 188215976Sjmallett count = count + 1; 189215976Sjmallett } 190215976Sjmallett buffer[count] = 0; 191215976Sjmallett 192215976Sjmallett if (ch == '#') 193215976Sjmallett { 194232812Sjmallett char csumchars0, csumchars1; 195215976Sjmallett unsigned xmitcsum; 196232812Sjmallett int n0, n1; 197215976Sjmallett 198232812Sjmallett csumchars0 = cvmx_uart_read_byte(cvmx_debug_uart); 199232812Sjmallett csumchars1 = cvmx_uart_read_byte(cvmx_debug_uart); 200232812Sjmallett n0 = cvmx_debug_uart_hex(csumchars0); 201232812Sjmallett n1 = cvmx_debug_uart_hex(csumchars1); 202232812Sjmallett if (n0 == -1 || n1 == -1) 203232812Sjmallett return 0; 204215976Sjmallett 205232812Sjmallett xmitcsum = (n0 << 4) | n1; 206215976Sjmallett return checksum == xmitcsum; 207215976Sjmallett } 208215976Sjmallett } 209215976Sjmallett return 0; 210215976Sjmallett} 211215976Sjmallett 212232812Sjmallett/* Put the hex value of t into str. */ 213232812Sjmallettstatic void cvmx_debug_uart_strhex(char *str, unsigned char t) 214232812Sjmallett{ 215232812Sjmallett char hexchar[] = "0123456789ABCDEF"; 216232812Sjmallett str[0] = hexchar[(t>>4)]; 217232812Sjmallett str[1] = hexchar[t&0xF]; 218232812Sjmallett str[2] = 0; 219232812Sjmallett} 220232812Sjmallett 221215976Sjmallettstatic int cvmx_debug_uart_putpacket(char *packet) 222215976Sjmallett{ 223215976Sjmallett size_t i; 224215976Sjmallett unsigned char csum; 225215976Sjmallett unsigned char *ptr = (unsigned char *) packet; 226215976Sjmallett char csumstr[3]; 227215976Sjmallett 228215976Sjmallett for (csum = 0, i = 0; ptr[i]; i++) 229215976Sjmallett csum += ptr[i]; 230232812Sjmallett cvmx_debug_uart_strhex(csumstr, csum); 231215976Sjmallett 232215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_uart_lock); 233215976Sjmallett cvmx_uart_write_byte(cvmx_debug_uart, '$'); 234215976Sjmallett cvmx_uart_write_string(cvmx_debug_uart, packet); 235215976Sjmallett cvmx_uart_write_byte(cvmx_debug_uart, '#'); 236215976Sjmallett cvmx_uart_write_string(cvmx_debug_uart, csumstr); 237215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_uart_lock); 238215976Sjmallett 239215976Sjmallett return 0; 240215976Sjmallett} 241215976Sjmallett 242215976Sjmallettstatic void cvmx_debug_uart_change_core(int oldcore, int newcore) 243215976Sjmallett{ 244215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 245215976Sjmallett cvmx_ciu_intx0_t irq_control; 246215976Sjmallett 247215976Sjmallett irq_control.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(newcore * 2)); 248232812Sjmallett irq_control.s.uart |= (1u<<cvmx_debug_uart); 249215976Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(newcore * 2), irq_control.u64); 250215976Sjmallett 251215976Sjmallett /* Disable interrupts to this core since he is about to die */ 252215976Sjmallett irq_control.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(oldcore * 2)); 253232812Sjmallett irq_control.s.uart &= ~(1u<<cvmx_debug_uart); 254215976Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(oldcore* 2), irq_control.u64); 255215976Sjmallett#endif 256215976Sjmallett} 257215976Sjmallett 258215976Sjmallettcvmx_debug_comm_t cvmx_debug_uart_comm = 259215976Sjmallett{ 260215976Sjmallett .init = cvmx_debug_uart_init, 261215976Sjmallett .install_break_handler = cvmx_debug_uart_install_break_handler, 262215976Sjmallett .needs_proxy = 1, 263215976Sjmallett .getpacket = cvmx_debug_uart_getpacket, 264215976Sjmallett .putpacket = cvmx_debug_uart_putpacket, 265215976Sjmallett .wait_for_resume = NULL, 266215976Sjmallett .change_core = cvmx_debug_uart_change_core, 267215976Sjmallett}; 268