1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
18 * * Neither the name of Cavium Networks nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
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
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM NETWORKS 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**************************************/
49 * Interface to the hardware Packet Order / Work unit.
51 * <hr>$Revision: 29727 $<hr>
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.
65 cvmx_pow_tag_load_resp_t sstatus[16][8];
66 cvmx_pow_tag_load_resp_t smemload[2048][3];
67 cvmx_pow_tag_load_resp_t sindexload[16][4];
72 CVMX_POW_LIST_UNKNOWN=0,
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+16,
77 CVMX_POW_LIST_NOSCHED=CVMX_POW_LIST_DESCHED+16,
78 } __cvmx_pow_list_types_t;
80 static const char *__cvmx_pow_list_names[] = {
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 "Desched 0", "Desched 1", "Desched 2", "Desched 3",
90 "Desched 4", "Desched 5", "Desched 6", "Desched 7",
91 "Desched 8", "Desched 9", "Desched 10", "Desched 11",
92 "Desched 12", "Desched 13", "Desched 14", "Desched 15",
93 "Nosched 0", "Nosched 1", "Nosched 2", "Nosched 3",
94 "Nosched 4", "Nosched 5", "Nosched 6", "Nosched 7",
95 "Nosched 8", "Nosched 9", "Nosched 10", "Nosched 11",
96 "Nosched 12", "Nosched 13", "Nosched 14", "Nosched 15"
101 * Return the number of POW entries supported by this chip
103 * @return Number of POW entries
105 int cvmx_pow_get_num_entries(void)
107 if (OCTEON_IS_MODEL(OCTEON_CN30XX))
109 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
111 else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
113 else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
121 * Store the current POW internal state into the supplied
122 * buffer. It is recommended that you pass a buffer of at least
123 * 128KB. The format of the capture may change based on SDK
124 * version and Octeon chip.
126 * @param buffer Buffer to store capture into
128 * The size of the supplied buffer
130 * @return Zero on sucess, negative on failure
132 int cvmx_pow_capture(void *buffer, int buffer_size)
134 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
136 int num_pow_entries = cvmx_pow_get_num_entries();
141 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
143 cvmx_dprintf("cvmx_pow_capture: Buffer too small\n");
147 num_cores = cvmx_octeon_num_cores();
149 /* Read all core related state */
150 for (core=0; core<num_cores; core++)
152 cvmx_pow_load_addr_t load_addr;
154 load_addr.sstatus.mem_region = CVMX_IO_SEG;
155 load_addr.sstatus.is_io = 1;
156 load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1;
157 load_addr.sstatus.coreid = core;
158 for (bits=0; bits<8; bits++)
160 load_addr.sstatus.get_rev = (bits & 1) != 0;
161 load_addr.sstatus.get_cur = (bits & 2) != 0;
162 load_addr.sstatus.get_wqp = (bits & 4) != 0;
163 if ((load_addr.sstatus.get_cur == 0) && load_addr.sstatus.get_rev)
164 dump->sstatus[core][bits].u64 = -1;
166 dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64);
170 /* Read all internal POW entries */
171 for (index=0; index<num_pow_entries; index++)
173 cvmx_pow_load_addr_t load_addr;
175 load_addr.smemload.mem_region = CVMX_IO_SEG;
176 load_addr.smemload.is_io = 1;
177 load_addr.smemload.did = CVMX_OCT_DID_TAG_TAG2;
178 load_addr.smemload.index = index;
179 for (bits=0; bits<3; bits++)
181 load_addr.smemload.get_des = (bits & 1) != 0;
182 load_addr.smemload.get_wqp = (bits & 2) != 0;
183 dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
187 /* Read all group and queue pointers */
188 for (index=0; index<16; index++)
190 cvmx_pow_load_addr_t load_addr;
192 load_addr.sindexload.mem_region = CVMX_IO_SEG;
193 load_addr.sindexload.is_io = 1;
194 load_addr.sindexload.did = CVMX_OCT_DID_TAG_TAG3;
195 load_addr.sindexload.qosgrp = index;
196 for (bits=0; bits<4; bits++)
198 load_addr.sindexload.get_rmt = (bits & 1) != 0;
199 load_addr.sindexload.get_des_get_tail = (bits & 2) != 0;
200 /* The first pass only has 8 valid index values */
201 if ((load_addr.sindexload.get_rmt == 0) &&
202 (load_addr.sindexload.get_des_get_tail == 0) &&
204 dump->sindexload[index][bits].u64 = -1;
206 dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
214 * Function to display a POW internal queue to the user
216 * @param name User visible name for the queue
217 * @param name_param Parameter for printf in creating the name
218 * @param valid Set if the queue contains any elements
219 * @param has_one Set if the queue contains exactly one element
220 * @param head The head pointer
221 * @param tail The tail pointer
223 static void __cvmx_pow_display_list(const char *name, int name_param, int valid, int has_one, uint64_t head, uint64_t tail)
225 printf(name, name_param);
230 printf("One element index=%llu(0x%llx)\n", CAST64(head), CAST64(head));
232 printf("Multiple elements head=%llu(0x%llx) tail=%llu(0x%llx)\n", CAST64(head), CAST64(head), CAST64(tail), CAST64(tail));
240 * Mark which list a POW entry is on. Print a warning message if the
241 * entry is already on a list. This happens if the POW changed while
242 * the capture was running.
244 * @param entry_num Entry number to mark
245 * @param entry_type List type
246 * @param entry_list Array to store marks
248 * @return Zero on success, negative if already on a list
250 static int __cvmx_pow_entry_mark_list(int entry_num, __cvmx_pow_list_types_t entry_type, uint8_t entry_list[])
252 if (entry_list[entry_num] == 0)
254 entry_list[entry_num] = entry_type;
259 printf("\nWARNING: Entry %d already on list %s, but we tried to add it to %s\n",
260 entry_num, __cvmx_pow_list_names[entry_list[entry_num]], __cvmx_pow_list_names[entry_type]);
267 * Display a list and mark all elements on the list as belonging to
270 * @param entry_type Type of the list to display and mark
271 * @param dump POW capture data
272 * @param entry_list Array to store marks in
273 * @param valid Set if the queue contains any elements
274 * @param has_one Set if the queue contains exactly one element
275 * @param head The head pointer
276 * @param tail The tail pointer
278 static void __cvmx_pow_display_list_and_walk(__cvmx_pow_list_types_t entry_type,
279 __cvmx_pow_dump_t *dump, uint8_t entry_list[],
280 int valid, int has_one, uint64_t head, uint64_t tail)
282 __cvmx_pow_display_list(__cvmx_pow_list_names[entry_type], 0, valid, has_one, head, tail);
286 __cvmx_pow_entry_mark_list(head, entry_type, entry_list);
291 if (__cvmx_pow_entry_mark_list(head, entry_type, entry_list))
293 head = dump->smemload[head][0].s_smemload0.next_index;
295 __cvmx_pow_entry_mark_list(tail, entry_type, entry_list);
302 * Dump a POW capture to the console in a human readable format.
304 * @param buffer POW capture from cvmx_pow_capture()
308 void cvmx_pow_display(void *buffer, int buffer_size)
310 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
311 int num_pow_entries = cvmx_pow_get_num_entries();
315 uint8_t entry_list[2048];
317 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
319 cvmx_dprintf("cvmx_pow_dump: Buffer too small\n");
323 memset(entry_list, 0, sizeof(entry_list));
324 num_cores = cvmx_octeon_num_cores();
326 printf("POW Display Start\n");
328 /* Print the free list info */
329 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_FREE, dump, entry_list,
330 dump->sindexload[0][0].sindexload0.free_val,
331 dump->sindexload[0][0].sindexload0.free_one,
332 dump->sindexload[0][0].sindexload0.free_head,
333 dump->sindexload[0][0].sindexload0.free_tail);
335 /* Print the core state */
336 for (core=0; core<num_cores; core++)
338 const int bit_rev = 1;
339 const int bit_cur = 2;
340 const int bit_wqp = 4;
341 printf("Core %d State: tag=%s,0x%08x", core,
342 OCT_TAG_TYPE_STRING(dump->sstatus[core][bit_cur].s_sstatus2.tag_type),
343 dump->sstatus[core][bit_cur].s_sstatus2.tag);
344 if (dump->sstatus[core][bit_cur].s_sstatus2.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL)
346 __cvmx_pow_entry_mark_list(dump->sstatus[core][bit_cur].s_sstatus2.index, CVMX_POW_LIST_CORE + core, entry_list);
347 printf(" grp=%d", dump->sstatus[core][bit_cur].s_sstatus2.grp);
348 printf(" wqp=0x%016llx", CAST64(dump->sstatus[core][bit_cur|bit_wqp].s_sstatus4.wqp));
349 printf(" index=%d", dump->sstatus[core][bit_cur].s_sstatus2.index);
350 if (dump->sstatus[core][bit_cur].s_sstatus2.head)
353 printf(" prev=%d", dump->sstatus[core][bit_cur|bit_rev].s_sstatus3.revlink_index);
354 if (dump->sstatus[core][bit_cur].s_sstatus2.tail)
357 printf(" next=%d", dump->sstatus[core][bit_cur].s_sstatus2.link_index);
360 if (dump->sstatus[core][0].s_sstatus0.pend_switch)
362 printf(" pend_switch=%d", dump->sstatus[core][0].s_sstatus0.pend_switch);
363 printf(" pend_switch_full=%d", dump->sstatus[core][0].s_sstatus0.pend_switch_full);
364 printf(" pend_switch_null=%d", dump->sstatus[core][0].s_sstatus0.pend_switch_null);
367 if (dump->sstatus[core][0].s_sstatus0.pend_desched)
369 printf(" pend_desched=%d", dump->sstatus[core][0].s_sstatus0.pend_desched);
370 printf(" pend_desched_switch=%d", dump->sstatus[core][0].s_sstatus0.pend_desched_switch);
371 printf(" pend_nosched=%d", dump->sstatus[core][0].s_sstatus0.pend_nosched);
372 if (dump->sstatus[core][0].s_sstatus0.pend_desched_switch)
373 printf(" pend_grp=%d", dump->sstatus[core][0].s_sstatus0.pend_grp);
376 if (dump->sstatus[core][0].s_sstatus0.pend_new_work)
378 if (dump->sstatus[core][0].s_sstatus0.pend_new_work_wait)
379 printf(" (Waiting for work)");
381 printf(" (Getting work)");
383 if (dump->sstatus[core][0].s_sstatus0.pend_null_rd)
384 printf(" pend_null_rd=%d", dump->sstatus[core][0].s_sstatus0.pend_null_rd);
385 if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
387 printf(" pend_nosched_clr=%d", dump->sstatus[core][0].s_sstatus0.pend_nosched_clr);
388 printf(" pend_index=%d", dump->sstatus[core][0].s_sstatus0.pend_index);
390 if (dump->sstatus[core][0].s_sstatus0.pend_switch ||
391 (dump->sstatus[core][0].s_sstatus0.pend_desched &&
392 dump->sstatus[core][0].s_sstatus0.pend_desched_switch))
394 printf(" pending tag=%s,0x%08x",
395 OCT_TAG_TYPE_STRING(dump->sstatus[core][0].s_sstatus0.pend_type),
396 dump->sstatus[core][0].s_sstatus0.pend_tag);
398 if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
399 printf(" pend_wqp=0x%016llx\n", CAST64(dump->sstatus[core][bit_wqp].s_sstatus1.pend_wqp));
403 /* Print out the state of the nosched list and the 16 deschedule lists. */
404 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED, dump, entry_list,
405 dump->sindexload[0][2].sindexload1.nosched_val,
406 dump->sindexload[0][2].sindexload1.nosched_one,
407 dump->sindexload[0][2].sindexload1.nosched_head,
408 dump->sindexload[0][2].sindexload1.nosched_tail);
409 for (index=0; index<16; index++)
411 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list,
412 dump->sindexload[index][2].sindexload1.des_val,
413 dump->sindexload[index][2].sindexload1.des_one,
414 dump->sindexload[index][2].sindexload1.des_head,
415 dump->sindexload[index][2].sindexload1.des_tail);
418 /* Print out the state of the 8 internal input queues */
419 for (index=0; index<8; index++)
421 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list,
422 dump->sindexload[index][0].sindexload0.loc_val,
423 dump->sindexload[index][0].sindexload0.loc_one,
424 dump->sindexload[index][0].sindexload0.loc_head,
425 dump->sindexload[index][0].sindexload0.loc_tail);
428 /* Print out the state of the 16 memory queues */
429 for (index=0; index<8; index++)
432 if (dump->sindexload[index][1].sindexload2.rmt_is_head)
433 name = "Queue %da Memory (is head)";
435 name = "Queue %da Memory";
436 __cvmx_pow_display_list(name, index,
437 dump->sindexload[index][1].sindexload2.rmt_val,
438 dump->sindexload[index][1].sindexload2.rmt_one,
439 dump->sindexload[index][1].sindexload2.rmt_head,
440 dump->sindexload[index][3].sindexload3.rmt_tail);
441 if (dump->sindexload[index+8][1].sindexload2.rmt_is_head)
442 name = "Queue %db Memory (is head)";
444 name = "Queue %db Memory";
445 __cvmx_pow_display_list(name, index,
446 dump->sindexload[index+8][1].sindexload2.rmt_val,
447 dump->sindexload[index+8][1].sindexload2.rmt_one,
448 dump->sindexload[index+8][1].sindexload2.rmt_head,
449 dump->sindexload[index+8][3].sindexload3.rmt_tail);
452 /* Print out each of the internal POW entries. Each entry has a tag, group,
453 wqe, and possibly a next pointer. The next pointer is only valid if this
454 entry isn't make as a tail */
455 for (index=0; index<num_pow_entries; index++)
457 printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index,
458 __cvmx_pow_list_names[entry_list[index]],
459 OCT_TAG_TYPE_STRING(dump->smemload[index][0].s_smemload0.tag_type),
460 dump->smemload[index][0].s_smemload0.tag,
461 dump->smemload[index][0].s_smemload0.grp,
462 CAST64(dump->smemload[index][2].s_smemload1.wqp));
463 if (dump->smemload[index][0].s_smemload0.tail)
466 printf(" next=%d", dump->smemload[index][0].s_smemload0.next_index);
467 if (entry_list[index] >= CVMX_POW_LIST_DESCHED)
469 printf(" prev=%d", dump->smemload[index][1].s_smemload2.fwd_index);
470 printf(" nosched=%d", dump->smemload[index][1].s_smemload2.nosched);
471 if (dump->smemload[index][1].s_smemload2.pend_switch)
473 printf(" pending tag=%s,0x%08x",
474 OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload2.pend_type),
475 dump->smemload[index][1].s_smemload2.pend_tag);
481 printf("POW Display End\n");