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

link.c (11521B)


      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:        link.c
      8  * Purpose:
      9  * Requires:
     10  */
     11 
     12 #include <shared/bsl.h>
     13 
     14 #include <shared/alloc.h>
     15 #include <sal/core/sync.h>
     16 
     17 #include <bcm/types.h>
     18 #include <bcm/port.h>
     19 #include <bcm/link.h>
     20 
     21 #include <bcmx/bcmx.h>
     22 #include <bcmx/link.h>
     23 #include <soc/mem.h>
     24 
     25 #include "bcmx_int.h"
     26 
     27 #define BCMX_LINK_SET_ERROR_CHECK(_unit, _check, _rv)    \
     28     BCMX_SET_ERROR_CHECK(_unit, _check, _rv)
     29 
     30 #define BCMX_LINK_GET_IS_VALID(_unit, _rv)    \
     31     BCMX_ERROR_IS_VALID(_unit, _rv)
     32 
     33 typedef struct lsx_handler_s {
     34     struct lsx_handler_s         *lh_next;
     35     bcmx_link_notify_f            lh_f;
     36 } lsx_handler_t;
     37 
     38 static sal_mutex_t         lsx_lock;     /* Synchronization */
     39 static lsx_handler_t      *lsx_handler; /* List of handlers */
     40 
     41 /* lsx_interval < 0 implies it hasn't been set yet */
     42 static int                 lsx_interval = -1;   /* STATUS ONLY */
     43 
     44 #define LSX_CHECK_INIT    do {                 \
     45     BCMX_READY_CHECK;                          \
     46     if (lsx_lock == NULL)                      \
     47         BCM_IF_ERROR_RETURN(_bcmx_lsx_init()); \
     48     } while (0)
     49 
     50 #define LSX_LOCK sal_mutex_take(lsx_lock, sal_mutex_FOREVER)
     51 #define LSX_UNLOCK sal_mutex_give(lsx_lock)
     52 
     53 STATIC int
     54 _bcmx_lsx_init(void)
     55 {
     56     lsx_lock = sal_mutex_create("bcmx_l2_notify");
     57     if (lsx_lock == NULL) {
     58         return BCM_E_MEMORY;
     59     }
     60 
     61     return BCM_E_NONE;
     62 }
     63 
     64 
     65 /* Callback registered with BCM layer */
     66 STATIC void
     67 bcmx_bcm_ls_cb(int unit, bcm_port_t port, bcm_port_info_t *info)
     68 {
     69     bcmx_lport_t lport;
     70     lsx_handler_t *cb; /* List of handlers */
     71 
     72     LOG_VERBOSE(BSL_LS_BCMX_LINK,
     73                 (BSL_META_U(unit,
     74                             "BCMX LS callback, u %d. p %d\n"), unit, port));
     75 
     76     if (lsx_lock == NULL || lsx_handler == NULL) {
     77         return;
     78     }
     79 
     80     /* Translate unit/port into lport */
     81     if (BCM_FAILURE(_bcmx_dest_from_unit_port(&lport, unit, port,
     82                                               BCMX_DEST_CONVERT_DEFAULT))) {
     83         return;
     84     }
     85 
     86     LSX_LOCK;
     87     cb = lsx_handler;
     88     while (cb != NULL) {
     89         cb->lh_f(lport, info);
     90         cb = cb->lh_next;
     91     }
     92     LSX_UNLOCK;
     93 }
     94 
     95 /* Make connection to BCM layer for all known units. */
     96 
     97 STATIC int
     98 _bcmx_linkscan_rlink_register(void)
     99 {
    100     int bcm_unit, i;
    101     int rv = BCM_E_UNAVAIL, tmp_rv;
    102 
    103     BCMX_UNIT_ITER(bcm_unit, i) {
    104         tmp_rv = bcm_linkscan_register(bcm_unit, bcmx_bcm_ls_cb);
    105         BCM_IF_ERROR_RETURN(BCMX_LINK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    106     }
    107 
    108     return rv;
    109 }
    110 
    111 /*
    112  * Function:
    113  *      bcmx_linkscan_register/unregister
    114  * Purpose:
    115  *      Register/unregister a BCMX level link change notification callback
    116  * Parameters:
    117  *      ln_cb          - The callback function pointer
    118  * Returns:
    119  *      BCM_E_XXX
    120  * Notes:
    121  *      Register may be called multiple times without burning more
    122  *      registration entries.  In addition, it always calls down to
    123  *      the lower layer to make sure registration exists on all
    124  *      currently known units.  In this way, after more units are
    125  *      added, call this again to ensure connections.
    126  */
    127 
    128 int
    129 bcmx_linkscan_register(bcmx_link_notify_f ln_cb)
    130 {
    131     lsx_handler_t *cb, *last;
    132     int registered = FALSE;  /* Successfully registered locally? */
    133     int rv = BCM_E_NONE;
    134 
    135     LSX_CHECK_INIT;
    136 
    137     LOG_VERBOSE(BSL_LS_BCMX_LINK,
    138                 (BSL_META("BCMX LS reg, %p\n"),
    139                  ln_cb));
    140 
    141     LSX_LOCK;
    142     last = NULL;
    143     cb = lsx_handler;
    144     while (cb != NULL) {
    145         if (cb->lh_f == ln_cb) {
    146             registered = TRUE;
    147             break;
    148         }
    149         last = cb;
    150         cb = cb->lh_next;
    151     }
    152 
    153     if (!registered) { /* Not found yet; add to list */
    154         cb = sal_alloc(sizeof(lsx_handler_t), "bcmx_ls_reg");
    155         if (cb != NULL) {
    156 
    157             /* Put into end of list */
    158             cb->lh_f = ln_cb;
    159             cb->lh_next = NULL;
    160             if (last != NULL) {
    161                 last->lh_next = cb;
    162             } else {  /* List currently empty */
    163                 lsx_handler = cb;
    164             }
    165             registered = TRUE;
    166         } else {
    167             rv = BCM_E_MEMORY;
    168         }
    169     }
    170 
    171     LSX_UNLOCK;
    172 
    173     if (registered) { /* Make sure registered with lower layer */
    174         _bcmx_linkscan_rlink_register();
    175     }
    176 
    177     return rv;
    178 }
    179 
    180 
    181 int
    182 bcmx_linkscan_unregister(bcmx_link_notify_f ln_cb)
    183 {
    184     lsx_handler_t *cb, *prev = NULL;
    185 
    186     LSX_CHECK_INIT;
    187 
    188     LOG_VERBOSE(BSL_LS_BCMX_LINK,
    189                 (BSL_META("BCMX LS unreg, %p\n"),
    190                  ln_cb));
    191 
    192     LSX_LOCK;
    193     cb = lsx_handler;
    194     while (cb != NULL) {
    195         if (cb->lh_f == ln_cb) {
    196             if (prev != NULL) {
    197                 prev->lh_next = cb->lh_next;
    198             } else {
    199                 lsx_handler = cb->lh_next;
    200             }
    201             sal_free(cb);
    202             break;
    203         }
    204         prev = cb;
    205         cb = cb->lh_next;
    206     }
    207     LSX_UNLOCK;
    208 
    209     return BCM_E_NONE;
    210 }
    211 
    212 
    213 /*
    214  * Function:
    215  *      bcmx_linkscan_enable_set
    216  * Purpose:
    217  *      Set linkscan state
    218  * Parameters:
    219  *      us              - Interval in microseconds; see notes
    220  * Returns:
    221  *      BCM_E_XXX
    222  * Notes:
    223  *      If us == 0, disables linkscan at lowest layer.  Note that
    224  *      registrations may still exist in this case.
    225  *
    226  *      If us < 0, then a sync is performed by looking for a unit
    227  *      which returns success; this value is then used to set all
    228  *      other devices.
    229  *
    230  *      If no device found indicating current setting, _E_FAIL
    231  *      is returned.
    232  */
    233 
    234 int
    235 bcmx_linkscan_enable_set(int us)
    236 {
    237     int rv = BCM_E_UNAVAIL, tmp_rv;
    238     int found = FALSE;
    239     int interval;
    240     int bcm_unit, i;
    241 
    242     LSX_CHECK_INIT;
    243 
    244     LOG_VERBOSE(BSL_LS_BCMX_LINK,
    245                 (BSL_META("BCMX LS enable set, %d\n"),
    246                  us));
    247 
    248     if (us < 0) {  /* Sync:  See notes above */
    249 
    250         /* Try to get current enable setting */
    251         BCMX_UNIT_ITER(bcm_unit, i) {
    252             tmp_rv = bcm_linkscan_enable_get(bcm_unit, &interval);
    253             if (BCMX_LINK_GET_IS_VALID(bcm_unit, tmp_rv)) {
    254                 rv = tmp_rv;
    255                 if (BCM_SUCCESS(tmp_rv)) {
    256                     found = TRUE;
    257                 }
    258                 break;
    259             }
    260         }
    261 
    262         if (found) {  /* Sync everyone to this setting */
    263             lsx_interval = interval;
    264             BCMX_UNIT_ITER(bcm_unit, i) {
    265                 tmp_rv = bcm_linkscan_register(bcm_unit, bcmx_bcm_ls_cb);
    266                 BCM_IF_ERROR_RETURN
    267                     (BCMX_LINK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    268             }
    269         } else {
    270             return BCM_E_FAIL;  /* Could not synchronize */
    271         }
    272 
    273     } else { /* Just set on all current units */
    274 
    275         if (us > 0) { /* Enabling:  Ensure registered */
    276             (void)_bcmx_linkscan_rlink_register();
    277         }
    278         lsx_interval = us;
    279         BCMX_UNIT_ITER(bcm_unit, i) {
    280             tmp_rv = bcm_linkscan_enable_set(bcm_unit, us);
    281             BCM_IF_ERROR_RETURN(BCMX_LINK_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    282         }
    283     }
    284 
    285     return rv;
    286 }
    287 
    288 
    289 /*
    290  * Function:
    291  *      bcmx_linkscan_enable_get
    292  * Purpose:
    293  *      Get linkscan state
    294  * Parameters:
    295  *      us              - (OUT) Current interval in microseconds
    296  *      consistent      - (OUT) If non-NULL, check for consistency
    297  *                        on all BCMX units and return Boolean value here.
    298  * Returns:
    299  *      BCM_E_XXX
    300  */
    301 
    302 int
    303 bcmx_linkscan_enable_get(int *us, int *consistent)
    304 {
    305     int bcm_unit, i;
    306     int rv = BCM_E_UNAVAIL, tmp_rv;
    307     int tmp_us;
    308 
    309     LSX_CHECK_INIT;
    310 
    311 
    312     if (lsx_interval >= 0) { /* Has been initialized */
    313         *us = lsx_interval;
    314     } else {  /* Look for a unit with info */
    315         BCMX_UNIT_ITER(bcm_unit, i) {
    316             tmp_rv = bcm_linkscan_enable_get(bcm_unit, &tmp_us);
    317             if (BCMX_LINK_GET_IS_VALID(bcm_unit, tmp_rv)) {
    318                 rv = tmp_rv;
    319                 if (BCM_SUCCESS(tmp_rv)) {
    320                     *us = lsx_interval = tmp_us;
    321                 }
    322                 break;
    323             }
    324         }
    325     }
    326 
    327     if (lsx_interval < 0) { /* Still unitialized */
    328         return rv;
    329     }
    330 
    331     if (consistent != NULL) { /* Check for consistency across units */
    332         *consistent = TRUE;
    333 
    334         BCMX_UNIT_ITER(bcm_unit, i) {
    335             tmp_rv = bcm_linkscan_enable_get(bcm_unit, &tmp_us);
    336             if (BCMX_LINK_GET_IS_VALID(bcm_unit, tmp_rv)) {
    337                 rv = tmp_rv;
    338                 if (BCM_SUCCESS(tmp_rv)) {
    339                     if (tmp_us != lsx_interval) {
    340                         *consistent = FALSE;
    341                         break;
    342                     }
    343                 } else {
    344                     break;
    345                 }
    346             }
    347         }
    348     }
    349 
    350     return rv;
    351 }
    352 
    353 
    354 /*
    355  * Function:
    356  *     bcmx_linkscan_enable_port_get
    357  * Purpose:
    358  *     Determine whether or not linkscan is managing a given port
    359  * Parameters:
    360  *     lport - Logical port to check.
    361  * Returns:
    362  *     BCM_E_NONE - port being scanned
    363  *     BCM_E_PARAM - invalid logical port
    364  *     BCM_E_DISABLED - port not being scanned
    365  */
    366 
    367 int
    368 bcmx_linkscan_enable_port_get(bcmx_lport_t lport)
    369 {
    370     int         bcm_unit;
    371     bcm_port_t  bcm_port;
    372 
    373     LSX_CHECK_INIT;
    374 
    375     if (BCM_FAILURE
    376         (_bcmx_dest_to_unit_port(lport, &bcm_unit, &bcm_port,
    377                                  BCMX_DEST_CONVERT_DEFAULT))) {
    378         return BCM_E_PARAM;
    379     }
    380 
    381     return bcm_linkscan_enable_port_get(bcm_unit, bcm_port);
    382 }
    383 
    384 /*
    385  * Function:
    386  *      bcmx_linkscan_device_add
    387  * Purpose:
    388  *      Add a unit to linkscanning
    389  * Notes:
    390  *      Registers linkscan callback
    391  */
    392 
    393 int
    394 bcmx_linkscan_device_add(int bcm_unit)
    395 {
    396     int rv;
    397 
    398     LSX_CHECK_INIT;
    399 
    400     if (lsx_interval >= 0) { /* Has been initialized */
    401         rv = bcm_linkscan_enable_set(bcm_unit, lsx_interval);
    402         if (rv < 0) {
    403             LOG_WARN(BSL_LS_BCMX_COMMON,
    404                      (BSL_META("WARN: BCMX LS dev add enable, %d: %s\n"),
    405                       rv, bcm_errmsg(rv)));
    406         }
    407     }
    408 
    409     /* Always register if possible */
    410     rv = bcm_linkscan_register(bcm_unit, bcmx_bcm_ls_cb);
    411 
    412     if (rv < 0) {
    413         LOG_WARN(BSL_LS_BCMX_COMMON,
    414                  (BSL_META("WARN: BCMX LS device add reg, %d: %s\n"),
    415                   rv, bcm_errmsg(rv)));
    416     }
    417 
    418     return rv;
    419 }
    420 
    421 /*
    422  * Function:
    423  *      bcmx_linkscan_device_remove
    424  * Purpose:
    425  *      Remove a unit from linkscanning
    426  */
    427 
    428 int
    429 bcmx_linkscan_device_remove(int bcm_unit)
    430 {
    431     LSX_CHECK_INIT;
    432 
    433     return bcm_linkscan_unregister(bcm_unit, bcmx_bcm_ls_cb);
    434 }
    435 
    436 
    437 
    438 #if defined(BROADCOM_DEBUG)
    439 void
    440 bcmx_linkscan_dump(void)
    441 {
    442     lsx_handler_t *ent;
    443 
    444     if (lsx_lock == NULL) {
    445         LOG_INFO(BSL_LS_BCMX_COMMON,
    446                  (BSL_META("BCMX linkscan not initialized\n")));
    447         return;
    448     }
    449 
    450     LOG_INFO(BSL_LS_BCMX_COMMON,
    451              (BSL_META("BCMX linkscan interval %d%s\n"),
    452               lsx_interval,
    453               lsx_interval < 0 ? " (un-init)" : ""));
    454 
    455     LOG_INFO(BSL_LS_BCMX_COMMON,
    456              (BSL_META("LSX handler list:  \n")));
    457     for (ent = lsx_handler; ent != NULL; ent = ent->lh_next) {
    458         LOG_INFO(BSL_LS_BCMX_COMMON,
    459                  (BSL_META("    Fn %p.\n"),
    460                   ent->lh_f));
    461     }
    462 
    463 }
    464 
    465 void
    466 bcmx_rlink_dump(void)
    467 {
    468 #ifdef  BCM_RPC_SUPPORT
    469     extern void bcm_rlink_dump(void);
    470 
    471     bcm_rlink_dump();
    472 #endif  /* BCM_RPC_SUPPORT */
    473     bcmx_linkscan_dump();
    474 }
    475 #endif /* BROADCOM_DEBUG */