1232809Sjmallett/***********************license start*************** 2232809Sjmallett * Copyright (c) 2011 Cavium Inc. (support@cavium.com). All rights 3232809Sjmallett * reserved. 4232809Sjmallett * 5232809Sjmallett * 6232809Sjmallett * Redistribution and use in source and binary forms, with or without 7232809Sjmallett * modification, are permitted provided that the following conditions are 8232809Sjmallett * met: 9232809Sjmallett * 10232809Sjmallett * * Redistributions of source code must retain the above copyright 11232809Sjmallett * notice, this list of conditions and the following disclaimer. 12232809Sjmallett * 13232809Sjmallett * * Redistributions in binary form must reproduce the above 14232809Sjmallett * copyright notice, this list of conditions and the following 15232809Sjmallett * disclaimer in the documentation and/or other materials provided 16232809Sjmallett * with the distribution. 17232809Sjmallett * 18232809Sjmallett * * Neither the name of Cavium Inc. nor the names of 19232809Sjmallett * its contributors may be used to endorse or promote products 20232809Sjmallett * derived from this software without specific prior written 21232809Sjmallett * permission. 22232809Sjmallett * 23232809Sjmallett * This Software, including technical data, may be subject to U.S. export control 24232809Sjmallett * laws, including the U.S. Export Administration Act and its associated 25232809Sjmallett * regulations, and may be subject to export or import regulations in other 26232809Sjmallett * countries. 27232809Sjmallett * 28232809Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232809Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30232809Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31232809Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32232809Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33232809Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34232809Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35232809Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36232809Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37232809Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38232809Sjmallett ************************license end**************************************/ 39232809Sjmallett 40232809Sjmallett/** 41232809Sjmallett * @file 42232809Sjmallett * 43232809Sjmallett * Interface to event profiler. 44232809Sjmallett * 45232809Sjmallett */ 46232809Sjmallett 47232809Sjmallett#include "cvmx-config.h" 48232809Sjmallett#include "cvmx.h" 49232809Sjmallett#include "cvmx-interrupt.h" 50232809Sjmallett#include "cvmx-sysinfo.h" 51232809Sjmallett#include "cvmx-coremask.h" 52232809Sjmallett#include "cvmx-spinlock.h" 53232809Sjmallett#include "cvmx-atomic.h" 54232816Sjmallett#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL) 55232809Sjmallett#include "cvmx-error.h" 56232816Sjmallett#endif 57232809Sjmallett#include "cvmx-asm.h" 58232809Sjmallett#include "cvmx-bootmem.h" 59232809Sjmallett#include "cvmx-profiler.h" 60232809Sjmallett 61232809Sjmallett#ifdef PROFILER_DEBUG 62232809Sjmallett#define PRINTF(fmt, args...) cvmx_safe_printf(fmt, ##args) 63232809Sjmallett#else 64232809Sjmallett#define PRINTF(fmt, args...) 65232809Sjmallett#endif 66232809Sjmallett 67232809SjmallettCVMX_SHARED static event_counter_control_block_t eccb; 68232809Sjmallettcvmx_config_block_t *pcpu_cfg_blk; 69232809Sjmallett 70232809Sjmallettint read_percpu_block = 1; 71232809Sjmallett 72232809Sjmallett/** 73232809Sjmallett * Set Interrupt IRQ line for Performance Counter 74232809Sjmallett * 75232809Sjmallett */ 76232809Sjmallettvoid cvmx_update_perfcnt_irq(void) 77232809Sjmallett{ 78232809Sjmallett uint64_t cvmctl; 79232809Sjmallett 80232809Sjmallett /* Clear CvmCtl[IPPCI] bit and move the Performance Counter 81232809Sjmallett * interrupt to IRQ 6 82232809Sjmallett */ 83232809Sjmallett CVMX_MF_COP0(cvmctl, COP0_CVMCTL); 84232809Sjmallett cvmctl &= ~(7 << 7); 85232809Sjmallett cvmctl |= 6 << 7; 86232809Sjmallett CVMX_MT_COP0(cvmctl, COP0_CVMCTL); 87232809Sjmallett} 88232809Sjmallett 89232809Sjmallett/** 90232809Sjmallett * @INTERNAL 91232809Sjmallett * Return the baseaddress of the namedblock 92232809Sjmallett * @param buf_name Name of Namedblock 93232809Sjmallett * 94232809Sjmallett * @return baseaddress of block on Success, NULL on failure. 95232809Sjmallett */ 96232809Sjmallettstatic 97232809Sjmallettvoid *cvmx_get_memory_addr(const char* buf_name) 98232809Sjmallett{ 99232809Sjmallett void *buffer_ptr = NULL; 100232809Sjmallett const struct cvmx_bootmem_named_block_desc *block_desc = cvmx_bootmem_find_named_block(buf_name); 101232809Sjmallett if (block_desc) 102232809Sjmallett buffer_ptr = cvmx_phys_to_ptr(block_desc->base_addr); 103232809Sjmallett assert (buffer_ptr != NULL); 104232809Sjmallett 105232809Sjmallett return buffer_ptr; 106232809Sjmallett} 107232809Sjmallett 108232809Sjmallett/** 109232809Sjmallett * @INTERNAL 110232809Sjmallett * Initialize the cpu block metadata. 111232809Sjmallett * 112232809Sjmallett * @param cpu core no 113232809Sjmallett * @param size size of per cpu memory in named block 114232809Sjmallett * 115232809Sjmallett */ 116232809Sjmallettstatic 117232809Sjmallettvoid cvmx_init_pcpu_block(int cpu, int size) 118232809Sjmallett{ 119232809Sjmallett eccb.cfg_blk.pcpu_base_addr[cpu] = (char *)cvmx_get_memory_addr(EVENT_BUFFER_BLOCK) + (size * cpu); 120232809Sjmallett assert (eccb.cfg_blk.pcpu_base_addr[cpu] != NULL); 121232809Sjmallett 122232809Sjmallett cvmx_ringbuf_t *cpu_buf = (cvmx_ringbuf_t *) eccb.cfg_blk.pcpu_base_addr[cpu]; 123232809Sjmallett 124232809Sjmallett cpu_buf->pcpu_blk_info.size = size; 125232809Sjmallett cpu_buf->pcpu_blk_info.max_samples = ((size - sizeof(cvmx_cpu_event_block_t)) / sizeof(cvmx_sample_entry_t)); 126232809Sjmallett cpu_buf->pcpu_blk_info.sample_count = 0; 127232809Sjmallett cpu_buf->pcpu_blk_info.sample_read = 0; 128232809Sjmallett cpu_buf->pcpu_blk_info.data = eccb.cfg_blk.pcpu_base_addr[cpu] + sizeof(cvmx_cpu_event_block_t) + PADBYTES; 129232809Sjmallett cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.tail = \ 130232809Sjmallett cpu_buf->pcpu_data = cpu_buf->pcpu_blk_info.data; 131232809Sjmallett cpu_buf->pcpu_blk_info.end = eccb.cfg_blk.pcpu_base_addr[cpu] + size; 132232809Sjmallett 133232809Sjmallett cvmx_atomic_set32(&read_percpu_block, 0); 134232809Sjmallett 135232809Sjmallett /* 136232809Sjmallett * Write per cpu mem base address info in to 'event config' named block, 137232809Sjmallett * This info is needed by oct-remote-profile to get Per cpu memory 138232809Sjmallett * base address of each core of the named block. 139232809Sjmallett */ 140232809Sjmallett pcpu_cfg_blk = (cvmx_config_block_t *) eccb.config_blk_base_addr; 141232809Sjmallett pcpu_cfg_blk->pcpu_base_addr[cpu] = eccb.cfg_blk.pcpu_base_addr[cpu]; 142232809Sjmallett} 143232809Sjmallett 144232809Sjmallett/** 145232809Sjmallett * @INTERNAL 146232809Sjmallett * Retrieve the info from the 'event_config' named block. 147232809Sjmallett * 148232809Sjmallett * Here events value is read(as passed to oct-remote-profile) to reset perf 149232809Sjmallett * counters on every Perf counter overflow. 150232809Sjmallett * 151232809Sjmallett */ 152232809Sjmallettstatic 153232809Sjmallettvoid cvmx_read_config_blk(void) 154232809Sjmallett{ 155232809Sjmallett eccb.config_blk_base_addr = (char *)cvmx_get_memory_addr(EVENT_BUFFER_CONFIG_BLOCK); 156232809Sjmallett memcpy(&(eccb.cfg_blk.events), eccb.config_blk_base_addr + \ 157232809Sjmallett offsetof(cvmx_config_block_t, events), sizeof(int64_t)); 158232809Sjmallett 159232809Sjmallett cvmx_atomic_set32(&eccb.read_cfg_blk,1); 160232809Sjmallett PRINTF("cfg_blk.events=%lu, sample_count=%ld\n", eccb.cfg_blk.events, eccb.cfg_blk.sample_count); 161232809Sjmallett} 162232809Sjmallett 163232809Sjmallett/** 164232809Sjmallett * @INTERNAL 165232809Sjmallett * Add new sample to the buffer and increment the head pointer and 166232809Sjmallett * global sample count(i.e sum total of samples collected on all cores) 167232809Sjmallett * 168232809Sjmallett */ 169232809Sjmallettstatic 170232809Sjmallettvoid cvmx_add_sample_to_buffer(void) 171232809Sjmallett{ 172232809Sjmallett uint32_t epc; 173232809Sjmallett int cpu = cvmx_get_core_num(); 174232809Sjmallett CVMX_MF_COP0(epc, COP0_EPC); 175232809Sjmallett 176232809Sjmallett cvmx_ringbuf_t *cpu_buf = (cvmx_ringbuf_t *) eccb.cfg_blk.pcpu_base_addr[cpu]; 177232809Sjmallett 178232809Sjmallett /* 179232809Sjmallett * head/tail pointer can be NULL, and this case arises when oct-remote-profile is 180232809Sjmallett * invoked afresh. To keep memory sane for current instance, we clear namedblock off 181232809Sjmallett * previous data and this is accomplished by octeon_remote_write_mem from host. 182232809Sjmallett */ 183232809Sjmallett if (cvmx_unlikely(!cpu_buf->pcpu_blk_info.head && !cpu_buf->pcpu_blk_info.end)) { 184232809Sjmallett /* Reread the event count as a different threshold val could be 185232809Sjmallett * passed with profiler alongside --events flag */ 186232809Sjmallett cvmx_read_config_blk(); 187232809Sjmallett cvmx_init_pcpu_block(cpu, EVENT_PERCPU_BUFFER_SIZE); 188232809Sjmallett } 189232809Sjmallett 190232809Sjmallett /* In case of hitting end of buffer, reset head,data ptr to start */ 191232809Sjmallett if (cpu_buf->pcpu_blk_info.head == cpu_buf->pcpu_blk_info.end) 192232809Sjmallett cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.data = cpu_buf->pcpu_data; 193232809Sjmallett 194232809Sjmallett /* Store the pc, respective core no.*/ 195232809Sjmallett cvmx_sample_entry_t *sample = (cvmx_sample_entry_t *) cpu_buf->pcpu_blk_info.data; 196232809Sjmallett sample->pc = epc; 197232809Sjmallett sample->core = cpu; 198232809Sjmallett 199232809Sjmallett /* Update Per CPU stats */ 200232809Sjmallett cpu_buf->pcpu_blk_info.sample_count++; 201232809Sjmallett cpu_buf->pcpu_blk_info.data += sizeof(cvmx_sample_entry_t); 202232809Sjmallett cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.data; 203232809Sjmallett 204232809Sjmallett /* Increment the global sample count i.e sum total of samples on all cores*/ 205232809Sjmallett cvmx_atomic_add64(&(pcpu_cfg_blk->sample_count), 1); 206232809Sjmallett 207232809Sjmallett PRINTF("the core%d:pc 0x%016lx, sample_count=%ld\n", cpu, sample->pc, cpu_buf->pcpu_blk_info.sample_count); 208232809Sjmallett} 209232809Sjmallett 210232809Sjmallett/** 211232809Sjmallett * @INTERNAL 212232809Sjmallett * Reset performance counters 213232809Sjmallett * 214232809Sjmallett * @param pf The performance counter Number (0, 1) 215232809Sjmallett * @param events The threshold value for which interrupt has to be asserted 216232809Sjmallett */ 217232809Sjmallettstatic 218232809Sjmallettvoid cvmx_reset_perf_counter(int pf, uint64_t events) 219232809Sjmallett{ 220232809Sjmallett uint64_t pfc; 221232809Sjmallett pfc = (1ull << 63) - events; 222232809Sjmallett 223232809Sjmallett if (!pf) { 224232809Sjmallett CVMX_MT_COP0(pfc, COP0_PERFVALUE0); 225232809Sjmallett } else 226232809Sjmallett CVMX_MT_COP0(pfc, COP0_PERFVALUE1); 227232809Sjmallett} 228232809Sjmallett 229232809Sjmallettvoid cvmx_collect_sample(void) 230232809Sjmallett{ 231232809Sjmallett if (!eccb.read_cfg_blk) 232232809Sjmallett cvmx_read_config_blk(); 233232809Sjmallett 234232809Sjmallett if (read_percpu_block) 235232809Sjmallett cvmx_init_pcpu_block(cvmx_get_core_num(), EVENT_PERCPU_BUFFER_SIZE); 236232809Sjmallett 237232809Sjmallett cvmx_add_sample_to_buffer(); 238232809Sjmallett cvmx_reset_perf_counter(0, eccb.cfg_blk.events); 239232809Sjmallett} 240