]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/octeon-sdk/cvmx-pow.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / octeon-sdk / cvmx-pow.c
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  */
63 typedef 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
70 typedef 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
80 static 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  */
118 int 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
135 static 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
215 static 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  */
293 int 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  */
311 static 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  */
338 static 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  */
366 static 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
398 void __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
569 void __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  */
776 void 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