cputrans.c (29683B)
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 * File: cputrans.c 8 * Purpose: TX and RX packet management routines 9 * Requires: bcm_trans_ptr_t structure 10 */ 11 12 #include <shared/bsl.h> 13 14 #include <appl/cputrans/cputrans.h> 15 16 #include <sal/core/sync.h> 17 #include <sal/core/libc.h> 18 #include <shared/alloc.h> 19 20 /* Currently used for sal_dma_alloc */ 21 #include <sal/appl/sal.h> 22 23 #include <bcm/error.h> 24 #include <bcm/pkt.h> 25 #include <bcm/rx.h> 26 #include <bcm_int/control.h> 27 28 #include "t_util.h" 29 30 /* MUTEX used by both RX and TX allocation routines */ 31 32 static sal_mutex_t ct_lock; 33 #define CPUTRANS_LOCK sal_mutex_take(ct_lock, sal_sem_FOREVER) 34 #define CPUTRANS_UNLOCK sal_mutex_give(ct_lock) 35 36 /**************************************************************** 37 * 38 * TX packet setup and allocation 39 * 40 * There is one free list of TX packets. Each TX packet has two 41 * data pointers allocated and one header buffer allocated. If the 42 * header buffer is not used, it is placed in the second pointer 43 * block and the number of blocks for the packet (blk_count) is 44 * set to 1. 45 * 46 * 47 * Static variables: 48 * _tx_trans_ptr Local transport driver list 49 * _tx_setup_done Boolean; packets allocated? 50 * _tx_pkt_free_list Head of TX packet free list 51 * _tx_pkts Allocation pointer for all TX packets 52 * _tx_pkt_blks Allocation pointer for all TX data pointer blocks 53 * _tx_header_data Allocation pointer for all header data 54 */ 55 56 static bcm_trans_ptr_t _tx_trans_ptr; 57 #define INIT_DONE (ct_lock != NULL) 58 #define CHECK_INIT if (!INIT_DONE) BCM_IF_ERROR_RETURN(_do_init()) 59 60 static int _tx_setup_done; 61 static bcm_pkt_t *_tx_pkt_free_list; 62 static bcm_pkt_t *_tx_pkts; 63 static bcm_pkt_blk_t *_tx_pkt_blks; 64 static uint8 *_tx_header_data; 65 66 /* This indicates an error which may cause internal corruption has been seen */ 67 volatile int cputrans_error_count; 68 #define CPUTRANS_ERROR_INCR (++cputrans_error_count) 69 70 /* Do local initalization */ 71 STATIC int 72 _do_init(void) 73 { 74 ct_lock = sal_mutex_create("ct_tx_lock"); 75 if (ct_lock == NULL) { 76 return BCM_E_MEMORY; 77 } 78 79 return BCM_E_NONE; 80 } 81 82 83 /* Group allocate and free macros */ 84 85 #define _ALLOC_CHECK(id, bytes, _cleanup, _str) \ 86 do { \ 87 (id) = sal_alloc((bytes), (_str)); \ 88 if ((id) == NULL) { \ 89 (_cleanup)(); \ 90 CPUTRANS_UNLOCK; \ 91 return BCM_E_MEMORY; \ 92 } \ 93 sal_memset((id), 0, bytes); \ 94 } while (0) 95 96 #define _FREE_CHECK(id) \ 97 do { \ 98 if ((id) != NULL) { \ 99 sal_free(id); \ 100 (id) = NULL; \ 101 } \ 102 } while (0) 103 104 /* 105 * Function: 106 * cputrans_tx_setup_done 107 * Purpose: 108 * Indicate if setup has been done for cputrans subsys 109 * Returns: 110 * Boolean: True if setup has been done 111 */ 112 113 int 114 cputrans_tx_setup_done(void) 115 { 116 return _tx_setup_done; 117 } 118 119 #define _TX_RESERVE_MAX BCM_COS_MAX 120 static int tx_reserve[_TX_RESERVE_MAX + 1] = CPUTRANS_TX_RESERVE_DEFAULT; 121 static int tx_pkts_avail; 122 static int tx_pool_size; 123 124 /* 125 * Function: 126 * cputrans_tx_pkt_setup 127 * Purpose: 128 * Setup the CPU transport tx packet pool 129 * Parameters: 130 * pkt_pool_size - Number of packets to use in pool; 131 * trans_ptr - Pointer to transport driver (for salloc/sfree). 132 * Returns: 133 * BCM_E_XXX 134 * Notes: 135 * If pkt_pool_size <= 0, use default value. 136 */ 137 138 int 139 cputrans_tx_pkt_setup(int pkt_pool_size, bcm_trans_ptr_t *trans_ptr) 140 { 141 int bytes; 142 int i; 143 bcm_pkt_t *pkt; 144 145 CHECK_INIT; 146 if (_tx_setup_done) { 147 return BCM_E_BUSY; 148 } 149 150 if (trans_ptr->tp_data_alloc == NULL || 151 trans_ptr->tp_data_free == NULL) { 152 return BCM_E_PARAM; 153 } 154 sal_memcpy(&_tx_trans_ptr, trans_ptr, sizeof(bcm_trans_ptr_t)); 155 156 if (pkt_pool_size <= 0) { 157 pkt_pool_size = CPUTRANS_PKT_POOL_SIZE_DEFAULT; 158 } 159 tx_pkts_avail = pkt_pool_size; 160 tx_pool_size = pkt_pool_size; 161 162 /* Allocate static data for TX queues */ 163 bytes = pkt_pool_size * CPUTRANS_HEADER_BYTES; 164 _tx_header_data = sal_dma_alloc(bytes, "CT_HDR"); 165 if (_tx_header_data == NULL) { 166 cputrans_tx_pkt_cleanup(); 167 return BCM_E_MEMORY; 168 } 169 170 /* Allocate tx pkts then data block ptrs, two per packet */ 171 bytes = pkt_pool_size * sizeof(bcm_pkt_t); 172 _ALLOC_CHECK(_tx_pkts, bytes, cputrans_tx_pkt_cleanup, "ct_tx_pkts"); 173 174 bytes = pkt_pool_size * 2 * sizeof(bcm_pkt_blk_t); 175 _ALLOC_CHECK(_tx_pkt_blks, bytes, cputrans_tx_pkt_cleanup, "ct_pkt_blks"); 176 177 /* Give each tx packet a header buffer and link to freelist */ 178 for (i = 0; i < pkt_pool_size; i++) { 179 _tx_pkts[i].next = &_tx_pkts[i + 1]; 180 pkt = &_tx_pkts[i]; 181 pkt->pkt_data = &_tx_pkt_blks[2 * i]; 182 pkt->pkt_data[0].data = &_tx_header_data[i * CPUTRANS_HEADER_BYTES]; 183 pkt->pkt_data[0].len = CPUTRANS_HEADER_BYTES; 184 pkt->flags = BCM_TX_CRC_APPEND; 185 } 186 _tx_pkts[i - 1].next = NULL; 187 _tx_pkt_free_list = _tx_pkts; 188 189 _tx_setup_done = TRUE; 190 191 return BCM_E_NONE; 192 } 193 194 /* 195 * Function: 196 * cputrans_tx_pkt_cleanup 197 * Purpose: 198 * Cleanup and deallocate static packet data for CPU transport 199 */ 200 201 void 202 cputrans_tx_pkt_cleanup(void) 203 { 204 if (!INIT_DONE) { 205 return; 206 } 207 208 CPUTRANS_LOCK; 209 210 if (_tx_header_data != NULL) { 211 sal_dma_free(_tx_header_data); 212 _tx_header_data = NULL; 213 } 214 215 _FREE_CHECK(_tx_pkts); 216 _FREE_CHECK(_tx_pkt_blks); 217 _tx_setup_done = FALSE; 218 219 CPUTRANS_UNLOCK; 220 } 221 222 /* Grab (extra_pkt_count + 1) packets from free list; return NULL if fails */ 223 static INLINE bcm_pkt_t * 224 grab_packets(int extra_pkt_count, int cos, uint32 ct_flags) 225 { 226 int _i; 227 bcm_pkt_t *_pkt; 228 bcm_pkt_t *first_pkt; 229 230 if (cos > _TX_RESERVE_MAX) { 231 return NULL; 232 } 233 234 CPUTRANS_LOCK; 235 if (_tx_pkt_free_list == NULL) { 236 CPUTRANS_UNLOCK; 237 return NULL; 238 } 239 if (cos >= 0) { 240 if (tx_pkts_avail - (extra_pkt_count + 1) < tx_reserve[cos]) { 241 CPUTRANS_UNLOCK; 242 return NULL; 243 } 244 } 245 _pkt = first_pkt = _tx_pkt_free_list; 246 _pkt->flags = BCM_TX_CRC_APPEND; 247 for (_i = 0; _i < extra_pkt_count; _i++) { 248 if (_pkt->next == NULL) { 249 CPUTRANS_UNLOCK; 250 return NULL; 251 } 252 _pkt = _pkt->next; 253 _pkt->flags = BCM_TX_CRC_APPEND; 254 } 255 /* pkt now points to last pkt in alloc chain. */ 256 _tx_pkt_free_list = _pkt->next; 257 _pkt->next = NULL; 258 first_pkt->_last_pkt = _pkt; 259 tx_pkts_avail -= (extra_pkt_count + 1); 260 261 if (ct_flags & CPUTRANS_CRC_REGEN) { 262 _pkt->flags = BCM_TX_CRC_REGEN; 263 } /* else, leave as append */ 264 265 CPUTRANS_UNLOCK; 266 267 return first_pkt; 268 } 269 270 /* See notes for cputrans_tx_alloc_empty_set below */ 271 272 /* 273 * Function: 274 * cputrans_tx_alloc_limit_set/get 275 * Purpose: 276 * Set the level at which the tx pkt alloc pool appears empty to a COS 277 * Parameters: 278 * cos - The COS whose low marker should be set 279 * reserve - Keep this many pkts available in pool; see Notes. 280 * Returns: 281 * BCM_E_XXX 282 * Notes: 283 * When an allocation request is made and the COS override flag 284 * is set in the ct_flags, the COS is extracted from the flags 285 * and a "pkt reserve" is checked. This represents the number of 286 * packets that must remain in the queue after the allocation. If 287 * not enough packets remain, the allocation will fail and return NULL. 288 * 289 * Normally, reserve is set to 0 for the highest COS. Allocations 290 * can be disabled for a COS by setting reserve >= pkt_pool_size 291 * (though this is not recommended). 292 */ 293 294 int 295 cputrans_tx_alloc_limit_set(int cos, int reserve) 296 { 297 if (cos < 0 || cos > _TX_RESERVE_MAX) { 298 return BCM_E_PARAM; 299 } 300 301 tx_reserve[cos] = reserve; 302 303 return BCM_E_NONE; 304 } 305 306 int 307 cputrans_tx_alloc_limit_get(int cos, int *reserve) 308 { 309 if (cos < 0 || cos > _TX_RESERVE_MAX) { 310 return BCM_E_PARAM; 311 } 312 313 *reserve = tx_reserve[cos]; 314 315 return BCM_E_NONE; 316 } 317 318 /* 319 * Function: 320 * cputrans_tx_pkt_alloc 321 * Purpose: 322 * Allocate a packet from the CPU trans pool 323 * Parameters: 324 * pkt_buf - Pointer to data to link to packet 325 * len - Length of packet buffer 326 * ct_flags - Flags for pkt: Mainly 327 * NO_HEADER_ALLOC: The header space is in pkt_buf 328 * CPUTRANS_COS_OVERRIDE: cos to check for packet allocation 329 * Returns: 330 * Pointer to packet or NULL if failed. 331 * Notes: 332 * Whether or not the header is in a separate block is indicated 333 * by the pkt->blk_count value. 334 * blk_count == 1 => Header is at start of pkt_buf in pkt_data[0] 335 * blk_count == 2 => Header is pkt_data[0], pkt_buf in pkt_data[1] 336 */ 337 338 bcm_pkt_t * 339 cputrans_tx_pkt_alloc(uint8 *pkt_buf, int len, uint32 ct_flags) 340 { 341 bcm_pkt_t *pkt; 342 int pkt_blk; 343 int cos = -1; 344 345 if (!_tx_setup_done) { 346 return NULL; 347 } 348 349 if (ct_flags & CPUTRANS_COS_OVERRIDE) { 350 cos = CPUTRANS_COS_GET(ct_flags); 351 } 352 /* Will return NULL if error */ 353 pkt = grab_packets(0, cos, ct_flags); 354 if (pkt == NULL) { 355 return NULL; 356 } 357 358 if (ct_flags & CPUTRANS_NO_HEADER_ALLOC) { 359 /* Save header buffer in data 1 */ 360 sal_memcpy(&pkt->pkt_data[1], &pkt->pkt_data[0], 361 sizeof(bcm_pkt_blk_t)); 362 pkt_blk = 0; 363 pkt->blk_count = 1; 364 } else { /* Header in first block */ 365 pkt_blk = 1; 366 pkt->blk_count = 2; 367 } 368 369 /* Put data pointers in proper place. */ 370 pkt->pkt_data[pkt_blk].data = pkt_buf; 371 pkt->pkt_data[pkt_blk].len = len; 372 /* Mark as a single packet, not in a linked list */ 373 pkt->next = NULL; 374 375 return pkt; 376 } 377 378 /* 379 * Function: 380 * cputrans_tx_pkt_list_alloc 381 * Purpose: 382 * Allocate a list of packets and segment the packet buffer 383 * Parameters: 384 * pkt_buf - Pointer to data to link to packet 385 * len - Length of packet buffer 386 * seg_len - Number of bytes in each segment, not including header 387 * ct_flags - Flags for pkt: Mainly 388 * NO_HEADER_ALLOC: The header space is in pkt_buf 389 * CPUTRANS_COS_OVERRIDE: cos to check for packet allocation 390 * num_pkt - (OUT) How many packets allocated 391 * Returns: 392 * BCM_E_XXX 393 * Notes: 394 * The last packet pointer is stored in _last_pkt of the first 395 * packet. The "next" pointers should not be 396 * altered in the list. CPUTRANS headers are always provided 397 * for the second, third... packets. The NO_HEADER_ALLOC flag 398 * only applies to the first buffer. 399 * 400 * The MTU for the channel must be at least seg_len + header_bytes. 401 * 402 * If NO_HEADER_ALLOC is set, then the length of the first chunk 403 * of data taken from pkt_buf is (seg_len + header_bytes). This way, 404 * there are always seg_len bytes of payload per packet. 405 */ 406 407 bcm_pkt_t * 408 cputrans_tx_pkt_list_alloc(uint8 *pkt_buf, int len, int seg_len, 409 uint32 ct_flags, int *num_segs) 410 { 411 bcm_pkt_t *first_pkt; 412 bcm_pkt_t *pkt; 413 int extra_pkt_count; 414 int offset; 415 int i; 416 int pkt_blk = 0; 417 int len_fld_val = 0x601; /* What goes in the pkt's length fld */ 418 int cos = -1; 419 420 if (!_tx_setup_done) { 421 return NULL; 422 } 423 424 extra_pkt_count = (len - 1) / seg_len; /* Packets needed beyond first */ 425 426 if (ct_flags & CPUTRANS_COS_OVERRIDE) { 427 cos = CPUTRANS_COS_GET(ct_flags); 428 } 429 430 /* Will return NULL if error */ 431 first_pkt = grab_packets(extra_pkt_count, cos, ct_flags); 432 if (first_pkt == NULL) { 433 return NULL; 434 } 435 436 if (num_segs != NULL) { 437 *num_segs = extra_pkt_count + 1; 438 } 439 440 offset = seg_len; /* Where second packet starts in payload */ 441 if (ct_flags & CPUTRANS_NO_HEADER_ALLOC) { 442 /* Save header buffer in data 1 */ 443 sal_memcpy(&first_pkt->pkt_data[1], &first_pkt->pkt_data[0], 444 sizeof(bcm_pkt_blk_t)); 445 pkt_blk = 0; 446 first_pkt->blk_count = 1; 447 offset += CPUTRANS_HEADER_BYTES; 448 } else { /* Header in first block */ 449 pkt_blk = 1; 450 first_pkt->blk_count = 2; 451 } 452 453 /* Put data pointers in proper place. */ 454 first_pkt->pkt_data[pkt_blk].data = pkt_buf; 455 first_pkt->call_back = NULL; 456 if (offset >= len) { /* Only one segment needed */ 457 first_pkt->pkt_data[pkt_blk].len = len; 458 PACK_SHORT(&first_pkt->pkt_data[0].data[CPUTRANS_LEN_OFS], 459 len_fld_val); 460 } else { /* Extra packets */ 461 first_pkt->pkt_data[pkt_blk].len = offset; 462 PACK_SHORT(&first_pkt->pkt_data[0].data[CPUTRANS_LEN_OFS], 463 len_fld_val); 464 /* Segment the rest of the packet */ 465 pkt = first_pkt->next; 466 for (i = 0; i < extra_pkt_count - 1; i++) { /* Not first or last */ 467 pkt->pkt_data[1].data = &pkt_buf[offset]; 468 pkt->pkt_data[1].len = seg_len; 469 PACK_SHORT(&first_pkt->pkt_data[0].data[CPUTRANS_LEN_OFS], 470 len_fld_val); 471 pkt->blk_count = 2; 472 offset += seg_len; 473 pkt = pkt->next; 474 pkt->call_back = NULL; 475 } 476 477 /* Take care of last pkt (pointed to by pkt) */ 478 pkt->pkt_data[1].data = &pkt_buf[offset]; 479 pkt->pkt_data[1].len = len - offset; 480 PACK_SHORT(&first_pkt->pkt_data[0].data[CPUTRANS_LEN_OFS], 481 len_fld_val); 482 pkt->blk_count = 2; 483 pkt->call_back = NULL; 484 } 485 first_pkt->alloc_ptr = pkt_buf; 486 if (first_pkt->next == first_pkt) { 487 LOG_INFO(BSL_LS_TKS_CTPKT, 488 (BSL_META("CT pkt list alloc: Internal corruption in pointers\n"))); 489 CPUTRANS_ERROR_INCR; 490 } 491 492 return first_pkt; 493 } 494 495 496 /* 497 * Function: 498 * cputrans_tx_pkt_list_free 499 * Purpose: 500 * Free a list of packets allocated by cputrans_tx_pkt_list_alloc 501 * Parameters: 502 * pkt - Pointer to start of list 503 * Returns: 504 * BCM_E_XXX 505 * Notes: 506 * Will work for a single packet as well, as long as _last_pkt 507 * points to self. 508 */ 509 510 void 511 cputrans_tx_pkt_list_free(bcm_pkt_t *pkt) 512 { 513 bcm_pkt_t *last_pkt, *t_pkt; 514 int count = 0; 515 516 if (pkt == NULL) { 517 LOG_INFO(BSL_LS_TKS_CTPKT, 518 (BSL_META("CT pkt list free: Packet NULL\n"))); 519 return; 520 } 521 if (pkt->next == pkt) { 522 LOG_INFO(BSL_LS_TKS_CTPKT, 523 (BSL_META("CT pkt list free: Circular list\n"))); 524 pkt->next = NULL; 525 pkt->_last_pkt = pkt; 526 CPUTRANS_ERROR_INCR; 527 } 528 if (pkt->_last_pkt == NULL) { 529 LOG_INFO(BSL_LS_TKS_CTPKT, 530 (BSL_META("CT pkt list free: No last pkt\n"))); 531 pkt->_last_pkt = pkt; 532 CPUTRANS_ERROR_INCR; 533 } 534 /* Check if header is saved in pkt block 1 */ 535 if (pkt->blk_count == 1) { 536 sal_memcpy(&pkt->pkt_data[0], &pkt->pkt_data[1], 537 sizeof(bcm_pkt_blk_t)); 538 } 539 540 for (t_pkt = pkt; t_pkt != NULL; t_pkt = t_pkt->next) { 541 if (count++ > tx_pool_size) { 542 LOG_INFO(BSL_LS_TKS_CTPKT, 543 (BSL_META("CT pkt list free: List too long\n"))); 544 CPUTRANS_ERROR_INCR; 545 return; 546 } 547 } 548 549 last_pkt = pkt->_last_pkt; 550 CPUTRANS_LOCK; 551 last_pkt->next = _tx_pkt_free_list; 552 _tx_pkt_free_list = pkt; 553 tx_pkts_avail += count; 554 CPUTRANS_UNLOCK; 555 } 556 557 558 /**************************************************************** 559 * 560 * RX Packet Setup and Allocation 561 * 562 * RX packets are set up to hold multiple packet blocks for 563 * reassembly. RX packets are not given data pointers; it 564 * is expected that the data will be gotten from the RX call 565 * or allocated by the application using these packets. 566 * 567 * On setup, multiple packets are allocated with block numbers 568 * at powers of two. When rx_pkt_alloc is called, the smallest block 569 * number large enough to satisfy the allocation and with free packets 570 * is used. 571 * 572 * CPUTRANS uses pkt->cookie2 for RX packets to store the index 573 * used, so pkt->cookie2 must NOT be used above this layer. 574 * 575 * CPUTRANS RX does not require a transport pointer; it only 576 * uses sal_alloc and sal_free. 577 * 578 * CPUTRANS RX packets have an extra pointer allocate at the 579 * beginning of the first block's packet buffer. This is used 580 * by ATP/BET and should not be used by applications. 581 * 582 * Static variables: 583 * _rx_setup_done Boolean; packets allocated? 584 * _rx_lists How many categories of packets set up 585 * _rx_free_lists Pointer to array of free list head ptrs 586 * _rx_alloc_pkts Allocation pointer for all RX packets 587 * _rx_pkt_blks Allocation pointer for all data pointer blocks 588 */ 589 590 static int _rx_setup_done; 591 592 static int _rx_lists; 593 static bcm_pkt_t **_rx_free_lists; 594 static bcm_pkt_t *_rx_alloc_pkts; 595 static bcm_pkt_blk_t *_rx_pkt_blks; 596 597 /* 598 * Function: 599 * cputrans_rx_setup_done 600 * Purpose: 601 * Indicate if setup has been done for RX part of cputrans subsys 602 * Returns: 603 * Boolean: True if setup has been done 604 */ 605 606 int 607 cputrans_rx_setup_done(void) 608 { 609 return _rx_setup_done; 610 } 611 612 613 /* 614 * Function: 615 * cputrans_rx_pkt_setup 616 * Purpose: 617 * Pre-allocate and set up RX packets 618 * Parameters: 619 * list_count - The number of lists to provide; if < 0, uses 620 * default values. 621 * blk_cnts - Pointer to an array with list_count entries. See notes. 622 * Returns: 623 * BCM_E_XXX 624 * Notes: 625 * Each entry is the number of packets to allocate with 2^n 626 * packet block pointers. The number of blocks needed by a long 627 * packet is about 2 * (pkt_len/seg_len + 1). With seg_len = 1400 628 * and pkt_len = 64K, this is about 94 blocks, so list count should 629 * generally be <= 8. 630 * 631 * Currently, if a packet is requested with too many blocks, 632 * it fails (no on-the-fly allocation.) 633 */ 634 635 int 636 cputrans_rx_pkt_setup(int list_count, int *blk_cnts) 637 { 638 int tot_pkts = 0; /* How many packets to allocate, total */ 639 int tot_blks = 0; /* How many pkt_blk structs to allocate, total */ 640 int bytes; 641 int pkt_cnt = 0; /* How many pkts filled in so far */ 642 bcm_pkt_t *pkt; 643 int blk_offset = 0; /* How many blocks used up so far */ 644 int i, j; 645 int blks; 646 static int deflt_blk_cnts[] = CPUTRANS_RX_BLK_CNTS_DEFAULT; 647 int deflt_count = CPUTRANS_RX_LIST_COUNT_DEFAULT; 648 649 if (_rx_setup_done) { 650 return BCM_E_BUSY; 651 } 652 653 if (list_count <= 0 || blk_cnts == NULL) { 654 list_count = deflt_count; 655 blk_cnts = deflt_blk_cnts; 656 } 657 _rx_lists = list_count; 658 659 for (i = 0; i < list_count; i++) { 660 tot_pkts += blk_cnts[i]; 661 tot_blks += blk_cnts[i] * (1 << i); 662 } 663 664 bytes = tot_pkts * sizeof(bcm_pkt_t); 665 _ALLOC_CHECK(_rx_alloc_pkts, bytes, cputrans_rx_pkt_cleanup, "CT_RX"); 666 667 bytes = list_count * sizeof(bcm_pkt_t *); 668 _ALLOC_CHECK(_rx_free_lists, bytes, cputrans_rx_pkt_cleanup, "CT_RX"); 669 670 bytes = tot_blks * sizeof(bcm_pkt_blk_t); 671 _ALLOC_CHECK(_rx_pkt_blks, bytes, cputrans_rx_pkt_cleanup, "CT_RX"); 672 673 /* Set up free lists and packet block pointers from the allocated data */ 674 pkt = &_rx_alloc_pkts[0]; /* Keep compiler happy */ 675 for (i = 0; i < list_count; i++) { 676 blks = 1 << i; /* Number of blocks this round */ 677 if (blk_cnts[i] > 0) { 678 _rx_free_lists[i] = &_rx_alloc_pkts[pkt_cnt]; 679 for (j = 0; j < blk_cnts[i]; j++) { 680 pkt = &_rx_alloc_pkts[pkt_cnt + j]; 681 pkt->blk_count = blks; 682 pkt->pkt_data = &_rx_pkt_blks[blk_offset]; 683 pkt->cookie2 = INT_TO_PTR(i); /* Record which free list */ 684 blk_offset += blks; 685 pkt->next = &_rx_alloc_pkts[pkt_cnt + j + 1]; 686 } 687 pkt->next = NULL; /* Terminate list */ 688 pkt_cnt += blk_cnts[i]; 689 } 690 } 691 692 _rx_setup_done = TRUE; 693 694 return BCM_E_NONE; 695 } 696 697 /* 698 * Function: 699 * cputrans_rx_pkt_alloc 700 * Purpose: 701 * Allocate a packet struct with sufficient RX block pointers. 702 * Parameters: 703 * num_blks - The number of blocks needed in the pkt_blk struct 704 * Returns: 705 * BCM_E_XXX 706 * Notes: 707 * Currently, will not allocate beyond the number 708 * set up in cputrans_rx_pkt_setup. Nor will it allocate if there 709 * are no free buffers available. 710 * 711 * Packets allocated with this routine must be freed by a call 712 * to cputrans_rx_pkt_free. 713 */ 714 715 bcm_pkt_t * 716 cputrans_rx_pkt_alloc(int num_blks) 717 { 718 int i; 719 int blks = 1; 720 bcm_pkt_t *pkt = NULL; 721 722 if (!_rx_setup_done) { 723 return NULL; 724 } 725 726 CPUTRANS_LOCK; 727 for (i = 0; i < _rx_lists; i++) { 728 if (num_blks <= blks && _rx_free_lists[i] != NULL) { 729 pkt = _rx_free_lists[i]; 730 _rx_free_lists[i] = pkt->next; 731 break; 732 } 733 blks <<= 1; 734 } 735 CPUTRANS_UNLOCK; 736 737 if (pkt != NULL) { 738 pkt->blk_count = num_blks; 739 } 740 return pkt; 741 } 742 743 744 /* 745 * Function: 746 * cputrans_rx_pkt_free 747 * Purpose: 748 * Free an RX packet allocated by cputrans_rx_pkt_alloc 749 * Parameters: 750 * pkt - pointer to packet to free 751 * Returns: 752 * BCM_E_XXX 753 * Notes: 754 * Should only be called on packets allocated by cputrans_rx_pkt_alloc. 755 */ 756 757 void 758 cputrans_rx_pkt_free(bcm_pkt_t *pkt) 759 { 760 int idx; 761 762 if (pkt == NULL) { 763 LOG_INFO(BSL_LS_TKS_CTPKT, 764 (BSL_META("CT free: Packet NULL\n"))); 765 return; 766 } 767 768 if (!_rx_setup_done) { 769 LOG_INFO(BSL_LS_TKS_CTPKT, 770 (BSL_META("CT free: Not initialized\n"))); 771 return; 772 } 773 774 idx = PTR_TO_INT(pkt->cookie2); 775 if (idx >= _rx_lists) { 776 LOG_INFO(BSL_LS_TKS_CTPKT, 777 (BSL_META("CT free: bad CT index: %d > %d\n"), 778 idx, _rx_lists)); 779 return; 780 } 781 782 CPUTRANS_LOCK; 783 pkt->next = _rx_free_lists[idx]; 784 _rx_free_lists[idx] = pkt; 785 CPUTRANS_UNLOCK; 786 } 787 788 789 /* 790 * Function: 791 * cputrans_rx_pkt_cleanup 792 * Purpose: 793 * Deallocate RX packets for CPUTRANS 794 */ 795 796 void 797 cputrans_rx_pkt_cleanup(void) 798 { 799 if (!INIT_DONE) { /* Create lock */ 800 if (_do_init() < 0) { 801 return; 802 } 803 } 804 805 CPUTRANS_LOCK; 806 _FREE_CHECK(_rx_free_lists); 807 _FREE_CHECK(_rx_alloc_pkts); 808 _FREE_CHECK(_rx_pkt_blks); 809 _rx_lists = 0; 810 _rx_setup_done = FALSE; 811 CPUTRANS_UNLOCK; 812 } 813 814 815 #undef _FREE_CHECK 816 #undef _ALLOC_CHECK 817 818 #define CT_TRANS_MAX 10 819 static bcm_trans_ptr_t *ct_trans[CT_TRANS_MAX]; 820 static int ct_trans_count; 821 822 int 823 cputrans_trans_count(void) 824 { 825 return ct_trans_count; 826 } 827 828 int 829 cputrans_trans_add(bcm_trans_ptr_t *trans) 830 { 831 int i; 832 833 for (i = 0; i < ct_trans_count; i++) { 834 if (ct_trans[i] == trans) { 835 return BCM_E_NONE; 836 } 837 } 838 839 if (ct_trans_count + 1 > CT_TRANS_MAX) { 840 return BCM_E_RESOURCE; 841 } 842 ct_trans[ct_trans_count++] = trans; 843 844 return BCM_E_NONE; 845 } 846 847 int 848 cputrans_trans_remove(bcm_trans_ptr_t *trans) 849 { 850 int i, j; 851 852 for (i = 0; i < ct_trans_count; i++) { 853 if (ct_trans[i] == trans) { 854 for (j = i; j < ct_trans_count - 1; j++) { 855 ct_trans[j] = ct_trans[j + 1]; 856 } 857 ct_trans_count--; 858 return BCM_E_NONE; 859 } 860 } 861 862 return BCM_E_NONE; 863 } 864 865 /* 866 * RX register on all known transports 867 * rx_unit_register -- on the specified unit 868 * rx_bmp_register -- on the specified bitmap of units (unit < 32) 869 * rx_register -- on all local units 870 * 871 * For rx_register and rx_bmp_register, if no units are found or 872 * specified, calls on unit -1. 873 */ 874 875 int 876 cputrans_rx_unit_register(int unit, 877 const char *name, 878 bcm_rx_cb_f callback, 879 uint8 priority, 880 void *cookie, 881 uint32 flags) 882 { 883 int rv = BCM_E_NONE; 884 int tmp_rv; 885 int i; 886 887 for (i = 0; i < ct_trans_count; i++) { 888 if (ct_trans[i]->tp_rx_reg != NULL) { 889 tmp_rv = ct_trans[i]->tp_rx_reg(unit, name, callback, 890 priority, cookie, flags); 891 if (tmp_rv < 0) { 892 rv = tmp_rv; 893 } 894 } 895 } 896 897 return rv; 898 } 899 900 int 901 cputrans_rx_register(const char *name, 902 bcm_rx_cb_f callback, 903 uint8 priority, 904 void *cookie, 905 uint32 flags) 906 { 907 int rv = BCM_E_NONE; 908 int tmp_rv; 909 int found = FALSE; 910 int unit; 911 912 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 913 if (BCM_UNIT_VALID(unit) && BCM_IS_LOCAL(unit)) { 914 found = TRUE; 915 tmp_rv = cputrans_rx_unit_register(unit, name, callback, 916 priority, cookie, flags); 917 if (tmp_rv < 0) { 918 LOG_VERBOSE(BSL_LS_TKS_CTPKT, 919 (BSL_META("CPU Trans reg failed %d, unit %d: %s\n"), 920 rv, unit, bcm_errmsg(rv))); 921 rv = tmp_rv; 922 } 923 } 924 } 925 926 if (!found) { /* Call transport pointers on unit -1 */ 927 tmp_rv = cputrans_rx_unit_register(-1, name, callback, priority, 928 cookie, flags); 929 if (tmp_rv < 0) { 930 LOG_VERBOSE(BSL_LS_TKS_CTPKT, 931 (BSL_META("CPU Trans reg failed %d, dflt unit: %s\n"), 932 rv, bcm_errmsg(rv))); 933 rv = tmp_rv; 934 } 935 } 936 937 return rv; 938 } 939 940 int 941 cputrans_rx_bmp_register(uint32 unit_bmp, 942 const char *name, 943 bcm_rx_cb_f callback, 944 uint8 priority, 945 void *cookie, 946 uint32 flags) 947 { 948 int rv = BCM_E_NONE; 949 int tmp_rv; 950 int unit; 951 952 if (unit_bmp == 0) { 953 rv = cputrans_rx_unit_register(-1, name, callback, priority, 954 cookie, flags); 955 } else { 956 for (unit = 0; unit < 32; unit++) { 957 if (BCM_UNIT_VALID(unit) && BCM_IS_LOCAL(unit) && 958 ((1 << unit) & unit_bmp)) { 959 tmp_rv = cputrans_rx_unit_register(unit, name, 960 callback, priority, 961 cookie, flags); 962 if (tmp_rv < 0) { 963 rv = tmp_rv; 964 } 965 } 966 } 967 } 968 969 return rv; 970 } 971 972 973 /* 974 * RX unregister on all known transports 975 */ 976 977 int 978 cputrans_rx_unit_unregister(int unit, bcm_rx_cb_f callback, uint8 priority) 979 { 980 int rv = BCM_E_NONE; 981 int tmp_rv; 982 int i; 983 984 for (i = 0; i < ct_trans_count; i++) { 985 if (ct_trans[i]->tp_rx_unreg != NULL) { 986 tmp_rv = ct_trans[i]-> 987 tp_rx_unreg(unit, callback, priority); 988 if (tmp_rv < 0) { 989 rv = tmp_rv; 990 } 991 } 992 } 993 994 return rv; 995 } 996 997 int 998 cputrans_rx_unregister(bcm_rx_cb_f callback, uint8 priority) 999 { 1000 int rv = BCM_E_NONE; 1001 int tmp_rv; 1002 int unit; 1003 int found = FALSE; 1004 1005 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 1006 if (BCM_UNIT_VALID(unit) && BCM_IS_LOCAL(unit)) { 1007 found = TRUE; 1008 tmp_rv = cputrans_rx_unit_unregister(unit, callback, priority); 1009 if (tmp_rv < 0) { 1010 rv = tmp_rv; 1011 } 1012 } 1013 } 1014 1015 if (!found) { /* Call transport pointers on unit -1 */ 1016 tmp_rv = cputrans_rx_unit_unregister(-1, callback, priority); 1017 if (tmp_rv < 0) { 1018 rv = tmp_rv; 1019 } 1020 } 1021 1022 return rv; 1023 } 1024 1025 int 1026 cputrans_rx_bmp_unregister(uint32 unit_bmp, 1027 bcm_rx_cb_f callback, 1028 uint8 priority) 1029 { 1030 int rv = BCM_E_NONE; 1031 int tmp_rv; 1032 int unit; 1033 1034 if (unit_bmp == 0) { 1035 rv = cputrans_rx_unit_unregister(-1, callback, priority); 1036 } else { 1037 for (unit = 0; unit < 32; unit++) { 1038 if (BCM_UNIT_VALID(unit) && BCM_IS_LOCAL(unit) && 1039 ((1 << unit) & unit_bmp)) { 1040 tmp_rv = cputrans_rx_unit_unregister(unit, callback, priority); 1041 if (tmp_rv < 0) { 1042 rv = tmp_rv; 1043 } 1044 } 1045 } 1046 } 1047 1048 return rv; 1049 } 1050 1051 1052 /* 1053 * Function: 1054 * cputrans_error_count_get 1055 * Purpose: 1056 * Get and optionally clear the error count in this layer 1057 * Parameters: 1058 * clear - Boolean: If set, will clear the error counter 1059 * Returns: 1060 * BCM_E_XXX 1061 */ 1062 1063 int 1064 cputrans_error_count_get(int clear) 1065 { 1066 int cur_cnt; 1067 1068 cur_cnt = cputrans_error_count; 1069 if (clear) { 1070 cputrans_error_count = 0; 1071 } 1072 1073 return cur_cnt; 1074 }