From f8b73ad2e16934621a86fd1fd67b46aa21521d0b Mon Sep 17 00:00:00 2001 From: Juli Mallett Date: Sun, 11 Mar 2012 04:14:00 +0000 Subject: Import Cavium Octeon SDK 2.3.0 Simple Executive from cnusers.org. --- cvmx-tra.c | 386 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 351 insertions(+), 35 deletions(-) (limited to 'cvmx-tra.c') diff --git a/cvmx-tra.c b/cvmx-tra.c index e1585ec161e3..4bf8f453853a 100644 --- a/cvmx-tra.c +++ b/cvmx-tra.c @@ -1,5 +1,5 @@ /***********************license start*************** - * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights + * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights * reserved. * * @@ -15,7 +15,7 @@ * disclaimer in the documentation and/or other materials provided * with the distribution. - * * Neither the name of Cavium Networks nor the names of + * * Neither the name of Cavium Inc. nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. @@ -26,7 +26,7 @@ * countries. * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR + * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM @@ -53,9 +53,11 @@ #include #include #include +#include #else #include "cvmx.h" #include "cvmx-tra.h" +#include "cvmx-l2c.h" #endif static const char *TYPE_ARRAY[] = { @@ -192,7 +194,23 @@ static const char *SOURCE_ARRAY[] = { "RSVD28", "RSVD29", "RSVD30", - "RSVD31" + "RSVD31", + "PP16", + "PP17", + "PP18", + "PP19", + "PP20", + "PP21", + "PP22", + "PP23", + "PP24", + "PP25", + "PP26", + "PP27", + "PP28", + "PP29", + "PP30", + "PP31" }; static const char *DEST_ARRAY[] = { @@ -230,6 +248,8 @@ static const char *DEST_ARRAY[] = { "RSVD31" }; +int _cvmx_tra_unit = 0; + #define CVMX_TRA_SOURCE_MASK (OCTEON_IS_MODEL(OCTEON_CN63XX) ? 0xf00ff : 0xfffff) #define CVMX_TRA_DESTINATION_MASK 0xfffffffful @@ -302,6 +322,7 @@ static uint64_t __cvmx_tra_set_filter_cmd_mask(cvmx_tra_filt_t filter) filter_command.cn63xx.reserved_60_61 = 0; filter_command.cn63xx.reserved_56_57 = 0; + filter_command.cn63xx.reserved_27_27 = 0; filter_command.cn63xx.reserved_10_14 = 0; filter_command.cn63xx.reserved_6_7 = 0; } @@ -329,22 +350,98 @@ void cvmx_tra_setup(cvmx_tra_ctl_t control, cvmx_tra_filt_t filter, cvmx_tra_filt_cmd_t filt_cmd; cvmx_tra_filt_sid_t filt_sid; cvmx_tra_filt_did_t filt_did; + int tad; filt_cmd.u64 = __cvmx_tra_set_filter_cmd_mask(filter); filt_sid.u64 = source_filter & CVMX_TRA_SOURCE_MASK; filt_did.u64 = dest_filter & CVMX_TRA_DESTINATION_MASK; - cvmx_write_csr(CVMX_TRA_CTL, control.u64); - cvmx_write_csr(CVMX_TRA_FILT_CMD, filt_cmd.u64); - cvmx_write_csr(CVMX_TRA_FILT_SID, filt_sid.u64); - cvmx_write_csr(CVMX_TRA_FILT_DID, filt_did.u64); - cvmx_write_csr(CVMX_TRA_FILT_ADR_ADR, address); - cvmx_write_csr(CVMX_TRA_FILT_ADR_MSK, address_mask); + /* Address filtering does not work when IOBDMA filter command is enabled + because of some caveats. Disable the IOBDMA filter command. */ + if ((OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) + && ((filt_cmd.u64 & CVMX_TRA_FILT_IOBDMA) == CVMX_TRA_FILT_IOBDMA) + && address_mask != 0) + { + cvmx_dprintf("The address-based filtering does not work with IOBDMAs, disabling the filter command.\n"); + filt_cmd.u64 &= ~(CVMX_TRA_FILT_IOBDMA); + } + + /* In OcteonII pass2, the mode bit is added to enable reading the trace + buffer data from different registers for lower and upper 64-bit value. + This bit is reserved in other Octeon models. */ + control.s.rdat_md = 1; + + for (tad = 0; tad < CVMX_L2C_TADS; tad++) + { + cvmx_write_csr(CVMX_TRAX_CTL(tad), control.u64); + cvmx_write_csr(CVMX_TRAX_FILT_CMD(tad), filt_cmd.u64); + cvmx_write_csr(CVMX_TRAX_FILT_SID(tad), filt_sid.u64); + cvmx_write_csr(CVMX_TRAX_FILT_DID(tad), filt_did.u64); + cvmx_write_csr(CVMX_TRAX_FILT_ADR_ADR(tad), address); + cvmx_write_csr(CVMX_TRAX_FILT_ADR_MSK(tad), address_mask); + } } #ifdef CVMX_BUILD_FOR_LINUX_KERNEL EXPORT_SYMBOL(cvmx_tra_setup); #endif +/** + * Setup each TRA buffer for use + * + * @param tra Which TRA buffer to use (0-3) + * @param control TRA control setup + * @param filter Which events to log + * @param source_filter + * Source match + * @param dest_filter + * Destination match + * @param address Address compare + * @param address_mask + * Address mask + */ +void cvmx_tra_setup_v2(int tra, cvmx_tra_ctl_t control, cvmx_tra_filt_t filter, + cvmx_tra_sid_t source_filter, cvmx_tra_did_t dest_filter, + uint64_t address, uint64_t address_mask) +{ + cvmx_tra_filt_cmd_t filt_cmd; + cvmx_tra_filt_sid_t filt_sid; + cvmx_tra_filt_did_t filt_did; + + if ((tra + 1) > CVMX_L2C_TADS) + { + cvmx_dprintf("cvmx_tra_setup_per_tra: Invalid tra(%d), max allowed (%d)\n", tra, CVMX_L2C_TADS - 1); + tra = 0; + } + + filt_cmd.u64 = __cvmx_tra_set_filter_cmd_mask(filter); + filt_sid.u64 = source_filter & CVMX_TRA_SOURCE_MASK; + filt_did.u64 = dest_filter & CVMX_TRA_DESTINATION_MASK; + + /* Address filtering does not work when IOBDMA filter command is enabled + because of some caveats. Disable the IOBDMA filter command. */ + if ((OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) + && ((filt_cmd.u64 & CVMX_TRA_FILT_IOBDMA) == CVMX_TRA_FILT_IOBDMA) + && address_mask != 0) + { + cvmx_dprintf("The address-based filtering does not work with IOBDMAs, disabling the filter command.\n"); + filt_cmd.u64 &= ~(CVMX_TRA_FILT_IOBDMA); + } + + /* In OcteonII pass2, the mode bit is added to enable reading the trace + buffer data from different registers for lower and upper 64-bit value. + This bit is reserved in other Octeon models. */ + control.s.rdat_md = 1; + + cvmx_write_csr(CVMX_TRAX_CTL(tra), control.u64); + cvmx_write_csr(CVMX_TRAX_FILT_CMD(tra), filt_cmd.u64); + cvmx_write_csr(CVMX_TRAX_FILT_SID(tra), filt_sid.u64); + cvmx_write_csr(CVMX_TRAX_FILT_DID(tra), filt_did.u64); + cvmx_write_csr(CVMX_TRAX_FILT_ADR_ADR(tra), address); + cvmx_write_csr(CVMX_TRAX_FILT_ADR_MSK(tra), address_mask); +} +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL +EXPORT_SYMBOL(cvmx_tra_setup_v2); +#endif /** * Setup a TRA trigger. How the triggers are used should be @@ -367,21 +464,81 @@ void cvmx_tra_trig_setup(uint64_t trigger, cvmx_tra_filt_t filter, cvmx_tra_filt_cmd_t tra_filt_cmd; cvmx_tra_filt_sid_t tra_filt_sid; cvmx_tra_filt_did_t tra_filt_did; + int tad; tra_filt_cmd.u64 = __cvmx_tra_set_filter_cmd_mask(filter); tra_filt_sid.u64 = source_filter & CVMX_TRA_SOURCE_MASK; tra_filt_did.u64 = dest_filter & CVMX_TRA_DESTINATION_MASK; - cvmx_write_csr(CVMX_TRA_TRIG0_CMD + trigger * 64, tra_filt_cmd.u64); - cvmx_write_csr(CVMX_TRA_TRIG0_SID + trigger * 64, tra_filt_sid.u64); - cvmx_write_csr(CVMX_TRA_TRIG0_DID + trigger * 64, tra_filt_did.u64); - cvmx_write_csr(CVMX_TRA_TRIG0_ADR_ADR + trigger * 64, address); - cvmx_write_csr(CVMX_TRA_TRIG0_ADR_MSK + trigger * 64, address_mask); + /* Address filtering does not work when IOBDMA filter command is enabled + because of some caveats. Disable the IOBDMA filter command. */ + if ((OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) + && ((tra_filt_cmd.u64 & CVMX_TRA_FILT_IOBDMA) == CVMX_TRA_FILT_IOBDMA) + && address_mask != 0) + { + cvmx_dprintf("The address-based filtering does not work with IOBDMAs, disabling the filter command.\n"); + tra_filt_cmd.u64 &= ~(CVMX_TRA_FILT_IOBDMA); + } + + for (tad = 0; tad < CVMX_L2C_TADS; tad++) + { + cvmx_write_csr(CVMX_TRAX_TRIG0_CMD(tad) + trigger * 64, tra_filt_cmd.u64); + cvmx_write_csr(CVMX_TRAX_TRIG0_SID(tad) + trigger * 64, tra_filt_sid.u64); + cvmx_write_csr(CVMX_TRAX_TRIG0_DID(tad) + trigger * 64, tra_filt_did.u64); + cvmx_write_csr(CVMX_TRAX_TRIG0_ADR_ADR(tad) + trigger * 64, address); + cvmx_write_csr(CVMX_TRAX_TRIG0_ADR_MSK(tad) + trigger * 64, address_mask); + } } #ifdef CVMX_BUILD_FOR_LINUX_KERNEL EXPORT_SYMBOL(cvmx_tra_trig_setup); #endif +/** + * Setup each TRA trigger. How the triggers are used should be + * setup using cvmx_tra_setup. + * + * @param tra Which TRA buffer to use (0-3) + * @param trigger Trigger to setup (0 or 1) + * @param filter Which types of events to trigger on + * @param source_filter + * Source trigger match + * @param dest_filter + * Destination trigger match + * @param address Trigger address compare + * @param address_mask + * Trigger address mask + */ +void cvmx_tra_trig_setup_v2(int tra, uint64_t trigger, cvmx_tra_filt_t filter, + cvmx_tra_sid_t source_filter, cvmx_tra_did_t dest_filter, + uint64_t address, uint64_t address_mask) +{ + cvmx_tra_filt_cmd_t tra_filt_cmd; + cvmx_tra_filt_sid_t tra_filt_sid; + cvmx_tra_filt_did_t tra_filt_did; + + tra_filt_cmd.u64 = __cvmx_tra_set_filter_cmd_mask(filter); + tra_filt_sid.u64 = source_filter & CVMX_TRA_SOURCE_MASK; + tra_filt_did.u64 = dest_filter & CVMX_TRA_DESTINATION_MASK; + + /* Address filtering does not work when IOBDMA filter command is enabled + because of some caveats. Disable the IOBDMA filter command. */ + if ((OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) + && ((tra_filt_cmd.u64 & CVMX_TRA_FILT_IOBDMA) == CVMX_TRA_FILT_IOBDMA) + && address_mask != 0) + { + cvmx_dprintf("The address-based filtering does not work with IOBDMAs, disabling the filter command.\n"); + tra_filt_cmd.u64 &= ~(CVMX_TRA_FILT_IOBDMA); + } + + cvmx_write_csr(CVMX_TRAX_TRIG0_CMD(tra) + trigger * 64, tra_filt_cmd.u64); + cvmx_write_csr(CVMX_TRAX_TRIG0_SID(tra) + trigger * 64, tra_filt_sid.u64); + cvmx_write_csr(CVMX_TRAX_TRIG0_DID(tra) + trigger * 64, tra_filt_did.u64); + cvmx_write_csr(CVMX_TRAX_TRIG0_ADR_ADR(tra) + trigger * 64, address); + cvmx_write_csr(CVMX_TRAX_TRIG0_ADR_MSK(tra) + trigger * 64, address_mask); +} +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL +EXPORT_SYMBOL(cvmx_tra_trig_setup_v2); +#endif /** * Read an entry from the TRA buffer @@ -393,14 +550,21 @@ cvmx_tra_data_t cvmx_tra_read(void) uint64_t address = CVMX_TRA_READ_DAT; cvmx_tra_data_t result; - /* The trace buffer format is wider than 64-bits in Octeon2 model, + /* The trace buffer format is wider than 64-bits in OcteonII model, read the register again to get the second part of the data. */ - if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) && !OCTEON_IS_MODEL(OCTEON_CN5XXX)) + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) { /* These reads need to be as close as possible to each other */ result.u128.data = cvmx_read_csr(address); result.u128.datahi = cvmx_read_csr(address); } + else if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) && !OCTEON_IS_MODEL(OCTEON_CN5XXX)) + { + /* OcteonII pass2 uses different trace buffer data register for reading + lower and upper 64-bit values */ + result.u128.data = cvmx_read_csr(address); + result.u128.datahi = cvmx_read_csr(CVMX_TRA_READ_DAT_HI); + } else { result.u128.data = cvmx_read_csr(address); @@ -410,6 +574,23 @@ cvmx_tra_data_t cvmx_tra_read(void) return result; } +/** + * Read an entry from the TRA buffer from a given TRA unit. + * + * @param tra_unit Trace buffer unit to read + * + * @return Value return. High bit will be zero if there wasn't any data + */ +cvmx_tra_data_t cvmx_tra_read_v2(int tra_unit) +{ + cvmx_tra_data_t result; + + result.u128.data = cvmx_read_csr(CVMX_TRAX_READ_DAT(tra_unit)); + result.u128.datahi = cvmx_read_csr(CVMX_TRAX_READ_DAT_HI(tra_unit)); + + return result; +} + /** * Decode a TRA entry into human readable output * @@ -494,6 +675,7 @@ void cvmx_tra_decode_text(cvmx_tra_ctl_t tra_ctl, cvmx_tra_data_t data) else { int type; + int srcId; type = data.cmn2.type; @@ -515,18 +697,40 @@ void cvmx_tra_decode_text(cvmx_tra_ctl_t tra_ctl, cvmx_tra_data_t data) case CVMX_TRA_FILT_SET32: case CVMX_TRA_FILT_SET16: case CVMX_TRA_FILT_SET8: + case CVMX_TRA_FILT_LCKL2: + case CVMX_TRA_FILT_WBIL2: + case CVMX_TRA_FILT_INVL2: + case CVMX_TRA_FILT_STGL2I: + case CVMX_TRA_FILT_LTGL2I: + case CVMX_TRA_FILT_WBIL2I: case CVMX_TRA_FILT_WBL2: case CVMX_TRA_FILT_DWB: case CVMX_TRA_FILT_RPL2: case CVMX_TRA_FILT_PL2: case CVMX_TRA_FILT_LDI: case CVMX_TRA_FILT_LDT: + /* CN68XX has 32 cores which are distributed to use different + trace buffers, decode the core that has data */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + { + if (data.cmn2.source <= 7) + { + srcId = _cvmx_tra_unit + (data.cmn2.source * 4); + if (srcId >= 16) + srcId += 16; + } + else + srcId = (data.cmn2.source); + } + else + srcId = (data.cmn2.source); + cvmx_dprintf("0x%016llx%016llx %c%+10d %s %s 0x%016llx%llx\n", (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data, (data.cmn2.discontinuity) ? 'D' : ' ', data.cmn2.timestamp << (tra_ctl.s.time_grn*3), TYPE_ARRAY2[type], - SOURCE_ARRAY[data.cmn2.source], + SOURCE_ARRAY[srcId], (unsigned long long)data.cmn2.addresshi, (unsigned long long)data.cmn2.addresslo); break; @@ -542,12 +746,30 @@ void cvmx_tra_decode_text(cvmx_tra_ctl_t tra_ctl, cvmx_tra_data_t data) case CVMX_TRA_FILT_STF: case CVMX_TRA_FILT_STP: case CVMX_TRA_FILT_STT: + case CVMX_TRA_FILT_STTIL1: + case CVMX_TRA_FILT_STFIL1: + /* CN68XX has 32 cores which are distributed to use different + trace buffers, decode the core that has data */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + { + if (data.store2.source <= 7) + { + srcId = _cvmx_tra_unit + (data.store2.source * 4); + if (srcId >= 16) + srcId += 16; + } + else + srcId = data.store2.source; + } + else + srcId = data.store2.source; + cvmx_dprintf("0x%016llx%016llx %c%+10d %s %s mask=0x%02x 0x%016llx%llx\n", (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data, (data.cmn2.discontinuity) ? 'D' : ' ', data.cmn2.timestamp << (tra_ctl.s.time_grn*3), TYPE_ARRAY2[type], - SOURCE_ARRAY[data.store2.source], + SOURCE_ARRAY[srcId], (unsigned int)data.store2.mask, (unsigned long long)data.store2.addresshi, (unsigned long long)data.store2.addresslo); @@ -560,24 +782,56 @@ void cvmx_tra_decode_text(cvmx_tra_ctl_t tra_ctl, cvmx_tra_data_t data) case CVMX_TRA_FILT_IOBLD32: case CVMX_TRA_FILT_IOBLD16: case CVMX_TRA_FILT_IOBLD8: + /* CN68XX has 32 cores which are distributed to use different + trace buffers, decode the core that has data */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + { + if (data.iobld2.source <= 7) + { + srcId = _cvmx_tra_unit + (data.iobld2.source * 4); + if (srcId >= 16) + srcId += 16; + } + else + srcId = data.iobld2.source; + } + else + srcId = data.iobld2.source; + cvmx_dprintf("0x%016llx%016llx %c%+10d %s %s->%s subdid=0x%x 0x%016llx%llx\n", (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data, (data.cmn2.discontinuity) ? 'D' : ' ', data.cmn2.timestamp << (tra_ctl.s.time_grn*3), TYPE_ARRAY2[type], - SOURCE_ARRAY[data.iobld2.source], + SOURCE_ARRAY[srcId], DEST_ARRAY[data.iobld2.dest], (unsigned int)data.iobld2.subid, (unsigned long long)data.iobld2.addresshi, (unsigned long long)data.iobld2.addresslo); break; case CVMX_TRA_FILT_IOBDMA: + /* CN68XX has 32 cores which are distributed to use different + trace buffers, decode the core that has data */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + { + if (data.iob2.source <= 7) + { + srcId = _cvmx_tra_unit + (data.iob2.source * 4); + if (srcId >= 16) + srcId += 16; + } + else + srcId = data.iob2.source; + } + else + srcId = data.iob2.source; + cvmx_dprintf("0x%016llx%016llx %c%+10d %s %s->%s len=0x%x 0x%016llx%llx\n", (unsigned long long)data.u128.datahi, (unsigned long long)data.u128.data, (data.iob2.discontinuity) ? 'D' : ' ', data.iob2.timestamp << (tra_ctl.s.time_grn*3), TYPE_ARRAY2[type], - SOURCE_ARRAY[data.iob2.source], + SOURCE_ARRAY[srcId], DEST_ARRAY[data.iob2.dest], (unsigned int)data.iob2.mask, (unsigned long long)data.iob2.addresshi << 3, @@ -601,27 +855,89 @@ void cvmx_tra_decode_text(cvmx_tra_ctl_t tra_ctl, cvmx_tra_data_t data) */ void cvmx_tra_display(void) { - cvmx_tra_ctl_t tra_ctl; - cvmx_tra_data_t data; int valid = 0; - tra_ctl.u64 = cvmx_read_csr(CVMX_TRA_CTL); - - do + /* Collect data from each TRA unit for decoding */ + if (CVMX_L2C_TADS > 1) { - data = cvmx_tra_read(); - if ((OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)) && data.cmn.valid) - valid = 1; - else if (data.cmn2.valid) - valid = 1; - else + cvmx_trax_ctl_t tra_ctl; + cvmx_tra_data_t data[4]; + int tad; + do + { valid = 0; + for (tad = 0; tad < CVMX_L2C_TADS; tad++) + data[tad] = cvmx_tra_read_v2(tad); + + for (tad = 0; tad < CVMX_L2C_TADS; tad++) + { + tra_ctl.u64 = cvmx_read_csr(CVMX_TRAX_CTL(tad)); + + if (data[tad].cmn2.valid) + { + _cvmx_tra_unit = tad; + cvmx_tra_decode_text(tra_ctl, data[tad]); + valid = 1; + } + } + } while (valid); + } + else + { + cvmx_tra_ctl_t tra_ctl; + cvmx_tra_data_t data; - if (valid) - cvmx_tra_decode_text(tra_ctl, data); + tra_ctl.u64 = cvmx_read_csr(CVMX_TRA_CTL); - } while (valid); + do + { + data = cvmx_tra_read(); + if ((OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)) && data.cmn.valid) + valid = 1; + else if (data.cmn2.valid) + valid = 1; + else + valid = 0; + + if (valid) + cvmx_tra_decode_text(tra_ctl, data); + + } while (valid); + } } #ifdef CVMX_BUILD_FOR_LINUX_KERNEL EXPORT_SYMBOL(cvmx_tra_display); #endif + +/** + * Display the entire trace buffer. It is advised that you + * disable the trace buffer before calling this routine + * otherwise it could infinitely loop displaying trace data + * that it created. + * + * @param tra_unit Which TRA buffer to use. + */ +void cvmx_tra_display_v2(int tra_unit) +{ + int valid = 0; + + cvmx_trax_ctl_t tra_ctl; + cvmx_tra_data_t data; + + valid = 0; + tra_ctl.u64 = cvmx_read_csr(CVMX_TRAX_CTL(tra_unit)); + + do + { + data = cvmx_tra_read_v2(tra_unit); + if (data.cmn2.valid) + { + _cvmx_tra_unit = tra_unit; + cvmx_tra_decode_text(tra_ctl, data); + valid = 1; + } + } while (valid); +} +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL +EXPORT_SYMBOL(cvmx_tra_display_v2); +#endif -- cgit v1.2.3