board.c (17195B)
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: board.c 8 * Purpose: High level board system API 9 * 10 * These APIs are intended to be called by SDK applications 11 */ 12 13 #include <shared/bsl.h> 14 15 #include <sal/core/alloc.h> 16 #include <sal/core/libc.h> 17 #include <sal/core/sync.h> 18 #include <bcm/error.h> 19 #include <board/board.h> 20 #include <board/manager.h> 21 #include <board_int/support.h> 22 #include "mgr.h" 23 24 typedef struct board_reg_s { 25 board_driver_t *driver; 26 struct board_reg_s *next; 27 } board_reg_t; 28 29 #define MAX_CONN 128 30 sal_mutex_t board_lock; 31 32 /* List of board registrations. Registrations are kept in 33 high to low priority order. */ 34 STATIC board_reg_t *driver_reg; 35 36 /* Current board driver; or NULL if no driver attached. */ 37 STATIC board_reg_t *current; 38 39 /* 40 * Function: 41 * board_driver 42 * Purpose: 43 * Return the current board driver, or NULL if there is no 44 * current board driver. 45 * Parameters: 46 * none 47 * Returns: 48 * Pointer to board driver or NULL. 49 */ 50 board_driver_t * 51 board_driver(void) 52 { 53 return current ? current->driver : NULL; 54 } 55 56 /* 57 * Function: 58 * _board_find_by_name 59 * Purpose: 60 * Return board driver registration by name, or NULL if there is no 61 * registered board driver by that name. 62 * Parameters: 63 * name - (IN) board driver name 64 * Returns: 65 * Pointer to board driver registration or NULL. 66 */ 67 board_reg_t * 68 _board_find_by_name(char *name) 69 { 70 board_reg_t *entry; 71 72 for (entry = driver_reg; entry != NULL; entry = entry->next) { 73 if (!sal_strcmp(entry->driver->name, name)) { 74 return entry; 75 } 76 } 77 78 return NULL; 79 } 80 81 /* 82 * Function: 83 * _board_insert 84 * Purpose: 85 * Locate board registration insertion point in registration list 86 * Parameters: 87 * driver - (IN) driver structure 88 * insp - (OUT) pointer to registration record insertion point 89 * none 90 * Returns: 91 * BCM_E_NONE - success 92 * BCM_E_EXISTS - already registered 93 * Notes: 94 * Insertion point is NULL if the insertion point is the head 95 * of the list, otherwise it is the record whose next pointer 96 * should point to the record being inserted. 97 */ 98 int 99 _board_insert(board_driver_t *driver, board_reg_t **insp) 100 { 101 board_reg_t *entry; 102 103 for (entry = driver_reg; entry != NULL; entry = entry->next) { 104 105 if (!sal_strcmp(entry->driver->name, driver->name)) { 106 return BCM_E_EXISTS; 107 } 108 109 if (driver->priority > entry->driver->priority) { 110 /* priority is greater than what we are finding, so it 111 must be inserted at the beginning */ 112 entry = NULL; 113 break; 114 } else if (entry->next == NULL || 115 entry->next->driver->priority < driver->priority) { 116 /* This is either the last entry, or before entries that have 117 a lower priority, so insertion point is after this entry */ 118 break; 119 } 120 } 121 122 *insp = entry; 123 124 return BCM_E_NONE; 125 } 126 127 /* 128 * Function: 129 * _board_find 130 * Purpose: 131 * Locate board registration and deletion point in registration list 132 * Parameters: 133 * driver - (IN) driver structure 134 * regp - (OUT) pointer to registration record 135 * delp - (OUT) pointer to registration record deletion point 136 * Returns: 137 * BCM_E_NONE - success 138 * BCM_E_NOT_FOUND - not registered 139 * Notes: 140 * Deletion point is NULL if the insertion point is the head 141 * of the list, otherwise it is the record whose next pointer 142 * points to the requested record. 143 */ 144 int 145 _board_find(board_driver_t *driver, board_reg_t **regp, board_reg_t **delp) 146 { 147 board_reg_t *entry, *prev = NULL; 148 149 for (entry = driver_reg; entry != NULL; entry = entry->next) { 150 151 if (entry->driver == driver) { 152 *regp = entry; 153 if (delp) { 154 *delp = prev; 155 } 156 return BCM_E_NONE; 157 } 158 prev = entry; 159 } 160 return BCM_E_NOT_FOUND; 161 } 162 163 /* Board Manager API */ 164 165 /* 166 * Function: 167 * board_init 168 * Purpose: 169 * Initialize the board driver subsystem. 170 * Parameters: 171 * none 172 * Returns: 173 * BCM_E_NONE - success 174 * BCM_E_XXX - board subsystem initialization failed 175 */ 176 int 177 board_init(void) 178 { 179 int rv = BCM_E_INIT; 180 181 rv = board_deinit(); 182 if (BCM_SUCCESS(rv)) { 183 board_lock = sal_mutex_create("board-lock"); 184 if (board_lock != NULL) { 185 rv = BCM_E_NONE; 186 } 187 } 188 189 return rv; 190 } 191 192 /* 193 * Function: 194 * board_deinit 195 * Purpose: 196 * Uninitialize the board subsystem and release any allocated resources. 197 * Parameters: 198 * none 199 * Returns: 200 * BCM_E_NONE - success 201 * BCM_E_XXX - board subsystem de-initialization failed 202 */ 203 int 204 board_deinit(void) 205 { 206 if (board_lock) { 207 sal_mutex_destroy(board_lock); 208 board_lock = NULL; 209 } 210 driver_reg = NULL; 211 current = NULL; 212 213 return BCM_E_NONE; 214 } 215 216 /* 217 * Function: 218 * board_driver_add 219 * Purpose: 220 * 221 * Registers the board driver. driver->name must be unique among 222 * all the currently registered drivers. driver->priority is used 223 * to order the probing of board drivers, with drivers having 224 * higher priority values being probed before lower ones. Drivers 225 * with the same priority value are probed in registration order. 226 * 227 * It is recommended that more specific board drivers be 228 * registered with a higher priority value than more generic board 229 * drivers. driver->name does not necessarily uniquely identify a 230 * board (although it does uniquely identify a board driver), as a 231 * specific board driver and a generic board driver may both probe 232 * successfully for the same board. 233 * 234 * Parameters: 235 * driver - (IN) driver structure 236 * Returns: 237 * BCM_E_NONE - success 238 * BCM_E_EXISTS - board driver by that name already registered 239 * BCM_E_XXX - other registration errors 240 */ 241 int 242 board_driver_add(board_driver_t *driver) 243 { 244 board_reg_t *reg, *ins; 245 int rv = BCM_E_INTERNAL; 246 247 BOARD_INIT; 248 BOARD_LOCK; 249 /* find existing driver */ 250 rv = _board_insert(driver, &ins); 251 if (BCM_SUCCESS(rv)) { 252 reg = ALLOC(sizeof(board_reg_t)); 253 if (reg) { 254 reg->driver = driver; 255 256 if (!ins) { 257 /* goes at beginning */ 258 reg->next = driver_reg; 259 driver_reg = reg; 260 } else { 261 reg->next = ins->next; 262 ins->next = reg; 263 } 264 265 rv = BCM_E_NONE; 266 } else { 267 rv = BCM_E_MEMORY; 268 } 269 } 270 BOARD_UNLOCK; 271 272 return rv; 273 } 274 275 /* 276 * Function: 277 * board_driver_delete 278 * Purpose: 279 * Unregisters a previously registered board driver. 280 * Parameters: 281 * driver - (IN) driver structure 282 * Returns: 283 * BCM_E_NONE - success 284 * BCM_E_XXX - failed 285 */ 286 int 287 board_driver_delete(board_driver_t *driver) 288 { 289 board_reg_t *reg, *prev; 290 int rv = BCM_E_INTERNAL; 291 292 BOARD_INIT; 293 BOARD_LOCK; 294 /* Can't unregister an active board driver */ 295 if (current && current->driver == driver) { 296 rv = BCM_E_BUSY; 297 } else { 298 /* find existing driver */ 299 rv = _board_find(driver, ®, &prev); 300 if (BCM_SUCCESS(rv)) { 301 if (prev) { 302 prev->next = reg->next; 303 } else { 304 driver_reg = reg->next; 305 } 306 307 FREE(reg); 308 rv = BCM_E_NONE; 309 } 310 } 311 BOARD_UNLOCK; 312 return rv; 313 } 314 315 /* 316 * Function: 317 * board_drivers_get 318 * Purpose: 319 * Returns an array of all registered board drivers. 320 * Parameters: 321 * max_num - (IN) length of board driver array 322 * driver - (OUT) array of pointers to board_driver_t 323 * actual - (OUT) actual board driver array length 324 * Returns: 325 * BCM_E_NONE - success 326 * BCM_E_XXX - failed 327 */ 328 int 329 board_drivers_get(int max_num, 330 board_driver_t **driver, 331 int *actual) 332 { 333 int count, copy; 334 board_reg_t *entry; 335 int rv = BCM_E_INTERNAL; 336 337 BOARD_INIT; 338 BOARD_LOCK; 339 340 rv = BCM_E_PARAM; 341 copy = max_num; 342 count = 0; 343 344 for (entry = driver_reg; entry != NULL; entry = entry->next) { 345 if (copy-- > 0) { 346 if (driver != NULL) { 347 driver[count] = entry->driver; 348 } else { 349 /* driver must be non-NULL if copying out */ 350 break; 351 } 352 } else if (driver) { 353 /* Destination at capacity */ 354 break; 355 } 356 count++; 357 } 358 359 if (actual) { 360 *actual = count; 361 rv = BCM_E_NONE; 362 } else if (max_num > 0) { 363 rv = BCM_E_NONE; 364 } 365 366 BOARD_UNLOCK; 367 368 return rv; 369 } 370 371 /* 372 * Function: 373 * _board_info 374 * Purpose: 375 * Return an allocated array of bcm_info_t structures to devp, 376 * count to countp. Free array with sal_free() when done. 377 * Parameters: 378 * countp - (OUT) 379 * devp - (OUT) 380 * Returns: 381 * BCM_E_MEMORY - out of memory 382 * BCM_E_NONE - success 383 */ 384 STATIC int 385 _board_info(int *countp, bcm_info_t **devp) 386 { 387 int rv, count; 388 bcm_info_t *dev; 389 390 rv = board_probe_get(0,NULL,&count); 391 if (BCM_SUCCESS(rv)) { 392 dev = ALLOC(sizeof(bcm_info_t) * count); 393 if (dev) { 394 rv = board_probe_get(count,dev,NULL); 395 if (BCM_SUCCESS(rv)) { 396 *countp = count; 397 *devp = dev; 398 } else { 399 FREE(dev); 400 } 401 } else { 402 rv = BCM_E_MEMORY; 403 } 404 } 405 406 return rv; 407 } 408 409 /* 410 * Function: 411 * board_probe 412 * Purpose: 413 * Iterates across all registered board drivers, from the highest 414 * priority value to the lowest, and returns the name of the first 415 * board driver whose probe function returns BCM_E_NONE. 416 * Parameters: 417 * none 418 * Returns: 419 * !NULL - success 420 * NULL - failed 421 */ 422 char * 423 board_probe(void) 424 { 425 board_reg_t *reg; 426 bcm_info_t *dev; 427 int count; 428 int rv = BCM_E_INTERNAL; 429 char *name = NULL; 430 431 BOARD_INIT_NULL; 432 BOARD_LOCK; 433 rv = _board_info(&count, &dev); 434 435 if (BCM_SUCCESS(rv)) { 436 #if defined(BROADCOM_DEBUG) 437 { 438 int i; 439 440 LOG_VERBOSE(BSL_LS_BOARD_COMMON, 441 (BSL_META("Board probe:\n"))); 442 for (i=0; i<count; i++) { 443 LOG_VERBOSE(BSL_LS_BOARD_COMMON, 444 (BSL_META(" %2d: %s\n"), 445 i, board_device_name(i))); 446 } 447 } 448 #endif 449 450 /* For each set of registered drivers */ 451 for (reg=driver_reg; reg != NULL; reg=reg->next) { 452 if (!reg->driver->probe) { 453 LOG_VERBOSE(BSL_LS_BOARD_COMMON, 454 (BSL_META("Board %s probe missing\n"), 455 reg->driver->name)); 456 continue; 457 } 458 rv = reg->driver->probe(reg->driver, count, dev); 459 if (BCM_SUCCESS(rv)) { 460 /* Board probe successful */ 461 name = reg->driver->name; 462 break; 463 } 464 } 465 466 FREE(dev); 467 } 468 BOARD_UNLOCK; 469 470 return BCM_SUCCESS(rv) ? name : NULL; 471 } 472 473 /* 474 * Function: 475 * board_find 476 * Purpose: 477 * Find a registered board driver of the given name, returning 478 * BCM_E_NONE if the board driver is found. This function only 479 * tests if a board driver of the given name is registered; no 480 * board driver interfaces are called. 481 * Parameters: 482 * name - (IN) name of board driver to find 483 * Returns: 484 * BCM_E_NONE - success 485 * BCM_E_XXX - failed 486 */ 487 int 488 board_find(char *name) 489 { 490 int rv; 491 492 BOARD_INIT; 493 BOARD_LOCK; 494 rv = _board_find_by_name(name) ? BCM_E_NONE : BCM_E_FAIL; 495 BOARD_UNLOCK; 496 497 return rv; 498 } 499 500 /* 501 * Function: 502 * board_attach 503 * Purpose: 504 * Make the board driver of the given name the current board 505 * manager driver. 506 * Parameters: 507 * name - (IN) name of board driver to attach 508 * Returns: 509 * BCM_E_NONE - success 510 * BCM_E_XXX - failed 511 */ 512 int 513 board_attach(char *name) 514 { 515 board_reg_t *reg; 516 int rv = BCM_E_INTERNAL; 517 518 BOARD_INIT; 519 520 if (!name) { return BCM_E_PARAM; } 521 if (current) { return BCM_E_BUSY; } 522 523 BOARD_LOCK; 524 reg = _board_find_by_name(name); 525 if (reg) { 526 current = reg; 527 rv = BCM_E_NONE; 528 } else { 529 rv = BCM_E_NOT_FOUND; 530 } 531 BOARD_UNLOCK; 532 533 return rv; 534 535 } 536 537 /* 538 * Function: 539 * board_detach 540 * Purpose: 541 * Detach the current board driver from the board manager. 542 * Parameters: 543 * none 544 * Returns: 545 * BCM_E_NONE - success 546 * BCM_E_XXX - failed 547 */ 548 int 549 board_detach(void) 550 { 551 int rv = BCM_E_FAIL; 552 553 BOARD_INIT; 554 BOARD_LOCK; 555 if (current) { 556 current = NULL; 557 rv = BCM_E_NONE; 558 } 559 BOARD_UNLOCK; 560 561 return rv; 562 } 563 564 /* Board Interface API */ 565 566 /* 567 * Function: 568 * board_name 569 * Purpose: 570 * Returns the attached board name. 571 * Parameters: 572 * none 573 * Returns: 574 * NULL - no current driver 575 * !NULL - current board driver name 576 */ 577 char * 578 board_name(void) 579 { 580 char *name; 581 582 BOARD_INIT_NULL; 583 BOARD_LOCK; 584 name = current ? current->driver->name : NULL; 585 BOARD_UNLOCK; 586 587 return name; 588 } 589 590 /* 591 * Function: 592 * board_description 593 * Purpose: 594 * Returns the attached board description. Board description strings 595 * are of indeterminate length, and may not be suitable for 596 * associative array keys, i.e., the same board driver may return 597 * different description strings for different hardware platforms. 598 * Parameters: 599 * none 600 * Returns: 601 * NULL - no current driver 602 * !NULL - current board driver name 603 */ 604 char * 605 board_description(void) 606 { 607 char *desc = NULL; 608 609 BOARD_INIT_NULL; 610 BOARD_LOCK; 611 if (current && current->driver->description) { 612 desc = current->driver->description(current->driver); 613 } 614 BOARD_UNLOCK; 615 616 return desc; 617 } 618 619 /* 620 * Function: 621 * board_start 622 * Purpose: 623 * Call the board driver start function with the given flags. 624 * 625 * Flags: 626 * 627 * BOARD_START_F_COLD_BOOT Cold boot the board. 628 * 629 * BOARD_START_F_WARM_BOOT Warm boot the board. 630 * 631 * BOARD_START_F_CLEAR Clear devices on the board and 632 * preserve the board stacking 633 * configuration such as device modid 634 * and stack ports. 635 * Parameters: 636 * flags - (IN) board start flags 637 * Returns: 638 * BCM_E_NONE - success 639 * BCM_E_XXX - failed 640 */ 641 int 642 board_start(uint32 flags) 643 { 644 int rv = BCM_E_FAIL; 645 646 BOARD_INIT; 647 /* You can have one or the other but not both */ 648 if (flags & (BOARD_START_F_CLEAR|BOARD_START_F_WARM_BOOT)) { 649 return BCM_E_PARAM; 650 } 651 652 BOARD_LOCK; 653 if (current && current->driver->start) { 654 rv = (current->driver->start(current->driver, flags)); 655 } 656 BOARD_UNLOCK; 657 658 return rv; 659 } 660 661 /* 662 * Function: 663 * board_stop 664 * Purpose: 665 * Call the board driver stop function. 666 * Parameters: 667 * none 668 * Returns: 669 * BCM_E_NONE - success 670 * BCM_E_XXX - failed 671 */ 672 int 673 board_stop(void) 674 { 675 int rv = BCM_E_FAIL; 676 677 BOARD_INIT; 678 BOARD_LOCK; 679 if (current && current->driver->stop) { 680 rv = current->driver->stop(current->driver); 681 } 682 BOARD_UNLOCK; 683 684 return rv; 685 } 686 687 /* 688 * Function: 689 * board_connections_get 690 * Purpose: 691 * Return an array of connections up to max_num number of 692 * connections. The actual length is returned via 'actual'. If 693 * 'max_num' is zero, then 'actual' will return the length of the 694 * connection array and not write to 'connection'. 695 * Parameters: 696 * max_num - (IN) length of connection array 697 * connection - (OUT) array of board_connection_t 698 * actual - (OUT) actual connection array length 699 * Returns: 700 * BCM_E_NONE - success 701 * BCM_E_XXX - failed 702 */ 703 int 704 board_connections_get(int max_num, 705 board_connection_t *connection, 706 int *actual) 707 { 708 int rv = BCM_E_UNAVAIL; 709 710 BOARD_INIT; 711 BOARD_LOCK; 712 if (current) { 713 if (!max_num) { 714 if (actual) { 715 *actual = current->driver->num_connection; 716 rv = BCM_E_NONE; 717 } else { 718 rv = BCM_E_PARAM; 719 } 720 } else { 721 if (connection) { 722 if (max_num < current->driver->num_connection) { 723 max_num = current->driver->num_connection; 724 } 725 sal_memcpy(connection, 726 current->driver->connection, 727 max_num*sizeof(board_connection_t)); 728 if (actual) { 729 *actual = max_num; 730 } 731 rv = BCM_E_NONE; 732 } else { 733 rv = BCM_E_PARAM; 734 } 735 } 736 } 737 BOARD_UNLOCK; 738 739 return rv; 740 } 741 742