]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/octeon-sdk/cvmx-profiler.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / octeon-sdk / cvmx-profiler.c
1 /***********************license start***************
2  * Copyright (c) 2011  Cavium Inc. (support@cavium.com). All rights
3  * reserved.
4  * 
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  * 
10  *   * Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  *  
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *
18  *   * Neither the name of Cavium Inc. nor the names of
19  *     its contributors may be used to endorse or promote products
20  *     derived from this software without specific prior written
21  *     permission.
22  *
23  * This Software, including technical data, may be subject to U.S. export  control
24  * laws, including the U.S. Export Administration Act and its  associated
25  * regulations, and may be subject to export or import  regulations in other
26  * countries.
27  *
28  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29  * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30  * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31  * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32  * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33  * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34  * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35  * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36  * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37  * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38  ************************license end**************************************/
39
40 /**
41  * @file
42  *
43  * Interface to event profiler.
44  *
45  */
46
47 #include "cvmx-config.h"
48 #include "cvmx.h"
49 #include "cvmx-interrupt.h"
50 #include "cvmx-sysinfo.h"
51 #include "cvmx-coremask.h"
52 #include "cvmx-spinlock.h"
53 #include "cvmx-atomic.h"
54 #if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)
55 #include "cvmx-error.h"
56 #endif
57 #include "cvmx-asm.h"
58 #include "cvmx-bootmem.h"
59 #include "cvmx-profiler.h"
60
61 #ifdef PROFILER_DEBUG
62 #define PRINTF(fmt, args...)    cvmx_safe_printf(fmt, ##args)
63 #else
64 #define PRINTF(fmt, args...)
65 #endif
66
67 CVMX_SHARED static event_counter_control_block_t eccb;
68 cvmx_config_block_t *pcpu_cfg_blk;
69
70 int read_percpu_block = 1;
71
72 /**
73  * Set Interrupt IRQ line for Performance Counter
74  *
75  */
76 void cvmx_update_perfcnt_irq(void)
77 {
78     uint64_t cvmctl;
79    
80     /* Clear CvmCtl[IPPCI] bit and move the Performance Counter
81      * interrupt to IRQ 6
82      */
83     CVMX_MF_COP0(cvmctl, COP0_CVMCTL);
84     cvmctl &= ~(7 << 7);
85     cvmctl |= 6 << 7;
86     CVMX_MT_COP0(cvmctl, COP0_CVMCTL);
87 }
88
89 /**
90  * @INTERNAL
91  * Return the baseaddress of the namedblock 
92  * @param buf_name  Name of Namedblock
93  *
94  * @return baseaddress of block on Success, NULL on failure.
95  */
96 static
97 void *cvmx_get_memory_addr(const char* buf_name)
98 {
99     void *buffer_ptr = NULL;
100     const struct cvmx_bootmem_named_block_desc *block_desc = cvmx_bootmem_find_named_block(buf_name);
101     if (block_desc)
102         buffer_ptr = cvmx_phys_to_ptr(block_desc->base_addr);
103     assert (buffer_ptr != NULL);
104
105     return buffer_ptr;
106 }
107
108 /**
109  * @INTERNAL
110  * Initialize the cpu block metadata. 
111  * 
112  * @param cpu   core no
113  * @param size  size of per cpu memory in named block
114  *
115  */
116 static
117 void cvmx_init_pcpu_block(int cpu, int size)
118 {
119     eccb.cfg_blk.pcpu_base_addr[cpu] = (char *)cvmx_get_memory_addr(EVENT_BUFFER_BLOCK) + (size * cpu); 
120     assert (eccb.cfg_blk.pcpu_base_addr[cpu] != NULL);
121
122     cvmx_ringbuf_t  *cpu_buf = (cvmx_ringbuf_t *) eccb.cfg_blk.pcpu_base_addr[cpu];
123
124     cpu_buf->pcpu_blk_info.size = size;
125     cpu_buf->pcpu_blk_info.max_samples = ((size - sizeof(cvmx_cpu_event_block_t)) / sizeof(cvmx_sample_entry_t));
126     cpu_buf->pcpu_blk_info.sample_count = 0;
127     cpu_buf->pcpu_blk_info.sample_read = 0;
128     cpu_buf->pcpu_blk_info.data = eccb.cfg_blk.pcpu_base_addr[cpu] + sizeof(cvmx_cpu_event_block_t) + PADBYTES;
129     cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.tail = \
130        cpu_buf->pcpu_data = cpu_buf->pcpu_blk_info.data;
131     cpu_buf->pcpu_blk_info.end = eccb.cfg_blk.pcpu_base_addr[cpu] + size;
132
133     cvmx_atomic_set32(&read_percpu_block, 0);
134
135     /*
136      * Write per cpu mem base address info in to 'event config' named block,
137      * This info is needed by oct-remote-profile to get Per cpu memory 
138      * base address of each core of the named block.
139      */
140     pcpu_cfg_blk = (cvmx_config_block_t *) eccb.config_blk_base_addr;
141     pcpu_cfg_blk->pcpu_base_addr[cpu] = eccb.cfg_blk.pcpu_base_addr[cpu];
142 }
143
144 /**
145  * @INTERNAL
146  * Retrieve the info from the 'event_config' named block.
147  *
148  * Here events value is read(as passed to oct-remote-profile) to reset perf 
149  * counters on every Perf counter overflow.
150  *
151  */
152 static
153 void cvmx_read_config_blk(void)
154 {
155     eccb.config_blk_base_addr = (char *)cvmx_get_memory_addr(EVENT_BUFFER_CONFIG_BLOCK);
156     memcpy(&(eccb.cfg_blk.events), eccb.config_blk_base_addr + \
157        offsetof(cvmx_config_block_t, events), sizeof(int64_t));
158
159     cvmx_atomic_set32(&eccb.read_cfg_blk,1);
160     PRINTF("cfg_blk.events=%lu, sample_count=%ld\n", eccb.cfg_blk.events, eccb.cfg_blk.sample_count);
161 }
162
163 /**
164  * @INTERNAL
165  * Add new sample to the buffer and increment the head pointer and 
166  * global sample count(i.e sum total of samples collected on all cores) 
167  *
168  */
169 static
170 void cvmx_add_sample_to_buffer(void)
171 {
172     uint32_t epc;
173     int cpu = cvmx_get_core_num();
174     CVMX_MF_COP0(epc, COP0_EPC);
175
176     cvmx_ringbuf_t  *cpu_buf = (cvmx_ringbuf_t *) eccb.cfg_blk.pcpu_base_addr[cpu];
177
178     /* 
179      * head/tail pointer can be NULL, and this case arises when oct-remote-profile is
180      * invoked afresh. To keep memory sane for current instance, we clear namedblock off 
181      * previous data and this is accomplished by octeon_remote_write_mem from host.
182      */
183     if (cvmx_unlikely(!cpu_buf->pcpu_blk_info.head && !cpu_buf->pcpu_blk_info.end)) {
184        /* Reread the event count as a different threshold val could be 
185         * passed with profiler alongside --events flag */
186         cvmx_read_config_blk();
187         cvmx_init_pcpu_block(cpu, EVENT_PERCPU_BUFFER_SIZE);
188     }
189
190     /* In case of hitting end of buffer, reset head,data ptr to start */
191     if (cpu_buf->pcpu_blk_info.head == cpu_buf->pcpu_blk_info.end)
192         cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.data = cpu_buf->pcpu_data; 
193
194     /* Store the pc, respective core no.*/
195     cvmx_sample_entry_t *sample = (cvmx_sample_entry_t *) cpu_buf->pcpu_blk_info.data;
196     sample->pc = epc;
197     sample->core = cpu;
198   
199     /* Update Per CPU stats */
200     cpu_buf->pcpu_blk_info.sample_count++;
201     cpu_buf->pcpu_blk_info.data += sizeof(cvmx_sample_entry_t);
202     cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.data;
203
204     /* Increment the global sample count i.e sum total of samples on all cores*/
205     cvmx_atomic_add64(&(pcpu_cfg_blk->sample_count), 1);
206
207     PRINTF("the core%d:pc 0x%016lx, sample_count=%ld\n", cpu, sample->pc, cpu_buf->pcpu_blk_info.sample_count);
208 }
209
210 /**
211  * @INTERNAL
212  * Reset performance counters
213  *
214  * @param pf     The performance counter Number (0, 1)
215  * @param events The threshold value for which interrupt has to be asserted
216  */
217 static
218 void cvmx_reset_perf_counter(int pf, uint64_t events)
219 {
220     uint64_t pfc;
221     pfc = (1ull << 63) - events;
222         
223     if (!pf) {
224         CVMX_MT_COP0(pfc, COP0_PERFVALUE0);
225     } else
226         CVMX_MT_COP0(pfc, COP0_PERFVALUE1);
227 }
228
229 void cvmx_collect_sample(void)
230 {
231     if (!eccb.read_cfg_blk)
232         cvmx_read_config_blk();
233
234     if (read_percpu_block)
235         cvmx_init_pcpu_block(cvmx_get_core_num(), EVENT_PERCPU_BUFFER_SIZE);
236
237     cvmx_add_sample_to_buffer();
238     cvmx_reset_perf_counter(0, eccb.cfg_blk.events);
239 }