lplist.c (17017B)
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: lplist.c 8 * Purpose: Logical port list functions 9 * Requires: 10 * 11 * Notes: The following is intended: 12 * 13 * bcmx_lplist_t alist; 14 * 15 * ... list is built up with some elements .... 16 * 17 * if (!bcmx_lplist_init(alist, 0, 0)) { 18 * 19 * ... list is built up with some elements, then .... 20 * 21 * BCMX_LPLIST_ITER(alist, lport, count) { 22 * .... do stuff with lport .... 23 * } 24 * } 25 */ 26 27 #include <sdk_config.h> 28 #include <sal/core/libc.h> 29 #include <shared/alloc.h> 30 31 #include <bcm/error.h> 32 33 #include <bcmx/bcmx.h> 34 #include <bcmx/lplist.h> 35 36 /* This is min size of a list when allocated. */ 37 #ifndef BCMX_LPLIST_MIN_COUNT 38 #define BCMX_LPLIST_MIN_COUNT 16 39 #endif 40 41 /* This is the increment when reallocating */ 42 #ifndef BCMX_LPLIST_MIN_INCREMENT 43 #define BCMX_LPLIST_MIN_INCREMENT 16 44 #endif 45 46 /* Is list empty? */ 47 #define LP_EMPTY(list) ((list)->lp_last < 0) 48 49 /* Number of elements currently in list */ 50 #define LP_COUNT(list) ((list)->lp_last + 1) 51 52 /* Size of an 'n' list elements */ 53 #define LP_ELSIZE(n) ((n) * sizeof(bcmx_lport_t)) 54 55 /* Next free cell on the list. No updates to list. */ 56 #define LP_FIRST_FREE(list) ((list)->lp_ports[(list)->lp_last + 1]) 57 58 /* 59 * Function: 60 * _bcmx_lplist_realloc 61 * Purpose: 62 * Re-allocate a port list 63 * Parameters: 64 * list - The port list to change 65 * new_count - The new count of ports 66 * Returns: 67 * BCM_E_XXX 68 */ 69 70 STATIC int 71 _bcmx_lplist_realloc(bcmx_lplist_t *list, int new_count) 72 { 73 bcmx_lport_t *old_ports; 74 75 if (list == NULL || list->lp_ports == NULL) { 76 return BCM_E_INTERNAL; 77 } 78 79 old_ports = list->lp_ports; 80 81 list->lp_ports = (bcmx_lport_t *) 82 sal_alloc(LP_ELSIZE(new_count), "lplist"); 83 84 if (!list->lp_ports) { 85 list->lp_ports = old_ports; 86 return BCM_E_MEMORY; 87 } 88 89 sal_memcpy(list->lp_ports, old_ports, LP_ELSIZE(LP_COUNT(list))); 90 91 list->lp_alloc = new_count; 92 93 sal_free(old_ports); 94 95 return BCM_E_NONE; 96 } 97 98 /* 99 * Function: 100 * bcmx_lplist_init 101 * Purpose: 102 * Allocate and initialize a port list 103 * Parameters: 104 * list - The port list to initialize 105 * init_count - The initial count to use 106 * flags - List flags - deprecated and ignored 107 * Returns: 108 * BCM_E_XXX 109 * Notes: 110 * If successful, then list->lp_max != 0. 111 * At least BCMX_LPLIST_MIN_COUNT ports will be allocated. 112 * The port list structure itself must be allocated already 113 * (that is, list != NULL). 114 */ 115 116 int 117 bcmx_lplist_init(bcmx_lplist_t *list, int init_count, uint32 flags) 118 { 119 int ports = BCMX_LPLIST_MIN_COUNT; 120 121 if (!list) { 122 return BCM_E_PARAM; 123 } 124 125 if (init_count > ports) { 126 ports = init_count; 127 } 128 129 list->lp_ports = sal_alloc(LP_ELSIZE(ports), "lpports"); 130 if (!list->lp_ports) { 131 return BCM_E_MEMORY; 132 } 133 134 list->lp_alloc = ports; 135 list->lp_last = -1; 136 137 return BCM_E_NONE; 138 } 139 140 /* 141 * Function: 142 * bcmx_lplist_t_init 143 * Purpose: 144 * Initialize the bcmx_lplist_t structure. 145 * Allocate and initialize a port list. 146 * Parameters: 147 * list - Pointer to port list structure to initialize 148 * Returns: 149 * None 150 * Note: 151 * Although the functionality of this routine is also provided by 152 * bcmx_lplist_init, this has an API interface consistent 153 * with other structure initialization/free routines. 154 */ 155 void 156 bcmx_lplist_t_init(bcmx_lplist_t *list) 157 { 158 bcmx_lplist_init(list, 0, 0); 159 } 160 161 /* 162 * Function: 163 * bcmx_lplist_free 164 * Purpose: 165 * De-allocate a port list 166 * Parameters: 167 * list - The port list to de-allocate 168 * Returns: 169 * BCM_E_XXX 170 */ 171 172 int 173 bcmx_lplist_free(bcmx_lplist_t *list) 174 { 175 int rv = BCM_E_PARAM; 176 177 if (!bcmx_lplist_is_null(list)) { 178 if (list->lp_ports) { 179 sal_free(list->lp_ports); 180 } 181 list->lp_ports = 0; 182 rv = BCM_E_NONE; 183 } 184 185 return rv; 186 } 187 188 /* 189 * Function: 190 * bcmx_lplist_t_free 191 * Purpose: 192 * De-allocate a port list 193 * Parameters: 194 * list - The port list to de-allocate 195 * Returns: 196 * None 197 * Note: 198 * Although the functionality of this routine is also provided by 199 * bcmx_lplist_free, this has an API interface consistent 200 * with other structure initialization/free routines. 201 */ 202 void 203 bcmx_lplist_t_free(bcmx_lplist_t *list) 204 { 205 bcmx_lplist_free(list); 206 } 207 208 /* 209 * Function: 210 * bcmx_lplist_clear 211 * Purpose: 212 * Make a port list empty 213 * Parameters: 214 * list - The port list to clear 215 * Returns: 216 * BCM_E_XXX 217 * Notes: 218 */ 219 220 int 221 bcmx_lplist_clear(bcmx_lplist_t *list) 222 { 223 if (!bcmx_lplist_is_null(list)) { 224 list->lp_last = -1; 225 } 226 227 return BCM_E_NONE; 228 } 229 230 231 /**************************************************************** 232 * 233 * The base Logical Port List functions. 234 * 235 * See also the macros BCMX_LPLIST_REMOVE, etc. 236 */ 237 238 239 /* 240 * Function: 241 * bcmx_lplist_index_get 242 * Purpose: 243 * Get the index of the first occurrance of a port on the list 244 * Parameters: 245 * list -- The list to search 246 * Returns: 247 * Index >= 0 if found; otherwise BCM_E_NOT_FOUND 248 */ 249 250 int 251 bcmx_lplist_index_get(bcmx_lplist_t *list, bcmx_lport_t port) 252 { 253 return bcmx_lplist_index_get_from(list, 0, port); 254 } 255 256 257 /* 258 * Function: 259 * bcmx_lplist_index_get_from 260 * Purpose: 261 * Get the index of the first occurrance of a port on the list 262 * starting at position 263 * Parameters: 264 * list -- The list to search 265 * position -- The position to start the search 266 * Returns: 267 * BCM_E_PARAM if position is out of range 268 * Index >= 0 if found; otherwise BCM_E_NOT_FOUND 269 */ 270 271 int 272 bcmx_lplist_index_get_from(bcmx_lplist_t *list, int position, bcmx_lport_t port) 273 { 274 int i; 275 276 if (bcmx_lplist_is_empty(list)) { 277 return BCM_E_NOT_FOUND; 278 } 279 280 if (position < 0 || position > list->lp_last) { 281 return BCM_E_PARAM; 282 } 283 284 for (i = position; i <= list->lp_last; i++) { 285 if (list->lp_ports[i] == port) { 286 return i; 287 } 288 } 289 290 return BCM_E_NOT_FOUND; 291 } 292 293 /* 294 * Function: 295 * bcmx_lplist_index 296 * Purpose: 297 * Get the lport at position 298 * Parameters: 299 * list -- The list to index 300 * position -- The position to retrieve lport 301 * Returns: 302 * BCMX_NO_SUCH_LPORT if position is out of range 303 * otherwise lport 304 */ 305 306 bcmx_lport_t 307 bcmx_lplist_index(bcmx_lplist_t *list, int position) 308 { 309 bcmx_lport_t lport = BCMX_NO_SUCH_LPORT; 310 311 if (!bcmx_lplist_is_null(list) && 312 position >= 0 && position <= list->lp_last) { 313 lport = list->lp_ports[position]; 314 } 315 316 return lport; 317 } 318 319 /* 320 * Function: 321 * bcmx_lplist_add 322 * Purpose: 323 * Add a port to the end of a lplist 324 * Parameters: 325 * list -- The list to update 326 * lport -- The port to add 327 * Returns: 328 * BCM_E_XXX 329 * Notes: 330 * Will initialize the list if it is NULL. 331 * Reallocates if not enough space for list. 332 */ 333 334 int 335 bcmx_lplist_add(bcmx_lplist_t *list, bcmx_lport_t lport) 336 { 337 if (bcmx_lplist_is_null(list)) { 338 BCM_IF_ERROR_RETURN(bcmx_lplist_init(list, -1, 0)); 339 } 340 341 if (BCMX_LPLIST_COUNT(list) + 1 >= list->lp_alloc) { 342 if (_bcmx_lplist_realloc(list, list->lp_alloc + 343 BCMX_LPLIST_MIN_INCREMENT) 344 != BCM_E_NONE) { 345 return BCM_E_MEMORY; 346 } 347 } 348 349 (list->lp_last)++; 350 list->lp_ports[list->lp_last] = lport; 351 352 return BCM_E_NONE; 353 } 354 355 356 /* 357 * Function: 358 * _bcmx_lplist_pbmp_add 359 * Purpose: 360 * 361 * Parameters: 362 * list - The port list to access 363 * unit 364 * pbm 365 * Returns: 366 * Notes: 367 */ 368 369 370 int 371 _bcmx_lplist_pbmp_add(bcmx_lplist_t *list, int unit, bcm_pbmp_t pbm) 372 { 373 bcmx_lport_t lport; 374 bcm_port_t port; 375 int rv = BCM_E_NONE; 376 377 BCM_PBMP_ITER(pbm, port) { 378 lport = bcmx_unit_port_to_lport(unit, port); 379 rv = bcmx_lplist_add(list, lport); 380 if (rv < 0) { 381 break; 382 } 383 } 384 385 return rv; 386 } 387 388 /* 389 * Function: 390 * bcmx_lplist_port_remove 391 * Purpose: 392 * Remove a port from the list. 393 * Parameters: 394 * list - The list to act on 395 * lport - The logical port to look for and remove 396 * all - If true, remove all occurances; otherwise just first. 397 * Returns: 398 * BCM_E_PARAM - parameter error 399 * BCM_E_NONE - port removed 400 * Notes: 401 */ 402 403 int 404 bcmx_lplist_port_remove(bcmx_lplist_t *list, bcmx_lport_t lport, int all) 405 { 406 int rv = BCM_E_NONE; 407 int count = 0; 408 int idx = 0; 409 410 while ((idx=bcmx_lplist_index_get_from(list, idx, lport)) >= 0) { 411 count++; 412 bcmx_lplist_idx_remove(list, idx); 413 if (!all || (idx > list->lp_last)) { 414 break; 415 } 416 } 417 418 if ((idx < 0 && idx != BCM_E_NOT_FOUND) || count == 0) { 419 rv = idx; 420 } 421 422 423 return rv; 424 } 425 426 /* 427 * Function: 428 * bcmx_lplist_eq 429 * Purpose: 430 * Compare two port lists 431 * Parameters: 432 * list1 - List to examine 433 * list2 - List to examine 434 * Returns: 435 * 1 if equal, 0 if not 436 * Notes: 437 * Just a simple check that every port in one list is in the other. 438 * Thus it doesn't detect differences in order or multiplicity. 439 */ 440 441 int 442 bcmx_lplist_eq(bcmx_lplist_t *list1, bcmx_lplist_t *list2) 443 { 444 bcmx_lport_t lport; 445 int count; 446 int list1_empty, list2_empty; 447 448 list1_empty = bcmx_lplist_is_empty(list1); 449 list2_empty = bcmx_lplist_is_empty(list2); 450 451 if (list1_empty && list2_empty) { 452 /* Both lists are empty */ 453 return 1; 454 } else if (list1_empty != list2_empty) { 455 /* One list is empty, the other not empty */ 456 return 0; 457 } else { 458 /* Both lists not empty */ 459 BCMX_LPLIST_IDX_ITER(list1, lport, count) { 460 if (bcmx_lplist_index_get(list2, lport) < 0) { 461 return 0; 462 } 463 } 464 465 BCMX_LPLIST_IDX_ITER(list2, lport, count) { 466 if (bcmx_lplist_index_get(list1, lport) < 0) { 467 return 0; 468 } 469 } 470 } 471 return 1; 472 } 473 474 /* 475 * Function: 476 * bcmx_lplist_append 477 * Purpose: 478 * Copy list2 to end of list1 479 * Parameters: 480 * list1 - List to change 481 * list2 - List copied onto the end of list1 482 * 483 * Returns: 484 * BCM_E_XXX 485 * Notes: 486 * Does not support sorted lists. 487 * Does not support extra flags for port types 488 */ 489 490 int 491 bcmx_lplist_append(bcmx_lplist_t *list1, bcmx_lplist_t *list2) 492 { 493 int total; 494 495 if (bcmx_lplist_is_null(list1)) { 496 BCM_IF_ERROR_RETURN(bcmx_lplist_init(list1, -1, 0)); 497 } 498 499 if (bcmx_lplist_is_empty(list2)) { 500 return BCM_E_NONE; 501 } 502 503 total = LP_COUNT(list1) + LP_COUNT(list2); 504 if (list1->lp_alloc <= total) { 505 BCM_IF_ERROR_RETURN(_bcmx_lplist_realloc(list1, 506 total + BCMX_LPLIST_MIN_INCREMENT)); 507 } 508 509 sal_memcpy(&(LP_FIRST_FREE(list1)), list2->lp_ports, 510 LP_ELSIZE(LP_COUNT(list2))); 511 512 list1->lp_last += LP_COUNT(list2); 513 514 return BCM_E_NONE; 515 } 516 517 /* 518 * Function: 519 * bcmx_lplist_copy 520 * Purpose: 521 * Copy src to dest, overwriting dest 522 * Parameters: 523 * dest - Destination list 524 * src - Source list 525 * Returns: 526 * BCM_E_XXX 527 * Notes: 528 */ 529 530 int 531 bcmx_lplist_copy(bcmx_lplist_t *dest, bcmx_lplist_t *src) 532 { 533 if (bcmx_lplist_is_null(dest)) { 534 BCM_IF_ERROR_RETURN(bcmx_lplist_init(dest, -1, 0)); 535 } 536 537 if (bcmx_lplist_is_empty(src)) { 538 return bcmx_lplist_clear(dest); 539 } 540 541 dest->lp_last = 0; 542 if (dest->lp_alloc < src->lp_alloc) { 543 BCM_IF_ERROR_RETURN(_bcmx_lplist_realloc(dest, src->lp_alloc)); 544 } 545 546 sal_memcpy(dest->lp_ports, src->lp_ports, LP_ELSIZE(LP_COUNT(src))); 547 dest->lp_last = src->lp_last; 548 549 return BCM_E_NONE; 550 } 551 552 553 554 /* Current absolute max for number of logical ports in a list */ 555 #ifndef BCMX_LPLIST_ABSOLUTE_MAX_LEN 556 #define BCMX_LPLIST_ABSOLUTE_MAX_LEN 3000 557 #endif 558 559 /* 560 * Function: 561 * bcmx_lplist_check 562 * Purpose: 563 * Debug function. Check the consistency of a list 564 * Parameters: 565 * list - List to examine 566 * Returns: 567 * 0 if okay, < 0 if not consistent 568 */ 569 570 int 571 bcmx_lplist_check(bcmx_lplist_t *list) 572 { 573 if (!list) { 574 return -1; 575 } 576 577 if (!list->lp_ports) { 578 return -2; 579 } 580 581 if (list->lp_alloc < 0) { 582 return -3; 583 } 584 585 if (list->lp_alloc > BCMX_LPLIST_ABSOLUTE_MAX_LEN) { 586 return -4; 587 } 588 589 if (list->lp_last >= list->lp_alloc) { 590 return -5; 591 } 592 593 return 0; 594 } 595 596 /* 597 * Function: 598 * bcmx_lplist_range 599 * Purpose: 600 * Add a range of ports to a port list 601 * Parameters: 602 * list - list to add ports to 603 * start - Low port to add 604 * end - Last port to add 605 * Returns: 606 * BCM_E_XXX 607 */ 608 609 int 610 bcmx_lplist_range(bcmx_lplist_t *list, bcmx_lport_t start, bcmx_lport_t end) 611 { 612 bcmx_lport_t curport = start; 613 int rv; 614 615 while ((curport != end) && (curport != BCMX_NO_SUCH_LPORT)) { 616 if ((rv = bcmx_lplist_add(list, curport)) < 0) { 617 return rv; 618 } 619 curport = BCMX_LPORT_NEXT(curport); 620 } 621 if (curport == end) { 622 if ((rv = bcmx_lplist_add(list, curport)) < 0) { 623 return rv; 624 } 625 } 626 627 return BCM_E_NONE; 628 } 629 630 /* Functional version of lplist macros */ 631 632 633 /* 634 * Function: 635 * bcmx_lplist_is_null 636 * Purpose: 637 * 638 * Parameters: 639 * list 640 * 641 * Returns: 642 */ 643 644 int 645 bcmx_lplist_is_null(bcmx_lplist_t *list) 646 { 647 return BCMX_LPLIST_IS_NULL(list); 648 } 649 650 651 /* 652 * Function: 653 * bcmx_lplist_is_empty 654 * Purpose: 655 * 656 * Parameters: 657 * list 658 * 659 * Returns: 660 */ 661 662 int 663 bcmx_lplist_is_empty(bcmx_lplist_t *list) 664 { 665 return BCMX_LPLIST_IS_EMPTY(list); 666 } 667 668 669 /* 670 * Function: 671 * bcmx_lplist_count 672 * Purpose: 673 * 674 * Parameters: 675 * list 676 * 677 * Returns: 678 */ 679 680 int 681 bcmx_lplist_count(bcmx_lplist_t *list) 682 { 683 return BCMX_LPLIST_COUNT(list); 684 } 685 686 687 /* 688 * Function: 689 * bcmx_lplist_remove 690 * Purpose: 691 * 692 * Parameters: 693 * list 694 * lport 695 * 696 * Returns: 697 */ 698 699 void 700 bcmx_lplist_remove(bcmx_lplist_t *list, int lport) 701 { 702 if (!bcmx_lplist_is_empty(list)) { 703 BCMX_LPLIST_REMOVE(list, lport); 704 } 705 } 706 707 708 /* 709 * Function: 710 * bcmx_lplist_idx_remove 711 * Purpose: 712 * 713 * Parameters: 714 * list 715 * idx 716 * 717 * Returns: 718 */ 719 720 void 721 bcmx_lplist_idx_remove(bcmx_lplist_t *list, int idx) 722 { 723 if (!bcmx_lplist_is_empty(list)) { 724 BCMX_LPLIST_IDX_REMOVE(list, idx); 725 } 726 } 727 728 729 /* 730 * Function: 731 * bcmx_lplist_pbmp_add 732 * Purpose: 733 * 734 * Parameters: 735 * list 736 * unit 737 * pbm 738 * 739 * Returns: 740 */ 741 742 int 743 bcmx_lplist_pbmp_add(bcmx_lplist_t *list, int unit, bcm_pbmp_t *pbm) 744 { 745 int rv = BCM_E_PARAM; 746 747 if (list) { 748 rv = _bcmx_lplist_pbmp_add(list, unit, *pbm); 749 } 750 751 return rv; 752 } 753 754 755 /* 756 * Function: 757 * bcmx_lplist_to_pbmp 758 * Purpose: 759 * 760 * Parameters: 761 * list 762 * unit 763 * pbm 764 * 765 * Returns: 766 * void 767 */ 768 769 void 770 bcmx_lplist_to_pbmp(bcmx_lplist_t *list, int unit, bcm_pbmp_t *pbm) 771 { 772 bcm_pbmp_t p; 773 774 BCM_PBMP_CLEAR(p); 775 if (!bcmx_lplist_is_empty(list)) { 776 BCMX_LPLISTPTR_TO_PBMP(list, unit, p); 777 } 778 *pbm = p; 779 } 780 781 782 /* 783 * Function: 784 * _bcmx_lplist_lport_compare 785 * Purpose: 786 * lport sort compare function 787 * Parameters: 788 * a - pointer to 1st element 789 * b - pointer to 2nd element 790 * Returns: 791 * -1 if *a < *b 792 * 0 if *a = *b 793 * +1 if *a > *b 794 */ 795 796 797 STATIC int 798 _bcmx_lplist_lport_compare(void *a, void *b) 799 { 800 bcmx_lport_t ap, bp; 801 int rv; 802 803 ap = *(bcmx_lport_t *)a; 804 bp = *(bcmx_lport_t *)b; 805 806 if (ap < bp) { 807 rv = -1; 808 } else if (ap > bp) { 809 rv = 1; 810 } else { 811 rv = 0; 812 } 813 814 return rv; 815 } 816 817 818 /* 819 * Function: 820 * bcmx_lplist_sort 821 * Purpose: 822 * Sort lplist in ascending order 823 * Parameters: 824 * list - List to sort 825 * Returns: 826 * BCM_E_NONE - list sorted 827 */ 828 829 int 830 bcmx_lplist_sort(bcmx_lplist_t *list) 831 { 832 if (!bcmx_lplist_is_empty(list)) { 833 _shr_sort(list->lp_ports, LP_COUNT(list), 834 sizeof(bcmx_lport_t), _bcmx_lplist_lport_compare); 835 } 836 837 return BCM_E_NONE; 838 } 839 840 841 /* 842 * Function: 843 * bcmx_lplist_uniq 844 * Purpose: 845 * Delete duplicate elements in list 846 * Parameters: 847 * list - List to uniqueify 848 * Returns: 849 * BCM_E_NONE 850 */ 851 852 int 853 bcmx_lplist_uniq(bcmx_lplist_t *list) 854 { 855 int idx, dup; 856 bcmx_lport_t lport; 857 858 if (!bcmx_lplist_is_empty(list)) { 859 for ( idx = 0; idx < list->lp_last; idx++ ) { 860 lport = list->lp_ports[idx]; 861 while ((dup = bcmx_lplist_index_get_from(list, 862 idx+1, lport)) >= 0) { 863 bcmx_lplist_idx_remove(list, dup); 864 } 865 } 866 } 867 868 return BCM_E_NONE; 869 }