1/***********************license start***************
2 * Copyright (c) 2003-2010  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
42
43
44
45/**
46 * @file
47 *
48 * Interface to the Trace buffer hardware.
49 *
50 * <hr>$Revision: 30644 $<hr>
51 */
52#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
53#include <linux/module.h>
54#include <asm/octeon/cvmx.h>
55#include <asm/octeon/cvmx-tra.h>
56#include <asm/octeon/cvmx-l2c.h>
57#else
58#include "cvmx.h"
59#include "cvmx-tra.h"
60#include "cvmx-l2c.h"
61#endif
62
63static const char *TYPE_ARRAY[] = {
64    "DWB - Don't write back",
65    "PL2 - Prefetch into L2",
66    "PSL1 - Dcache fill, skip L2",
67    "LDD - Dcache fill",
68    "LDI - Icache/IO fill",
69    "LDT - Icache/IO fill, skip L2",
70    "STF - Store full",
71    "STC - Store conditional",
72    "STP - Store partial",
73    "STT - Store full, skip L2",
74    "IOBLD8 - IOB 8bit load",
75    "IOBLD16 - IOB 16bit load",
76    "IOBLD32 - IOB 32bit load",
77    "IOBLD64 - IOB 64bit load",
78    "IOBST - IOB store",
79    "IOBDMA - Async IOB",
80    "SAA - Store atomic add",
81    "RSVD17",
82    "RSVD18",
83    "RSVD19",
84    "RSVD20",
85    "RSVD21",
86    "RSVD22",
87    "RSVD23",
88    "RSVD24",
89    "RSVD25",
90    "RSVD26",
91    "RSVD27",
92    "RSVD28",
93    "RSVD29",
94    "RSVD30",
95    "RSVD31"
96};
97
98static const char *TYPE_ARRAY2[] = {
99    "NOP - None",
100    "LDT - Icache/IO fill, skip L2",
101    "LDI - Icache/IO fill",
102    "PL2 - Prefetch into L2",
103    "RPL2 - Mark for replacement in L2",
104    "DWB - Don't write back",
105    "RSVD6",
106    "RSVD7",
107    "LDD - Dcache fill",
108    "PSL1 - Prefetch L1, skip L2",
109    "RSVD10",
110    "RSVD11",
111    "RSVD12",
112    "RSVD13",
113    "RSVD14",
114    "IOBDMA - Async IOB",
115    "STF - Store full",
116    "STT - Store full, skip L2",
117    "STP - Store partial",
118    "STC - Store conditional",
119    "STFIL1 - Store full, invalidate L1",
120    "STTIL1 - Store full, skip L2, invalidate L1",
121    "FAS32 - Atomic 32bit swap",
122    "FAS64 - Atomic 64bit swap",
123    "WBIL2i - Writeback, invalidate, by index/way",
124    "LTGL2i - Read tag@index/way",
125    "STGL2i - Write tag@index/way",
126    "RSVD27",
127    "INVL2 - Invalidate, by address",
128    "WBIL2 - Writeback, invalidate, by address",
129    "WBL2 - Writeback, by address",
130    "LCKL2 - Allocate, lock, by address",
131    "IOBLD8 - IOB 8bit load",
132    "IOBLD16 - IOB 16bit load",
133    "IOBLD32 - IOB 32bit load",
134    "IOBLD64 - IOB 64bit load",
135    "IOBST8 - IOB 8bit store",
136    "IOBST16 - IOB 16bit store",
137    "IOBST32 - IOB 32bit store",
138    "IOBST64 - IOB 64bit store",
139    "SET8 - 8bit Atomic swap with 1's",
140    "SET16 - 16bit Atomic swap with 1's",
141    "SET32 - 32bit Atomic swap with 1's",
142    "SET64 - 64bit Atomic swap with 1's",
143    "CLR8 - 8bit Atomic swap with 0's",
144    "CLR16 - 16bit Atomic swap with 0's",
145    "CLR32 - 32bit Atomic swap with 0's",
146    "CLR64 - 64bit Atomic swap with 0's",
147    "INCR8 - 8bit Atomic fetch & add by 1",
148    "INCR16 - 16bit Atomic fetch & add by 1",
149    "INCR32 - 32bit Atomic fetch & add by 1",
150    "INCR64 - 64bit Atomic fetch & add by 1",
151    "DECR8 - 8bit Atomic fetch & add by -1",
152    "DECR16 - 16bit Atomic fetch & add by -1",
153    "DECR32 - 32bit Atomic fetch & add by -1",
154    "DECR64 - 64bit Atomic fetch & add by -1",
155    "RSVD56",
156    "RSVD57",
157    "FAA32 - 32bit Atomic fetch and add",
158    "FAA64 - 64bit Atomic fetch and add",
159    "RSVD60",
160    "RSVD61",
161    "SAA32 - 32bit Atomic add",
162    "SAA64 - 64bit Atomic add"
163};
164
165static const char *SOURCE_ARRAY[] = {
166    "PP0",
167    "PP1",
168    "PP2",
169    "PP3",
170    "PP4",
171    "PP5",
172    "PP6",
173    "PP7",
174    "PP8",
175    "PP9",
176    "PP10",
177    "PP11",
178    "PP12",
179    "PP13",
180    "PP14",
181    "PP15",
182    "PIP/IPD",
183    "PKO-R",
184    "FPA/TIM/DFA/PCI/ZIP/POW/PKO-W",
185    "DWB",
186    "RSVD20",
187    "RSVD21",
188    "RSVD22",
189    "RSVD23",
190    "RSVD24",
191    "RSVD25",
192    "RSVD26",
193    "RSVD27",
194    "RSVD28",
195    "RSVD29",
196    "RSVD30",
197    "RSVD31",
198    "PP16",
199    "PP17",
200    "PP18",
201    "PP19",
202    "PP20",
203    "PP21",
204    "PP22",
205    "PP23",
206    "PP24",
207    "PP25",
208    "PP26",
209    "PP27",
210    "PP28",
211    "PP29",
212    "PP30",
213    "PP31"
214};
215
216static const char *DEST_ARRAY[] = {
217    "CIU/GPIO",
218    "RSVD1",
219    "RSVD2",
220    "PCI/PCIe/SLI",
221    "KEY",
222    "FPA",
223    "DFA",
224    "ZIP",
225    "RNG",
226    "IPD",
227    "PKO",
228    "RSVD11",
229    "POW",
230    "USB0",
231    "RAD",
232    "RSVD15",
233    "RSVD16",
234    "RSVD17",
235    "RSVD18",
236    "RSVD19",
237    "RSVD20",
238    "RSVD21",
239    "RSVD22",
240    "RSVD23",
241    "RSVD24",
242    "RSVD25",
243    "RSVD26",
244    "DPI",
245    "RSVD28",
246    "RSVD29",
247    "FAU",
248    "RSVD31"
249};
250
251int _cvmx_tra_unit = 0;
252
253#define CVMX_TRA_SOURCE_MASK       (OCTEON_IS_MODEL(OCTEON_CN63XX) ? 0xf00ff : 0xfffff)
254#define CVMX_TRA_DESTINATION_MASK  0xfffffffful
255
256/**
257 * @INTERNAL
258 * Setup the trace buffer filter command mask. The bit position of filter commands
259 * are different for each Octeon model.
260 *
261 * @param filter    Which event to log
262 * @return          Bitmask of filter command based on the event.
263 */
264static uint64_t __cvmx_tra_set_filter_cmd_mask(cvmx_tra_filt_t filter)
265{
266    cvmx_tra_filt_cmd_t filter_command;
267
268    if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX))
269    {
270        /* Bit positions of filter commands are different, map it accordingly */
271        uint64_t cmd = 0;
272        if ((filter & CVMX_TRA_FILT_ALL) == -1ull)
273        {
274            if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
275                cmd = 0x1ffff;
276            else
277                cmd = 0xffff;
278        }
279        if (filter & CVMX_TRA_FILT_DWB)
280            cmd |= 1ull<<0;
281        if (filter & CVMX_TRA_FILT_PL2)
282            cmd |= 1ull<<1;
283        if (filter & CVMX_TRA_FILT_PSL1)
284            cmd |= 1ull<<2;
285        if (filter & CVMX_TRA_FILT_LDD)
286            cmd |= 1ull<<3;
287        if (filter & CVMX_TRA_FILT_LDI)
288            cmd |= 1ull<<4;
289        if (filter & CVMX_TRA_FILT_LDT)
290            cmd |= 1ull<<5;
291        if (filter & CVMX_TRA_FILT_STF)
292            cmd |= 1ull<<6;
293        if (filter & CVMX_TRA_FILT_STC)
294            cmd |= 1ull<<7;
295        if (filter & CVMX_TRA_FILT_STP)
296            cmd |= 1ull<<8;
297        if (filter & CVMX_TRA_FILT_STT)
298            cmd |= 1ull<<9;
299        if (filter & CVMX_TRA_FILT_IOBLD8)
300            cmd |= 1ull<<10;
301        if (filter & CVMX_TRA_FILT_IOBLD16)
302            cmd |= 1ull<<11;
303        if (filter & CVMX_TRA_FILT_IOBLD32)
304            cmd |= 1ull<<12;
305        if (filter & CVMX_TRA_FILT_IOBLD64)
306            cmd |= 1ull<<13;
307        if (filter & CVMX_TRA_FILT_IOBST)
308            cmd |= 1ull<<14;
309        if (filter & CVMX_TRA_FILT_IOBDMA)
310            cmd |= 1ull<<15;
311        if (OCTEON_IS_MODEL(OCTEON_CN5XXX) && (filter & CVMX_TRA_FILT_SAA))
312            cmd |= 1ull<<16;
313
314        filter_command.u64 = cmd;
315    }
316    else
317    {
318        if ((filter & CVMX_TRA_FILT_ALL) == -1ull)
319            filter_command.u64 = CVMX_TRA_FILT_ALL;
320        else
321            filter_command.u64 = filter;
322
323        filter_command.cn63xx.reserved_60_61 = 0;
324        filter_command.cn63xx.reserved_56_57 = 0;
325        filter_command.cn63xx.reserved_27_27 = 0;
326        filter_command.cn63xx.reserved_10_14 = 0;
327        filter_command.cn63xx.reserved_6_7 = 0;
328    }
329    return filter_command.u64;
330}
331
332
333/**
334 * Setup the TRA buffer for use
335 *
336 * @param control TRA control setup
337 * @param filter  Which events to log
338 * @param source_filter
339 *                Source match
340 * @param dest_filter
341 *                Destination match
342 * @param address Address compare
343 * @param address_mask
344 *                Address mask
345 */
346void cvmx_tra_setup(cvmx_tra_ctl_t control, cvmx_tra_filt_t filter,
347                    cvmx_tra_sid_t source_filter, cvmx_tra_did_t dest_filter,
348                    uint64_t address, uint64_t address_mask)
349{
350    cvmx_tra_filt_cmd_t filt_cmd;
351    cvmx_tra_filt_sid_t filt_sid;
352    cvmx_tra_filt_did_t filt_did;
353    int tad;
354
355    filt_cmd.u64 = __cvmx_tra_set_filter_cmd_mask(filter);
356    filt_sid.u64 = source_filter & CVMX_TRA_SOURCE_MASK;
357    filt_did.u64 = dest_filter & CVMX_TRA_DESTINATION_MASK;
358
359    /* Address filtering does not work when IOBDMA filter command is enabled
360       because of some caveats.  Disable the IOBDMA filter command. */
361    if ((OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
362        && ((filt_cmd.u64 & CVMX_TRA_FILT_IOBDMA) == CVMX_TRA_FILT_IOBDMA)
363        && address_mask != 0)
364    {
365        cvmx_dprintf("The address-based filtering does not work with IOBDMAs, disabling the filter command.\n");
366        filt_cmd.u64 &= ~(CVMX_TRA_FILT_IOBDMA);
367    }
368
369    /* In OcteonII pass2, the mode bit is added to enable reading the trace
370       buffer data from different registers for lower and upper 64-bit value.
371       This bit is reserved in other Octeon models. */
372    control.s.rdat_md = 1;
373
374    for (tad = 0; tad < CVMX_L2C_TADS; tad++)
375    {
376        cvmx_write_csr(CVMX_TRAX_CTL(tad),            control.u64);
377        cvmx_write_csr(CVMX_TRAX_FILT_CMD(tad),       filt_cmd.u64);
378        cvmx_write_csr(CVMX_TRAX_FILT_SID(tad),       filt_sid.u64);
379        cvmx_write_csr(CVMX_TRAX_FILT_DID(tad),       filt_did.u64);
380        cvmx_write_csr(CVMX_TRAX_FILT_ADR_ADR(tad),   address);
381        cvmx_write_csr(CVMX_TRAX_FILT_ADR_MSK(tad),   address_mask);
382    }
383}
384#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
385EXPORT_SYMBOL(cvmx_tra_setup);
386#endif
387
388/**
389 * Setup each TRA buffer for use
390 *
391 * @param tra     Which TRA buffer to use (0-3)
392 * @param control TRA control setup
393 * @param filter  Which events to log
394 * @param source_filter
395 *                Source match
396 * @param dest_filter
397 *                Destination match
398 * @param address Address compare
399 * @param address_mask
400 *                Address mask
401 */
402void cvmx_tra_setup_v2(int tra, cvmx_tra_ctl_t control, cvmx_tra_filt_t filter,
403                    cvmx_tra_sid_t source_filter, cvmx_tra_did_t dest_filter,
404                    uint64_t address, uint64_t address_mask)
405{
406    cvmx_tra_filt_cmd_t filt_cmd;
407    cvmx_tra_filt_sid_t filt_sid;
408    cvmx_tra_filt_did_t filt_did;
409
410    if ((tra + 1) > CVMX_L2C_TADS)
411    {
412        cvmx_dprintf("cvmx_tra_setup_per_tra: Invalid tra(%d), max allowed (%d)\n", tra, CVMX_L2C_TADS - 1);
413        tra = 0;
414    }
415
416    filt_cmd.u64 = __cvmx_tra_set_filter_cmd_mask(filter);
417    filt_sid.u64 = source_filter & CVMX_TRA_SOURCE_MASK;
418    filt_did.u64 = dest_filter & CVMX_TRA_DESTINATION_MASK;
419
420    /* Address filtering does not work when IOBDMA filter command is enabled
421       because of some caveats.  Disable the IOBDMA filter command. */
422    if ((OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
423        && ((filt_cmd.u64 & CVMX_TRA_FILT_IOBDMA) == CVMX_TRA_FILT_IOBDMA)
424        && address_mask != 0)
425    {
426        cvmx_dprintf("The address-based filtering does not work with IOBDMAs, disabling the filter command.\n");
427        filt_cmd.u64 &= ~(CVMX_TRA_FILT_IOBDMA);
428    }
429
430    /* In OcteonII pass2, the mode bit is added to enable reading the trace
431       buffer data from different registers for lower and upper 64-bit value.
432       This bit is reserved in other Octeon models. */
433    control.s.rdat_md = 1;
434
435    cvmx_write_csr(CVMX_TRAX_CTL(tra),            control.u64);
436    cvmx_write_csr(CVMX_TRAX_FILT_CMD(tra),       filt_cmd.u64);
437    cvmx_write_csr(CVMX_TRAX_FILT_SID(tra),       filt_sid.u64);
438    cvmx_write_csr(CVMX_TRAX_FILT_DID(tra),       filt_did.u64);
439    cvmx_write_csr(CVMX_TRAX_FILT_ADR_ADR(tra),   address);
440    cvmx_write_csr(CVMX_TRAX_FILT_ADR_MSK(tra),   address_mask);
441}
442#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
443EXPORT_SYMBOL(cvmx_tra_setup_v2);
444#endif
445
446/**
447 * Setup a TRA trigger. How the triggers are used should be
448 * setup using cvmx_tra_setup.
449 *
450 * @param trigger Trigger to setup (0 or 1)
451 * @param filter  Which types of events to trigger on
452 * @param source_filter
453 *                Source trigger match
454 * @param dest_filter
455 *                Destination trigger match
456 * @param address Trigger address compare
457 * @param address_mask
458 *                Trigger address mask
459 */
460void cvmx_tra_trig_setup(uint64_t trigger, cvmx_tra_filt_t filter,
461                         cvmx_tra_sid_t source_filter, cvmx_tra_did_t dest_filter,
462                         uint64_t address, uint64_t address_mask)
463{
464    cvmx_tra_filt_cmd_t tra_filt_cmd;
465    cvmx_tra_filt_sid_t tra_filt_sid;
466    cvmx_tra_filt_did_t tra_filt_did;
467    int tad;
468
469    tra_filt_cmd.u64 = __cvmx_tra_set_filter_cmd_mask(filter);
470    tra_filt_sid.u64 = source_filter & CVMX_TRA_SOURCE_MASK;
471    tra_filt_did.u64 = dest_filter & CVMX_TRA_DESTINATION_MASK;
472
473    /* Address filtering does not work when IOBDMA filter command is enabled
474       because of some caveats.  Disable the IOBDMA filter command. */
475    if ((OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
476        && ((tra_filt_cmd.u64 & CVMX_TRA_FILT_IOBDMA) == CVMX_TRA_FILT_IOBDMA)
477        && address_mask != 0)
478    {
479        cvmx_dprintf("The address-based filtering does not work with IOBDMAs, disabling the filter command.\n");
480        tra_filt_cmd.u64 &= ~(CVMX_TRA_FILT_IOBDMA);
481    }
482
483    for (tad = 0; tad < CVMX_L2C_TADS; tad++)
484    {
485        cvmx_write_csr(CVMX_TRAX_TRIG0_CMD(tad) + trigger * 64,       tra_filt_cmd.u64);
486        cvmx_write_csr(CVMX_TRAX_TRIG0_SID(tad) + trigger * 64,       tra_filt_sid.u64);
487        cvmx_write_csr(CVMX_TRAX_TRIG0_DID(tad) + trigger * 64,       tra_filt_did.u64);
488        cvmx_write_csr(CVMX_TRAX_TRIG0_ADR_ADR(tad) + trigger * 64,   address);
489        cvmx_write_csr(CVMX_TRAX_TRIG0_ADR_MSK(tad) + trigger * 64,   address_mask);
490    }
491}
492#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
493EXPORT_SYMBOL(cvmx_tra_trig_setup);
494#endif
495
496/**
497 * Setup each TRA trigger. How the triggers are used should be
498 * setup using cvmx_tra_setup.
499 *
500 * @param tra     Which TRA buffer to use (0-3)
501 * @param trigger Trigger to setup (0 or 1)
502 * @param filter  Which types of events to trigger on
503 * @param source_filter
504 *                Source trigger match
505 * @param dest_filter
506 *                Destination trigger match
507 * @param address Trigger address compare
508 * @param address_mask
509 *                Trigger address mask
510 */
511void cvmx_tra_trig_setup_v2(int tra, uint64_t trigger, cvmx_tra_filt_t filter,
512                         cvmx_tra_sid_t source_filter, cvmx_tra_did_t dest_filter,
513                         uint64_t address, uint64_t address_mask)
514{
515    cvmx_tra_filt_cmd_t tra_filt_cmd;
516    cvmx_tra_filt_sid_t tra_filt_sid;
517    cvmx_tra_filt_did_t tra_filt_did;
518
519    tra_filt_cmd.u64 = __cvmx_tra_set_filter_cmd_mask(filter);
520    tra_filt_sid.u64 = source_filter & CVMX_TRA_SOURCE_MASK;
521    tra_filt_did.u64 = dest_filter & CVMX_TRA_DESTINATION_MASK;
522
523    /* Address filtering does not work when IOBDMA filter command is enabled
524       because of some caveats.  Disable the IOBDMA filter command. */
525    if ((OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
526        && ((tra_filt_cmd.u64 & CVMX_TRA_FILT_IOBDMA) == CVMX_TRA_FILT_IOBDMA)
527        && address_mask != 0)
528    {
529        cvmx_dprintf("The address-based filtering does not work with IOBDMAs, disabling the filter command.\n");
530        tra_filt_cmd.u64 &= ~(CVMX_TRA_FILT_IOBDMA);
531    }
532
533    cvmx_write_csr(CVMX_TRAX_TRIG0_CMD(tra) + trigger * 64,       tra_filt_cmd.u64);
534    cvmx_write_csr(CVMX_TRAX_TRIG0_SID(tra) + trigger * 64,       tra_filt_sid.u64);
535    cvmx_write_csr(CVMX_TRAX_TRIG0_DID(tra) + trigger * 64,       tra_filt_did.u64);
536    cvmx_write_csr(CVMX_TRAX_TRIG0_ADR_ADR(tra) + trigger * 64,   address);
537    cvmx_write_csr(CVMX_TRAX_TRIG0_ADR_MSK(tra) + trigger * 64,   address_mask);
538}
539#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
540EXPORT_SYMBOL(cvmx_tra_trig_setup_v2);
541#endif
542
543/**
544 * Read an entry from the TRA buffer
545 *
546 * @return Value return. High bit will be zero if there wasn't any data
547 */
548cvmx_tra_data_t cvmx_tra_read(void)
549{
550    uint64_t address = CVMX_TRA_READ_DAT;
551    cvmx_tra_data_t result;
552
553    /* The trace buffer format is wider than 64-bits in OcteonII model,
554       read the register again to get the second part of the data. */
555    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
556    {
557        /* These reads need to be as close as possible to each other */
558        result.u128.data = cvmx_read_csr(address);
559        result.u128.datahi = cvmx_read_csr(address);
560    }
561    else if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) && !OCTEON_IS_MODEL(OCTEON_CN5XXX))
562    {
563        /* OcteonII pass2 uses different trace buffer data register for reading
564           lower and upper 64-bit values */
565        result.u128.data = cvmx_read_csr(address);
566        result.u128.datahi = cvmx_read_csr(CVMX_TRA_READ_DAT_HI);
567    }
568    else
569    {
570        result.u128.data = cvmx_read_csr(address);
571        result.u128.datahi = 0;
572    }
573
574    return result;
575}
576
577/**
578 * Read an entry from the TRA buffer from a given TRA unit.
579 *
580 * @param tra_unit  Trace buffer unit to read
581 *
582 * @return Value return. High bit will be zero if there wasn't any data
583 */
584cvmx_tra_data_t cvmx_tra_read_v2(int tra_unit)
585{
586    cvmx_tra_data_t result;
587
588    result.u128.data = cvmx_read_csr(CVMX_TRAX_READ_DAT(tra_unit));
589    result.u128.datahi = cvmx_read_csr(CVMX_TRAX_READ_DAT_HI(tra_unit));
590
591    return result;
592}
593
594/**
595 * Decode a TRA entry into human readable output
596 *
597 * @param tra_ctl Trace control setup
598 * @param data    Data to decode
599 */
600void cvmx_tra_decode_text(cvmx_tra_ctl_t tra_ctl, cvmx_tra_data_t data)
601{
602    if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX))
603    {
604        /* The type is a five bit field for some entries and 4 for other. The four
605           bit entries can be mis-typed if the top is set */
606        int type = data.cmn.type;
607
608        if (type >= 0x1a)
609            type &= 0xf;
610
611        switch (type)
612        {
613            case 0:  /* DWB */
614            case 1:  /* PL2 */
615            case 2:  /* PSL1 */
616            case 3:  /* LDD */
617            case 4:  /* LDI */
618            case 5:  /* LDT */
619                cvmx_dprintf("0x%016llx %c%+10d %s %s 0x%016llx\n",
620                    (unsigned long long)data.u128.data,
621                    (data.cmn.discontinuity) ? 'D' : ' ',
622                    data.cmn.timestamp << (tra_ctl.s.time_grn*3),
623                    TYPE_ARRAY[type],
624                    SOURCE_ARRAY[data.cmn.source],
625                    (unsigned long long)data.cmn.address);
626                break;
627            case 6:  /* STF */
628            case 7:  /* STC */
629            case 8:  /* STP */
630            case 9:  /* STT */
631            case 16: /* SAA */
632                cvmx_dprintf("0x%016llx %c%+10d %s %s mask=0x%02x 0x%016llx\n",
633                   (unsigned long long)data.u128.data,
634                   (data.cmn.discontinuity) ? 'D' : ' ',
635                   data.cmn.timestamp << (tra_ctl.s.time_grn*3),
636                   TYPE_ARRAY[type],
637                   SOURCE_ARRAY[data.store.source],
638                   (unsigned int)data.store.mask,
639                   (unsigned long long)data.store.address << 3);
640                break;
641            case 10:  /* IOBLD8 */
642            case 11:  /* IOBLD16 */
643            case 12:  /* IOBLD32 */
644            case 13:  /* IOBLD64 */
645            case 14:  /* IOBST */
646                cvmx_dprintf("0x%016llx %c%+10d %s %s->%s subdid=0x%x 0x%016llx\n",
647                   (unsigned long long)data.u128.data,
648                   (data.cmn.discontinuity) ? 'D' : ' ',
649                   data.cmn.timestamp << (tra_ctl.s.time_grn*3),
650                   TYPE_ARRAY[type],
651                   SOURCE_ARRAY[data.iobld.source],
652                   DEST_ARRAY[data.iobld.dest],
653                   (unsigned int)data.iobld.subid,
654                   (unsigned long long)data.iobld.address);
655                break;
656            case 15:  /* IOBDMA */
657                cvmx_dprintf("0x%016llx %c%+10d %s %s->%s len=0x%x 0x%016llx\n",
658                   (unsigned long long)data.u128.data,
659                   (data.cmn.discontinuity) ? 'D' : ' ',
660                   data.cmn.timestamp << (tra_ctl.s.time_grn*3),
661                   TYPE_ARRAY[type],
662                   SOURCE_ARRAY[data.iob.source],
663                   DEST_ARRAY[data.iob.dest],
664                   (unsigned int)data.iob.mask,
665                   (unsigned long long)data.iob.address << 3);
666                break;
667            default:
668                cvmx_dprintf("0x%016llx %c%+10d Unknown format\n",
669                   (unsigned long long)data.u128.data,
670                   (data.cmn.discontinuity) ? 'D' : ' ',
671                   data.cmn.timestamp << (tra_ctl.s.time_grn*3));
672                break;
673        }
674    }
675    else
676    {
677        int type;
678        int srcId;
679
680        type = data.cmn2.type;
681
682        switch (1ull<<type)
683        {
684            case CVMX_TRA_FILT_DECR64:
685            case CVMX_TRA_FILT_DECR32:
686            case CVMX_TRA_FILT_DECR16:
687            case CVMX_TRA_FILT_DECR8:
688            case CVMX_TRA_FILT_INCR64:
689            case CVMX_TRA_FILT_INCR32:
690            case CVMX_TRA_FILT_INCR16:
691            case CVMX_TRA_FILT_INCR8:
692            case CVMX_TRA_FILT_CLR64:
693            case CVMX_TRA_FILT_CLR32:
694            case CVMX_TRA_FILT_CLR16:
695            case CVMX_TRA_FILT_CLR8:
696            case CVMX_TRA_FILT_SET64:
697            case CVMX_TRA_FILT_SET32:
698            case CVMX_TRA_FILT_SET16:
699            case CVMX_TRA_FILT_SET8:
700            case CVMX_TRA_FILT_LCKL2:
701            case CVMX_TRA_FILT_WBIL2:
702            case CVMX_TRA_FILT_INVL2:
703            case CVMX_TRA_FILT_STGL2I:
704            case CVMX_TRA_FILT_LTGL2I:
705            case CVMX_TRA_FILT_WBIL2I:
706            case CVMX_TRA_FILT_WBL2:
707            case CVMX_TRA_FILT_DWB:
708            case CVMX_TRA_FILT_RPL2:
709            case CVMX_TRA_FILT_PL2:
710            case CVMX_TRA_FILT_LDI:
711            case CVMX_TRA_FILT_LDT:
712                /* CN68XX has 32 cores which are distributed to use different
713                   trace buffers, decode the core that has data */
714                if (OCTEON_IS_MODEL(OCTEON_CN68XX))
715                {
716                    if (data.cmn2.source <= 7)
717                    {
718                        srcId = _cvmx_tra_unit + (data.cmn2.source * 4);
719                        if (srcId >= 16)
720                            srcId += 16;
721                    }
722                    else
723                        srcId = (data.cmn2.source);
724                }
725                else
726                        srcId = (data.cmn2.source);
727
728                cvmx_dprintf("0x%016llx%016llx %c%+10d %s %s 0x%016llx%llx\n",
729                   (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data,
730                   (data.cmn2.discontinuity) ? 'D' : ' ',
731                   data.cmn2.timestamp << (tra_ctl.s.time_grn*3),
732                   TYPE_ARRAY2[type],
733                   SOURCE_ARRAY[srcId],
734                   (unsigned long long)data.cmn2.addresshi,
735                   (unsigned long long)data.cmn2.addresslo);
736                break;
737            case CVMX_TRA_FILT_PSL1:
738            case CVMX_TRA_FILT_LDD:
739            case CVMX_TRA_FILT_FAS64:
740            case CVMX_TRA_FILT_FAS32:
741            case CVMX_TRA_FILT_FAA64:
742            case CVMX_TRA_FILT_FAA32:
743            case CVMX_TRA_FILT_SAA64:
744            case CVMX_TRA_FILT_SAA32:
745            case CVMX_TRA_FILT_STC:
746            case CVMX_TRA_FILT_STF:
747            case CVMX_TRA_FILT_STP:
748            case CVMX_TRA_FILT_STT:
749            case CVMX_TRA_FILT_STTIL1:
750            case CVMX_TRA_FILT_STFIL1:
751                /* CN68XX has 32 cores which are distributed to use different
752                   trace buffers, decode the core that has data */
753                if (OCTEON_IS_MODEL(OCTEON_CN68XX))
754                {
755                    if (data.store2.source <= 7)
756                    {
757                        srcId = _cvmx_tra_unit + (data.store2.source * 4);
758                        if (srcId >= 16)
759                            srcId += 16;
760                    }
761                    else
762                        srcId = data.store2.source;
763                }
764                else
765                        srcId = data.store2.source;
766
767                cvmx_dprintf("0x%016llx%016llx %c%+10d %s %s mask=0x%02x 0x%016llx%llx\n",
768                   (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data,
769                   (data.cmn2.discontinuity) ? 'D' : ' ',
770                   data.cmn2.timestamp << (tra_ctl.s.time_grn*3),
771                   TYPE_ARRAY2[type],
772                   SOURCE_ARRAY[srcId],
773                   (unsigned int)data.store2.mask,
774                   (unsigned long long)data.store2.addresshi,
775                   (unsigned long long)data.store2.addresslo);
776                break;
777            case CVMX_TRA_FILT_IOBST64:
778            case CVMX_TRA_FILT_IOBST32:
779            case CVMX_TRA_FILT_IOBST16:
780            case CVMX_TRA_FILT_IOBST8:
781            case CVMX_TRA_FILT_IOBLD64:
782            case CVMX_TRA_FILT_IOBLD32:
783            case CVMX_TRA_FILT_IOBLD16:
784            case CVMX_TRA_FILT_IOBLD8:
785                /* CN68XX has 32 cores which are distributed to use different
786                   trace buffers, decode the core that has data */
787                if (OCTEON_IS_MODEL(OCTEON_CN68XX))
788                {
789                    if (data.iobld2.source <= 7)
790                    {
791                        srcId = _cvmx_tra_unit + (data.iobld2.source * 4);
792                        if (srcId >= 16)
793                            srcId += 16;
794                    }
795                    else
796                        srcId = data.iobld2.source;
797                }
798                else
799                        srcId = data.iobld2.source;
800
801                cvmx_dprintf("0x%016llx%016llx %c%+10d %s %s->%s subdid=0x%x 0x%016llx%llx\n",
802                   (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data,
803                   (data.cmn2.discontinuity) ? 'D' : ' ',
804                   data.cmn2.timestamp << (tra_ctl.s.time_grn*3),
805                   TYPE_ARRAY2[type],
806                   SOURCE_ARRAY[srcId],
807                   DEST_ARRAY[data.iobld2.dest],
808                   (unsigned int)data.iobld2.subid,
809                   (unsigned long long)data.iobld2.addresshi,
810                   (unsigned long long)data.iobld2.addresslo);
811                break;
812            case CVMX_TRA_FILT_IOBDMA:
813                /* CN68XX has 32 cores which are distributed to use different
814                   trace buffers, decode the core that has data */
815                if (OCTEON_IS_MODEL(OCTEON_CN68XX))
816                {
817                    if (data.iob2.source <= 7)
818                    {
819                        srcId = _cvmx_tra_unit + (data.iob2.source * 4);
820                        if (srcId >= 16)
821                            srcId += 16;
822                    }
823                    else
824                        srcId = data.iob2.source;
825                }
826                else
827                        srcId = data.iob2.source;
828
829                cvmx_dprintf("0x%016llx%016llx %c%+10d %s %s->%s len=0x%x 0x%016llx%llx\n",
830                   (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data,
831                   (data.iob2.discontinuity) ? 'D' : ' ',
832                   data.iob2.timestamp << (tra_ctl.s.time_grn*3),
833                   TYPE_ARRAY2[type],
834                   SOURCE_ARRAY[srcId],
835                   DEST_ARRAY[data.iob2.dest],
836                   (unsigned int)data.iob2.mask,
837                   (unsigned long long)data.iob2.addresshi << 3,
838                   (unsigned long long)data.iob2.addresslo << 3);
839                break;
840            default:
841                cvmx_dprintf("0x%016llx%016llx %c%+10d Unknown format\n",
842                   (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data,
843                   (data.cmn2.discontinuity) ? 'D' : ' ',
844                   data.cmn2.timestamp << (tra_ctl.s.time_grn*3));
845                break;
846        }
847    }
848}
849
850/**
851 * Display the entire trace buffer. It is advised that you
852 * disable the trace buffer before calling this routine
853 * otherwise it could infinitely loop displaying trace data
854 * that it created.
855 */
856void cvmx_tra_display(void)
857{
858    int valid = 0;
859
860    /* Collect data from each TRA unit for decoding */
861    if (CVMX_L2C_TADS > 1)
862    {
863        cvmx_trax_ctl_t tra_ctl;
864        cvmx_tra_data_t data[4];
865        int tad;
866        do
867        {
868            valid = 0;
869            for (tad = 0; tad < CVMX_L2C_TADS; tad++)
870                data[tad] = cvmx_tra_read_v2(tad);
871
872            for (tad = 0; tad < CVMX_L2C_TADS; tad++)
873            {
874                tra_ctl.u64 = cvmx_read_csr(CVMX_TRAX_CTL(tad));
875
876                if (data[tad].cmn2.valid)
877                {
878                    _cvmx_tra_unit = tad;
879                    cvmx_tra_decode_text(tra_ctl, data[tad]);
880                    valid = 1;
881                }
882            }
883        } while (valid);
884    }
885    else
886    {
887        cvmx_tra_ctl_t tra_ctl;
888        cvmx_tra_data_t data;
889
890        tra_ctl.u64 = cvmx_read_csr(CVMX_TRA_CTL);
891
892        do
893        {
894            data = cvmx_tra_read();
895            if ((OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)) && data.cmn.valid)
896                valid = 1;
897            else if (data.cmn2.valid)
898                valid = 1;
899            else
900                valid = 0;
901
902            if (valid)
903                cvmx_tra_decode_text(tra_ctl, data);
904
905        } while (valid);
906    }
907}
908#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
909EXPORT_SYMBOL(cvmx_tra_display);
910#endif
911
912/**
913 * Display the entire trace buffer. It is advised that you
914 * disable the trace buffer before calling this routine
915 * otherwise it could infinitely loop displaying trace data
916 * that it created.
917 *
918 * @param tra_unit   Which TRA buffer to use.
919 */
920void cvmx_tra_display_v2(int tra_unit)
921{
922    int valid = 0;
923
924    cvmx_trax_ctl_t tra_ctl;
925    cvmx_tra_data_t data;
926
927    valid = 0;
928    tra_ctl.u64 = cvmx_read_csr(CVMX_TRAX_CTL(tra_unit));
929
930    do
931    {
932        data = cvmx_tra_read_v2(tra_unit);
933        if (data.cmn2.valid)
934        {
935            _cvmx_tra_unit = tra_unit;
936            cvmx_tra_decode_text(tra_ctl, data);
937            valid = 1;
938        }
939    } while (valid);
940}
941#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
942EXPORT_SYMBOL(cvmx_tra_display_v2);
943#endif
944