diff options
Diffstat (limited to 'cvmx-pow.c')
-rw-r--r-- | cvmx-pow.c | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/cvmx-pow.c b/cvmx-pow.c new file mode 100644 index 0000000000000..2a0902a6f8a54 --- /dev/null +++ b/cvmx-pow.c @@ -0,0 +1,481 @@ +/***********************license start*************** + * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights + * reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * * Neither the name of Cavium Networks nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * 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 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 SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES + * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR + * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET + * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT + * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. + * + * + * For any questions regarding licensing please contact marketing@caviumnetworks.com + * + ***********************license end**************************************/ + + + + + + +/** + * @file + * + * Interface to the hardware Packet Order / Work unit. + * + * <hr>$Revision: 29727 $<hr> + */ + +#include "cvmx.h" +#include "cvmx-pow.h" + +/** + * @INTERNAL + * This structure stores the internal POW state captured by + * cvmx_pow_capture(). It is purposely not exposed to the user + * since the format may change without notice. + */ +typedef struct +{ + cvmx_pow_tag_load_resp_t sstatus[16][8]; + cvmx_pow_tag_load_resp_t smemload[2048][3]; + cvmx_pow_tag_load_resp_t sindexload[16][4]; +} __cvmx_pow_dump_t; + +typedef enum +{ + CVMX_POW_LIST_UNKNOWN=0, + CVMX_POW_LIST_FREE=1, + CVMX_POW_LIST_INPUT=2, + CVMX_POW_LIST_CORE=CVMX_POW_LIST_INPUT+8, + CVMX_POW_LIST_DESCHED=CVMX_POW_LIST_CORE+16, + CVMX_POW_LIST_NOSCHED=CVMX_POW_LIST_DESCHED+16, +} __cvmx_pow_list_types_t; + +static const char *__cvmx_pow_list_names[] = { + "Unknown", + "Free List", + "Queue 0", "Queue 1", "Queue 2", "Queue 3", + "Queue 4", "Queue 5", "Queue 6", "Queue 7", + "Core 0", "Core 1", "Core 2", "Core 3", + "Core 4", "Core 5", "Core 6", "Core 7", + "Core 8", "Core 9", "Core 10", "Core 11", + "Core 12", "Core 13", "Core 14", "Core 15", + "Desched 0", "Desched 1", "Desched 2", "Desched 3", + "Desched 4", "Desched 5", "Desched 6", "Desched 7", + "Desched 8", "Desched 9", "Desched 10", "Desched 11", + "Desched 12", "Desched 13", "Desched 14", "Desched 15", + "Nosched 0", "Nosched 1", "Nosched 2", "Nosched 3", + "Nosched 4", "Nosched 5", "Nosched 6", "Nosched 7", + "Nosched 8", "Nosched 9", "Nosched 10", "Nosched 11", + "Nosched 12", "Nosched 13", "Nosched 14", "Nosched 15" +}; + + +/** + * Return the number of POW entries supported by this chip + * + * @return Number of POW entries + */ +int cvmx_pow_get_num_entries(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN30XX)) + return 64; + else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) + return 256; + else if (OCTEON_IS_MODEL(OCTEON_CN52XX)) + return 512; + else + return 2048; +} + + +/** + * Store the current POW internal state into the supplied + * buffer. It is recommended that you pass a buffer of at least + * 128KB. The format of the capture may change based on SDK + * version and Octeon chip. + * + * @param buffer Buffer to store capture into + * @param buffer_size + * The size of the supplied buffer + * + * @return Zero on sucess, negative on failure + */ +int cvmx_pow_capture(void *buffer, int buffer_size) +{ + __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer; + int num_cores; + int num_pow_entries = cvmx_pow_get_num_entries(); + int core; + int index; + int bits; + + if (buffer_size < (int)sizeof(__cvmx_pow_dump_t)) + { + cvmx_dprintf("cvmx_pow_capture: Buffer too small\n"); + return -1; + } + + num_cores = cvmx_octeon_num_cores(); + + /* Read all core related state */ + for (core=0; core<num_cores; core++) + { + cvmx_pow_load_addr_t load_addr; + load_addr.u64 = 0; + load_addr.sstatus.mem_region = CVMX_IO_SEG; + load_addr.sstatus.is_io = 1; + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; + load_addr.sstatus.coreid = core; + for (bits=0; bits<8; bits++) + { + load_addr.sstatus.get_rev = (bits & 1) != 0; + load_addr.sstatus.get_cur = (bits & 2) != 0; + load_addr.sstatus.get_wqp = (bits & 4) != 0; + if ((load_addr.sstatus.get_cur == 0) && load_addr.sstatus.get_rev) + dump->sstatus[core][bits].u64 = -1; + else + dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64); + } + } + + /* Read all internal POW entries */ + for (index=0; index<num_pow_entries; index++) + { + cvmx_pow_load_addr_t load_addr; + load_addr.u64 = 0; + load_addr.smemload.mem_region = CVMX_IO_SEG; + load_addr.smemload.is_io = 1; + load_addr.smemload.did = CVMX_OCT_DID_TAG_TAG2; + load_addr.smemload.index = index; + for (bits=0; bits<3; bits++) + { + load_addr.smemload.get_des = (bits & 1) != 0; + load_addr.smemload.get_wqp = (bits & 2) != 0; + dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64); + } + } + + /* Read all group and queue pointers */ + for (index=0; index<16; index++) + { + cvmx_pow_load_addr_t load_addr; + load_addr.u64 = 0; + load_addr.sindexload.mem_region = CVMX_IO_SEG; + load_addr.sindexload.is_io = 1; + load_addr.sindexload.did = CVMX_OCT_DID_TAG_TAG3; + load_addr.sindexload.qosgrp = index; + for (bits=0; bits<4; bits++) + { + load_addr.sindexload.get_rmt = (bits & 1) != 0; + load_addr.sindexload.get_des_get_tail = (bits & 2) != 0; + /* The first pass only has 8 valid index values */ + if ((load_addr.sindexload.get_rmt == 0) && + (load_addr.sindexload.get_des_get_tail == 0) && + (index >= 8)) + dump->sindexload[index][bits].u64 = -1; + else + dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64); + } + } + return 0; +} + + +/** + * Function to display a POW internal queue to the user + * + * @param name User visible name for the queue + * @param name_param Parameter for printf in creating the name + * @param valid Set if the queue contains any elements + * @param has_one Set if the queue contains exactly one element + * @param head The head pointer + * @param tail The tail pointer + */ +static void __cvmx_pow_display_list(const char *name, int name_param, int valid, int has_one, uint64_t head, uint64_t tail) +{ + printf(name, name_param); + printf(": "); + if (valid) + { + if (has_one) + printf("One element index=%llu(0x%llx)\n", CAST64(head), CAST64(head)); + else + printf("Multiple elements head=%llu(0x%llx) tail=%llu(0x%llx)\n", CAST64(head), CAST64(head), CAST64(tail), CAST64(tail)); + } + else + printf("Empty\n"); +} + + +/** + * Mark which list a POW entry is on. Print a warning message if the + * entry is already on a list. This happens if the POW changed while + * the capture was running. + * + * @param entry_num Entry number to mark + * @param entry_type List type + * @param entry_list Array to store marks + * + * @return Zero on success, negative if already on a list + */ +static int __cvmx_pow_entry_mark_list(int entry_num, __cvmx_pow_list_types_t entry_type, uint8_t entry_list[]) +{ + if (entry_list[entry_num] == 0) + { + entry_list[entry_num] = entry_type; + return 0; + } + else + { + printf("\nWARNING: Entry %d already on list %s, but we tried to add it to %s\n", + entry_num, __cvmx_pow_list_names[entry_list[entry_num]], __cvmx_pow_list_names[entry_type]); + return -1; + } +} + + +/** + * Display a list and mark all elements on the list as belonging to + * the list. + * + * @param entry_type Type of the list to display and mark + * @param dump POW capture data + * @param entry_list Array to store marks in + * @param valid Set if the queue contains any elements + * @param has_one Set if the queue contains exactly one element + * @param head The head pointer + * @param tail The tail pointer + */ +static void __cvmx_pow_display_list_and_walk(__cvmx_pow_list_types_t entry_type, + __cvmx_pow_dump_t *dump, uint8_t entry_list[], + int valid, int has_one, uint64_t head, uint64_t tail) +{ + __cvmx_pow_display_list(__cvmx_pow_list_names[entry_type], 0, valid, has_one, head, tail); + if (valid) + { + if (has_one) + __cvmx_pow_entry_mark_list(head, entry_type, entry_list); + else + { + while (head != tail) + { + if (__cvmx_pow_entry_mark_list(head, entry_type, entry_list)) + break; + head = dump->smemload[head][0].s_smemload0.next_index; + } + __cvmx_pow_entry_mark_list(tail, entry_type, entry_list); + } + } +} + + +/** + * Dump a POW capture to the console in a human readable format. + * + * @param buffer POW capture from cvmx_pow_capture() + * @param buffer_size + * Size of the buffer + */ +void cvmx_pow_display(void *buffer, int buffer_size) +{ + __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer; + int num_pow_entries = cvmx_pow_get_num_entries(); + int num_cores; + int core; + int index; + uint8_t entry_list[2048]; + + if (buffer_size < (int)sizeof(__cvmx_pow_dump_t)) + { + cvmx_dprintf("cvmx_pow_dump: Buffer too small\n"); + return; + } + + memset(entry_list, 0, sizeof(entry_list)); + num_cores = cvmx_octeon_num_cores(); + + printf("POW Display Start\n"); + + /* Print the free list info */ + __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_FREE, dump, entry_list, + dump->sindexload[0][0].sindexload0.free_val, + dump->sindexload[0][0].sindexload0.free_one, + dump->sindexload[0][0].sindexload0.free_head, + dump->sindexload[0][0].sindexload0.free_tail); + + /* Print the core state */ + for (core=0; core<num_cores; core++) + { + const int bit_rev = 1; + const int bit_cur = 2; + const int bit_wqp = 4; + printf("Core %d State: tag=%s,0x%08x", core, + OCT_TAG_TYPE_STRING(dump->sstatus[core][bit_cur].s_sstatus2.tag_type), + dump->sstatus[core][bit_cur].s_sstatus2.tag); + if (dump->sstatus[core][bit_cur].s_sstatus2.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL) + { + __cvmx_pow_entry_mark_list(dump->sstatus[core][bit_cur].s_sstatus2.index, CVMX_POW_LIST_CORE + core, entry_list); + printf(" grp=%d", dump->sstatus[core][bit_cur].s_sstatus2.grp); + printf(" wqp=0x%016llx", CAST64(dump->sstatus[core][bit_cur|bit_wqp].s_sstatus4.wqp)); + printf(" index=%d", dump->sstatus[core][bit_cur].s_sstatus2.index); + if (dump->sstatus[core][bit_cur].s_sstatus2.head) + printf(" head"); + else + printf(" prev=%d", dump->sstatus[core][bit_cur|bit_rev].s_sstatus3.revlink_index); + if (dump->sstatus[core][bit_cur].s_sstatus2.tail) + printf(" tail"); + else + printf(" next=%d", dump->sstatus[core][bit_cur].s_sstatus2.link_index); + } + + if (dump->sstatus[core][0].s_sstatus0.pend_switch) + { + printf(" pend_switch=%d", dump->sstatus[core][0].s_sstatus0.pend_switch); + printf(" pend_switch_full=%d", dump->sstatus[core][0].s_sstatus0.pend_switch_full); + printf(" pend_switch_null=%d", dump->sstatus[core][0].s_sstatus0.pend_switch_null); + } + + if (dump->sstatus[core][0].s_sstatus0.pend_desched) + { + printf(" pend_desched=%d", dump->sstatus[core][0].s_sstatus0.pend_desched); + printf(" pend_desched_switch=%d", dump->sstatus[core][0].s_sstatus0.pend_desched_switch); + printf(" pend_nosched=%d", dump->sstatus[core][0].s_sstatus0.pend_nosched); + if (dump->sstatus[core][0].s_sstatus0.pend_desched_switch) + printf(" pend_grp=%d", dump->sstatus[core][0].s_sstatus0.pend_grp); + } + + if (dump->sstatus[core][0].s_sstatus0.pend_new_work) + { + if (dump->sstatus[core][0].s_sstatus0.pend_new_work_wait) + printf(" (Waiting for work)"); + else + printf(" (Getting work)"); + } + if (dump->sstatus[core][0].s_sstatus0.pend_null_rd) + printf(" pend_null_rd=%d", dump->sstatus[core][0].s_sstatus0.pend_null_rd); + if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr) + { + printf(" pend_nosched_clr=%d", dump->sstatus[core][0].s_sstatus0.pend_nosched_clr); + printf(" pend_index=%d", dump->sstatus[core][0].s_sstatus0.pend_index); + } + if (dump->sstatus[core][0].s_sstatus0.pend_switch || + (dump->sstatus[core][0].s_sstatus0.pend_desched && + dump->sstatus[core][0].s_sstatus0.pend_desched_switch)) + { + printf(" pending tag=%s,0x%08x", + OCT_TAG_TYPE_STRING(dump->sstatus[core][0].s_sstatus0.pend_type), + dump->sstatus[core][0].s_sstatus0.pend_tag); + } + if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr) + printf(" pend_wqp=0x%016llx\n", CAST64(dump->sstatus[core][bit_wqp].s_sstatus1.pend_wqp)); + printf("\n"); + } + + /* Print out the state of the 16 deschedule lists. Each group has two + lists. One for entries marked noshed, the other for normal + deschedules */ + for (index=0; index<16; index++) + { + __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED + index, dump, entry_list, + dump->sindexload[index][2].sindexload1.nosched_val, + dump->sindexload[index][2].sindexload1.nosched_one, + dump->sindexload[index][2].sindexload1.nosched_head, + dump->sindexload[index][2].sindexload1.nosched_tail); + __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list, + dump->sindexload[index][2].sindexload1.des_val, + dump->sindexload[index][2].sindexload1.des_one, + dump->sindexload[index][2].sindexload1.des_head, + dump->sindexload[index][2].sindexload1.des_tail); + } + + /* Print out the state of the 8 internal input queues */ + for (index=0; index<8; index++) + { + __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list, + dump->sindexload[index][0].sindexload0.loc_val, + dump->sindexload[index][0].sindexload0.loc_one, + dump->sindexload[index][0].sindexload0.loc_head, + dump->sindexload[index][0].sindexload0.loc_tail); + } + + /* Print out the state of the 16 memory queues */ + for (index=0; index<8; index++) + { + const char *name; + if (dump->sindexload[index][1].sindexload2.rmt_is_head) + name = "Queue %da Memory (is head)"; + else + name = "Queue %da Memory"; + __cvmx_pow_display_list(name, index, + dump->sindexload[index][1].sindexload2.rmt_val, + dump->sindexload[index][1].sindexload2.rmt_one, + dump->sindexload[index][1].sindexload2.rmt_head, + dump->sindexload[index][3].sindexload3.rmt_tail); + if (dump->sindexload[index+8][1].sindexload2.rmt_is_head) + name = "Queue %db Memory (is head)"; + else + name = "Queue %db Memory"; + __cvmx_pow_display_list(name, index, + dump->sindexload[index+8][1].sindexload2.rmt_val, + dump->sindexload[index+8][1].sindexload2.rmt_one, + dump->sindexload[index+8][1].sindexload2.rmt_head, + dump->sindexload[index+8][3].sindexload3.rmt_tail); + } + + /* Print out each of the internal POW entries. Each entry has a tag, group, + wqe, and possibly a next pointer. The next pointer is only valid if this + entry isn't make as a tail */ + for (index=0; index<num_pow_entries; index++) + { + printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index, + __cvmx_pow_list_names[entry_list[index]], + OCT_TAG_TYPE_STRING(dump->smemload[index][0].s_smemload0.tag_type), + dump->smemload[index][0].s_smemload0.tag, + dump->smemload[index][0].s_smemload0.grp, + CAST64(dump->smemload[index][2].s_smemload1.wqp)); + if (dump->smemload[index][0].s_smemload0.tail) + printf(" tail"); + else + printf(" next=%d", dump->smemload[index][0].s_smemload0.next_index); + if (entry_list[index] >= CVMX_POW_LIST_DESCHED) + { + printf(" prev=%d", dump->smemload[index][1].s_smemload2.fwd_index); + printf(" nosched=%d", dump->smemload[index][1].s_smemload2.nosched); + if (dump->smemload[index][1].s_smemload2.pend_switch) + { + printf(" pending tag=%s,0x%08x", + OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload2.pend_type), + dump->smemload[index][1].s_smemload2.pend_tag); + } + } + printf("\n"); + } + + printf("POW Display End\n"); +} + |