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/**
47 * @file
48 *
49 * Interface to the hardware Packet Order / Work unit.
50 *
51 * <hr>$Revision: 29727 $<hr>
52 */
53
54#include "cvmx.h"
55#include "cvmx-pow.h"
56
57/**
58 * @INTERNAL
59 * This structure stores the internal POW state captured by
60 * cvmx_pow_capture(). It is purposely not exposed to the user
61 * since the format may change without notice.
62 */
63typedef struct
64{
65    cvmx_pow_tag_load_resp_t sstatus[CVMX_MAX_CORES][8];
66    cvmx_pow_tag_load_resp_t smemload[2048][8];
67    cvmx_pow_tag_load_resp_t sindexload[64][8];
68} __cvmx_pow_dump_t;
69
70typedef enum
71{
72    CVMX_POW_LIST_UNKNOWN=0,
73    CVMX_POW_LIST_FREE=1,
74    CVMX_POW_LIST_INPUT=2,
75    CVMX_POW_LIST_CORE=CVMX_POW_LIST_INPUT+8,
76    CVMX_POW_LIST_DESCHED=CVMX_POW_LIST_CORE+32,
77    CVMX_POW_LIST_NOSCHED=CVMX_POW_LIST_DESCHED+64,
78} __cvmx_pow_list_types_t;
79
80static const char *__cvmx_pow_list_names[] = {
81    "Unknown",
82    "Free List",
83    "Queue 0", "Queue 1", "Queue 2", "Queue 3",
84    "Queue 4", "Queue 5", "Queue 6", "Queue 7",
85    "Core 0", "Core 1", "Core 2", "Core 3",
86    "Core 4", "Core 5", "Core 6", "Core 7",
87    "Core 8", "Core 9", "Core 10", "Core 11",
88    "Core 12", "Core 13", "Core 14", "Core 15",
89    "Core 16", "Core 17", "Core 18", "Core 19",
90    "Core 20", "Core 21", "Core 22", "Core 23",
91    "Core 24", "Core 25", "Core 26", "Core 27",
92    "Core 28", "Core 29", "Core 30", "Core 31",
93    "Desched 0", "Desched 1", "Desched 2", "Desched 3",
94    "Desched 4", "Desched 5", "Desched 6", "Desched 7",
95    "Desched 8", "Desched 9", "Desched 10", "Desched 11",
96    "Desched 12", "Desched 13", "Desched 14", "Desched 15",
97    "Desched 16", "Desched 17", "Desched 18", "Desched 19",
98    "Desched 20", "Desched 21", "Desched 22", "Desched 23",
99    "Desched 24", "Desched 25", "Desched 26", "Desched 27",
100    "Desched 28", "Desched 29", "Desched 30", "Desched 31",
101    "Desched 32", "Desched 33", "Desched 34", "Desched 35",
102    "Desched 36", "Desched 37", "Desched 38", "Desched 39",
103    "Desched 40", "Desched 41", "Desched 42", "Desched 43",
104    "Desched 44", "Desched 45", "Desched 46", "Desched 47",
105    "Desched 48", "Desched 49", "Desched 50", "Desched 51",
106    "Desched 52", "Desched 53", "Desched 54", "Desched 55",
107    "Desched 56", "Desched 57", "Desched 58", "Desched 59",
108    "Desched 60", "Desched 61", "Desched 62", "Desched 63",
109    "Nosched 0"
110};
111
112
113/**
114 * Return the number of POW entries supported by this chip
115 *
116 * @return Number of POW entries
117 */
118int cvmx_pow_get_num_entries(void)
119{
120    if (OCTEON_IS_MODEL(OCTEON_CN30XX))
121        return 64;
122    else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
123        return 256;
124    else if (OCTEON_IS_MODEL(OCTEON_CN52XX)
125             || OCTEON_IS_MODEL(OCTEON_CN61XX)
126             || OCTEON_IS_MODEL(OCTEON_CNF71XX))
127        return 512;
128    else if (OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CN66XX))
129	return 1024;
130    else
131        return 2048;
132}
133
134
135static int __cvmx_pow_capture_v1(void *buffer, int buffer_size)
136{
137    __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
138    int num_cores;
139    int num_pow_entries = cvmx_pow_get_num_entries();
140    int core;
141    int index;
142    int bits;
143
144    if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
145    {
146        cvmx_dprintf("cvmx_pow_capture: Buffer too small\n");
147        return -1;
148    }
149
150    num_cores = cvmx_octeon_num_cores();
151
152    /* Read all core related state */
153    for (core=0; core<num_cores; core++)
154    {
155        cvmx_pow_load_addr_t load_addr;
156        load_addr.u64 = 0;
157        load_addr.sstatus.mem_region = CVMX_IO_SEG;
158        load_addr.sstatus.is_io = 1;
159        load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1;
160        load_addr.sstatus.coreid = core;
161        for (bits=0; bits<8; bits++)
162        {
163            load_addr.sstatus.get_rev = (bits & 1) != 0;
164            load_addr.sstatus.get_cur = (bits & 2) != 0;
165            load_addr.sstatus.get_wqp = (bits & 4) != 0;
166            if ((load_addr.sstatus.get_cur == 0) && load_addr.sstatus.get_rev)
167                dump->sstatus[core][bits].u64 = -1;
168            else
169                dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64);
170        }
171    }
172
173    /* Read all internal POW entries */
174    for (index=0; index<num_pow_entries; index++)
175    {
176        cvmx_pow_load_addr_t load_addr;
177        load_addr.u64 = 0;
178        load_addr.smemload.mem_region = CVMX_IO_SEG;
179        load_addr.smemload.is_io = 1;
180        load_addr.smemload.did = CVMX_OCT_DID_TAG_TAG2;
181        load_addr.smemload.index = index;
182        for (bits=0; bits<3; bits++)
183        {
184            load_addr.smemload.get_des = (bits & 1) != 0;
185            load_addr.smemload.get_wqp = (bits & 2) != 0;
186            dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
187        }
188    }
189
190    /* Read all group and queue pointers */
191    for (index=0; index<16; index++)
192    {
193        cvmx_pow_load_addr_t load_addr;
194        load_addr.u64 = 0;
195        load_addr.sindexload.mem_region = CVMX_IO_SEG;
196        load_addr.sindexload.is_io = 1;
197        load_addr.sindexload.did = CVMX_OCT_DID_TAG_TAG3;
198        load_addr.sindexload.qosgrp = index;
199        for (bits=0; bits<4; bits++)
200        {
201            load_addr.sindexload.get_rmt =  (bits & 1) != 0;
202            load_addr.sindexload.get_des_get_tail =  (bits & 2) != 0;
203            /* The first pass only has 8 valid index values */
204            if ((load_addr.sindexload.get_rmt == 0) &&
205                (load_addr.sindexload.get_des_get_tail == 0) &&
206                (index >= 8))
207                dump->sindexload[index][bits].u64 = -1;
208            else
209                dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
210        }
211    }
212    return 0;
213}
214
215static int __cvmx_pow_capture_v2(void *buffer, int buffer_size)
216{
217    __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
218    int num_cores;
219    int num_pow_entries = cvmx_pow_get_num_entries();
220    int core;
221    int index;
222    int bits;
223
224    if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
225    {
226        cvmx_dprintf("cvmx_pow_capture: Buffer too small\n");
227        return -1;
228    }
229
230    num_cores = cvmx_octeon_num_cores();
231
232    /* Read all core related state */
233    for (core=0; core<num_cores; core++)
234    {
235        cvmx_pow_load_addr_t load_addr;
236        load_addr.u64 = 0;
237        load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG;
238        load_addr.sstatus_cn68xx.is_io = 1;
239        load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5;
240        load_addr.sstatus_cn68xx.coreid = core;
241        for (bits=1; bits<6; bits++)
242        {
243            load_addr.sstatus_cn68xx.opcode = bits;
244            dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64);
245        }
246    }
247    /* Read all internal POW entries */
248    for (index=0; index<num_pow_entries; index++)
249    {
250        cvmx_pow_load_addr_t load_addr;
251        load_addr.u64 = 0;
252        load_addr.smemload_cn68xx.mem_region = CVMX_IO_SEG;
253        load_addr.smemload_cn68xx.is_io = 1;
254        load_addr.smemload_cn68xx.did = CVMX_OCT_DID_TAG_TAG2;
255        load_addr.smemload_cn68xx.index = index;
256        for (bits=1; bits<5; bits++)
257        {
258            load_addr.smemload_cn68xx.opcode = bits;
259            dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
260        }
261    }
262
263    /* Read all group and queue pointers */
264    for (index=0; index<64; index++)
265    {
266        cvmx_pow_load_addr_t load_addr;
267        load_addr.u64 = 0;
268        load_addr.sindexload_cn68xx.mem_region = CVMX_IO_SEG;
269        load_addr.sindexload_cn68xx.is_io = 1;
270        load_addr.sindexload_cn68xx.did = CVMX_OCT_DID_TAG_TAG3;
271        load_addr.sindexload_cn68xx.qos_grp = index;
272        for (bits=1; bits<7; bits++)
273        {
274            load_addr.sindexload_cn68xx.opcode = bits;
275            dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
276        }
277    }
278    return 0;
279}
280
281/**
282 * Store the current POW internal state into the supplied
283 * buffer. It is recommended that you pass a buffer of at least
284 * 128KB. The format of the capture may change based on SDK
285 * version and Octeon chip.
286 *
287 * @param buffer Buffer to store capture into
288 * @param buffer_size
289 *               The size of the supplied buffer
290 *
291 * @return Zero on sucess, negative on failure
292 */
293int cvmx_pow_capture(void *buffer, int buffer_size)
294{
295    if (octeon_has_feature(OCTEON_FEATURE_PKND))
296        return __cvmx_pow_capture_v2(buffer, buffer_size);
297    else
298        return __cvmx_pow_capture_v1(buffer, buffer_size);
299}
300
301/**
302 * Function to display a POW internal queue to the user
303 *
304 * @param name       User visible name for the queue
305 * @param name_param Parameter for printf in creating the name
306 * @param valid      Set if the queue contains any elements
307 * @param has_one    Set if the queue contains exactly one element
308 * @param head       The head pointer
309 * @param tail       The tail pointer
310 */
311static void __cvmx_pow_display_list(const char *name, int name_param, int valid, int has_one, uint64_t head, uint64_t tail)
312{
313    printf(name, name_param);
314    printf(": ");
315    if (valid)
316    {
317        if (has_one)
318            printf("One element index=%llu(0x%llx)\n", CAST64(head), CAST64(head));
319        else
320            printf("Multiple elements head=%llu(0x%llx) tail=%llu(0x%llx)\n", CAST64(head), CAST64(head), CAST64(tail), CAST64(tail));
321    }
322    else
323        printf("Empty\n");
324}
325
326
327/**
328 * Mark which list a POW entry is on. Print a warning message if the
329 * entry is already on a list. This happens if the POW changed while
330 * the capture was running.
331 *
332 * @param entry_num  Entry number to mark
333 * @param entry_type List type
334 * @param entry_list Array to store marks
335 *
336 * @return Zero on success, negative if already on a list
337 */
338static int __cvmx_pow_entry_mark_list(int entry_num, __cvmx_pow_list_types_t entry_type, uint8_t entry_list[])
339{
340    if (entry_list[entry_num] == 0)
341    {
342        entry_list[entry_num] = entry_type;
343        return 0;
344    }
345    else
346    {
347        printf("\nWARNING: Entry %d already on list %s, but we tried to add it to %s\n",
348               entry_num, __cvmx_pow_list_names[entry_list[entry_num]], __cvmx_pow_list_names[entry_type]);
349        return -1;
350    }
351}
352
353
354/**
355 * Display a list and mark all elements on the list as belonging to
356 * the list.
357 *
358 * @param entry_type Type of the list to display and mark
359 * @param dump       POW capture data
360 * @param entry_list Array to store marks in
361 * @param valid      Set if the queue contains any elements
362 * @param has_one    Set if the queue contains exactly one element
363 * @param head       The head pointer
364 * @param tail       The tail pointer
365 */
366static void __cvmx_pow_display_list_and_walk(__cvmx_pow_list_types_t entry_type,
367                                             __cvmx_pow_dump_t *dump, uint8_t entry_list[],
368                                             int valid, int has_one, uint64_t head, uint64_t tail)
369{
370    __cvmx_pow_display_list(__cvmx_pow_list_names[entry_type], 0, valid, has_one, head, tail);
371    if (valid)
372    {
373        if (has_one)
374            __cvmx_pow_entry_mark_list(head, entry_type, entry_list);
375        else
376        {
377            while (head != tail)
378            {
379                if (__cvmx_pow_entry_mark_list(head, entry_type, entry_list))
380                    break;
381                if (octeon_has_feature(OCTEON_FEATURE_PKND))
382                {
383                    if (entry_type >= CVMX_POW_LIST_INPUT && entry_type < CVMX_POW_LIST_CORE)
384
385                        head = dump->smemload[head][4].s_smemload3_cn68xx.next_index;
386                    else
387                        head = dump->smemload[head][4].s_smemload3_cn68xx.fwd_index;
388                }
389                else
390                    head = dump->smemload[head][0].s_smemload0.next_index;
391            }
392            __cvmx_pow_entry_mark_list(tail, entry_type, entry_list);
393        }
394    }
395}
396
397
398void __cvmx_pow_display_v1(void *buffer, int buffer_size)
399{
400    __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
401    int num_pow_entries = cvmx_pow_get_num_entries();
402    int num_cores;
403    int core;
404    int index;
405    uint8_t entry_list[2048];
406
407    if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
408    {
409        cvmx_dprintf("cvmx_pow_dump: Buffer too small\n");
410        return;
411    }
412
413    memset(entry_list, 0, sizeof(entry_list));
414    num_cores = cvmx_octeon_num_cores();
415
416    /* Print the free list info */
417    __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_FREE, dump, entry_list,
418                                     dump->sindexload[0][0].sindexload0.free_val,
419                                     dump->sindexload[0][0].sindexload0.free_one,
420                                     dump->sindexload[0][0].sindexload0.free_head,
421                                     dump->sindexload[0][0].sindexload0.free_tail);
422
423    /* Print the core state */
424    for (core=0; core<num_cores; core++)
425    {
426        const int bit_rev = 1;
427        const int bit_cur = 2;
428        const int bit_wqp = 4;
429        printf("Core %d State:  tag=%s,0x%08x", core,
430               OCT_TAG_TYPE_STRING(dump->sstatus[core][bit_cur].s_sstatus2.tag_type),
431               dump->sstatus[core][bit_cur].s_sstatus2.tag);
432        if (dump->sstatus[core][bit_cur].s_sstatus2.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL)
433        {
434            __cvmx_pow_entry_mark_list(dump->sstatus[core][bit_cur].s_sstatus2.index, CVMX_POW_LIST_CORE + core, entry_list);
435            printf(" grp=%d",                   dump->sstatus[core][bit_cur].s_sstatus2.grp);
436            printf(" wqp=0x%016llx",            CAST64(dump->sstatus[core][bit_cur|bit_wqp].s_sstatus4.wqp));
437            printf(" index=%d",                 dump->sstatus[core][bit_cur].s_sstatus2.index);
438            if (dump->sstatus[core][bit_cur].s_sstatus2.head)
439                printf(" head");
440            else
441                printf(" prev=%d", dump->sstatus[core][bit_cur|bit_rev].s_sstatus3.revlink_index);
442            if (dump->sstatus[core][bit_cur].s_sstatus2.tail)
443                printf(" tail");
444            else
445                printf(" next=%d", dump->sstatus[core][bit_cur].s_sstatus2.link_index);
446        }
447
448        if (dump->sstatus[core][0].s_sstatus0.pend_switch)
449        {
450            printf(" pend_switch=%d",           dump->sstatus[core][0].s_sstatus0.pend_switch);
451            printf(" pend_switch_full=%d",      dump->sstatus[core][0].s_sstatus0.pend_switch_full);
452            printf(" pend_switch_null=%d",      dump->sstatus[core][0].s_sstatus0.pend_switch_null);
453        }
454
455        if (dump->sstatus[core][0].s_sstatus0.pend_desched)
456        {
457            printf(" pend_desched=%d",          dump->sstatus[core][0].s_sstatus0.pend_desched);
458            printf(" pend_desched_switch=%d",   dump->sstatus[core][0].s_sstatus0.pend_desched_switch);
459            printf(" pend_nosched=%d",          dump->sstatus[core][0].s_sstatus0.pend_nosched);
460            if (dump->sstatus[core][0].s_sstatus0.pend_desched_switch)
461                printf(" pend_grp=%d",              dump->sstatus[core][0].s_sstatus0.pend_grp);
462        }
463
464        if (dump->sstatus[core][0].s_sstatus0.pend_new_work)
465        {
466            if (dump->sstatus[core][0].s_sstatus0.pend_new_work_wait)
467                printf(" (Waiting for work)");
468            else
469                printf(" (Getting work)");
470        }
471        if (dump->sstatus[core][0].s_sstatus0.pend_null_rd)
472            printf(" pend_null_rd=%d",          dump->sstatus[core][0].s_sstatus0.pend_null_rd);
473        if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
474        {
475            printf(" pend_nosched_clr=%d",      dump->sstatus[core][0].s_sstatus0.pend_nosched_clr);
476            printf(" pend_index=%d",            dump->sstatus[core][0].s_sstatus0.pend_index);
477        }
478        if (dump->sstatus[core][0].s_sstatus0.pend_switch ||
479            (dump->sstatus[core][0].s_sstatus0.pend_desched &&
480            dump->sstatus[core][0].s_sstatus0.pend_desched_switch))
481        {
482            printf(" pending tag=%s,0x%08x",
483                   OCT_TAG_TYPE_STRING(dump->sstatus[core][0].s_sstatus0.pend_type),
484                   dump->sstatus[core][0].s_sstatus0.pend_tag);
485        }
486        if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
487            printf(" pend_wqp=0x%016llx\n",     CAST64(dump->sstatus[core][bit_wqp].s_sstatus1.pend_wqp));
488        printf("\n");
489    }
490
491    /* Print out the state of the nosched list and the 16 deschedule lists. */
492    __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED, dump, entry_list,
493                            dump->sindexload[0][2].sindexload1.nosched_val,
494                            dump->sindexload[0][2].sindexload1.nosched_one,
495                            dump->sindexload[0][2].sindexload1.nosched_head,
496                            dump->sindexload[0][2].sindexload1.nosched_tail);
497    for (index=0; index<16; index++)
498    {
499        __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list,
500                                dump->sindexload[index][2].sindexload1.des_val,
501                                dump->sindexload[index][2].sindexload1.des_one,
502                                dump->sindexload[index][2].sindexload1.des_head,
503                                dump->sindexload[index][2].sindexload1.des_tail);
504    }
505
506    /* Print out the state of the 8 internal input queues */
507    for (index=0; index<8; index++)
508    {
509        __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list,
510                                dump->sindexload[index][0].sindexload0.loc_val,
511                                dump->sindexload[index][0].sindexload0.loc_one,
512                                dump->sindexload[index][0].sindexload0.loc_head,
513                                dump->sindexload[index][0].sindexload0.loc_tail);
514    }
515
516    /* Print out the state of the 16 memory queues */
517    for (index=0; index<8; index++)
518    {
519        const char *name;
520        if (dump->sindexload[index][1].sindexload2.rmt_is_head)
521            name = "Queue %da Memory (is head)";
522        else
523            name = "Queue %da Memory";
524        __cvmx_pow_display_list(name, index,
525                                dump->sindexload[index][1].sindexload2.rmt_val,
526                                dump->sindexload[index][1].sindexload2.rmt_one,
527                                dump->sindexload[index][1].sindexload2.rmt_head,
528                                dump->sindexload[index][3].sindexload3.rmt_tail);
529        if (dump->sindexload[index+8][1].sindexload2.rmt_is_head)
530            name = "Queue %db Memory (is head)";
531        else
532            name = "Queue %db Memory";
533        __cvmx_pow_display_list(name, index,
534                                dump->sindexload[index+8][1].sindexload2.rmt_val,
535                                dump->sindexload[index+8][1].sindexload2.rmt_one,
536                                dump->sindexload[index+8][1].sindexload2.rmt_head,
537                                dump->sindexload[index+8][3].sindexload3.rmt_tail);
538    }
539
540    /* Print out each of the internal POW entries. Each entry has a tag, group,
541        wqe, and possibly a next pointer. The next pointer is only valid if this
542        entry isn't make as a tail */
543    for (index=0; index<num_pow_entries; index++)
544    {
545        printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index,
546               __cvmx_pow_list_names[entry_list[index]],
547               OCT_TAG_TYPE_STRING(dump->smemload[index][0].s_smemload0.tag_type),
548               dump->smemload[index][0].s_smemload0.tag,
549               dump->smemload[index][0].s_smemload0.grp,
550               CAST64(dump->smemload[index][2].s_smemload1.wqp));
551        if (dump->smemload[index][0].s_smemload0.tail)
552            printf(" tail");
553        else
554            printf(" next=%d", dump->smemload[index][0].s_smemload0.next_index);
555        if (entry_list[index] >= CVMX_POW_LIST_DESCHED)
556        {
557            printf(" nosched=%d", dump->smemload[index][1].s_smemload2.nosched);
558            if (dump->smemload[index][1].s_smemload2.pend_switch)
559            {
560                printf(" pending tag=%s,0x%08x",
561                       OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload2.pend_type),
562                       dump->smemload[index][1].s_smemload2.pend_tag);
563            }
564        }
565        printf("\n");
566    }
567}
568
569void __cvmx_pow_display_v2(void *buffer, int buffer_size)
570{
571    __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
572    int num_pow_entries = cvmx_pow_get_num_entries();
573    int num_cores;
574    int core;
575    int index;
576    uint8_t entry_list[2048];
577
578    if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
579    {
580        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);
581        return;
582    }
583
584    memset(entry_list, 0, sizeof(entry_list));
585    num_cores = cvmx_octeon_num_cores();
586
587    /* Print the free list info */
588    {
589        int valid[3], has_one[3], head[3], tail[3], qnum_head, qnum_tail;
590        int idx;
591
592        valid[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_val;
593        valid[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_val;
594        valid[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_val;
595        has_one[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_one;
596        has_one[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_one;
597        has_one[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_one;
598        head[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_head;
599        head[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_head;
600        head[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_head;
601        tail[0] = dump->sindexload[0][4].sindexload1_cn68xx.queue_tail;
602        tail[1] = dump->sindexload[0][5].sindexload1_cn68xx.queue_tail;
603        tail[2] = dump->sindexload[0][6].sindexload1_cn68xx.queue_tail;
604        qnum_head = dump->sindexload[0][4].sindexload1_cn68xx.qnum_head;
605        qnum_tail = dump->sindexload[0][4].sindexload1_cn68xx.qnum_tail;
606
607        printf("Free List: qnum_head=%d, qnum_tail=%d\n", qnum_head, qnum_tail);
608        printf("Free0: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[0], has_one[0], CAST64(head[0]), CAST64(tail[0]));
609        printf("Free1: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[1], has_one[1], CAST64(head[1]), CAST64(tail[1]));
610        printf("Free2: valid=%d, one=%d, head=%llu, tail=%llu\n", valid[2], has_one[2], CAST64(head[2]), CAST64(tail[2]));
611
612        idx=qnum_head;
613        while (valid[0] || valid[1] || valid[2])
614        {
615            int qidx = idx % 3;
616
617            if (head[qidx] == tail[qidx])
618                valid[qidx] = 0;
619
620            if (__cvmx_pow_entry_mark_list(head[qidx], CVMX_POW_LIST_FREE, entry_list))
621                break;
622            head[qidx] = dump->smemload[head[qidx]][4].s_smemload3_cn68xx.fwd_index;
623            //printf("qidx = %d, idx = %d, head[qidx] = %d\n", qidx, idx, head[qidx]);
624            idx++;
625        }
626    }
627
628    /* Print the core state */
629    for (core = 0; core < num_cores; core++)
630    {
631        int pendtag = 1;
632        int pendwqp = 2;
633        int tag = 3;
634        int wqp = 4;
635        int links = 5;
636
637        printf("Core %d State: tag=%s,0x%08x", core,
638               OCT_TAG_TYPE_STRING(dump->sstatus[core][tag].s_sstatus2_cn68xx.tag_type),
639               dump->sstatus[core][tag].s_sstatus2_cn68xx.tag);
640        if (dump->sstatus[core][tag].s_sstatus2_cn68xx.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL)
641        {
642            __cvmx_pow_entry_mark_list(dump->sstatus[core][tag].s_sstatus2_cn68xx.index, CVMX_POW_LIST_CORE + core, entry_list);
643            printf(" grp=%d",                   dump->sstatus[core][tag].s_sstatus2_cn68xx.grp);
644            printf(" wqp=0x%016llx",            CAST64(dump->sstatus[core][wqp].s_sstatus3_cn68xx.wqp));
645            printf(" index=%d",                 dump->sstatus[core][tag].s_sstatus2_cn68xx.index);
646            if (dump->sstatus[core][links].s_sstatus4_cn68xx.head)
647                printf(" head");
648            else
649                printf(" prev=%d", dump->sstatus[core][links].s_sstatus4_cn68xx.revlink_index);
650            if (dump->sstatus[core][links].s_sstatus4_cn68xx.tail)
651                printf(" tail");
652            else
653                printf(" next=%d", dump->sstatus[core][links].s_sstatus4_cn68xx.link_index);
654        }
655        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch)
656        {
657            printf(" pend_switch=%d",           dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch);
658        }
659
660        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_desched)
661        {
662            printf(" pend_desched=%d",          dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_desched);
663            printf(" pend_nosched=%d",          dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched);
664        }
665        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_get_work)
666        {
667            if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_get_work_wait)
668                printf(" (Waiting for work)");
669            else
670                printf(" (Getting work)");
671        }
672        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_alloc_we)
673            printf(" pend_alloc_we=%d",          dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_alloc_we);
674        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched_clr)
675        {
676            printf(" pend_nosched_clr=%d",      dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_nosched_clr);
677            printf(" pend_index=%d",            dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_index);
678        }
679        if (dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_switch)
680        {
681            printf(" pending tag=%s,0x%08x",
682                   OCT_TAG_TYPE_STRING(dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_type),
683                   dump->sstatus[core][pendtag].s_sstatus0_cn68xx.pend_tag);
684        }
685        if (dump->sstatus[core][pendwqp].s_sstatus1_cn68xx.pend_nosched_clr)
686            printf(" pend_wqp=0x%016llx\n",     CAST64(dump->sstatus[core][pendwqp].s_sstatus1_cn68xx.pend_wqp));
687        printf("\n");
688    }
689
690    /* Print out the state of the nosched list and the 16 deschedule lists. */
691    __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED, dump, entry_list,
692                            dump->sindexload[0][3].sindexload0_cn68xx.queue_val,
693                            dump->sindexload[0][3].sindexload0_cn68xx.queue_one,
694                            dump->sindexload[0][3].sindexload0_cn68xx.queue_head,
695                            dump->sindexload[0][3].sindexload0_cn68xx.queue_tail);
696    for (index=0; index<64; index++)
697    {
698        __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list,
699                                dump->sindexload[index][2].sindexload0_cn68xx.queue_val,
700                                dump->sindexload[index][2].sindexload0_cn68xx.queue_one,
701                                dump->sindexload[index][2].sindexload0_cn68xx.queue_head,
702                                dump->sindexload[index][2].sindexload0_cn68xx.queue_tail);
703    }
704
705    /* Print out the state of the 8 internal input queues */
706    for (index=0; index<8; index++)
707    {
708        __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list,
709                                dump->sindexload[index][1].sindexload0_cn68xx.queue_val,
710                                dump->sindexload[index][1].sindexload0_cn68xx.queue_one,
711                                dump->sindexload[index][1].sindexload0_cn68xx.queue_head,
712                                dump->sindexload[index][1].sindexload0_cn68xx.queue_tail);
713    }
714
715    /* Print out the state of the 16 memory queues */
716    for (index=0; index<8; index++)
717    {
718        const char *name;
719        if (dump->sindexload[index][1].sindexload0_cn68xx.queue_head)
720            name = "Queue %da Memory (is head)";
721        else
722            name = "Queue %da Memory";
723        __cvmx_pow_display_list(name, index,
724                                dump->sindexload[index][1].sindexload0_cn68xx.queue_val,
725                                dump->sindexload[index][1].sindexload0_cn68xx.queue_one,
726                                dump->sindexload[index][1].sindexload0_cn68xx.queue_head,
727                                dump->sindexload[index][1].sindexload0_cn68xx.queue_tail);
728        if (dump->sindexload[index+8][1].sindexload0_cn68xx.queue_head)
729            name = "Queue %db Memory (is head)";
730        else
731            name = "Queue %db Memory";
732        __cvmx_pow_display_list(name, index,
733                                dump->sindexload[index+8][1].sindexload0_cn68xx.queue_val,
734                                dump->sindexload[index+8][1].sindexload0_cn68xx.queue_one,
735                                dump->sindexload[index+8][1].sindexload0_cn68xx.queue_head,
736                                dump->sindexload[index+8][1].sindexload0_cn68xx.queue_tail);
737    }
738
739    /* Print out each of the internal POW entries. Each entry has a tag, group,
740       wqe, and possibly a next pointer. The next pointer is only valid if this
741       entry isn't make as a tail */
742    for (index=0; index<num_pow_entries; index++)
743    {
744        printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index,
745               __cvmx_pow_list_names[entry_list[index]],
746               OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload0_cn68xx.tag_type),
747               dump->smemload[index][1].s_smemload0_cn68xx.tag,
748               dump->smemload[index][2].s_smemload1_cn68xx.grp,
749               CAST64(dump->smemload[index][2].s_smemload1_cn68xx.wqp));
750        if (dump->smemload[index][1].s_smemload0_cn68xx.tail)
751            printf(" tail");
752        else
753            printf(" next=%d", dump->smemload[index][4].s_smemload3_cn68xx.fwd_index);
754        if (entry_list[index] >= CVMX_POW_LIST_DESCHED)
755        {
756            printf(" prev=%d", dump->smemload[index][4].s_smemload3_cn68xx.fwd_index);
757            printf(" nosched=%d", dump->smemload[index][1].s_smemload1_cn68xx.nosched);
758            if (dump->smemload[index][3].s_smemload2_cn68xx.pend_switch)
759            {
760                printf(" pending tag=%s,0x%08x",
761                       OCT_TAG_TYPE_STRING(dump->smemload[index][3].s_smemload2_cn68xx.pend_type),
762                       dump->smemload[index][3].s_smemload2_cn68xx.pend_tag);
763            }
764        }
765        printf("\n");
766    }
767}
768
769/**
770 * Dump a POW capture to the console in a human readable format.
771 *
772 * @param buffer POW capture from cvmx_pow_capture()
773 * @param buffer_size
774 *               Size of the buffer
775 */
776void cvmx_pow_display(void *buffer, int buffer_size)
777{
778    printf("POW Display Start\n");
779
780    if (octeon_has_feature(OCTEON_FEATURE_PKND))
781        __cvmx_pow_display_v2(buffer, buffer_size);
782    else
783        __cvmx_pow_display_v1(buffer, buffer_size);
784
785    printf("POW Display End\n");
786    return;
787}
788
789