pcktwatch.c (54600B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Packet Watcher 8 */ 9 10 #include <sal/types.h> 11 #include <shared/bsl.h> 12 #ifndef __KERNEL__ 13 #include <sys/types.h> 14 #include <netinet/in.h> 15 #endif 16 17 #include <soc/debug.h> 18 #include <soc/cm.h> 19 #include <soc/dma.h> 20 21 #include <sal/appl/io.h> 22 #include <sal/appl/sal.h> 23 #include <sal/core/thread.h> 24 #include <sal/core/sync.h> 25 #include <sal/core/spl.h> 26 #include <sal/core/libc.h> 27 28 #include <appl/diag/shell.h> 29 #include <appl/diag/parse.h> 30 #include <appl/diag/system.h> 31 #include <appl/diag/decode.h> 32 33 #include <bcm/rx.h> 34 #include <bcm/error.h> 35 36 #ifdef GHS 37 #define d_packet_format(pfx, decode, pkt, count, p) 38 #endif 39 40 /* 41 * Maximum packet size we will read in. 42 */ 43 #define PW_PACKET_SIZE 10240 44 45 #define PW_COUNT_DEFAULT 100 46 47 static char pw_name[SOC_MAX_NUM_DEVICES][16]; 48 49 /* 50 * Define 2 of the public fields in the dv structure for our use. 51 */ 52 #define dv_pw_pup dv_public1.ptr 53 #define dv_pw_chan dv_public2.u32 54 55 56 /* 57 * Typedef: pup_t 58 * Purpose: Maps out each packet array entry - pkt_cnt is sort of 59 * useless, but it makes life easier so we use it to track 60 * the pack # received. 61 * 62 * Notes: Each entry is either FREE or on a circular/double linked 63 * list used for the LOG. When the LOG is full, there are 3 extra 64 * pups used to suppor the up to 3 outstanding DMA operations. 65 */ 66 typedef struct pup_s { 67 struct pup_s *pup_next, *pup_prev; /* Next and previous pointers */ 68 dv_t *pup_esw_dv; /* DMA descriptor, ESW SOC mode only */ 69 int pup_seqno; /* Packet # */ 70 void *pup_pkt; /* Actual packet pointer, for soc */ 71 bcm_pkt_t rx_pkt; /* Packet data for RX */ 72 } pup_t; 73 74 #define REPORT_COUNT 0x01 /* Report packet count */ 75 #define REPORT_RAW 0x02 /* Report Raw packet data */ 76 #define REPORT_DECODE 0x04 /* Report Decode */ 77 #define REPORT_DMA 0x08 /* Report RX Dma */ 78 #define REPORT_CHANNEL 0x10 /* Report RX channel */ 79 80 typedef struct pwu_s { 81 volatile uint32 pu_flags; /* Flags this unit PU_F_XXX */ 82 # define PU_F_RUN 0x01 83 # define PU_F_STOP 0x02 84 # define PU_F_SYNC 0x04 /* Wake up request thread */ 85 sal_mutex_t pu_lock; /* Syncronize updates */ 86 sal_spinlock_t pu_spinlock; /* Protect updates */ 87 int32 pu_channel; /* RX channel list 1 << ch # */ 88 # define PU_CHANNEL(_c) (1 << (_c)) 89 uint32 pu_report; /* Reporting level */ 90 uint32 pu_dump_options; /* Reporting level when dumping logs */ 91 COMPILER_DOUBLE pu_count_last; /* Last count displayed */ 92 COMPILER_DOUBLE pu_count_time; /* Last time count was displayed */ 93 sal_thread_t pu_pid; /* pid this unit */ 94 sal_sem_t pu_sema; /* Sleep semaphore this unit */ 95 sal_sem_t pu_sync; /* Sync command semaphore */ 96 97 /* 98 * pu_pending - a single linked list, where the head's prev pointer 99 * points to the tail. 100 * pu_ch_active - pointers to DMA active on the given channel. 101 */ 102 103 VOL pup_t *pu_pending; /* Pending interrupt servicing */ 104 VOL pup_t *pu_ch_active[MAX_N_DMA_CHAN+1]; /* Active DMA operations */ 105 int pu_ch_count[MAX_N_DMA_CHAN+1]; /* # received on channel */ 106 pup_t *pu_log; /* Last N packets - head is LRU */ 107 pup_t *pu_log_free; /* Last N packets - head is LRU */ 108 pup_t *pup_list; /* List of all PUPs for free */ 109 int pu_log_cnt; /* # packets on LOG list */ 110 int pu_log_max; /* Max # packets logged */ 111 # define PU_LOG_CNT 64 /* Default # log entries */ 112 uint32 pu_packet_received; /* total # received packets */ 113 int pu_interval; /* usec between pkt rcv & next dma */ 114 115 int mode; /* What mode are we in */ 116 #define PW_MODE_RX 0 117 #define PW_MODE_SOC 1 118 #define PW_MODE_PMUX 2 119 #define PW_INIT_STRINGS \ 120 "RX", \ 121 "SOC", \ 122 "PMUX" 123 int chan; 124 int rx_pri; 125 uint32 rx_flags; 126 int pkt_size; 127 bcm_rx_cfg_t rx_cfg; 128 int rate; /* Current global rate, pps */ 129 int last_pkt_count; /* How many pkts processed last wake */ 130 131 int init_done; 132 uint32 hdr_dump; /* Header dump for cmicx */ 133 } pwu_t; 134 135 char *pw_modes[3] = {PW_INIT_STRINGS}; 136 137 STATIC bcm_rx_t pw_rx_callback(int unit, bcm_pkt_t *pkt, 138 void *cookie); 139 140 STATIC void pw_cleanup_dma(int unit); 141 STATIC pup_t * pw_pup_alloc(int unit); 142 STATIC void pw_pup_free(int unit, pup_t *pup); 143 STATIC void pw_dump_packet(int unit, pup_t *pup, uint32 report); 144 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 145 STATIC void pw_esw_done_intr(int unit, dv_t *dv); 146 STATIC int pw_channel_config(int unit); 147 #endif /* BCM_ESW_SUPPORT */ 148 STATIC cmd_result_t pw_start_channel(int unit, dma_chan_t chan); 149 STATIC void pw_thread(void *up); 150 STATIC void pw_process_pending(int unit); 151 STATIC cmd_result_t pw_dump_log(int unit, int n); 152 153 char pw_usage[] = 154 "Parameters: [report +/-<values>] [stop|start] [count]\n" 155 #ifndef COMPILER_STRING_CONST_LIMIT 156 "\tlog # - specifies # packets to remember\n" 157 "\tdump [# | options] - # > 0 dumps # packets from start of log\n" 158 "\t # < 0 dumps last # packets\n" 159 "\t nothing - dumps all logs\n" 160 "\t options - count - print packet # only\n" 161 "\t decode - attempt to decode packet\n" 162 "\t raw - dump raw byte stream (host order)\n" 163 "\t dma - dump DMA descriptors (SOC mode only)\n" 164 "\t channel - dump DMA channel\n" 165 "\t Prepend + to set, - to clear, nothing to toggle\n" 166 "\tinterval # - # us to wait after a packet arrives before next\n" 167 "\t DMA starts (SOC mode only)\n" 168 "\treport- count - print packet # only\n" 169 "\t decode - attempt to decode packet\n" 170 "\t raw - dump raw byte stream (host order)\n" 171 "\t dma - dump DMA descriptors (SOC mode only)\n" 172 "\t channel - dump DMA channel\n" 173 "\t Prepend + to set, - to clear, nothing to toggle\n" 174 "\tquiet - disable all reporting\n" 175 "\tchannel x [y z] - configure PW to use the specified RX channels\n" 176 "\trate n - Set the globally accepted pps rate\n" 177 "\tstart - start the PW-daemon\n" 178 "\tstop - stop the PW-daemon and deallocate log space\n" 179 "\tcount - print # packets received.\n" 180 "\treset - reinitialize configuration from bcm_rx_* API state\n" 181 "\tmode [soc | rx] - set packetwatcher mode\n" 182 "\t With no parameters, reports current mode\n" 183 "\t soc - Use the soc layer calls directly\n" 184 "\t rx - Use the RX API\n" 185 #endif 186 ; 187 188 pwu_t pw_units[SOC_MAX_NUM_DEVICES]; 189 190 STATIC void 191 pw_init(int unit) 192 { 193 pwu_t *pu = &pw_units[unit]; /* Control this unit */ 194 195 if (pu->init_done) { 196 return; 197 } 198 199 sal_snprintf(pw_name[unit], sizeof(pw_name[unit]), "bcmPW.%d", unit); 200 201 /* 202 * sync and lock semaphores are only created once, the others 203 * are created and destroyed every time the packet watcher is 204 * started and stopped. 205 * 206 * We need to check if they already exist to support the 207 * pw reset option. 208 */ 209 if (!pu->pu_sync) { 210 pu->pu_sync = sal_sem_create("pw_sync", sal_sem_BINARY, 0); 211 } 212 if (!pu->pu_lock) { 213 pu->pu_lock = sal_mutex_create("pw_lock"); 214 } 215 if (!pu->pu_spinlock) { 216 pu->pu_spinlock = sal_spinlock_create("pw_spinlock"); 217 } 218 219 if (!pu->pu_sync || !pu->pu_lock || !pu->pu_spinlock) { 220 cli_out("%s ERROR: Could not allocate sync/lock\n", pw_name[unit]); 221 } 222 pu->chan = 0; 223 pu->rx_pri = 100; 224 pu->rx_flags = BCM_RCO_F_ALL_COS; 225 pu->pkt_size = 10 * 1024; 226 227 bcm_rx_cfg_get(unit, &pu->rx_cfg); 228 pu->rate = pu->rx_cfg.global_pps; 229 230 pu->init_done = TRUE; 231 } 232 233 STATIC int 234 _pw_set_rate(int unit) 235 { 236 pwu_t *pu = &pw_units[unit]; /* Control this unit */ 237 int rv = BCM_E_NONE; 238 239 /* Always calculate SOC interval in case modes are switched. */ 240 if (pu->rate <= 0) { 241 pu->pu_interval = 1000000; 242 pu->rate = 0; 243 } else { 244 pu->pu_interval = 1000000 / pu->rate; 245 } 246 247 switch (pu->mode) { 248 case PW_MODE_RX: 249 if ((rv = bcm_rx_rate_set(unit, pu->rate)) < 0) { 250 cli_out("PW RX rate set error: %s.\n", bcm_errmsg(rv)); 251 } 252 /* Then set the burst size to equal the rate */ 253 if ((rv = bcm_rx_burst_set(unit, pu->rate)) < 0) { 254 cli_out("PW RX burst set error: %s.\n", bcm_errmsg(rv)); 255 } 256 break; 257 case PW_MODE_SOC: 258 break; 259 default: 260 break; 261 } 262 263 return rv; 264 } 265 266 #define PW_LOCK(_u) sal_mutex_take(pw_units[_u].pu_lock, \ 267 sal_mutex_FOREVER) 268 #define PW_UNLOCK(_u) sal_mutex_give(pw_units[_u].pu_lock) 269 #define PW_SPIN_LOCK(_u) sal_spinlock_lock(pw_units[_u].pu_spinlock) 270 #define PW_SPIN_UNLOCK(_u) sal_spinlock_unlock(pw_units[_u].pu_spinlock) 271 272 int 273 pw_start(int unit, int sync) 274 /* 275 * Function: pw_start 276 * Purpose: Start the packet watcher 277 * Parameters: unit - unit to start. 278 * sync - if true, wait for watcher to start. 279 * Returns: 0 - success, -1 failed. 280 */ 281 { 282 pwu_t *pu = &pw_units[unit]; /* Control this unit */ 283 284 pw_init(unit); 285 if (pu->pu_sync == NULL || pu->pu_lock == NULL || pu->pu_spinlock == NULL) { 286 return -1; 287 } 288 289 sal_memset(pu->pu_ch_active, 0, sizeof(pu->pu_ch_active)); 290 sal_memset(pu->pu_ch_count, 0, sizeof(pu->pu_ch_count)); 291 292 pu->pu_pending = NULL; 293 pu->pu_log = NULL; 294 pu->pu_log_free = NULL; 295 pu->pu_log_cnt = 0; 296 #ifdef BCM_PETRA_SUPPORT 297 if (SOC_IS_ARAD(unit) ) { 298 if (bcm_rx_active(unit)) { 299 bcm_rx_stop(unit, NULL); 300 } 301 } 302 #endif /* BCM_PETRA_SUPPORT */ 303 304 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 305 if (SOC_IS_ESW(unit) || SOC_IS_ARAD(unit)) { 306 if (pw_channel_config(unit) < 0) { 307 return -1; 308 } 309 } 310 #endif 311 312 pu->pu_sema = sal_sem_create("pw_thread", sal_sem_BINARY, 0); 313 if (pu->pu_sema == 0) { 314 return -1; 315 } 316 317 pu->pu_flags |= PU_F_RUN; 318 if (sync) { 319 pu->pu_flags |= PU_F_SYNC; 320 } 321 322 pu->pu_pid = 323 sal_thread_create(pw_name[unit], SAL_THREAD_STKSZ, 324 soc_property_get(unit, spn_DIAG_PW_THREAD_PRI, 100), 325 pw_thread, INT_TO_PTR(unit)); 326 327 if (pu->pu_pid == SAL_THREAD_ERROR) { 328 cli_out("%s: Unable to start task\n", pw_name[unit]); 329 sal_sem_destroy(pu->pu_sema); 330 pu->pu_sema = 0; 331 pu->pu_flags &= PU_F_RUN|PU_F_SYNC; 332 return -1; 333 } 334 335 pu->pu_count_last = 0; 336 pu->pu_count_time = SAL_TIME_DOUBLE(); 337 338 pu->pu_packet_received = 0; 339 340 if (sync) { 341 if (sal_sem_take(pu->pu_sync, sal_sem_FOREVER)) { 342 cli_out("%s: Failed to wait for start\n", pw_name[unit]); 343 return -1; 344 } 345 } 346 347 return 0; 348 } 349 350 cmd_result_t 351 pw_stop(int unit, int sync) 352 /* 353 * Function: pw_stop 354 * Purpose: Stop the packet watcher 355 * Parameters: unit - unit to stop. 356 * sync - if true, wait for watcher to finish. 357 * Returns: 0 - success, -1 failed. 358 */ 359 { 360 pwu_t *pu = &pw_units[unit]; /* Control this unit */ 361 soc_timeout_t to; 362 sal_usecs_t pw_timeout; 363 364 pw_timeout = soc_property_get(unit, spn_CDMA_TIMEOUT_USEC, 10000000); 365 366 pu->pu_flags |= PU_F_STOP; 367 if (sync) { 368 pu->pu_flags |= PU_F_SYNC; 369 } 370 sal_sem_give(pu->pu_sema); 371 soc_timeout_init(&to, pw_timeout, 0); 372 373 /* Check for pw_thread exit */ 374 while (pu->pu_pid != SAL_THREAD_ERROR) { 375 /* Handle the case of pw_thread not exiting */ 376 if (soc_timeout_check(&to)) { 377 cli_out("pw_stop: pw_thread did not exit\n"); 378 pu->pu_pid = SAL_THREAD_ERROR; 379 break; 380 } 381 382 sal_usleep(80000); 383 } 384 385 if (pu->pu_pid == SAL_THREAD_ERROR) { 386 /* Abnormal thread exit: Free semaphore resource */ 387 /* coverity[check_after_deref] */ 388 if (pu->pu_sema) { 389 /* Must check, because may have been destroyed by pw_exit */ 390 sal_sem_destroy(pu->pu_sema); 391 pu->pu_sema = 0; 392 } 393 } 394 395 if (sync) { 396 (void)sal_sem_take(pu->pu_sync, sal_sem_FOREVER); 397 } else { 398 cli_out("%s: Termination requested...\n", pw_name[unit]); 399 } 400 return CMD_OK; 401 } 402 403 int 404 pw_running(int unit) 405 /* 406 * Function: pw_running 407 * Purpose: Determine if packet watcher is running for the specified 408 * unit. 409 * Parameters: unit - unit # 410 * Returns: 0 - not running, !0 - running 411 */ 412 { 413 return pw_units[unit].pu_flags & PU_F_RUN; 414 } 415 416 STATIC void 417 pw_exit(int unit, int stat) 418 /* 419 * Function: pw_exit 420 * Purpose: Exit a packetwatcher thread. 421 * Parameters: unit - unit #. 422 * stat - exit status (passed to exit). 423 * Returns: Does not return. 424 * 425 * Notes: ASSUMES LOCK held on entry, released in this routine 426 */ 427 { 428 pwu_t *pu = &pw_units[unit]; 429 int rv; 430 char thread_name[SAL_THREAD_NAME_MAX_LEN]; 431 sal_thread_t thread; 432 #if defined(BCM_PETRA_SUPPORT) 433 bcm_rx_cfg_t cfg; 434 #endif 435 436 thread = sal_thread_self(); 437 thread_name[0] = 0; 438 sal_thread_name(thread, thread_name, sizeof (thread_name)); 439 440 switch (pu->mode) { 441 case PW_MODE_RX: 442 /* pw_exit() is called holding the lock. Give it up 443 * momentarily while we stop the RX task. 444 */ 445 PW_UNLOCK(unit); 446 if ((rv = bcm_rx_stop(unit, NULL)) < 0) { 447 cli_out("PW stop error: Cannot stop RX: %s.\n", 448 bcm_errmsg(rv)); 449 } 450 #if defined(BCM_PETRA_SUPPORT) 451 /* init rx cfg as no cos */ 452 bcm_rx_cfg_t_init(&cfg); 453 cfg.pkt_size = 16*1024; 454 cfg.pkts_per_chain = 15; 455 cfg.global_pps = 0; 456 cfg.max_burst = 15; 457 cfg.rx_alloc = NULL; 458 cfg.rx_free = NULL; 459 cfg.flags = 0; 460 cfg.chan_cfg[1].chains = 4; 461 cfg.chan_cfg[1].flags = 0; 462 cfg.chan_cfg[1].cos_bmp = 0xFffffffF; 463 464 if ((rv = bcm_rx_start(unit, &cfg)) < 0) { 465 cli_out("PW re-start error: Cannot re-start RX: %s.\n", 466 bcm_errmsg(rv)); 467 } 468 #endif 469 if ((rv = bcm_rx_queue_unregister(unit, BCM_RX_COS_ALL, 470 pw_rx_callback, pu->rx_pri)) 471 < 0) { 472 cli_out("PW stop error: Cannot unregister handler: %s.\n", 473 bcm_errmsg(rv)); 474 } 475 PW_LOCK(unit); 476 477 break; 478 #if defined(BCM_PETRA_SUPPORT) 479 case PW_MODE_SOC: 480 PW_UNLOCK(unit); 481 if (bcm_rx_active(unit)) { 482 if ((rv = bcm_rx_stop(unit, NULL)) < 0) { 483 cli_out("PW stop error: Cannot stop RX: %s.\n", 484 bcm_errmsg(rv)); 485 } 486 } 487 /* init rx cfg as no cos */ 488 bcm_rx_cfg_t_init(&cfg); 489 cfg.pkt_size = 16*1024; 490 cfg.pkts_per_chain = 15; 491 cfg.global_pps = 0; 492 cfg.max_burst = 15; 493 cfg.rx_alloc = NULL; 494 cfg.rx_free = NULL; 495 cfg.flags = 0; 496 cfg.chan_cfg[1].chains = 4; 497 cfg.chan_cfg[1].flags = 0; 498 cfg.chan_cfg[1].cos_bmp = 0xFffffffF; 499 500 if ((rv = bcm_rx_start(unit, &cfg)) < 0) { 501 cli_out("PW re-start error: Cannot re-start RX: %s.\n", 502 bcm_errmsg(rv)); 503 } 504 PW_LOCK(unit); 505 break; 506 #endif 507 default: 508 break; 509 } 510 511 if (pu->pu_sema) { 512 sal_sem_destroy(pu->pu_sema); 513 pu->pu_sema = 0; 514 } 515 516 pu->pu_pid = SAL_THREAD_ERROR; 517 518 /* Put logs on the free list - not fast but .... oh well */ 519 520 if (pu->pu_log != NULL) { 521 pu->pu_log->pup_prev->pup_next = NULL; /* NUll list */ 522 while (pu->pu_log != NULL) { 523 pup_t *pup = pu->pu_log->pup_next; 524 pw_pup_free(unit, pu->pu_log); 525 pu->pu_log = pup; 526 } 527 } 528 529 /* Now free the free list */ 530 531 while (pu->pu_log_free) { 532 pup_t *pup = pu->pu_log_free; 533 pu->pu_log_free = pup->pup_next; 534 if (pu->mode == PW_MODE_SOC) { 535 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 536 soc_dma_dv_free(unit, pup->pup_esw_dv); 537 #endif 538 soc_cm_sfree(unit, pup->pup_pkt); 539 } 540 } 541 if (pu->pup_list) { 542 sal_free(pu->pup_list); 543 } 544 545 if (pu->pu_flags & PU_F_SYNC) { 546 sal_sem_give(pu->pu_sync); 547 } else { 548 LOG_VERBOSE(BSL_LS_SOC_COMMON, 549 (BSL_META_U(unit, 550 "PW-Daemon[%d]: Exiting\n"), unit)); 551 } 552 553 pu->pu_flags = 0; 554 555 PW_UNLOCK(unit); 556 if (stat < 0) { 557 LOG_ERROR(BSL_LS_SOC_PKT, 558 (BSL_META_U(unit, 559 "AbnormalThreadExit:%s\n"), thread_name)); 560 } 561 562 sal_thread_exit(stat); 563 } 564 565 /* Start the packet watcher operation depending on the mode */ 566 STATIC int 567 _pw_start_op(int unit) 568 { 569 pwu_t *pu = &pw_units[unit]; 570 int pkt_size; 571 int rv = BCM_E_NONE; 572 573 switch (pu->mode) { 574 case PW_MODE_RX: 575 pu->rx_cfg.global_pps = pu->rate; 576 577 /* 578 * Allow the packet watcher to run in truncating mode 579 * by allocating smaller Rx buffers and accepting 580 * oversized packets on all Rx DMA channels. 581 */ 582 pkt_size = soc_property_get(unit, spn_DIAG_PW_BUFFER_SIZE, -1); 583 584 if (pkt_size >= 68) { 585 int chan; 586 dma_chan_t dma_chan; 587 pu->rx_cfg.pkt_size = pkt_size; 588 589 if (soc_feature(unit, soc_feature_cmicx)) { 590 dma_chan = BCM_CMICX_RX_CHANNELS; 591 } else { 592 dma_chan = BCM_RX_CHANNELS; 593 } 594 595 for (chan = 0; chan < dma_chan; chan++) { 596 pu->rx_cfg.chan_cfg[chan].flags |= BCM_RX_F_OVERSIZED_OK; 597 } 598 } 599 600 if ((rv = bcm_rx_start(unit, &pu->rx_cfg)) < 0) { 601 return rv; 602 } 603 604 if ((rv = bcm_rx_queue_register(unit, "RX CMD", BCM_RX_COS_ALL, 605 pw_rx_callback, pu->rx_pri, NULL, pu->rx_flags)) < 0) { 606 return rv; 607 } 608 break; 609 case PW_MODE_SOC: 610 if (pu->pu_channel == 0) { /* Use default RX channel */ 611 pw_start_channel(unit, -1); 612 } else { 613 dma_chan_t chan; 614 dma_chan_t dma_chan; 615 616 if (soc_feature(unit, soc_feature_cmicx)) { 617 dma_chan = CMICX_N_DMA_CHAN; 618 } else { 619 dma_chan = N_DMA_CHAN; 620 } 621 for (chan = 0; chan < dma_chan; chan++) { 622 if (pu->pu_channel & PU_CHANNEL(chan)) { 623 pw_start_channel(unit, chan); 624 } 625 } 626 } 627 break; 628 default: 629 assert("Unknown pkt watcher mode"); 630 break; 631 } 632 633 return rv; 634 } 635 636 STATIC void 637 pw_thread(void *up) 638 /* 639 * Function: pw_thread 640 * Purpose: Waits for packets to arrive destined for the CPU and 641 * saves them in a queue. 642 * Parameters: unit - SOC unit # 643 * Returns: Does not return. 644 */ 645 { 646 int unit = PTR_TO_INT(up); 647 int i; 648 pwu_t *pu = &pw_units[unit]; 649 int rv; 650 int pup_count; 651 pup_t *pup; 652 653 PW_LOCK(unit); 654 655 /* Allocate packet pointer array */ 656 657 if (0 == pu->pu_log_max) { 658 pu->pu_log_max = PW_COUNT_DEFAULT; 659 } 660 661 /* Extra for multiple DMA channels */ 662 if (pu->mode == PW_MODE_SOC) { 663 if (soc_feature(unit, soc_feature_cmicx)) { 664 pup_count = pu->pu_log_max + CMICX_N_DMA_CHAN; 665 } else { 666 pup_count = pu->pu_log_max + N_DMA_CHAN; 667 } 668 } else { 669 pup_count = pu->pu_log_max; 670 } 671 672 /* Bump up pup_count to be twice the log size so pups will 673 * be available even when log queue is full. 674 */ 675 pup_count += pu->pu_log_max; 676 677 pu->pup_list = sal_alloc(sizeof(pup_t) * pup_count, "PW-pup"); 678 if (pu->pup_list == NULL) { 679 pw_exit(unit, -1); 680 } 681 /* No forwaqrding null. If the allocation failed, the call to pw_exit will end the process and we sould never reach here. */ 682 /* coverity[var_deref_model:FALSE] */ 683 sal_memset(pu->pup_list, 0, sizeof(pup_t) * pup_count); 684 685 for (i = 0; i < pup_count; i++) { 686 687 pup = &pu->pup_list[i]; 688 689 if (pu->mode == PW_MODE_SOC) { 690 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 691 pup->pup_esw_dv = soc_dma_dv_alloc(unit, DV_RX, 1); 692 if (pup->pup_esw_dv == NULL) { 693 pw_exit(unit, -1); 694 } 695 #endif 696 pup->pup_pkt = soc_cm_salloc(unit, PW_PACKET_SIZE, "pw_thread"); 697 if (pup->pup_pkt == NULL) { 698 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 699 soc_dma_dv_free(unit, pup->pup_esw_dv); 700 #endif 701 pw_exit(unit, -1); 702 } 703 } 704 pw_pup_free(unit, pup); /* Put on free list */ 705 } 706 707 if (pu->pu_flags & PU_F_SYNC) { 708 pu->pu_flags &= ~PU_F_SYNC; 709 sal_sem_give(pu->pu_sync); 710 } else { 711 cli_out("PW-daemon[%d] -- Started\n", unit); 712 } 713 714 /* Kick Start channels */ 715 if ((rv = _pw_start_op(unit)) < 0) { 716 cli_out("PW rx mode: Cannot start %s: %s.\n", pw_modes[pu->mode], 717 bcm_errmsg(rv)); 718 pw_exit(unit, -1); 719 } 720 721 PW_UNLOCK(unit); 722 723 /* 724 * Check if there are any actions for us. 725 */ 726 while (1) { 727 int sem_rv; 728 729 sem_rv = sal_sem_take(pw_units[unit].pu_sema, sal_sem_FOREVER); 730 731 if (sem_rv < 0) { 732 cli_out("Failed sem_take, exiting\n"); 733 pw_exit(unit, -1); 734 } 735 736 PW_LOCK(unit); /* Block log dumps */ 737 738 if (pu->pu_flags & PU_F_STOP) { /* Time to exit */ 739 if (pu->mode == PW_MODE_SOC) { 740 pw_cleanup_dma(unit); 741 } 742 pw_exit(unit, 0); 743 } 744 745 pw_process_pending(unit); 746 747 PW_UNLOCK(unit); 748 749 /* If limiting using interval, sleep intvl * num pkts processed */ 750 if (pu->mode == PW_MODE_SOC) { 751 if (pu->pu_interval != 0 && pu->last_pkt_count != 0) { 752 sal_usleep(pu->pu_interval * pu->last_pkt_count); 753 } 754 } 755 } 756 757 pw_exit(unit, 0); 758 } 759 760 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 761 STATIC int 762 pw_channel_config(int unit) 763 /* 764 * Function: pw_channel_config 765 * Purpose: Configure DMA RX channels for PW. 766 * Parameters: unit - unit to configure. 767 * Returns: 0 - success 768 * -1 - failed. 769 */ 770 { 771 pwu_t *pu = &pw_units[unit]; /* Control this unit */ 772 dma_chan_t tx, i; 773 int rv = SOC_E_NONE; 774 dma_chan_t dma_chan; 775 776 if (pu->pu_channel == 0) { /* Use default */ 777 return 0; 778 } 779 780 if (soc_feature(unit, soc_feature_cmicx)) { 781 dma_chan = CMICX_N_DMA_CHAN; 782 } else { 783 dma_chan = N_DMA_CHAN; 784 } 785 786 /* Pick lowest # free channel for TX default */ 787 tx = -1; 788 for (i = 0; i < dma_chan; i++) { 789 if (pu->pu_channel & (1 << i)) { 790 rv = soc_dma_chan_config(unit, i, DV_RX, SOC_DMA_F_INTR); 791 if (rv < 0) { 792 cli_out("%s: DMA channel configuration failed: %s\n", 793 pw_name[unit], soc_errmsg(rv)); 794 } 795 #if defined(BCM_PETRA_SUPPORT) 796 /* enable all cos on the channel */ 797 soc_dma_chan_cos_ctrl_set(unit, i, 1, 0xffffffff); 798 soc_dma_chan_cos_ctrl_set(unit, i, 2, 0xffffffff); 799 #endif 800 } else if (tx == -1) { 801 tx = i; 802 } 803 } 804 805 if ((tx == -1) || 806 ((rv = soc_dma_chan_config(unit, tx, DV_TX, 807 SOC_DMA_F_INTR |SOC_DMA_F_DEFAULT)) < 0)) { 808 cli_out("%s: Unable to configure TX DMA channel: %s\n", 809 pw_name[unit], 810 tx == -1 ? "No remaining channels" : soc_errmsg(rv)); 811 812 rv = soc_dma_init(unit); 813 cli_out("%s: Unable to re-initialize DMA: %s\n", 814 pw_name[unit], 815 soc_errmsg(rv)); 816 817 return -1; 818 } 819 return 0; 820 } 821 #endif 822 823 static const parse_pm_t pw_report_table[] = { 824 {"Count", REPORT_COUNT}, 825 {"DECode", REPORT_DECODE}, 826 {"Raw", REPORT_RAW}, 827 {"DMA", REPORT_DMA}, 828 {"CHannel", REPORT_CHANNEL}, 829 {"@ALL", ~0}, 830 {"@*", ~0}, 831 {NULL, 0} 832 }; 833 834 static const parse_pm_t pw_channel_table[] = { 835 {"0", 1 << 0}, 836 {"1", 1 << 1}, 837 {"2", 1 << 2}, 838 {"3", 1 << 3}, 839 {"4", 1 << 4}, 840 {"5", 1 << 5}, 841 {"6", 1 << 6}, 842 {"7", 1 << 7}, 843 {NULL, 0} 844 }; 845 846 cmd_result_t 847 pw_command(int unit, args_t *a) 848 /* 849 * Function: pw_command 850 * Purpose: Command interface to the "packet watcher" thread. 851 * Parameters: 852 * "verbose" - print lots of stuff. 853 * "start" - start packet watcher thread. 854 * "stop" - stop packet watcher thread. 855 * "quiet" - print no stuff. 856 * Returns: CMD_OK - success 857 * CMD_FAIL - failed 858 * CMD_USAGE - print usage instructions 859 */ 860 { 861 char *c; 862 int n; 863 uint32 on = 0; /* flags to turn on */ 864 pwu_t *pu = &pw_units[unit]; /* Control this unit */ 865 866 if (!sh_check_attached(ARG_CMD(a), unit)) { 867 return(CMD_FAIL); 868 } 869 870 if (!pu->init_done) { 871 pw_init(unit); 872 } 873 874 if (!ARG_CNT(a)) { /* Nothing passed */ 875 cli_out("%s: Status: %s. Mode %s. Buffering up to %d packets.%s\n", 876 pw_name[unit], 877 (pu->pu_flags & PU_F_RUN) ? "Running" : "Not Running", 878 pw_modes[pu->mode], pu->pu_log_max, 879 (pu->pu_flags & PU_F_STOP) ? " STOP Requested." : ""); 880 if (pu->mode == PW_MODE_SOC) { 881 if (pu->pu_interval != 0) { 882 cli_out("Interval %d us", pu->pu_interval); 883 } 884 } 885 if (pu->rate <= 0) { 886 cli_out("Rate limiting is off.\n"); 887 } else { 888 cli_out("Rate limit is %d (soc intvl %d).\n", pu->rate, 889 pu->pu_interval); 890 } 891 892 cli_out("Reporting is enabled for: "); 893 parse_mask_format(80, pw_report_table, pu->pu_report); 894 cli_out("Reporting is disabled for: "); 895 parse_mask_format(80, pw_report_table, pu->pu_report ^ ~0); 896 897 cli_out("Dump options are enabled for: "); 898 parse_mask_format(80, pw_report_table, pu->pu_dump_options); 899 cli_out("Dump options are disabled for: "); 900 parse_mask_format(80, pw_report_table, pu->pu_dump_options ^ ~0); 901 902 cli_out("RX on for channel(s): "); 903 if (pu->pu_channel) { 904 parse_mask_format(50, pw_channel_table, pu->pu_channel); 905 cli_out("RX off for channel(s): "); 906 parse_mask_format(50, pw_channel_table, ~pu->pu_channel); 907 } else { 908 cli_out(" -- using default --\n"); 909 } 910 #ifdef BROADCOM_DEBUG 911 if (pu->mode == PW_MODE_RX) { 912 bcm_rx_show(unit); 913 } 914 #endif /* BROADCOM_DEBUG */ 915 return(CMD_OK); 916 } 917 918 /* Scan args and see what's up */ 919 920 while ((c = ARG_GET(a)) != NULL) { 921 if (!sal_strcasecmp(c, "start")) { 922 if (pu->pu_flags & PU_F_RUN) { 923 cli_out("%s: WARNING: Already running\n", pw_name[unit]); 924 } else { 925 on |= PU_F_RUN; 926 } 927 } else if (!sal_strcasecmp(c, "stop")) { 928 if (!(pu->pu_flags & PU_F_RUN)) { 929 cli_out("%s: WARNING: Not running\n", pw_name[unit]); 930 return(CMD_OK); /* Return OK to avoid rc aborts */ 931 } 932 on |= PU_F_STOP; 933 } else if (!sal_strcasecmp(c, "reset")) { 934 if (pu->pu_flags & PU_F_RUN) { 935 cli_out("%s: Unable to reset configuration " 936 "while running\n", pw_name[unit]); 937 return(CMD_FAIL); 938 } else { 939 pu->init_done = FALSE; 940 pw_init(unit); 941 return CMD_OK; 942 } 943 } else if (!sal_strcasecmp(c, "channel")) { 944 if (ARG_CNT(a) == 0) { 945 cli_out("%s: RX on for channel(s): ", pw_name[unit]); 946 if (pu->pu_channel) { 947 parse_mask_format(50, pw_channel_table, pu->pu_channel); 948 cli_out("%s: RX off for channel(s): ", pw_name[unit]); 949 parse_mask_format(50, pw_channel_table, ~pu->pu_channel); 950 } else { 951 cli_out(" -- using default --\n"); 952 } 953 return(CMD_OK); 954 } else if (pu->pu_flags & PU_F_RUN) { 955 cli_out("%s: Unable to configure DMA channels " 956 "while running\n", pw_name[unit]); 957 return(CMD_FAIL); 958 } 959 960 /* Set channels */ 961 while ((c = ARG_CUR(a)) != NULL && 962 !parse_mask(c, pw_channel_table, 963 (uint32 *)&pu->pu_channel)) { 964 ARG_NEXT(a); /* Bump arg if matched report */ 965 } 966 967 if (pu->pu_flags & PU_F_RUN) { 968 cli_out("%s: Warning channel re-assignment will not take\n" 969 "%s: until restarted.\n", 970 pw_name[unit], pw_name[unit]); 971 } 972 } else if (!sal_strcasecmp(c, "quiet")) { 973 pu->pu_report = 0; 974 } else if (!sal_strcasecmp(c, "rate")) { 975 c = ARG_GET(a); 976 if (c == NULL) { 977 if (pu->rate <= 0) { 978 cli_out("%s: No rate limiting.\n", pw_name[unit]); 979 } else { 980 cli_out("%s: Rate limit is currently %d pkts/sec.\n", 981 pw_name[unit], pu->rate); 982 } 983 return CMD_OK; 984 } 985 pu->rate = strtoul(c, NULL, 10); 986 if (_pw_set_rate(unit) < 0) { 987 return CMD_FAIL; 988 } 989 return CMD_OK; 990 } else if (!sal_strcasecmp(c, "report")) { 991 if (ARG_CNT(a)) { 992 while ((c = ARG_CUR(a)) != NULL && 993 !parse_mask(c, pw_report_table, &pu->pu_report)) { 994 ARG_NEXT(a); /* Bump arg if matched report */ 995 } 996 } else { /* Print values */ 997 cli_out("%s: Reporting on for: ", pw_name[unit]); 998 parse_mask_format(50, pw_report_table, pu->pu_report); 999 cli_out("%s: Reporting off for: ", pw_name[unit]); 1000 parse_mask_format(50, pw_report_table, ~pu->pu_report); 1001 } 1002 } else if (!sal_strcasecmp(c, "log")) { 1003 c = ARG_GET(a); 1004 if (c) { /* We have an option */ 1005 if (pu->pu_flags & PU_F_RUN) { 1006 cli_out("%s: Can not change \"log\" " 1007 "while PW-daemon running\n", pw_name[unit]); 1008 return(CMD_FAIL); 1009 } 1010 if (!sal_strcasecmp(c, "on")) { 1011 n = PU_LOG_CNT; 1012 } else if (!sal_strcasecmp(c, "off")) { 1013 n = 1; 1014 } else if (isint(c)) { /* Set log size */ 1015 n = parse_integer(c); 1016 if (n < 1) { 1017 cli_out("%s: What is %s?\n", pw_name[unit], c); 1018 n = 1; 1019 } 1020 } else { 1021 cli_out("%s: Invalid count \"%s\"\n", pw_name[unit], c); 1022 return(CMD_FAIL); 1023 } 1024 pu->pu_log_max = n; 1025 } 1026 cli_out("%s: Logging(%d-packets)\n", 1027 pw_name[unit], pu->pu_log_max); 1028 if (!c || !*c) { 1029 return(CMD_OK); 1030 } 1031 } else if (!sal_strcasecmp(c, "dump")) { 1032 c = ARG_GET(a); 1033 if (!c) { /* no args */ 1034 n = pu->pu_log_cnt; 1035 } else if (!isint(c)) { 1036 if (!sal_strcasecmp(c, "options")) { 1037 if (ARG_CNT(a)) { 1038 while ((c = ARG_CUR(a)) != NULL && 1039 !parse_mask(c, pw_report_table, 1040 &pu->pu_dump_options)) { 1041 ARG_NEXT(a); /* Bump arg if matched report */ 1042 } 1043 } else { /* Print values */ 1044 cli_out("%s: Dump options on for: ", pw_name[unit]); 1045 parse_mask_format(50, pw_report_table, pu->pu_dump_options); 1046 cli_out("%s: Dump options off for: ", pw_name[unit]); 1047 parse_mask_format(50, pw_report_table, ~pu->pu_dump_options); 1048 } 1049 return(CMD_OK); 1050 } else { 1051 cli_out("%s: Invalid log count \"%s\"\n", pw_name[unit], c); 1052 return(CMD_FAIL); 1053 } 1054 } else { 1055 n = parse_integer(c); 1056 } 1057 return(pw_dump_log(unit, n)); 1058 } else if (!sal_strcasecmp(c, "count")) { 1059 COMPILER_DOUBLE cur_time, last_time; 1060 int cur_count, last_count; 1061 int rate; 1062 1063 cur_time = SAL_TIME_DOUBLE(); 1064 1065 last_time = pu->pu_count_time; 1066 last_count = pu->pu_count_last; 1067 cur_count = pu->pu_packet_received; 1068 1069 if (cur_time == last_time) { 1070 rate = 0; 1071 } else { 1072 rate = (int) ((cur_count - last_count) / 1073 (cur_time - last_time)); 1074 } 1075 1076 cli_out("%s: Received %d packets [(%d),%d,%d,%d,%d] (%d/sec), " 1077 "last %d packet(s) logged\n", 1078 pw_name[unit], 1079 pu->pu_packet_received, 1080 pu->pu_ch_count[0], 1081 pu->pu_ch_count[1], 1082 pu->pu_ch_count[2], 1083 pu->pu_ch_count[3], 1084 pu->pu_ch_count[4], 1085 rate, 1086 pu->pu_log_cnt); 1087 1088 pu->pu_count_last = cur_count; 1089 pu->pu_count_time = cur_time; 1090 } else if (!sal_strcasecmp(c, "interval")) { 1091 c = ARG_GET(a); 1092 if (!c || !isint(c)) { 1093 return(CMD_USAGE); 1094 } 1095 n = parse_integer(c); 1096 if (n < 0) { 1097 cli_out("%s: Invalid interval: %s\n", pw_name[unit], c); 1098 return(CMD_FAIL); 1099 } 1100 pu->pu_interval = n; 1101 } else if (!sal_strcasecmp(c, "mode")) { 1102 if ((c = ARG_GET(a)) == NULL) { 1103 cli_out("Current mode is %s\n", pw_modes[pu->mode]); 1104 return CMD_OK; 1105 } 1106 1107 if (pw_running(unit)) { 1108 cli_out("Can't set modes while running\n"); 1109 return CMD_FAIL; 1110 } 1111 1112 if (!sal_strcasecmp(c, "soc")) { 1113 pu->mode = PW_MODE_SOC; 1114 } else if (!sal_strcasecmp(c, "rx")) { 1115 pu->mode = PW_MODE_RX; 1116 } else { 1117 cli_out("Unknown mode: %s\n", c); 1118 return CMD_FAIL; 1119 } 1120 1121 return CMD_OK; 1122 } else if (!sal_strcasecmp(c, "hdr")) { 1123 c = ARG_GET(a); 1124 if (c) { /* We have an option */ 1125 if (!sal_strcasecmp(c, "on")) { 1126 pu->hdr_dump = 1; 1127 } else if (!sal_strcasecmp(c, "off")) { 1128 pu->hdr_dump = 0; 1129 } 1130 } 1131 } else { 1132 return(CMD_USAGE); 1133 } 1134 } 1135 1136 /* Everything OK, start or stop packet watcher now */ 1137 1138 if (on & PU_F_RUN) { /* start off thread */ 1139 return(pw_start(unit, TRUE)); 1140 } else if (on & PU_F_STOP) { /* stop task */ 1141 return(pw_stop(unit, TRUE)); 1142 } 1143 1144 return(CMD_OK); 1145 } 1146 1147 /**************************************************************** 1148 * 1149 * Common packet watcher routines 1150 */ 1151 1152 1153 STATIC pup_t * 1154 pw_pup_alloc(int unit) 1155 /* 1156 * Function: pw_alloc 1157 * Purpose: Alloc a pup off the free list. 1158 * Parameters: unit - unit # 1159 * Returns: Pointer to pup. 1160 */ 1161 { 1162 pwu_t *pu = &pw_units[unit]; 1163 pup_t *pup; 1164 1165 PW_LOCK(unit); 1166 pup = pu->pu_log_free; 1167 if (pup) { 1168 pu->pu_log_free = pup->pup_next; 1169 } 1170 PW_UNLOCK(unit); 1171 1172 return(pup); 1173 } 1174 1175 STATIC void 1176 pw_pup_free(int unit, pup_t *pup) 1177 /* 1178 * Function: pw_pup_free 1179 * Purpose: Put a pup on the free list. 1180 * Parameters: unit - unit # 1181 * pup - pointer to pup to free. 1182 * Returns: Nothing. 1183 */ 1184 { 1185 pwu_t *pu = &pw_units[unit]; 1186 1187 pup->pup_next = pu->pu_log_free; 1188 pu->pu_log_free = pup; 1189 1190 if (pu->mode == PW_MODE_RX) { 1191 bcm_rx_free(unit, pup->rx_pkt.alloc_ptr); 1192 } 1193 } 1194 1195 STATIC void 1196 pw_dump_start(int unit, char *pfx, pup_t *pup, uint32 report, 1197 int chan, int count) 1198 { 1199 char *channel; 1200 1201 if (!report) { 1202 return; 1203 } 1204 1205 cli_out("\n"); 1206 1207 if (report & REPORT_CHANNEL) { 1208 switch (chan) { 1209 case -1: channel = ""; break; 1210 case 0: channel = "-chn0"; break; 1211 case 1: channel = "-chn1"; break; 1212 case 2: channel = "-chn2"; break; 1213 case 3: channel = "-chn3"; break; 1214 case 4: channel = "-chn4"; break; 1215 case 5: channel = "-chn5"; break; 1216 case 6: channel = "-chn6"; break; 1217 case 7: channel = "-chn7"; break; 1218 default: channel = "-----"; break; 1219 } 1220 } else { 1221 channel = ""; 1222 } 1223 1224 sal_sprintf(pfx, "Packet[%d]%s: ", pup->pup_seqno, channel); 1225 1226 if ((report & REPORT_COUNT) && (count >= 0)) { 1227 cli_out("%sTotal %d\n", pfx, count); 1228 } 1229 1230 } 1231 1232 1233 STATIC void 1234 pw_dump_packet_soc(int unit, pup_t *pup, uint32 report) 1235 /* 1236 * Function: pw_dump_packet 1237 * Purpose: dumps out a packet based on the flags set in pw_flags. 1238 * Parameters: unit - SOC unit #. 1239 * pup - packet structure 1240 * report - report flags 1241 * Returns: d - pointer to dcb containing packet 1242 */ 1243 { 1244 1245 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1246 dcb_t *esw_dcb = NULL; 1247 #endif 1248 1249 char pfx[64]; 1250 1251 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1252 esw_dcb = pup->pup_esw_dv->dv_dcb; 1253 #endif 1254 1255 1256 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1257 pw_dump_start(unit, pfx, pup, report, (int)pup->pup_esw_dv->dv_pw_chan, -1); 1258 #endif 1259 1260 if (report & REPORT_COUNT) { 1261 cli_out("%sReceived\n", pfx); 1262 #ifdef BROADCOM_DEBUG 1263 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1264 SOC_DCB_REASON_DUMP(unit, esw_dcb, pfx); 1265 #endif 1266 #endif /* BROADCOM_DEBUG */ 1267 } 1268 1269 if (report & REPORT_DMA) { 1270 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1271 soc_dma_dump_dv(unit, pfx, pup->pup_esw_dv); 1272 #endif 1273 } 1274 1275 if (report & REPORT_RAW) { 1276 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1277 soc_dma_dump_pkt(unit, pfx, 1278 (uint8 *) SOC_DCB_ADDR_GET(unit, esw_dcb), 1279 SOC_DCB_XFERCOUNT_GET(unit, esw_dcb), 1280 TRUE); 1281 #endif 1282 } 1283 1284 #ifndef NO_SAL_APPL 1285 #ifndef __STRICT_ANSI__ 1286 #ifndef __KERNEL__ 1287 if (report & REPORT_DECODE) { 1288 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1289 d_packet_format(pfx, DECODE_ETHER, pup->pup_pkt, 1290 SOC_DCB_XFERCOUNT_GET(unit, esw_dcb), 1291 SOC_IS_ENDURO(unit)?esw_dcb:NULL); 1292 #endif 1293 } 1294 #endif /* __KERNEL__ */ 1295 #endif /* __STRICT_ANSI__ */ 1296 #endif /* NO_SAL_APPL */ 1297 } 1298 1299 STATIC char *_pw_reason_names[bcmRxReasonCount] = BCM_RX_REASON_NAMES_INITIALIZER; 1300 1301 STATIC void 1302 pw_dump_packet_rx(int unit, pup_t *pup, uint32 report) 1303 { 1304 bcm_pkt_t *pkt; 1305 char pfx[64]; 1306 char info_str[256]; 1307 pwu_t *pu = &pw_units[unit]; 1308 int i; 1309 #ifndef NO_SAL_APPL 1310 #ifndef __STRICT_ANSI__ 1311 #ifndef __KERNEL__ 1312 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1313 dv_t *pdv; 1314 #endif 1315 #endif /* __KERNEL__ */ 1316 #endif /* __STRICT_ANSI__ */ 1317 #endif /* NO_SAL_APPL */ 1318 #ifdef BCM_PETRA_SUPPORT 1319 int hdr_len = 0; 1320 #endif 1321 1322 pkt = &pup->rx_pkt; 1323 1324 #ifdef BCM_PETRA_SUPPORT 1325 if (SOC_IS_ARAD(unit)) { 1326 hdr_len = pkt->tot_len - pkt->pkt_len; 1327 } 1328 #endif 1329 1330 pw_dump_start(unit, pfx, pup, report, pkt->dma_channel, 1331 pu->pu_packet_received); 1332 1333 if (report & REPORT_DMA) { 1334 if (pkt->_dv) { 1335 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1336 soc_dma_dump_dv(unit, pfx, (dv_t *)pkt->_dv); 1337 #endif 1338 } 1339 } 1340 1341 if (report & REPORT_RAW) { 1342 #ifdef BCM_XGS12_FABRIC_SUPPORT 1343 if (SOC_IS_XGS12_FABRIC(unit)) { 1344 soc_dma_higig_dump(unit, pfx, pkt->_higig, 0, pkt->pkt_len, NULL); 1345 } 1346 #endif 1347 if (SOC_IS_ARAD(unit)) { 1348 #if defined(BCM_PETRA_SUPPORT) 1349 soc_dma_ether_dump(unit, pfx, pkt->_pkt_data.data + hdr_len, pkt->pkt_len, 0); 1350 #endif 1351 } 1352 else { 1353 #if defined(BCM_ESW_SUPPORT) 1354 #if defined(BCM_CMICX_SUPPORT) 1355 if (soc_feature(unit, soc_feature_cmicx)) { 1356 if (pu->hdr_dump == 1) { 1357 soc_dma_ep_to_cpu_hdr_dump(unit, pfx, pkt->_pkt_data.data - pkt->egress_to_cpu_hdr_size, 1358 pkt->egress_to_cpu_hdr_size, 0); 1359 } 1360 1361 if (report & REPORT_DMA) { 1362 uint8 *c = (uint8 *)pkt->_pkt_data.data; 1363 c -= pkt->egress_to_cpu_hdr_size; 1364 #ifdef LE_HOST 1365 { 1366 /* Higig field accessors expect network byte ordering, 1367 * so we must reverse the bytes on LE hosts */ 1368 int word; 1369 uint32 *hg_data = (uint32 *)c; 1370 for (word = 0; word < BYTES2WORDS(pkt->egress_to_cpu_hdr_size); word++) { 1371 hg_data[word] = _shr_swap32(hg_data[word]); 1372 } 1373 c = (uint8 *)hg_data; 1374 } 1375 #endif 1376 soc_dma_higig_dump(unit, pfx, c, 0, 0, NULL); 1377 soc_dma_ep_to_cpu_hdr_decoded_dump(unit, pfx, (void *)c, 1, pkt->egress_to_cpu_hdr_size); 1378 } 1379 } 1380 #endif 1381 soc_dma_ether_dump(unit, pfx, pkt->_pkt_data.data, pkt->pkt_len, 0); 1382 #endif 1383 } 1384 if (!SOC_IS_ARAD(unit)) { 1385 cli_out("%slength %d (%d). rx-port %d. cos %d. prio_int %d. vlan %d. " 1386 "reason 0x%x. %s.\n", pfx, 1387 pkt->pkt_len, pkt->tot_len, pkt->rx_port, 1388 pkt->cos, pkt->prio_int, pkt->vlan, 1389 pkt->rx_reason, 1390 (pkt->rx_untagged & BCM_PKT_OUTER_UNTAGGED) ? 1391 ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ? 1392 "Untagged" : "Inner tagged") : 1393 ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ? 1394 "Outer tagged" : "Double tagged")); 1395 } 1396 else { 1397 cli_out("%slength %d (%d). rx-port %d. cos %d. prio_int %d. vlan %d. " 1398 "reason 0x%x.\n", pfx, 1399 pkt->pkt_len, pkt->tot_len, pkt->rx_port, 1400 pkt->cos, pkt->prio_int, pkt->vlan, 1401 pkt->rx_reason); 1402 } 1403 if ((pkt->stk_flags & BCM_PKT_STK_F_SRC_PORT) && 1404 (pkt->stk_flags & BCM_PKT_STK_F_DST_PORT)) { 1405 1406 sal_sprintf(info_str, 1407 "dest-gport %d. src-gport %d. ", 1408 pkt->dst_gport, pkt->src_gport); 1409 } else if ((pkt->stk_flags & BCM_PKT_STK_F_SRC_PORT)) { 1410 1411 sal_sprintf(info_str, 1412 "dest-port %d. dest-mod %d. src-gport %d. ", 1413 pkt->dest_port, pkt->dest_mod, pkt->src_gport); 1414 } else if ((pkt->stk_flags & BCM_PKT_STK_F_DST_PORT)) { 1415 1416 sal_sprintf(info_str, 1417 "dest-gport %d. %s %d. src-mod %d. ", 1418 pkt->dst_gport, 1419 (pkt->flags & BCM_PKT_F_TRUNK) ? "src-trunk" : "src-port", 1420 (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port, 1421 pkt->src_mod); 1422 } else { 1423 1424 sal_sprintf(info_str, 1425 "dest-port %d. dest-mod %d. %s %d. src-mod %d. ", 1426 pkt->dest_port, pkt->dest_mod, 1427 (pkt->flags & BCM_PKT_F_TRUNK) ? "src-trunk" : "src-port", 1428 (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port, 1429 pkt->src_mod); 1430 } 1431 if (!SOC_IS_ARAD(unit)) { 1432 cli_out("%s%sopcode %d. %s matched %d. classification-tag %d.\n", 1433 pfx, info_str, 1434 pkt->opcode, 1435 (pkt->flags & BCM_RX_TRUNCATED) ? "Truncated." : "", 1436 pkt->rx_matched, pkt->rx_classification_tag); 1437 } 1438 else { 1439 cli_out("%s%s%s \n", 1440 pfx, info_str, 1441 (pkt->flags & BCM_RX_TRUNCATED) ? "Truncated." : ""); 1442 } 1443 for (i = 0; i < bcmRxReasonCount; i++) { 1444 if (BCM_RX_REASON_GET(pkt->rx_reasons, i)) { 1445 cli_out("%sreasons: %s\n", pfx, _pw_reason_names[i]); 1446 } 1447 } 1448 1449 /* 1450 * Seamless Redundancy(SR) copy to CPU 1451 * SR custom RX reason code (1~63) for IFP action bcmFieldActionSrCopyToCpu . 1452 * construct reason code (1~63) from 6-bit binary encoding 1453 */ 1454 #define SR_CUSTOM_RX_REASON_CODE \ 1455 ((BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit0) << 0)| \ 1456 (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit1) << 1)| \ 1457 (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit2) << 2)| \ 1458 (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit3) << 3)| \ 1459 (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit4) << 4)| \ 1460 (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit5) << 5)) 1461 1462 /* no copy to CPU when SR_CUSTOM_RX_REASON_CODE == 0 */ 1463 if(SR_CUSTOM_RX_REASON_CODE != 0) { 1464 cli_out("%sSR custom RX reason code: %d\n", 1465 pfx, 1466 SR_CUSTOM_RX_REASON_CODE); 1467 } 1468 } 1469 1470 #ifndef NO_SAL_APPL 1471 #ifndef __STRICT_ANSI__ 1472 #ifndef __KERNEL__ 1473 if (report & REPORT_DECODE) { 1474 if (pkt->_dv) { 1475 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1476 pdv = (dv_t *)(pkt->_dv); 1477 #if defined(BCM_PETRA_SUPPORT) 1478 if (SOC_IS_ARAD(unit)) { 1479 d_packet_format(pfx, DECODE_ETHER, pkt->_pkt_data.data + hdr_len, 1480 pkt->pkt_len, SOC_IS_ENDURO(unit)? pdv->dv_dcb:NULL); 1481 } 1482 else 1483 #endif 1484 { 1485 d_packet_format(pfx, DECODE_ETHER, pkt->_pkt_data.data, 1486 pkt->pkt_len, SOC_IS_ENDURO(unit)? pdv->dv_dcb:NULL); 1487 } 1488 #endif 1489 } 1490 } 1491 #endif /* __KERNEL__ */ 1492 #endif /* __STRICT_ANSI__ */ 1493 #endif /* NO_SAL_APPL */ 1494 1495 } 1496 1497 STATIC void 1498 pw_dump_packet(int unit, pup_t *pup, uint32 report) 1499 { 1500 pwu_t *pu = &pw_units[unit]; 1501 1502 switch (pu->mode) { 1503 case PW_MODE_RX: 1504 pw_dump_packet_rx(unit, pup, report); 1505 break; 1506 case PW_MODE_SOC: 1507 pw_dump_packet_soc(unit, pup, report); 1508 break; 1509 default: 1510 break; 1511 } 1512 } 1513 1514 STATIC cmd_result_t 1515 pw_dump_log(int unit, int n) 1516 /* 1517 * Function: pw_dump_log 1518 * Purpose: Dump out currently logged packets 1519 * Parameters: unit - unit # 1520 * n - number of packets to dump, -n means last "n" 1521 * packets. 1522 * Returns: CMD_OK - success 1523 */ 1524 { 1525 pwu_t *pu = &pw_units[unit]; 1526 pup_t *pup; 1527 int abs_n; 1528 1529 PW_LOCK(unit); /* Stop updates */ 1530 1531 if ((pu->pu_log == NULL) || (n == 0)) { /* Nothing to show */ 1532 PW_UNLOCK(unit); 1533 cli_out("pw_dump_log[%d]: Warning: no packets logged " 1534 "or selected to dump\n", unit); 1535 return CMD_OK; /* Return nothing */ 1536 } 1537 1538 /* 1539 * Loop through list of packets, stop when we have dumped the correct 1540 * number - we know there is at least one logged since we checked above. 1541 * If dumping the last n packets, move backwards, otherwise move forwards. 1542 * Anything on this list is complete, so the PW_LOCK protects this 1543 * operation. 1544 */ 1545 abs_n = n < 0 ? -n : n; 1546 abs_n = abs_n > pu->pu_log_cnt ? pu->pu_log_cnt : abs_n; 1547 1548 if (n < 0) { /* Dump last N packets */ 1549 for (pup = pu->pu_log; abs_n-- != 0; pup = pup->pup_next) { 1550 pw_dump_packet(unit, pup, pu->pu_dump_options); 1551 } 1552 } else { /* Dump first N packets */ 1553 for (pup = pu->pu_log->pup_prev; abs_n-- != 0; pup = pup->pup_prev) { 1554 pw_dump_packet(unit, pup, pu->pu_dump_options); 1555 } 1556 } 1557 PW_UNLOCK(unit); 1558 1559 return CMD_OK; 1560 } 1561 1562 STATIC void 1563 pw_log_packet(int unit, pup_t *pup) 1564 /* 1565 * Function: pw_log_packet 1566 * Purpose: Commit a recieved packet to the logs. 1567 * Parameters: unit - unit # 1568 * pup - pointer to pup to add to log. 1569 * Returns: Nothing. 1570 * 1571 * Notes: Assumes PW_LOCK held. 1572 */ 1573 { 1574 pwu_t *pu = &pw_units[unit]; 1575 1576 /* 1577 * There are 2 cases: 1578 * 1) First entry 1579 * 2) Log is full so the LRU packet is dropped (common case) 1580 * 3) Log is not full, no packet is dropped. 1581 */ 1582 1583 if (pu->pu_log_cnt == 0) { /* 1) First entry */ 1584 pu->pu_log = pup->pup_next = pup->pup_prev = pup; 1585 pu->pu_log_cnt = 1; 1586 } else if (pu->pu_log_cnt == pu->pu_log_max) { /* 2) Full log, drop one */ 1587 pup_t *tp; 1588 1589 tp = pu->pu_log->pup_prev; /* Entry to delete */ 1590 pup->pup_next = pu->pu_log; /* Link new one in at head */ 1591 pup->pup_prev = tp->pup_prev; 1592 pup->pup_next->pup_prev = pup; 1593 pup->pup_prev->pup_next = pup; 1594 1595 pw_pup_free(unit, tp); 1596 } else { /* 3) Just add to chain */ 1597 /* 1598 * Case 2 - add new entry and increment log count. 1599 */ 1600 pu->pu_log_cnt++; 1601 pup->pup_next = pu->pu_log; 1602 pup->pup_prev = pu->pu_log->pup_prev; 1603 pup->pup_next->pup_prev = pup; 1604 pup->pup_prev->pup_next = pup; 1605 } 1606 pu->pu_log = pup; /* Set new list */ 1607 } 1608 1609 1610 STATIC void 1611 pw_process_pending(int unit) 1612 /* 1613 * Function: pw_process_pending 1614 * Purpose: Process packets queued from interrupt 1615 * Parameters: unit - unit # 1616 * Returns: Nothing. 1617 * 1618 * Notes: Can be called only from a non-interrupt context. 1619 */ 1620 { 1621 pwu_t *pu = &pw_units[unit]; 1622 pup_t *pup; 1623 int chan; 1624 chan = 0; 1625 /* 1626 * Pick up current done list and process in order. 1627 */ 1628 PW_SPIN_LOCK(unit); 1629 pup = (pup_t *)pu->pu_pending; 1630 pu->pu_pending = NULL; 1631 PW_SPIN_UNLOCK(unit); 1632 1633 pu->last_pkt_count = 0; 1634 while (pup) { 1635 pup_t *tp = pup->pup_next; 1636 1637 pup->pup_seqno = ++pu->pu_packet_received; 1638 pw_log_packet(unit, (pup_t *)pup); 1639 if (pu->mode == PW_MODE_SOC) { 1640 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1641 pw_start_channel(unit, (dma_chan_t)pup->pup_esw_dv->dv_pw_chan); 1642 chan = (int)pup->pup_esw_dv->dv_pw_chan + 1; 1643 #endif 1644 } else { 1645 chan = 0; /* Per-channel counted in Rx call-back */ 1646 } 1647 pu->pu_ch_count[chan]++; 1648 pw_dump_packet(unit, (pup_t *)pup, pu->pu_report); /* Dump packet */ 1649 pup = tp; 1650 pu->last_pkt_count++; 1651 } 1652 } 1653 1654 /**************************************************************** 1655 * 1656 * RX API packet watcher code, non-interrupt 1657 */ 1658 STATIC bcm_rx_t 1659 pw_rx_callback(int unit, bcm_pkt_t *pkt, void *cookie) 1660 { 1661 pup_t *pup; 1662 pwu_t *pu = &pw_units[unit]; 1663 int8 chan; 1664 dma_chan_t dma_chan; 1665 1666 chan = pkt->dma_channel; 1667 1668 if (soc_feature(unit, soc_feature_cmicx)) { 1669 dma_chan = CMICX_N_DMA_CHAN; 1670 } else { 1671 dma_chan = N_DMA_CHAN; 1672 } 1673 1674 if (chan >= 0 && chan < dma_chan) { 1675 pu->pu_ch_count[chan + 1]++; 1676 } 1677 if (pu->pu_report == 0 && pu->pu_log_max == 1) { 1678 /* No post-processing - just count packet */ 1679 return BCM_RX_HANDLED; 1680 } 1681 1682 pup = pw_pup_alloc(unit); 1683 if (!pup) { 1684 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1685 (BSL_META_U(unit, 1686 "PW: Failed to allocate pup struct. Discarding\n"))); 1687 return BCM_RX_NOT_HANDLED; 1688 } 1689 1690 sal_memcpy(&pup->rx_pkt, pkt, sizeof(bcm_pkt_t)); 1691 1692 PW_SPIN_LOCK(unit); 1693 pup->pup_next = NULL; 1694 if (pu->pu_pending == NULL) { 1695 pup->pup_prev = pup; 1696 pu->pu_pending = pup; 1697 } else { 1698 pu->pu_pending->pup_prev->pup_next = pup; 1699 pu->pu_pending->pup_prev = pup; 1700 } 1701 PW_SPIN_UNLOCK(unit); 1702 1703 sal_sem_give(pw_units[unit].pu_sema); 1704 return BCM_RX_HANDLED_OWNED; 1705 } 1706 1707 /**************************************************************** 1708 * 1709 * SOC layer packet watcher code 1710 */ 1711 1712 1713 STATIC cmd_result_t 1714 pw_start_channel(int unit, dma_chan_t chan) 1715 /* 1716 * Function: pw_start_chanel 1717 * Purpose: Re-init dv and start a new DMA read operation. 1718 * Parameters: unit - SOC unit # 1719 * chan - DMA channel, if -1, uses default RX channel. 1720 * Returns: CMD_OK/CMD_FAIL 1721 */ 1722 { 1723 pwu_t *pu = &pw_units[unit]; 1724 pup_t *pup; 1725 int rv = 0; 1726 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1727 dv_t *esw_dv; 1728 pbmp_t empty; 1729 #endif 1730 1731 pup = pw_pup_alloc(unit); 1732 1733 assert(pu->pu_ch_active[chan + 1] == NULL); 1734 assert(pup); 1735 1736 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1737 SOC_PBMP_CLEAR(empty); 1738 #endif 1739 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1740 esw_dv = pup->pup_esw_dv; 1741 soc_dma_dv_reset(DV_RX, esw_dv); 1742 soc_dma_desc_add(esw_dv, (sal_vaddr_t)pup->pup_pkt, PW_PACKET_SIZE, 1743 PBMP_ALL(unit), empty, empty, 0, NULL); 1744 soc_dma_desc_end_packet(esw_dv); 1745 esw_dv->dv_done_chain = pw_esw_done_intr; 1746 esw_dv->dv_flags |= DV_F_NOTIFY_CHN; 1747 1748 esw_dv->dv_pw_chan = (uint32)chan; 1749 esw_dv->dv_pw_pup = pup; 1750 1751 pu->pu_ch_active[chan + 1] = pup; 1752 1753 rv = soc_dma_start(unit, chan, esw_dv); 1754 if (rv < 0) { 1755 pu->pu_ch_active[chan + 1] = NULL; 1756 pw_pup_free(unit, pup); 1757 cli_out("Failed to start DMA: %s\n", soc_errmsg(rv)); 1758 } 1759 #endif 1760 1761 1762 return(rv < 0 ? CMD_FAIL : CMD_OK); 1763 } 1764 1765 STATIC void 1766 pw_cleanup_dma(int unit) 1767 /* 1768 * Function: pw_cleanup_dma 1769 * Purpose: Clean up outstanding DMA operations. 1770 * Parameters: unit - unit # 1771 * Returns: Nothing. 1772 * 1773 * Notes: Cleans up active DMA operations, and DMA operations that have 1774 * completed but have not been processed yet. 1775 */ 1776 { 1777 pwu_t *pu = &pw_units[unit]; 1778 dma_chan_t chan, dma_chan; 1779 1780 if (soc_feature(unit, soc_feature_cmicx)) { 1781 dma_chan = CMICX_N_DMA_CHAN; 1782 } else { 1783 dma_chan = N_DMA_CHAN; 1784 } 1785 for (chan = 0; chan < dma_chan + 1; chan++) { 1786 1787 /* Clean up Active DMA */ 1788 1789 if (pu->pu_ch_active[chan]) { 1790 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1791 if (SOC_IS_ESW(unit) || SOC_IS_ARAD(unit)) { 1792 (void)soc_dma_abort_dv(unit, pu->pu_ch_active[chan]->pup_esw_dv); 1793 } 1794 #endif 1795 pw_pup_free(unit, (pup_t *)pu->pu_ch_active[chan]); 1796 pu->pu_ch_active[chan] = NULL; 1797 } 1798 1799 } 1800 1801 /* Clean up those that are complete but not processed */ 1802 1803 PW_SPIN_LOCK(unit); 1804 while (pu->pu_pending != NULL) { 1805 pup_t *tp = (pup_t *)pu->pu_pending; 1806 pu->pu_pending = tp->pup_next; 1807 pw_pup_free(unit, tp); 1808 } 1809 PW_SPIN_UNLOCK(unit); 1810 } 1811 1812 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT) 1813 /* 1814 * Function: pw_esw_done_intr 1815 * Purpose: Process a chain done interrupt. 1816 * Parameters: unit - unit # 1817 * dv - pointer to dv_chain associated with request. 1818 * Returns: Nothing. 1819 * 1820 * Notes: All this routine does is wake up the packet watcher 1821 * thread. 1822 */ 1823 STATIC void 1824 pw_esw_done_intr(int unit, dv_t *dv) 1825 { 1826 pwu_t *pu = &pw_units[unit]; 1827 pup_t *pup = (pup_t *)dv->dv_pw_pup; 1828 1829 pu->pu_ch_active[(int)dv->dv_pw_chan + 1] = NULL; 1830 pup->pup_next = NULL; 1831 PW_SPIN_LOCK(unit); 1832 if (pu->pu_pending == NULL) { 1833 pup->pup_prev = pup; 1834 pu->pu_pending = pup; 1835 } else { 1836 pu->pu_pending->pup_prev->pup_next = pup; 1837 pu->pu_pending->pup_prev = pup; 1838 } 1839 PW_SPIN_UNLOCK(unit); 1840 1841 sal_sem_give(pw_units[unit].pu_sema); 1842 } 1843 #endif /* BCM_ESW_SUPPORT */