cvmx-pow.c revision 267654
117680Spst/***********************license start*************** 217680Spst * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights 317680Spst * reserved. 417680Spst * 517680Spst * 617680Spst * Redistribution and use in source and binary forms, with or without 717680Spst * modification, are permitted provided that the following conditions are 817680Spst * met: 917680Spst * 1017680Spst * * Redistributions of source code must retain the above copyright 1117680Spst * notice, this list of conditions and the following disclaimer. 1217680Spst * 1317680Spst * * Redistributions in binary form must reproduce the above 1417680Spst * copyright notice, this list of conditions and the following 1517680Spst * disclaimer in the documentation and/or other materials provided 1617680Spst * with the distribution. 1717680Spst 1817680Spst * * Neither the name of Cavium Networks nor the names of 1917680Spst * its contributors may be used to endorse or promote products 2017680Spst * derived from this software without specific prior written 2117680Spst * permission. 2217680Spst 2317680Spst * This Software, including technical data, may be subject to U.S. export control 2417680Spst * laws, including the U.S. Export Administration Act and its associated 2517680Spst * regulations, and may be subject to export or import regulations in other 2617680Spst * countries. 2717680Spst 2817680Spst * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 2917680Spst * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR 3017680Spst * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 3117680Spst * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 3217680Spst * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 3317680Spst * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 3417680Spst * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 3517680Spst * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 3617680Spst * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 3717680Spst * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 3817680Spst ***********************license end**************************************/ 3917680Spst 4017680Spst 4117680Spst 4217680Spst 4317680Spst 4417680Spst 4517680Spst 4617680Spst/** 4717680Spst * @file 4817680Spst * 4917680Spst * Interface to the hardware Packet Order / Work unit. 5017680Spst * 5117680Spst * <hr>$Revision: 29727 $<hr> 5217680Spst */ 5317680Spst 5417680Spst#include "cvmx.h" 5517680Spst#include "cvmx-pow.h" 5617680Spst 5717680Spst/** 5817680Spst * @INTERNAL 5917680Spst * This structure stores the internal POW state captured by 6017680Spst * cvmx_pow_capture(). It is purposely not exposed to the user 6117680Spst * since the format may change without notice. 6217680Spst */ 6317680Spsttypedef struct 6417680Spst{ 6517680Spst cvmx_pow_tag_load_resp_t sstatus[16][8]; 6617680Spst cvmx_pow_tag_load_resp_t smemload[2048][3]; 6717680Spst cvmx_pow_tag_load_resp_t sindexload[16][4]; 6817680Spst} __cvmx_pow_dump_t; 6917680Spst 7017680Spsttypedef enum 7117680Spst{ 7217680Spst CVMX_POW_LIST_UNKNOWN=0, 7317680Spst CVMX_POW_LIST_FREE=1, 7417680Spst CVMX_POW_LIST_INPUT=2, 7517680Spst CVMX_POW_LIST_CORE=CVMX_POW_LIST_INPUT+8, 7617680Spst CVMX_POW_LIST_DESCHED=CVMX_POW_LIST_CORE+16, 7717680Spst CVMX_POW_LIST_NOSCHED=CVMX_POW_LIST_DESCHED+16, 7817680Spst} __cvmx_pow_list_types_t; 7917680Spst 8017680Spststatic const char *__cvmx_pow_list_names[] = { 8117680Spst "Unknown", 8217680Spst "Free List", 8317680Spst "Queue 0", "Queue 1", "Queue 2", "Queue 3", 8417680Spst "Queue 4", "Queue 5", "Queue 6", "Queue 7", 8517680Spst "Core 0", "Core 1", "Core 2", "Core 3", 8617680Spst "Core 4", "Core 5", "Core 6", "Core 7", 8717680Spst "Core 8", "Core 9", "Core 10", "Core 11", 8817680Spst "Core 12", "Core 13", "Core 14", "Core 15", 8917680Spst "Desched 0", "Desched 1", "Desched 2", "Desched 3", 9017680Spst "Desched 4", "Desched 5", "Desched 6", "Desched 7", 9117680Spst "Desched 8", "Desched 9", "Desched 10", "Desched 11", 9217680Spst "Desched 12", "Desched 13", "Desched 14", "Desched 15", 9317680Spst "Nosched 0", "Nosched 1", "Nosched 2", "Nosched 3", 9417680Spst "Nosched 4", "Nosched 5", "Nosched 6", "Nosched 7", 9517680Spst "Nosched 8", "Nosched 9", "Nosched 10", "Nosched 11", 9617680Spst "Nosched 12", "Nosched 13", "Nosched 14", "Nosched 15" 9717680Spst}; 9817680Spst 9917680Spst 10017680Spst/** 10117680Spst * Return the number of POW entries supported by this chip 10217680Spst * 10317680Spst * @return Number of POW entries 10417680Spst */ 10517680Spstint cvmx_pow_get_num_entries(void) 10617680Spst{ 10717680Spst if (OCTEON_IS_MODEL(OCTEON_CN30XX)) 10817680Spst return 64; 10917680Spst else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 11017680Spst return 256; 11117680Spst else if (OCTEON_IS_MODEL(OCTEON_CN52XX)) 11217680Spst return 512; 11317680Spst else if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 11417680Spst return 1024; 11517680Spst else 11617680Spst return 2048; 11717680Spst} 11817680Spst 11917680Spst 12017680Spst/** 12117680Spst * Store the current POW internal state into the supplied 12217680Spst * buffer. It is recommended that you pass a buffer of at least 12317680Spst * 128KB. The format of the capture may change based on SDK 12417680Spst * version and Octeon chip. 12517680Spst * 12617680Spst * @param buffer Buffer to store capture into 12717680Spst * @param buffer_size 12817680Spst * The size of the supplied buffer 12917680Spst * 13017680Spst * @return Zero on sucess, negative on failure 13117680Spst */ 13217680Spstint cvmx_pow_capture(void *buffer, int buffer_size) 13317680Spst{ 13417680Spst __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer; 13517680Spst int num_cores; 13617680Spst int num_pow_entries = cvmx_pow_get_num_entries(); 13717680Spst int core; 13817680Spst int index; 13917680Spst int bits; 140 141 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t)) 142 { 143 cvmx_dprintf("cvmx_pow_capture: Buffer too small\n"); 144 return -1; 145 } 146 147 num_cores = cvmx_octeon_num_cores(); 148 149 /* Read all core related state */ 150 for (core=0; core<num_cores; core++) 151 { 152 cvmx_pow_load_addr_t load_addr; 153 load_addr.u64 = 0; 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++) 159 { 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; 165 else 166 dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64); 167 } 168 } 169 170 /* Read all internal POW entries */ 171 for (index=0; index<num_pow_entries; index++) 172 { 173 cvmx_pow_load_addr_t load_addr; 174 load_addr.u64 = 0; 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++) 180 { 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); 184 } 185 } 186 187 /* Read all group and queue pointers */ 188 for (index=0; index<16; index++) 189 { 190 cvmx_pow_load_addr_t load_addr; 191 load_addr.u64 = 0; 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++) 197 { 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) && 203 (index >= 8)) 204 dump->sindexload[index][bits].u64 = -1; 205 else 206 dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64); 207 } 208 } 209 return 0; 210} 211 212 213/** 214 * Function to display a POW internal queue to the user 215 * 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 222 */ 223static void __cvmx_pow_display_list(const char *name, int name_param, int valid, int has_one, uint64_t head, uint64_t tail) 224{ 225 printf(name, name_param); 226 printf(": "); 227 if (valid) 228 { 229 if (has_one) 230 printf("One element index=%llu(0x%llx)\n", CAST64(head), CAST64(head)); 231 else 232 printf("Multiple elements head=%llu(0x%llx) tail=%llu(0x%llx)\n", CAST64(head), CAST64(head), CAST64(tail), CAST64(tail)); 233 } 234 else 235 printf("Empty\n"); 236} 237 238 239/** 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. 243 * 244 * @param entry_num Entry number to mark 245 * @param entry_type List type 246 * @param entry_list Array to store marks 247 * 248 * @return Zero on success, negative if already on a list 249 */ 250static int __cvmx_pow_entry_mark_list(int entry_num, __cvmx_pow_list_types_t entry_type, uint8_t entry_list[]) 251{ 252 if (entry_list[entry_num] == 0) 253 { 254 entry_list[entry_num] = entry_type; 255 return 0; 256 } 257 else 258 { 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]); 261 return -1; 262 } 263} 264 265 266/** 267 * Display a list and mark all elements on the list as belonging to 268 * the list. 269 * 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 277 */ 278static 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) 281{ 282 __cvmx_pow_display_list(__cvmx_pow_list_names[entry_type], 0, valid, has_one, head, tail); 283 if (valid) 284 { 285 if (has_one) 286 __cvmx_pow_entry_mark_list(head, entry_type, entry_list); 287 else 288 { 289 while (head != tail) 290 { 291 if (__cvmx_pow_entry_mark_list(head, entry_type, entry_list)) 292 break; 293 head = dump->smemload[head][0].s_smemload0.next_index; 294 } 295 __cvmx_pow_entry_mark_list(tail, entry_type, entry_list); 296 } 297 } 298} 299 300 301/** 302 * Dump a POW capture to the console in a human readable format. 303 * 304 * @param buffer POW capture from cvmx_pow_capture() 305 * @param buffer_size 306 * Size of the buffer 307 */ 308void cvmx_pow_display(void *buffer, int buffer_size) 309{ 310 __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer; 311 int num_pow_entries = cvmx_pow_get_num_entries(); 312 int num_cores; 313 int core; 314 int index; 315 uint8_t entry_list[2048]; 316 317 if (buffer_size < (int)sizeof(__cvmx_pow_dump_t)) 318 { 319 cvmx_dprintf("cvmx_pow_dump: Buffer too small\n"); 320 return; 321 } 322 323 memset(entry_list, 0, sizeof(entry_list)); 324 num_cores = cvmx_octeon_num_cores(); 325 326 printf("POW Display Start\n"); 327 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); 334 335 /* Print the core state */ 336 for (core=0; core<num_cores; core++) 337 { 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) 345 { 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) 351 printf(" head"); 352 else 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) 355 printf(" tail"); 356 else 357 printf(" next=%d", dump->sstatus[core][bit_cur].s_sstatus2.link_index); 358 } 359 360 if (dump->sstatus[core][0].s_sstatus0.pend_switch) 361 { 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); 365 } 366 367 if (dump->sstatus[core][0].s_sstatus0.pend_desched) 368 { 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); 374 } 375 376 if (dump->sstatus[core][0].s_sstatus0.pend_new_work) 377 { 378 if (dump->sstatus[core][0].s_sstatus0.pend_new_work_wait) 379 printf(" (Waiting for work)"); 380 else 381 printf(" (Getting work)"); 382 } 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) 386 { 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); 389 } 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)) 393 { 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); 397 } 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)); 400 printf("\n"); 401 } 402 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++) 410 { 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); 416 } 417 418 /* Print out the state of the 8 internal input queues */ 419 for (index=0; index<8; index++) 420 { 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); 426 } 427 428 /* Print out the state of the 16 memory queues */ 429 for (index=0; index<8; index++) 430 { 431 const char *name; 432 if (dump->sindexload[index][1].sindexload2.rmt_is_head) 433 name = "Queue %da Memory (is head)"; 434 else 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)"; 443 else 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); 450 } 451 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++) 456 { 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) 464 printf(" tail"); 465 else 466 printf(" next=%d", dump->smemload[index][0].s_smemload0.next_index); 467 if (entry_list[index] >= CVMX_POW_LIST_DESCHED) 468 { 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) 472 { 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); 476 } 477 } 478 printf("\n"); 479 } 480 481 printf("POW Display End\n"); 482} 483 484