1 /***********************license start***************
2 * Copyright (c) 2003-2008 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 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT
32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
35 * For any questions regarding licensing please contact marketing@caviumnetworks.com
37 ***********************license end**************************************/
47 * Interface to the hardware Packet Order / Work unit.
49 * <hr>$Revision: 29727 $<hr>
57 * This structure stores the internal POW state captured by
58 * cvmx_pow_capture(). It is purposely not exposed to the user
59 * since the format may change without notice.
63 cvmx_pow_tag_load_resp_t sstatus[16][8];
64 cvmx_pow_tag_load_resp_t smemload[2048][3];
65 cvmx_pow_tag_load_resp_t sindexload[16][4];
70 CVMX_POW_LIST_UNKNOWN=0,
72 CVMX_POW_LIST_INPUT=2,
73 CVMX_POW_LIST_CORE=CVMX_POW_LIST_INPUT+8,
74 CVMX_POW_LIST_DESCHED=CVMX_POW_LIST_CORE+16,
75 CVMX_POW_LIST_NOSCHED=CVMX_POW_LIST_DESCHED+16,
76 } __cvmx_pow_list_types_t;
78 static const char *__cvmx_pow_list_names[] = {
81 "Queue 0", "Queue 1", "Queue 2", "Queue 3",
82 "Queue 4", "Queue 5", "Queue 6", "Queue 7",
83 "Core 0", "Core 1", "Core 2", "Core 3",
84 "Core 4", "Core 5", "Core 6", "Core 7",
85 "Core 8", "Core 9", "Core 10", "Core 11",
86 "Core 12", "Core 13", "Core 14", "Core 15",
87 "Desched 0", "Desched 1", "Desched 2", "Desched 3",
88 "Desched 4", "Desched 5", "Desched 6", "Desched 7",
89 "Desched 8", "Desched 9", "Desched 10", "Desched 11",
90 "Desched 12", "Desched 13", "Desched 14", "Desched 15",
91 "Nosched 0", "Nosched 1", "Nosched 2", "Nosched 3",
92 "Nosched 4", "Nosched 5", "Nosched 6", "Nosched 7",
93 "Nosched 8", "Nosched 9", "Nosched 10", "Nosched 11",
94 "Nosched 12", "Nosched 13", "Nosched 14", "Nosched 15"
99 * Return the number of POW entries supported by this chip
101 * @return Number of POW entries
103 int cvmx_pow_get_num_entries(void)
105 if (OCTEON_IS_MODEL(OCTEON_CN30XX))
107 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
109 else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
117 * Store the current POW internal state into the supplied
118 * buffer. It is recommended that you pass a buffer of at least
119 * 128KB. The format of the capture may change based on SDK
120 * version and Octeon chip.
122 * @param buffer Buffer to store capture into
124 * The size of the supplied buffer
126 * @return Zero on sucess, negative on failure
128 int cvmx_pow_capture(void *buffer, int buffer_size)
130 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
132 int num_pow_entries = cvmx_pow_get_num_entries();
137 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
139 cvmx_dprintf("cvmx_pow_capture: Buffer too small\n");
143 num_cores = cvmx_octeon_num_cores();
145 /* Read all core related state */
146 for (core=0; core<num_cores; core++)
148 cvmx_pow_load_addr_t load_addr;
150 load_addr.sstatus.mem_region = CVMX_IO_SEG;
151 load_addr.sstatus.is_io = 1;
152 load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1;
153 load_addr.sstatus.coreid = core;
154 for (bits=0; bits<8; bits++)
156 load_addr.sstatus.get_rev = (bits & 1) != 0;
157 load_addr.sstatus.get_cur = (bits & 2) != 0;
158 load_addr.sstatus.get_wqp = (bits & 4) != 0;
159 if ((load_addr.sstatus.get_cur == 0) && load_addr.sstatus.get_rev)
160 dump->sstatus[core][bits].u64 = -1;
162 dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64);
166 /* Read all internal POW entries */
167 for (index=0; index<num_pow_entries; index++)
169 cvmx_pow_load_addr_t load_addr;
171 load_addr.smemload.mem_region = CVMX_IO_SEG;
172 load_addr.smemload.is_io = 1;
173 load_addr.smemload.did = CVMX_OCT_DID_TAG_TAG2;
174 load_addr.smemload.index = index;
175 for (bits=0; bits<3; bits++)
177 load_addr.smemload.get_des = (bits & 1) != 0;
178 load_addr.smemload.get_wqp = (bits & 2) != 0;
179 dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
183 /* Read all group and queue pointers */
184 for (index=0; index<16; index++)
186 cvmx_pow_load_addr_t load_addr;
188 load_addr.sindexload.mem_region = CVMX_IO_SEG;
189 load_addr.sindexload.is_io = 1;
190 load_addr.sindexload.did = CVMX_OCT_DID_TAG_TAG3;
191 load_addr.sindexload.qosgrp = index;
192 for (bits=0; bits<4; bits++)
194 load_addr.sindexload.get_rmt = (bits & 1) != 0;
195 load_addr.sindexload.get_des_get_tail = (bits & 2) != 0;
196 /* The first pass only has 8 valid index values */
197 if ((load_addr.sindexload.get_rmt == 0) &&
198 (load_addr.sindexload.get_des_get_tail == 0) &&
200 dump->sindexload[index][bits].u64 = -1;
202 dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
210 * Function to display a POW internal queue to the user
212 * @param name User visible name for the queue
213 * @param name_param Parameter for printf in creating the name
214 * @param valid Set if the queue contains any elements
215 * @param has_one Set if the queue contains exactly one element
216 * @param head The head pointer
217 * @param tail The tail pointer
219 static void __cvmx_pow_display_list(const char *name, int name_param, int valid, int has_one, uint64_t head, uint64_t tail)
221 printf(name, name_param);
226 printf("One element index=%llu(0x%llx)\n", CAST64(head), CAST64(head));
228 printf("Multiple elements head=%llu(0x%llx) tail=%llu(0x%llx)\n", CAST64(head), CAST64(head), CAST64(tail), CAST64(tail));
236 * Mark which list a POW entry is on. Print a warning message if the
237 * entry is already on a list. This happens if the POW changed while
238 * the capture was running.
240 * @param entry_num Entry number to mark
241 * @param entry_type List type
242 * @param entry_list Array to store marks
244 * @return Zero on success, negative if already on a list
246 static int __cvmx_pow_entry_mark_list(int entry_num, __cvmx_pow_list_types_t entry_type, uint8_t entry_list[])
248 if (entry_list[entry_num] == 0)
250 entry_list[entry_num] = entry_type;
255 printf("\nWARNING: Entry %d already on list %s, but we tried to add it to %s\n",
256 entry_num, __cvmx_pow_list_names[entry_list[entry_num]], __cvmx_pow_list_names[entry_type]);
263 * Display a list and mark all elements on the list as belonging to
266 * @param entry_type Type of the list to display and mark
267 * @param dump POW capture data
268 * @param entry_list Array to store marks in
269 * @param valid Set if the queue contains any elements
270 * @param has_one Set if the queue contains exactly one element
271 * @param head The head pointer
272 * @param tail The tail pointer
274 static void __cvmx_pow_display_list_and_walk(__cvmx_pow_list_types_t entry_type,
275 __cvmx_pow_dump_t *dump, uint8_t entry_list[],
276 int valid, int has_one, uint64_t head, uint64_t tail)
278 __cvmx_pow_display_list(__cvmx_pow_list_names[entry_type], 0, valid, has_one, head, tail);
282 __cvmx_pow_entry_mark_list(head, entry_type, entry_list);
287 if (__cvmx_pow_entry_mark_list(head, entry_type, entry_list))
289 head = dump->smemload[head][0].s_smemload0.next_index;
291 __cvmx_pow_entry_mark_list(tail, entry_type, entry_list);
298 * Dump a POW capture to the console in a human readable format.
300 * @param buffer POW capture from cvmx_pow_capture()
304 void cvmx_pow_display(void *buffer, int buffer_size)
306 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
307 int num_pow_entries = cvmx_pow_get_num_entries();
311 uint8_t entry_list[2048];
313 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
315 cvmx_dprintf("cvmx_pow_dump: Buffer too small\n");
319 memset(entry_list, 0, sizeof(entry_list));
320 num_cores = cvmx_octeon_num_cores();
322 printf("POW Display Start\n");
324 /* Print the free list info */
325 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_FREE, dump, entry_list,
326 dump->sindexload[0][0].sindexload0.free_val,
327 dump->sindexload[0][0].sindexload0.free_one,
328 dump->sindexload[0][0].sindexload0.free_head,
329 dump->sindexload[0][0].sindexload0.free_tail);
331 /* Print the core state */
332 for (core=0; core<num_cores; core++)
334 const int bit_rev = 1;
335 const int bit_cur = 2;
336 const int bit_wqp = 4;
337 printf("Core %d State: tag=%s,0x%08x", core,
338 OCT_TAG_TYPE_STRING(dump->sstatus[core][bit_cur].s_sstatus2.tag_type),
339 dump->sstatus[core][bit_cur].s_sstatus2.tag);
340 if (dump->sstatus[core][bit_cur].s_sstatus2.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL)
342 __cvmx_pow_entry_mark_list(dump->sstatus[core][bit_cur].s_sstatus2.index, CVMX_POW_LIST_CORE + core, entry_list);
343 printf(" grp=%d", dump->sstatus[core][bit_cur].s_sstatus2.grp);
344 printf(" wqp=0x%016llx", CAST64(dump->sstatus[core][bit_cur|bit_wqp].s_sstatus4.wqp));
345 printf(" index=%d", dump->sstatus[core][bit_cur].s_sstatus2.index);
346 if (dump->sstatus[core][bit_cur].s_sstatus2.head)
349 printf(" prev=%d", dump->sstatus[core][bit_cur|bit_rev].s_sstatus3.revlink_index);
350 if (dump->sstatus[core][bit_cur].s_sstatus2.tail)
353 printf(" next=%d", dump->sstatus[core][bit_cur].s_sstatus2.link_index);
356 if (dump->sstatus[core][0].s_sstatus0.pend_switch)
358 printf(" pend_switch=%d", dump->sstatus[core][0].s_sstatus0.pend_switch);
359 printf(" pend_switch_full=%d", dump->sstatus[core][0].s_sstatus0.pend_switch_full);
360 printf(" pend_switch_null=%d", dump->sstatus[core][0].s_sstatus0.pend_switch_null);
363 if (dump->sstatus[core][0].s_sstatus0.pend_desched)
365 printf(" pend_desched=%d", dump->sstatus[core][0].s_sstatus0.pend_desched);
366 printf(" pend_desched_switch=%d", dump->sstatus[core][0].s_sstatus0.pend_desched_switch);
367 printf(" pend_nosched=%d", dump->sstatus[core][0].s_sstatus0.pend_nosched);
368 if (dump->sstatus[core][0].s_sstatus0.pend_desched_switch)
369 printf(" pend_grp=%d", dump->sstatus[core][0].s_sstatus0.pend_grp);
372 if (dump->sstatus[core][0].s_sstatus0.pend_new_work)
374 if (dump->sstatus[core][0].s_sstatus0.pend_new_work_wait)
375 printf(" (Waiting for work)");
377 printf(" (Getting work)");
379 if (dump->sstatus[core][0].s_sstatus0.pend_null_rd)
380 printf(" pend_null_rd=%d", dump->sstatus[core][0].s_sstatus0.pend_null_rd);
381 if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
383 printf(" pend_nosched_clr=%d", dump->sstatus[core][0].s_sstatus0.pend_nosched_clr);
384 printf(" pend_index=%d", dump->sstatus[core][0].s_sstatus0.pend_index);
386 if (dump->sstatus[core][0].s_sstatus0.pend_switch ||
387 (dump->sstatus[core][0].s_sstatus0.pend_desched &&
388 dump->sstatus[core][0].s_sstatus0.pend_desched_switch))
390 printf(" pending tag=%s,0x%08x",
391 OCT_TAG_TYPE_STRING(dump->sstatus[core][0].s_sstatus0.pend_type),
392 dump->sstatus[core][0].s_sstatus0.pend_tag);
394 if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
395 printf(" pend_wqp=0x%016llx\n", CAST64(dump->sstatus[core][bit_wqp].s_sstatus1.pend_wqp));
399 /* Print out the state of the 16 deschedule lists. Each group has two
400 lists. One for entries marked noshed, the other for normal
402 for (index=0; index<16; index++)
404 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED + index, dump, entry_list,
405 dump->sindexload[index][2].sindexload1.nosched_val,
406 dump->sindexload[index][2].sindexload1.nosched_one,
407 dump->sindexload[index][2].sindexload1.nosched_head,
408 dump->sindexload[index][2].sindexload1.nosched_tail);
409 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list,
410 dump->sindexload[index][2].sindexload1.des_val,
411 dump->sindexload[index][2].sindexload1.des_one,
412 dump->sindexload[index][2].sindexload1.des_head,
413 dump->sindexload[index][2].sindexload1.des_tail);
416 /* Print out the state of the 8 internal input queues */
417 for (index=0; index<8; index++)
419 __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list,
420 dump->sindexload[index][0].sindexload0.loc_val,
421 dump->sindexload[index][0].sindexload0.loc_one,
422 dump->sindexload[index][0].sindexload0.loc_head,
423 dump->sindexload[index][0].sindexload0.loc_tail);
426 /* Print out the state of the 16 memory queues */
427 for (index=0; index<8; index++)
430 if (dump->sindexload[index][1].sindexload2.rmt_is_head)
431 name = "Queue %da Memory (is head)";
433 name = "Queue %da Memory";
434 __cvmx_pow_display_list(name, index,
435 dump->sindexload[index][1].sindexload2.rmt_val,
436 dump->sindexload[index][1].sindexload2.rmt_one,
437 dump->sindexload[index][1].sindexload2.rmt_head,
438 dump->sindexload[index][3].sindexload3.rmt_tail);
439 if (dump->sindexload[index+8][1].sindexload2.rmt_is_head)
440 name = "Queue %db Memory (is head)";
442 name = "Queue %db Memory";
443 __cvmx_pow_display_list(name, index,
444 dump->sindexload[index+8][1].sindexload2.rmt_val,
445 dump->sindexload[index+8][1].sindexload2.rmt_one,
446 dump->sindexload[index+8][1].sindexload2.rmt_head,
447 dump->sindexload[index+8][3].sindexload3.rmt_tail);
450 /* Print out each of the internal POW entries. Each entry has a tag, group,
451 wqe, and possibly a next pointer. The next pointer is only valid if this
452 entry isn't make as a tail */
453 for (index=0; index<num_pow_entries; index++)
455 printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index,
456 __cvmx_pow_list_names[entry_list[index]],
457 OCT_TAG_TYPE_STRING(dump->smemload[index][0].s_smemload0.tag_type),
458 dump->smemload[index][0].s_smemload0.tag,
459 dump->smemload[index][0].s_smemload0.grp,
460 CAST64(dump->smemload[index][2].s_smemload1.wqp));
461 if (dump->smemload[index][0].s_smemload0.tail)
464 printf(" next=%d", dump->smemload[index][0].s_smemload0.next_index);
465 if (entry_list[index] >= CVMX_POW_LIST_DESCHED)
467 printf(" prev=%d", dump->smemload[index][1].s_smemload2.fwd_index);
468 printf(" nosched=%d", dump->smemload[index][1].s_smemload2.nosched);
469 if (dump->smemload[index][1].s_smemload2.pend_switch)
471 printf(" pending tag=%s,0x%08x",
472 OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload2.pend_type),
473 dump->smemload[index][1].s_smemload2.pend_tag);
479 printf("POW Display End\n");