1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Trace commands				File: cfe_trace.c
5    *
6    *  A minimal interface for running the SB-1250 trace buffer under CFE
7    *
8    *********************************************************************
9    *
10    *  Copyright 2000,2001,2002,2003
11    *  Broadcom Corporation. All rights reserved.
12    *
13    *  This software is furnished under license and may be used and
14    *  copied only in accordance with the following terms and
15    *  conditions.  Subject to these conditions, you may download,
16    *  copy, install, use, modify and distribute modified or unmodified
17    *  copies of this software in source and/or binary form.  No title
18    *  or ownership is transferred hereby.
19    *
20    *  1) Any source code used, modified or distributed must reproduce
21    *     and retain this copyright notice and list of conditions
22    *     as they appear in the source file.
23    *
24    *  2) No right is granted to use any trade name, trademark, or
25    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
26    *     name may not be used to endorse or promote products derived
27    *     from this software without the prior written permission of
28    *     Broadcom Corporation.
29    *
30    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
31    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
32    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
33    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
34    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
35    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
36    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
38    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
39    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
40    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
41    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
42    *     THE POSSIBILITY OF SUCH DAMAGE.
43    ********************************************************************* */
44
45
46#include "cfe.h"
47#include "sbmips.h"
48#include "sb1250_regs.h"
49#include "sb1250_scd.h"
50
51#include "ui_command.h"
52
53int ui_init_tracecmds(void);
54static int ui_cmd_tracestart(ui_cmdline_t *cmd,int argc,char *argv[]);
55static int ui_cmd_tracestop(ui_cmdline_t *cmd,int argc,char *argv[]);
56static int ui_cmd_tracefreeze(ui_cmdline_t *cmd,int argc,char *argv[]);
57static int ui_cmd_traceread(ui_cmdline_t *cmd,int argc,char *argv[]);
58
59
60int ui_init_tracecmds(void)
61{
62
63    cmd_addcmd("trace start",
64	       ui_cmd_tracestart,
65	       NULL,
66	       "Start trace buffer data collection",
67	       "trace start [n [agent]]\n\n"
68	       "Start tracing ZBbus transactions, using the n-th canned\n"
69               "trigger/filter condition\n"
70	       " n = 0: <agent>-mastered transactions\n"
71	       " n = 1: CPU0 accesses to LDT dual-hosted region\n",
72	       "");
73    cmd_addcmd("trace stop",
74	       ui_cmd_tracestop,
75	       NULL,
76	       "Stop trace buffer data collection",
77	       "trace stop\n\n"
78	       "Stop tracing ZBbus transactions",
79	       "");
80    cmd_addcmd("trace freeze",
81	       ui_cmd_tracefreeze,
82	       NULL,
83	       "Freeze trace buffer",
84	       "trace freeze\n\n"
85	       "Freeze the trace buffer",
86	       "");
87    cmd_addcmd("trace read",
88	       ui_cmd_traceread,
89	       NULL,
90	       "Read trace buffer into memory",
91	       "trace read\n\n"
92	       "Allocate a block of memory, copy the unprocessed contents\n"
93	       "of the trace buffer into it, and generate a command template\n"
94	       "for writing it to a file via TFTP.",
95	       "");
96
97    return 0;
98}
99
100#define TB_SIZE (256*48)    /* 256 entries, 384 bits/entry */
101#define ZB_AGENT_CPU0 0
102#define ZB_AGENT_CPU1 1
103#define ZB_AGENT_IOB0 2
104#define ZB_AGENT_IOB1 3
105#define ZB_AGENT_SCD  4
106#define ZB_AGENT_L2C  6
107#define ZB_AGENT_MC   7
108
109static const struct {
110    const char *id;
111    int         code;
112} agent_id[] = {
113    { "cpu0", ZB_AGENT_CPU0 },
114    { "cpu1", ZB_AGENT_CPU1 },
115    { "iob0", ZB_AGENT_IOB0 },
116    { "iob1", ZB_AGENT_IOB1 },
117    { "scd",  ZB_AGENT_SCD  },
118    { "l2c",  ZB_AGENT_L2C  },
119    { "mc",   ZB_AGENT_MC   },
120    { NULL,   0             }
121};
122
123static int
124getagentarg (const char *id, int *agent)
125{
126    int  i;
127
128    for (i = 0; agent_id[i].id != NULL; i++) {
129	if (strcmp(id, agent_id[i].id) == 0) {
130	    *agent = agent_id[i].code;
131	    return 1;
132	    }
133	}
134    return 0;
135}
136
137static int
138getaddrarg (const char *x, long *addr)
139{
140    int res;
141
142    res = 0;
143    *addr = 0;
144
145    if (x) {
146	/*
147	 * Following gdb, we make 64-bit addresses expressed as
148	 * 8-digit numbers sign extend automagically.  Saves
149	 * typing, but is very gross.
150	 */
151	int longaddr;
152
153	longaddr = strlen(x);
154	if (memcmp(x,"0x",2) == 0) longaddr -= 2;
155
156	*addr = (longaddr > 8) ? (long) xtoq(x) : (long) xtoi(x);
157	res = 1;
158	}
159
160    return res;
161}
162
163
164static int ui_cmd_tracestart(ui_cmdline_t *cmd, int argc, char *argv[])
165{
166    volatile uint64_t *tb_cfg;
167
168    tb_cfg = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_CFG);
169
170    if (argc != 0) {
171        volatile uint64_t *at_down_0, *at_up_0, *at_cfg_0;
172        volatile uint64_t *tb_evt_0, *tb_evt_4;
173	volatile uint64_t *tb_seq_0, *tb_seq_4;
174	int i, n;
175	int found;
176	int agent;
177
178	/* Place holder: parse new trace spec (select an option for now) */
179
180	n = atoi(cmd_getarg(cmd,0));
181
182	at_down_0 = (volatile uint64_t *) PHYS_TO_K1(A_ADDR_TRAP_DOWN_0);
183	at_up_0   = (volatile uint64_t *) PHYS_TO_K1(A_ADDR_TRAP_UP_0);
184	at_cfg_0  = (volatile uint64_t *) PHYS_TO_K1(A_ADDR_TRAP_CFG_0);
185
186	tb_evt_0 = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_EVENT_0);
187	tb_evt_4 = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_EVENT_4);
188	tb_seq_0 = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_SEQUENCE_0);
189	tb_seq_4 = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_SEQUENCE_4);
190
191	/* Reset everything */
192	*tb_cfg = M_SCD_TRACE_CFG_RESET;
193	__asm__ __volatile__ ("sync" : : : "memory");
194
195	for (i = 0; i < 4; i++) {
196	    tb_evt_0[i] = 0;  tb_evt_4[i] = 0;
197	    tb_seq_0[i] = 0;  tb_seq_4[i] = 0;
198	}
199	__asm__ __volatile__ ("sync" : : : "memory");
200
201	switch (n) {
202	case 0:
203	    /* Filter on agent request or response */
204	    if (argc > 1)
205		found = getagentarg(cmd_getarg(cmd,1), &agent);
206	    else
207		found = 0;
208	    if (!found)
209	        agent = ZB_AGENT_IOB0;   /* temporary, for backward compat */
210
211	    tb_evt_0[0] = M_SCD_TREVT_REQID_MATCH
212	                | (M_SCD_TREVT_READ | M_SCD_TREVT_WRITE)
213	       	        | V_SCD_TREVT_REQID(agent);
214	    tb_evt_0[1] = M_SCD_TREVT_DATAID_MATCH
215	                | V_SCD_TREVT_DATAID(agent);
216
217	    tb_seq_0[0] = 0x0fff
218                        | M_SCD_TRSEQ_ASAMPLE;
219	    tb_seq_0[1] = 0x1fff
220                        | M_SCD_TRSEQ_DSAMPLE;
221	    break;
222	case 1:
223	    /* Filter on CPU accesses in LDT mirror region. */
224	    (void)getaddrarg;
225
226	    at_down_0[0] = 0xe000000000;
227	    at_up_0[0]   = 0xefffffffff;
228	    at_cfg_0[0]  = M_ATRAP_CFG_ALL;
229
230	    tb_evt_0[0] = M_SCD_TREVT_REQID_MATCH
231	                | V_SCD_TREVT_ADDR_MATCH(0x1) /* addr trap 0 */
232	                | (M_SCD_TREVT_READ | M_SCD_TREVT_WRITE)
233	                | V_SCD_TREVT_REQID(ZB_AGENT_CPU0);
234	    tb_evt_0[1] = M_SCD_TREVT_RESPID_MATCH
235	                | V_SCD_TREVT_RESPID(ZB_AGENT_IOB0);
236
237	    tb_seq_0[0] = 0x0fff
238	                | M_SCD_TRSEQ_ASAMPLE;
239	    tb_seq_0[1] = 0x1fff
240	                | M_SCD_TRSEQ_DSAMPLE;
241	    break;
242	default:
243	    break;
244	}
245
246	__asm__ __volatile__ ("sync" : : : "memory");
247printf("trace start: trace 0: %llx 1: %llx\n", tb_evt_0[0], tb_evt_0[1]);
248printf("             seq   0: %llx 1: %llx\n", tb_seq_0[0], tb_seq_0[1]);
249    }
250
251    *tb_cfg = M_SCD_TRACE_CFG_START;
252    __asm__ __volatile__ ("sync" : : : "memory");
253
254printf("trace start: cfg %llx\n", *tb_cfg);
255    return 0;
256}
257
258static int ui_cmd_tracestop(ui_cmdline_t *cmd, int argc, char *argv[])
259{
260    volatile uint64_t *tb_cfg;
261
262    tb_cfg = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_CFG);
263    *tb_cfg = M_SCD_TRACE_CFG_STOP;
264    __asm__ __volatile__ ("sync" : : : "memory");
265
266printf("trace stop: cfg %llx\n", *tb_cfg);
267    return 0;
268}
269
270static int ui_cmd_tracefreeze(ui_cmdline_t *cmd, int argc, char *argv[])
271{
272    volatile uint64_t *tb_cfg;
273
274    tb_cfg = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_CFG);
275    *tb_cfg = M_SCD_TRACE_CFG_FREEZE;
276    __asm__ __volatile__ ("sync" : : : "memory");
277
278printf("trace freeze: cfg %llx\n", *tb_cfg);
279    return 0;
280}
281
282/* read out trace buffer to dump to a file */
283
284static int ui_cmd_traceread(ui_cmdline_t *cmd, int argc, char *argv[])
285{
286    uint64_t *p;
287    volatile uint64_t *tb_cfg;
288    volatile uint64_t *tb_read;
289    int  i;
290
291    p = KMALLOC(TB_SIZE, 0);
292    if (!p) {
293	printf("trace read: buffer allocation failed\n");
294	return -1;
295	}
296
297    tb_cfg = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_CFG);
298    tb_read = (volatile uint64_t *) PHYS_TO_K1(A_SCD_TRACE_READ);
299
300    while ((*tb_cfg & M_SCD_TRACE_CFG_FREEZE) == 0) {
301        *tb_cfg = M_SCD_TRACE_CFG_FREEZE;
302	__asm__ __volatile__ ("sync" : : : "memory");
303	}
304
305    *tb_cfg = M_SCD_TRACE_CFG_START_READ;
306    __asm__ __volatile__ ("sync" : : : "memory");
307
308    /* Loop runs backward because bundles are read out in reverse order. */
309    for (i = 256*6; i > 0; i -= 6) {
310        /* Subscripts decrease to put bundle in order. */
311	p[i-1] = *tb_read;    /* t2 hi */
312        p[i-2] = *tb_read;    /* t2 lo */
313        p[i-3] = *tb_read;    /* t1 hi */
314        p[i-4] = *tb_read;    /* t1 lo */
315        p[i-5] = *tb_read;    /* t0 hi */
316        p[i-6] = *tb_read;    /* t0 lo */
317	}
318
319    printf("save hardy:ehs/sample.trace %p 0x%lx\n", p, TB_SIZE);
320
321    return 0;
322}
323