1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Inc. ([email protected]). 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 */
cvmx_pow_get_num_entries(void)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
__cvmx_pow_capture_v1(void * buffer,int buffer_size)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
__cvmx_pow_capture_v2(void * buffer,int buffer_size)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 */
cvmx_pow_capture(void * buffer,int buffer_size)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 */
__cvmx_pow_display_list(const char * name,int name_param,int valid,int has_one,uint64_t head,uint64_t tail)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 */
__cvmx_pow_entry_mark_list(int entry_num,__cvmx_pow_list_types_t entry_type,uint8_t entry_list[])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 */
__cvmx_pow_display_list_and_walk(__cvmx_pow_list_types_t entry_type,__cvmx_pow_dump_t * dump,uint8_t entry_list[],int valid,int has_one,uint64_t head,uint64_t tail)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
__cvmx_pow_display_v1(void * buffer,int buffer_size)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
__cvmx_pow_display_v2(void * buffer,int buffer_size)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 */
cvmx_pow_display(void * buffer,int buffer_size)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
789