cvmx-pow.c revision 302408
1151497Sru/***********************license start***************
2151497Sru * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3151497Sru * reserved.
4151497Sru *
5151497Sru *
6151497Sru * Redistribution and use in source and binary forms, with or without
7151497Sru * modification, are permitted provided that the following conditions are
8151497Sru * met:
9151497Sru *
10151497Sru *   * Redistributions of source code must retain the above copyright
11151497Sru *     notice, this list of conditions and the following disclaimer.
12151497Sru *
13151497Sru *   * Redistributions in binary form must reproduce the above
14151497Sru *     copyright notice, this list of conditions and the following
15151497Sru *     disclaimer in the documentation and/or other materials provided
16151497Sru *     with the distribution.
17151497Sru
18151497Sru *   * Neither the name of Cavium Inc. nor the names of
19151497Sru *     its contributors may be used to endorse or promote products
20151497Sru *     derived from this software without specific prior written
21151497Sru *     permission.
22151497Sru
23151497Sru * This Software, including technical data, may be subject to U.S. export  control
24151497Sru * laws, including the U.S. Export Administration Act and its  associated
25151497Sru * regulations, and may be subject to export or import  regulations in other
26151497Sru * countries.
27151497Sru
28151497Sru * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29151497Sru * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30151497Sru * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31151497Sru * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32151497Sru * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33151497Sru * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34151497Sru * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35151497Sru * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36151497Sru * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37151497Sru * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38151497Sru ***********************license end**************************************/
39151497Sru
40151497Sru
41151497Sru
42151497Sru
43151497Sru
44151497Sru
45151497Sru
46151497Sru/**
47151497Sru * @file
48151497Sru *
49151497Sru * Interface to the hardware Packet Order / Work unit.
50151497Sru *
51151497Sru * <hr>$Revision: 29727 $<hr>
52151497Sru */
53151497Sru
54151497Sru#include "cvmx.h"
55151497Sru#include "cvmx-pow.h"
56151497Sru
57151497Sru/**
58151497Sru * @INTERNAL
59151497Sru * This structure stores the internal POW state captured by
60151497Sru * cvmx_pow_capture(). It is purposely not exposed to the user
61151497Sru * since the format may change without notice.
62151497Sru */
63151497Srutypedef struct
64151497Sru{
65151497Sru    cvmx_pow_tag_load_resp_t sstatus[CVMX_MAX_CORES][8];
66151497Sru    cvmx_pow_tag_load_resp_t smemload[2048][8];
67151497Sru    cvmx_pow_tag_load_resp_t sindexload[64][8];
68151497Sru} __cvmx_pow_dump_t;
69151497Sru
70151497Srutypedef enum
71151497Sru{
72151497Sru    CVMX_POW_LIST_UNKNOWN=0,
73151497Sru    CVMX_POW_LIST_FREE=1,
74151497Sru    CVMX_POW_LIST_INPUT=2,
75151497Sru    CVMX_POW_LIST_CORE=CVMX_POW_LIST_INPUT+8,
76151497Sru    CVMX_POW_LIST_DESCHED=CVMX_POW_LIST_CORE+32,
77151497Sru    CVMX_POW_LIST_NOSCHED=CVMX_POW_LIST_DESCHED+64,
78151497Sru} __cvmx_pow_list_types_t;
79151497Sru
80151497Srustatic const char *__cvmx_pow_list_names[] = {
81151497Sru    "Unknown",
82151497Sru    "Free List",
83151497Sru    "Queue 0", "Queue 1", "Queue 2", "Queue 3",
84151497Sru    "Queue 4", "Queue 5", "Queue 6", "Queue 7",
85151497Sru    "Core 0", "Core 1", "Core 2", "Core 3",
86151497Sru    "Core 4", "Core 5", "Core 6", "Core 7",
87151497Sru    "Core 8", "Core 9", "Core 10", "Core 11",
88151497Sru    "Core 12", "Core 13", "Core 14", "Core 15",
89151497Sru    "Core 16", "Core 17", "Core 18", "Core 19",
90151497Sru    "Core 20", "Core 21", "Core 22", "Core 23",
91151497Sru    "Core 24", "Core 25", "Core 26", "Core 27",
92151497Sru    "Core 28", "Core 29", "Core 30", "Core 31",
93151497Sru    "Desched 0", "Desched 1", "Desched 2", "Desched 3",
94151497Sru    "Desched 4", "Desched 5", "Desched 6", "Desched 7",
95151497Sru    "Desched 8", "Desched 9", "Desched 10", "Desched 11",
96151497Sru    "Desched 12", "Desched 13", "Desched 14", "Desched 15",
97151497Sru    "Desched 16", "Desched 17", "Desched 18", "Desched 19",
98151497Sru    "Desched 20", "Desched 21", "Desched 22", "Desched 23",
99151497Sru    "Desched 24", "Desched 25", "Desched 26", "Desched 27",
100151497Sru    "Desched 28", "Desched 29", "Desched 30", "Desched 31",
101151497Sru    "Desched 32", "Desched 33", "Desched 34", "Desched 35",
102151497Sru    "Desched 36", "Desched 37", "Desched 38", "Desched 39",
103151497Sru    "Desched 40", "Desched 41", "Desched 42", "Desched 43",
104151497Sru    "Desched 44", "Desched 45", "Desched 46", "Desched 47",
105151497Sru    "Desched 48", "Desched 49", "Desched 50", "Desched 51",
106151497Sru    "Desched 52", "Desched 53", "Desched 54", "Desched 55",
107151497Sru    "Desched 56", "Desched 57", "Desched 58", "Desched 59",
108151497Sru    "Desched 60", "Desched 61", "Desched 62", "Desched 63",
109151497Sru    "Nosched 0"
110151497Sru};
111151497Sru
112151497Sru
113151497Sru/**
114151497Sru * Return the number of POW entries supported by this chip
115151497Sru *
116151497Sru * @return Number of POW entries
117151497Sru */
118151497Sruint cvmx_pow_get_num_entries(void)
119151497Sru{
120151497Sru    if (OCTEON_IS_MODEL(OCTEON_CN30XX))
121151497Sru        return 64;
122151497Sru    else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
123151497Sru        return 256;
124151497Sru    else if (OCTEON_IS_MODEL(OCTEON_CN52XX)
125151497Sru             || OCTEON_IS_MODEL(OCTEON_CN61XX)
126151497Sru             || OCTEON_IS_MODEL(OCTEON_CNF71XX))
127151497Sru        return 512;
128151497Sru    else if (OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CN66XX))
129151497Sru	return 1024;
130151497Sru    else
131151497Sru        return 2048;
132151497Sru}
133151497Sru
134151497Sru
135151497Srustatic int __cvmx_pow_capture_v1(void *buffer, int buffer_size)
136151497Sru{
137151497Sru    __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
138151497Sru    int num_cores;
139151497Sru    int num_pow_entries = cvmx_pow_get_num_entries();
140151497Sru    int core;
141151497Sru    int index;
142151497Sru    int bits;
143151497Sru
144151497Sru    if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
145151497Sru    {
146151497Sru        cvmx_dprintf("cvmx_pow_capture: Buffer too small\n");
147151497Sru        return -1;
148151497Sru    }
149151497Sru
150151497Sru    num_cores = cvmx_octeon_num_cores();
151151497Sru
152151497Sru    /* Read all core related state */
153151497Sru    for (core=0; core<num_cores; core++)
154151497Sru    {
155151497Sru        cvmx_pow_load_addr_t load_addr;
156151497Sru        load_addr.u64 = 0;
157151497Sru        load_addr.sstatus.mem_region = CVMX_IO_SEG;
158151497Sru        load_addr.sstatus.is_io = 1;
159151497Sru        load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1;
160151497Sru        load_addr.sstatus.coreid = core;
161151497Sru        for (bits=0; bits<8; bits++)
162151497Sru        {
163151497Sru            load_addr.sstatus.get_rev = (bits & 1) != 0;
164151497Sru            load_addr.sstatus.get_cur = (bits & 2) != 0;
165151497Sru            load_addr.sstatus.get_wqp = (bits & 4) != 0;
166151497Sru            if ((load_addr.sstatus.get_cur == 0) && load_addr.sstatus.get_rev)
167151497Sru                dump->sstatus[core][bits].u64 = -1;
168151497Sru            else
169151497Sru                dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64);
170151497Sru        }
171151497Sru    }
172151497Sru
173151497Sru    /* Read all internal POW entries */
174151497Sru    for (index=0; index<num_pow_entries; index++)
175151497Sru    {
176151497Sru        cvmx_pow_load_addr_t load_addr;
177151497Sru        load_addr.u64 = 0;
178151497Sru        load_addr.smemload.mem_region = CVMX_IO_SEG;
179151497Sru        load_addr.smemload.is_io = 1;
180151497Sru        load_addr.smemload.did = CVMX_OCT_DID_TAG_TAG2;
181151497Sru        load_addr.smemload.index = index;
182151497Sru        for (bits=0; bits<3; bits++)
183151497Sru        {
184151497Sru            load_addr.smemload.get_des = (bits & 1) != 0;
185151497Sru            load_addr.smemload.get_wqp = (bits & 2) != 0;
186151497Sru            dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
187151497Sru        }
188151497Sru    }
189151497Sru
190151497Sru    /* Read all group and queue pointers */
191151497Sru    for (index=0; index<16; index++)
192151497Sru    {
193151497Sru        cvmx_pow_load_addr_t load_addr;
194151497Sru        load_addr.u64 = 0;
195151497Sru        load_addr.sindexload.mem_region = CVMX_IO_SEG;
196151497Sru        load_addr.sindexload.is_io = 1;
197151497Sru        load_addr.sindexload.did = CVMX_OCT_DID_TAG_TAG3;
198151497Sru        load_addr.sindexload.qosgrp = index;
199151497Sru        for (bits=0; bits<4; bits++)
200151497Sru        {
201151497Sru            load_addr.sindexload.get_rmt =  (bits & 1) != 0;
202151497Sru            load_addr.sindexload.get_des_get_tail =  (bits & 2) != 0;
203151497Sru            /* The first pass only has 8 valid index values */
204151497Sru            if ((load_addr.sindexload.get_rmt == 0) &&
205151497Sru                (load_addr.sindexload.get_des_get_tail == 0) &&
206151497Sru                (index >= 8))
207151497Sru                dump->sindexload[index][bits].u64 = -1;
208151497Sru            else
209151497Sru                dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
210151497Sru        }
211151497Sru    }
212151497Sru    return 0;
213151497Sru}
214151497Sru
215151497Srustatic int __cvmx_pow_capture_v2(void *buffer, int buffer_size)
216151497Sru{
217151497Sru    __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
218151497Sru    int num_cores;
219151497Sru    int num_pow_entries = cvmx_pow_get_num_entries();
220151497Sru    int core;
221151497Sru    int index;
222151497Sru    int bits;
223151497Sru
224151497Sru    if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
225151497Sru    {
226151497Sru        cvmx_dprintf("cvmx_pow_capture: Buffer too small\n");
227151497Sru        return -1;
228151497Sru    }
229151497Sru
230151497Sru    num_cores = cvmx_octeon_num_cores();
231151497Sru
232151497Sru    /* Read all core related state */
233151497Sru    for (core=0; core<num_cores; core++)
234151497Sru    {
235151497Sru        cvmx_pow_load_addr_t load_addr;
236151497Sru        load_addr.u64 = 0;
237151497Sru        load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG;
238151497Sru        load_addr.sstatus_cn68xx.is_io = 1;
239151497Sru        load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5;
240151497Sru        load_addr.sstatus_cn68xx.coreid = core;
241151497Sru        for (bits=1; bits<6; bits++)
242151497Sru        {
243151497Sru            load_addr.sstatus_cn68xx.opcode = bits;
244151497Sru            dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64);
245151497Sru        }
246151497Sru    }
247151497Sru    /* Read all internal POW entries */
248151497Sru    for (index=0; index<num_pow_entries; index++)
249151497Sru    {
250151497Sru        cvmx_pow_load_addr_t load_addr;
251151497Sru        load_addr.u64 = 0;
252151497Sru        load_addr.smemload_cn68xx.mem_region = CVMX_IO_SEG;
253151497Sru        load_addr.smemload_cn68xx.is_io = 1;
254151497Sru        load_addr.smemload_cn68xx.did = CVMX_OCT_DID_TAG_TAG2;
255151497Sru        load_addr.smemload_cn68xx.index = index;
256151497Sru        for (bits=1; bits<5; bits++)
257151497Sru        {
258151497Sru            load_addr.smemload_cn68xx.opcode = bits;
259151497Sru            dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
260151497Sru        }
261151497Sru    }
262151497Sru
263151497Sru    /* Read all group and queue pointers */
264151497Sru    for (index=0; index<64; index++)
265151497Sru    {
266151497Sru        cvmx_pow_load_addr_t load_addr;
267151497Sru        load_addr.u64 = 0;
268151497Sru        load_addr.sindexload_cn68xx.mem_region = CVMX_IO_SEG;
269151497Sru        load_addr.sindexload_cn68xx.is_io = 1;
270151497Sru        load_addr.sindexload_cn68xx.did = CVMX_OCT_DID_TAG_TAG3;
271151497Sru        load_addr.sindexload_cn68xx.qos_grp = index;
272151497Sru        for (bits=1; bits<7; bits++)
273151497Sru        {
274151497Sru            load_addr.sindexload_cn68xx.opcode = bits;
275151497Sru            dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
276151497Sru        }
277151497Sru    }
278151497Sru    return 0;
279151497Sru}
280151497Sru
281151497Sru/**
282151497Sru * Store the current POW internal state into the supplied
283151497Sru * buffer. It is recommended that you pass a buffer of at least
284151497Sru * 128KB. The format of the capture may change based on SDK
285151497Sru * version and Octeon chip.
286151497Sru *
287151497Sru * @param buffer Buffer to store capture into
288151497Sru * @param buffer_size
289151497Sru *               The size of the supplied buffer
290151497Sru *
291151497Sru * @return Zero on sucess, negative on failure
292151497Sru */
293151497Sruint cvmx_pow_capture(void *buffer, int buffer_size)
294151497Sru{
295151497Sru    if (octeon_has_feature(OCTEON_FEATURE_PKND))
296151497Sru        return __cvmx_pow_capture_v2(buffer, buffer_size);
297151497Sru    else
298151497Sru        return __cvmx_pow_capture_v1(buffer, buffer_size);
299151497Sru}
300151497Sru
301151497Sru/**
302151497Sru * Function to display a POW internal queue to the user
303151497Sru *
304151497Sru * @param name       User visible name for the queue
305151497Sru * @param name_param Parameter for printf in creating the name
306151497Sru * @param valid      Set if the queue contains any elements
307151497Sru * @param has_one    Set if the queue contains exactly one element
308151497Sru * @param head       The head pointer
309151497Sru * @param tail       The tail pointer
310151497Sru */
311151497Srustatic void __cvmx_pow_display_list(const char *name, int name_param, int valid, int has_one, uint64_t head, uint64_t tail)
312151497Sru{
313151497Sru    printf(name, name_param);
314151497Sru    printf(": ");
315151497Sru    if (valid)
316151497Sru    {
317151497Sru        if (has_one)
318151497Sru            printf("One element index=%llu(0x%llx)\n", CAST64(head), CAST64(head));
319151497Sru        else
320151497Sru            printf("Multiple elements head=%llu(0x%llx) tail=%llu(0x%llx)\n", CAST64(head), CAST64(head), CAST64(tail), CAST64(tail));
321151497Sru    }
322151497Sru    else
323151497Sru        printf("Empty\n");
324151497Sru}
325151497Sru
326151497Sru
327151497Sru/**
328151497Sru * Mark which list a POW entry is on. Print a warning message if the
329151497Sru * entry is already on a list. This happens if the POW changed while
330151497Sru * the capture was running.
331151497Sru *
332151497Sru * @param entry_num  Entry number to mark
333151497Sru * @param entry_type List type
334151497Sru * @param entry_list Array to store marks
335151497Sru *
336151497Sru * @return Zero on success, negative if already on a list
337151497Sru */
338151497Srustatic int __cvmx_pow_entry_mark_list(int entry_num, __cvmx_pow_list_types_t entry_type, uint8_t entry_list[])
339151497Sru{
340151497Sru    if (entry_list[entry_num] == 0)
341151497Sru    {
342151497Sru        entry_list[entry_num] = entry_type;
343151497Sru        return 0;
344151497Sru    }
345151497Sru    else
346151497Sru    {
347151497Sru        printf("\nWARNING: Entry %d already on list %s, but we tried to add it to %s\n",
348151497Sru               entry_num, __cvmx_pow_list_names[entry_list[entry_num]], __cvmx_pow_list_names[entry_type]);
349151497Sru        return -1;
350151497Sru    }
351151497Sru}
352151497Sru
353151497Sru
354151497Sru/**
355151497Sru * Display a list and mark all elements on the list as belonging to
356151497Sru * the list.
357151497Sru *
358151497Sru * @param entry_type Type of the list to display and mark
359151497Sru * @param dump       POW capture data
360151497Sru * @param entry_list Array to store marks in
361151497Sru * @param valid      Set if the queue contains any elements
362151497Sru * @param has_one    Set if the queue contains exactly one element
363151497Sru * @param head       The head pointer
364151497Sru * @param tail       The tail pointer
365151497Sru */
366151497Srustatic void __cvmx_pow_display_list_and_walk(__cvmx_pow_list_types_t entry_type,
367151497Sru                                             __cvmx_pow_dump_t *dump, uint8_t entry_list[],
368151497Sru                                             int valid, int has_one, uint64_t head, uint64_t tail)
369151497Sru{
370151497Sru    __cvmx_pow_display_list(__cvmx_pow_list_names[entry_type], 0, valid, has_one, head, tail);
371151497Sru    if (valid)
372151497Sru    {
373151497Sru        if (has_one)
374151497Sru            __cvmx_pow_entry_mark_list(head, entry_type, entry_list);
375151497Sru        else
376151497Sru        {
377151497Sru            while (head != tail)
378151497Sru            {
379151497Sru                if (__cvmx_pow_entry_mark_list(head, entry_type, entry_list))
380151497Sru                    break;
381151497Sru                if (octeon_has_feature(OCTEON_FEATURE_PKND))
382151497Sru                {
383151497Sru                    if (entry_type >= CVMX_POW_LIST_INPUT && entry_type < CVMX_POW_LIST_CORE)
384151497Sru
385151497Sru                        head = dump->smemload[head][4].s_smemload3_cn68xx.next_index;
386151497Sru                    else
387151497Sru                        head = dump->smemload[head][4].s_smemload3_cn68xx.fwd_index;
388151497Sru                }
389151497Sru                else
390151497Sru                    head = dump->smemload[head][0].s_smemload0.next_index;
391151497Sru            }
392151497Sru            __cvmx_pow_entry_mark_list(tail, entry_type, entry_list);
393151497Sru        }
394151497Sru    }
395151497Sru}
396151497Sru
397151497Sru
398151497Sruvoid __cvmx_pow_display_v1(void *buffer, int buffer_size)
399151497Sru{
400151497Sru    __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
401151497Sru    int num_pow_entries = cvmx_pow_get_num_entries();
402151497Sru    int num_cores;
403151497Sru    int core;
404151497Sru    int index;
405151497Sru    uint8_t entry_list[2048];
406151497Sru
407151497Sru    if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
408151497Sru    {
409151497Sru        cvmx_dprintf("cvmx_pow_dump: Buffer too small\n");
410151497Sru        return;
411151497Sru    }
412151497Sru
413151497Sru    memset(entry_list, 0, sizeof(entry_list));
414151497Sru    num_cores = cvmx_octeon_num_cores();
415151497Sru
416151497Sru    /* Print the free list info */
417151497Sru    __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_FREE, dump, entry_list,
418151497Sru                                     dump->sindexload[0][0].sindexload0.free_val,
419151497Sru                                     dump->sindexload[0][0].sindexload0.free_one,
420151497Sru                                     dump->sindexload[0][0].sindexload0.free_head,
421151497Sru                                     dump->sindexload[0][0].sindexload0.free_tail);
422151497Sru
423151497Sru    /* Print the core state */
424151497Sru    for (core=0; core<num_cores; core++)
425151497Sru    {
426151497Sru        const int bit_rev = 1;
427151497Sru        const int bit_cur = 2;
428151497Sru        const int bit_wqp = 4;
429151497Sru        printf("Core %d State:  tag=%s,0x%08x", core,
430151497Sru               OCT_TAG_TYPE_STRING(dump->sstatus[core][bit_cur].s_sstatus2.tag_type),
431151497Sru               dump->sstatus[core][bit_cur].s_sstatus2.tag);
432151497Sru        if (dump->sstatus[core][bit_cur].s_sstatus2.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL)
433151497Sru        {
434151497Sru            __cvmx_pow_entry_mark_list(dump->sstatus[core][bit_cur].s_sstatus2.index, CVMX_POW_LIST_CORE + core, entry_list);
435151497Sru            printf(" grp=%d",                   dump->sstatus[core][bit_cur].s_sstatus2.grp);
436151497Sru            printf(" wqp=0x%016llx",            CAST64(dump->sstatus[core][bit_cur|bit_wqp].s_sstatus4.wqp));
437151497Sru            printf(" index=%d",                 dump->sstatus[core][bit_cur].s_sstatus2.index);
438151497Sru            if (dump->sstatus[core][bit_cur].s_sstatus2.head)
439151497Sru                printf(" head");
440151497Sru            else
441151497Sru                printf(" prev=%d", dump->sstatus[core][bit_cur|bit_rev].s_sstatus3.revlink_index);
442151497Sru            if (dump->sstatus[core][bit_cur].s_sstatus2.tail)
443151497Sru                printf(" tail");
444151497Sru            else
445151497Sru                printf(" next=%d", dump->sstatus[core][bit_cur].s_sstatus2.link_index);
446151497Sru        }
447151497Sru
448151497Sru        if (dump->sstatus[core][0].s_sstatus0.pend_switch)
449151497Sru        {
450151497Sru            printf(" pend_switch=%d",           dump->sstatus[core][0].s_sstatus0.pend_switch);
451151497Sru            printf(" pend_switch_full=%d",      dump->sstatus[core][0].s_sstatus0.pend_switch_full);
452151497Sru            printf(" pend_switch_null=%d",      dump->sstatus[core][0].s_sstatus0.pend_switch_null);
453151497Sru        }
454151497Sru
455151497Sru        if (dump->sstatus[core][0].s_sstatus0.pend_desched)
456151497Sru        {
457151497Sru            printf(" pend_desched=%d",          dump->sstatus[core][0].s_sstatus0.pend_desched);
458151497Sru            printf(" pend_desched_switch=%d",   dump->sstatus[core][0].s_sstatus0.pend_desched_switch);
459151497Sru            printf(" pend_nosched=%d",          dump->sstatus[core][0].s_sstatus0.pend_nosched);
460151497Sru            if (dump->sstatus[core][0].s_sstatus0.pend_desched_switch)
461151497Sru                printf(" pend_grp=%d",              dump->sstatus[core][0].s_sstatus0.pend_grp);
462151497Sru        }
463151497Sru
464151497Sru        if (dump->sstatus[core][0].s_sstatus0.pend_new_work)
465151497Sru        {
466151497Sru            if (dump->sstatus[core][0].s_sstatus0.pend_new_work_wait)
467151497Sru                printf(" (Waiting for work)");
468151497Sru            else
469151497Sru                printf(" (Getting work)");
470151497Sru        }
471151497Sru        if (dump->sstatus[core][0].s_sstatus0.pend_null_rd)
472151497Sru            printf(" pend_null_rd=%d",          dump->sstatus[core][0].s_sstatus0.pend_null_rd);
473151497Sru        if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
474151497Sru        {
475151497Sru            printf(" pend_nosched_clr=%d",      dump->sstatus[core][0].s_sstatus0.pend_nosched_clr);
476151497Sru            printf(" pend_index=%d",            dump->sstatus[core][0].s_sstatus0.pend_index);
477151497Sru        }
478151497Sru        if (dump->sstatus[core][0].s_sstatus0.pend_switch ||
479151497Sru            (dump->sstatus[core][0].s_sstatus0.pend_desched &&
480151497Sru            dump->sstatus[core][0].s_sstatus0.pend_desched_switch))
481151497Sru        {
482151497Sru            printf(" pending tag=%s,0x%08x",
483151497Sru                   OCT_TAG_TYPE_STRING(dump->sstatus[core][0].s_sstatus0.pend_type),
484151497Sru                   dump->sstatus[core][0].s_sstatus0.pend_tag);
485151497Sru        }
486151497Sru        if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
487151497Sru            printf(" pend_wqp=0x%016llx\n",     CAST64(dump->sstatus[core][bit_wqp].s_sstatus1.pend_wqp));
488151497Sru        printf("\n");
489151497Sru    }
490151497Sru
491151497Sru    /* Print out the state of the nosched list and the 16 deschedule lists. */
492151497Sru    __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED, dump, entry_list,
493151497Sru                            dump->sindexload[0][2].sindexload1.nosched_val,
494151497Sru                            dump->sindexload[0][2].sindexload1.nosched_one,
495151497Sru                            dump->sindexload[0][2].sindexload1.nosched_head,
496151497Sru                            dump->sindexload[0][2].sindexload1.nosched_tail);
497151497Sru    for (index=0; index<16; index++)
498151497Sru    {
499151497Sru        __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list,
500151497Sru                                dump->sindexload[index][2].sindexload1.des_val,
501151497Sru                                dump->sindexload[index][2].sindexload1.des_one,
502151497Sru                                dump->sindexload[index][2].sindexload1.des_head,
503151497Sru                                dump->sindexload[index][2].sindexload1.des_tail);
504151497Sru    }
505151497Sru
506151497Sru    /* Print out the state of the 8 internal input queues */
507151497Sru    for (index=0; index<8; index++)
508151497Sru    {
509151497Sru        __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list,
510151497Sru                                dump->sindexload[index][0].sindexload0.loc_val,
511151497Sru                                dump->sindexload[index][0].sindexload0.loc_one,
512151497Sru                                dump->sindexload[index][0].sindexload0.loc_head,
513151497Sru                                dump->sindexload[index][0].sindexload0.loc_tail);
514151497Sru    }
515151497Sru
516151497Sru    /* Print out the state of the 16 memory queues */
517151497Sru    for (index=0; index<8; index++)
518151497Sru    {
519151497Sru        const char *name;
520151497Sru        if (dump->sindexload[index][1].sindexload2.rmt_is_head)
521151497Sru            name = "Queue %da Memory (is head)";
522151497Sru        else
523151497Sru            name = "Queue %da Memory";
524151497Sru        __cvmx_pow_display_list(name, index,
525151497Sru                                dump->sindexload[index][1].sindexload2.rmt_val,
526151497Sru                                dump->sindexload[index][1].sindexload2.rmt_one,
527151497Sru                                dump->sindexload[index][1].sindexload2.rmt_head,
528151497Sru                                dump->sindexload[index][3].sindexload3.rmt_tail);
529151497Sru        if (dump->sindexload[index+8][1].sindexload2.rmt_is_head)
530151497Sru            name = "Queue %db Memory (is head)";
531151497Sru        else
532151497Sru            name = "Queue %db Memory";
533151497Sru        __cvmx_pow_display_list(name, index,
534151497Sru                                dump->sindexload[index+8][1].sindexload2.rmt_val,
535151497Sru                                dump->sindexload[index+8][1].sindexload2.rmt_one,
536151497Sru                                dump->sindexload[index+8][1].sindexload2.rmt_head,
537151497Sru                                dump->sindexload[index+8][3].sindexload3.rmt_tail);
538151497Sru    }
539151497Sru
540151497Sru    /* Print out each of the internal POW entries. Each entry has a tag, group,
541151497Sru        wqe, and possibly a next pointer. The next pointer is only valid if this
542151497Sru        entry isn't make as a tail */
543151497Sru    for (index=0; index<num_pow_entries; index++)
544151497Sru    {
545151497Sru        printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index,
546151497Sru               __cvmx_pow_list_names[entry_list[index]],
547151497Sru               OCT_TAG_TYPE_STRING(dump->smemload[index][0].s_smemload0.tag_type),
548151497Sru               dump->smemload[index][0].s_smemload0.tag,
549151497Sru               dump->smemload[index][0].s_smemload0.grp,
550151497Sru               CAST64(dump->smemload[index][2].s_smemload1.wqp));
551151497Sru        if (dump->smemload[index][0].s_smemload0.tail)
552151497Sru            printf(" tail");
553151497Sru        else
554151497Sru            printf(" next=%d", dump->smemload[index][0].s_smemload0.next_index);
555151497Sru        if (entry_list[index] >= CVMX_POW_LIST_DESCHED)
556151497Sru        {
557151497Sru            printf(" nosched=%d", dump->smemload[index][1].s_smemload2.nosched);
558151497Sru            if (dump->smemload[index][1].s_smemload2.pend_switch)
559151497Sru            {
560151497Sru                printf(" pending tag=%s,0x%08x",
561151497Sru                       OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload2.pend_type),
562151497Sru                       dump->smemload[index][1].s_smemload2.pend_tag);
563151497Sru            }
564151497Sru        }
565151497Sru        printf("\n");
566151497Sru    }
567151497Sru}
568151497Sru
569151497Sruvoid __cvmx_pow_display_v2(void *buffer, int buffer_size)
570151497Sru{
571151497Sru    __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
572151497Sru    int num_pow_entries = cvmx_pow_get_num_entries();
573151497Sru    int num_cores;
574151497Sru    int core;
575151497Sru    int index;
576151497Sru    uint8_t entry_list[2048];
577151497Sru
578151497Sru    if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
579151497Sru    {
580151497Sru        cvmx_dprintf("cvmx_pow_dump: Buffer too small, pow_dump_t = 0x%x, buffer_size = 0x%x\n", (int)sizeof(__cvmx_pow_dump_t), buffer_size);
581151497Sru        return;
582151497Sru    }
583151497Sru
584151497Sru    memset(entry_list, 0, sizeof(entry_list));
585151497Sru    num_cores = cvmx_octeon_num_cores();
586151497Sru
587151497Sru    /* Print the free list info */
588151497Sru    {
589151497Sru        int valid[3], has_one[3], head[3], tail[3], qnum_head, qnum_tail;
590151497Sru        int idx;
591151497Sru
592151497Sru        valid[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_val;
593151497Sru        valid[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_val;
594151497Sru        valid[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_val;
595151497Sru        has_one[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_one;
596151497Sru        has_one[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_one;
597151497Sru        has_one[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_one;
598151497Sru        head[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_head;
599151497Sru        head[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_head;
600151497Sru        head[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_head;
601151497Sru        tail[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_tail;
602151497Sru        tail[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_tail;
603151497Sru        tail[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_tail;
604151497Sru        qnum_head = dump->sindexload[0][4].sindexload1_cn68xx.qnum_head;
605151497Sru        qnum_tail = dump->sindexload[0][4].sindexload1_cn68xx.qnum_tail;
606151497Sru
607151497Sru        printf("Free List: qnum_head=%d, qnum_tail=%d\n", qnum_head, qnum_tail);
608151497Sru        printf("Free0: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[0], has_one[0], CAST64(head[0]), CAST64(tail[0]));
609151497Sru        printf("Free1: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[1], has_one[1], CAST64(head[1]), CAST64(tail[1]));
610151497Sru        printf("Free2: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[2], has_one[2], CAST64(head[2]), CAST64(tail[2]));
611151497Sru
612151497Sru        idx=qnum_head;
613151497Sru        while (valid[0] || valid[1] || valid[2])
614151497Sru        {
615151497Sru            int qidx = idx % 3;
616151497Sru
617151497Sru            if (head[qidx] == tail[qidx])
618151497Sru                valid[qidx] = 0;
619151497Sru
620151497Sru            if (__cvmx_pow_entry_mark_list(head[qidx], CVMX_POW_LIST_FREE, entry_list))
621151497Sru                break;
622151497Sru            head[qidx] = dump->smemload[head[qidx]][4].s_smemload3_cn68xx.fwd_index;
623151497Sru            //printf("qidx = %d, idx = %d, head[qidx] = %d\n", qidx, idx, head[qidx]);
624151497Sru            idx++;
625151497Sru        }
626151497Sru    }
627151497Sru
628151497Sru    /* Print the core state */
629151497Sru    for (core = 0; core < num_cores; core++)
630151497Sru    {
631151497Sru        int pendtag = 1;
632151497Sru        int pendwqp = 2;
633151497Sru        int tag = 3;
634151497Sru        int wqp = 4;
635151497Sru        int links = 5;
636151497Sru
637151497Sru        printf("Core %d State: tag=%s,0x%08x", core,
638151497Sru               OCT_TAG_TYPE_STRING(dump->sstatus[core][tag].s_sstatus2_cn68xx.tag_type),
639151497Sru               dump->sstatus[core][tag].s_sstatus2_cn68xx.tag);
640151497Sru        if (dump->sstatus[core][tag].s_sstatus2_cn68xx.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL)
641151497Sru        {
642151497Sru            __cvmx_pow_entry_mark_list(dump->sstatus[core][tag].s_sstatus2_cn68xx.index, CVMX_POW_LIST_CORE + core, entry_list);
643151497Sru            printf(" grp=%d",                   dump->sstatus[core][tag].s_sstatus2_cn68xx.grp);
644151497Sru            printf(" wqp=0x%016llx",            CAST64(dump->sstatus[core][wqp].s_sstatus3_cn68xx.wqp));
645151497Sru            printf(" index=%d",                 dump->sstatus[core][tag].s_sstatus2_cn68xx.index);
646151497Sru            if (dump->sstatus[core][links].s_sstatus4_cn68xx.head)
647151497Sru                printf(" head");
648151497Sru            else
649151497Sru                printf(" prev=%d", dump->sstatus[core][links].s_sstatus4_cn68xx.revlink_index);
650151497Sru            if (dump->sstatus[core][links].s_sstatus4_cn68xx.tail)
651151497Sru                printf(" tail");
652151497Sru            else
653151497Sru                printf(" next=%d", dump->sstatus[core][links].s_sstatus4_cn68xx.link_index);
654151497Sru        }
655151497Sru        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch)
656151497Sru        {
657151497Sru            printf(" pend_switch=%d",           dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch);
658151497Sru        }
659151497Sru
660151497Sru        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_desched)
661151497Sru        {
662151497Sru            printf(" pend_desched=%d",          dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_desched);
663151497Sru            printf(" pend_nosched=%d",          dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched);
664151497Sru        }
665151497Sru        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_get_work)
666151497Sru        {
667151497Sru            if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_get_work_wait)
668151497Sru                printf(" (Waiting for work)");
669151497Sru            else
670151497Sru                printf(" (Getting work)");
671151497Sru        }
672151497Sru        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_alloc_we)
673151497Sru            printf(" pend_alloc_we=%d",          dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_alloc_we);
674151497Sru        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched_clr)
675151497Sru        {
676151497Sru            printf(" pend_nosched_clr=%d",      dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched_clr);
677151497Sru            printf(" pend_index=%d",            dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_index);
678151497Sru        }
679151497Sru        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch)
680151497Sru        {
681151497Sru            printf(" pending tag=%s,0x%08x",
682151497Sru                   OCT_TAG_TYPE_STRING(dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_type),
683151497Sru                   dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_tag);
684151497Sru        }
685151497Sru        if (dump->sstatus[core][pendwqp].s_sstatus1_cn68xx.pend_nosched_clr)
686151497Sru            printf(" pend_wqp=0x%016llx\n",     CAST64(dump->sstatus[core][pendwqp].s_sstatus1_cn68xx.pend_wqp));
687151497Sru        printf("\n");
688151497Sru    }
689151497Sru
690151497Sru    /* Print out the state of the nosched list and the 16 deschedule lists. */
691151497Sru    __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED, dump, entry_list,
692151497Sru                            dump->sindexload[0][3].sindexload0_cn68xx.queue_val,
693151497Sru                            dump->sindexload[0][3].sindexload0_cn68xx.queue_one,
694151497Sru                            dump->sindexload[0][3].sindexload0_cn68xx.queue_head,
695151497Sru                            dump->sindexload[0][3].sindexload0_cn68xx.queue_tail);
696151497Sru    for (index=0; index<64; index++)
697151497Sru    {
698151497Sru        __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list,
699151497Sru                                dump->sindexload[index][2].sindexload0_cn68xx.queue_val,
700151497Sru                                dump->sindexload[index][2].sindexload0_cn68xx.queue_one,
701151497Sru                                dump->sindexload[index][2].sindexload0_cn68xx.queue_head,
702151497Sru                                dump->sindexload[index][2].sindexload0_cn68xx.queue_tail);
703151497Sru    }
704151497Sru
705151497Sru    /* Print out the state of the 8 internal input queues */
706151497Sru    for (index=0; index<8; index++)
707151497Sru    {
708151497Sru        __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list,
709151497Sru                                dump->sindexload[index][1].sindexload0_cn68xx.queue_val,
710151497Sru                                dump->sindexload[index][1].sindexload0_cn68xx.queue_one,
711151497Sru                                dump->sindexload[index][1].sindexload0_cn68xx.queue_head,
712151497Sru                                dump->sindexload[index][1].sindexload0_cn68xx.queue_tail);
713151497Sru    }
714151497Sru
715151497Sru    /* Print out the state of the 16 memory queues */
716151497Sru    for (index=0; index<8; index++)
717151497Sru    {
718151497Sru        const char *name;
719151497Sru        if (dump->sindexload[index][1].sindexload0_cn68xx.queue_head)
720151497Sru            name = "Queue %da Memory (is head)";
721151497Sru        else
722151497Sru            name = "Queue %da Memory";
723151497Sru        __cvmx_pow_display_list(name, index,
724151497Sru                                dump->sindexload[index][1].sindexload0_cn68xx.queue_val,
725151497Sru                                dump->sindexload[index][1].sindexload0_cn68xx.queue_one,
726151497Sru                                dump->sindexload[index][1].sindexload0_cn68xx.queue_head,
727151497Sru                                dump->sindexload[index][1].sindexload0_cn68xx.queue_tail);
728151497Sru        if (dump->sindexload[index+8][1].sindexload0_cn68xx.queue_head)
729151497Sru            name = "Queue %db Memory (is head)";
730151497Sru        else
731151497Sru            name = "Queue %db Memory";
732151497Sru        __cvmx_pow_display_list(name, index,
733151497Sru                                dump->sindexload[index+8][1].sindexload0_cn68xx.queue_val,
734151497Sru                                dump->sindexload[index+8][1].sindexload0_cn68xx.queue_one,
735151497Sru                                dump->sindexload[index+8][1].sindexload0_cn68xx.queue_head,
736151497Sru                                dump->sindexload[index+8][1].sindexload0_cn68xx.queue_tail);
737151497Sru    }
738151497Sru
739151497Sru    /* Print out each of the internal POW entries. Each entry has a tag, group,
740151497Sru       wqe, and possibly a next pointer. The next pointer is only valid if this
741151497Sru       entry isn't make as a tail */
742151497Sru    for (index=0; index<num_pow_entries; index++)
743151497Sru    {
744151497Sru        printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index,
745151497Sru               __cvmx_pow_list_names[entry_list[index]],
746151497Sru               OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload0_cn68xx.tag_type),
747151497Sru               dump->smemload[index][1].s_smemload0_cn68xx.tag,
748151497Sru               dump->smemload[index][2].s_smemload1_cn68xx.grp,
749151497Sru               CAST64(dump->smemload[index][2].s_smemload1_cn68xx.wqp));
750151497Sru        if (dump->smemload[index][1].s_smemload0_cn68xx.tail)
751151497Sru            printf(" tail");
752151497Sru        else
753151497Sru            printf(" next=%d", dump->smemload[index][4].s_smemload3_cn68xx.fwd_index);
754151497Sru        if (entry_list[index] >= CVMX_POW_LIST_DESCHED)
755151497Sru        {
756151497Sru            printf(" prev=%d", dump->smemload[index][4].s_smemload3_cn68xx.fwd_index);
757151497Sru            printf(" nosched=%d", dump->smemload[index][1].s_smemload1_cn68xx.nosched);
758151497Sru            if (dump->smemload[index][3].s_smemload2_cn68xx.pend_switch)
759151497Sru            {
760151497Sru                printf(" pending tag=%s,0x%08x",
761151497Sru                       OCT_TAG_TYPE_STRING(dump->smemload[index][3].s_smemload2_cn68xx.pend_type),
762151497Sru                       dump->smemload[index][3].s_smemload2_cn68xx.pend_tag);
763151497Sru            }
764151497Sru        }
765151497Sru        printf("\n");
766151497Sru    }
767151497Sru}
768151497Sru
769151497Sru/**
770151497Sru * Dump a POW capture to the console in a human readable format.
771151497Sru *
772151497Sru * @param buffer POW capture from cvmx_pow_capture()
773151497Sru * @param buffer_size
774151497Sru *               Size of the buffer
775151497Sru */
776151497Sruvoid cvmx_pow_display(void *buffer, int buffer_size)
777151497Sru{
778151497Sru    printf("POW Display Start\n");
779151497Sru
780151497Sru    if (octeon_has_feature(OCTEON_FEATURE_PKND))
781151497Sru        __cvmx_pow_display_v2(buffer, buffer_size);
782151497Sru    else
783151497Sru        __cvmx_pow_display_v1(buffer, buffer_size);
784151497Sru
785151497Sru    printf("POW Display End\n");
786151497Sru    return;
787151497Sru}
788151497Sru
789151497Sru