openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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, &reg, &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