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

attach.c (11235B)


      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  * Attach Application
      8  *
      9  * A callback suitable for use in the stack task database update
     10  * callback is provided.  It automatically attaches and detaches
     11  * units through the BCM RPC attachments.  A callback mechanism
     12  * is provided to notify users (BCMX for example) that a unit has
     13  * been added or removed.
     14  */
     15 
     16 #include <shared/bsl.h>
     17 
     18 #include <sdk_config.h>
     19 #include <assert.h>
     20 #include <shared/alloc.h>
     21 #include <sal/core/libc.h>
     22 #include <sal/core/thread.h>
     23 
     24 #include <bcm/types.h>
     25 #include <bcm/error.h>
     26 #include <bcm/init.h>
     27 
     28 #include <bcm_int/control.h>
     29 #ifdef BCM_RPC_SUPPORT
     30 #include <bcm_int/rpc/rpc.h>
     31 #endif /* BCM_RPC_SUPPORT */
     32 
     33 #include <appl/stktask/attach.h>
     34 #include <appl/stktask/stktask.h>
     35 
     36 #ifndef ATTACH_THREAD_STACK
     37 #define ATTACH_THREAD_STACK  SAL_THREAD_STKSZ
     38 #endif
     39 
     40 #ifndef ATTACH_THREAD_PRIO
     41 #define ATTACH_THREAD_PRIO   50
     42 #endif
     43 
     44 
     45 static volatile int _bcm_stack_attach_thread_active;
     46 
     47 typedef struct _attach_cb_s {
     48     struct _attach_cb_s      *next;
     49     bcm_stack_attach_cb_f    callback;
     50 } _attach_cb_t;
     51 
     52 static _attach_cb_t *_attach_cb;
     53 
     54 static sal_mutex_t at_lock;
     55 #define AT_LOCK sal_mutex_take(at_lock, sal_mutex_FOREVER)
     56 #define AT_UNLOCK sal_mutex_give(at_lock)
     57 
     58 /*
     59  * Add a function to the callback list
     60  */
     61 int
     62 bcm_stack_attach_register(bcm_stack_attach_cb_f callback)
     63 {
     64     _attach_cb_t  *acb;
     65 
     66     if (callback == NULL) {
     67         return BCM_E_FAIL;
     68     }
     69     acb = sal_alloc(sizeof(*acb), "attach cb");
     70     if (acb == NULL) {
     71         return BCM_E_MEMORY;
     72     }
     73     acb->callback = callback;
     74     acb->next = _attach_cb;
     75     _attach_cb = acb;
     76     return BCM_E_NONE;
     77 }
     78 
     79 /*
     80  * Remove a function from the callback list
     81  */
     82 int
     83 bcm_stack_attach_unregister(bcm_stack_attach_cb_f callback)
     84 {
     85     _attach_cb_t  *acb, *pacb;
     86 
     87     pacb = NULL;
     88     for (acb = _attach_cb; acb; pacb = acb, acb = acb->next) {
     89         if (acb->callback == callback) {
     90             if (pacb == NULL) {
     91                 _attach_cb = acb->next;
     92             } else {
     93                 pacb->next = acb->next;
     94             }
     95             sal_free(acb);
     96             return BCM_E_NONE;
     97         }
     98     }
     99     return BCM_E_NOT_FOUND;
    100 }
    101 
    102 /*
    103  * Run the callback list
    104  */
    105 STATIC void
    106 _bcm_stack_attach_cb_run(int unit, int attached,
    107                          cpudb_entry_t *cpuent, int cpuunit)
    108 {
    109     _attach_cb_t  *acb;
    110 
    111     for (acb = _attach_cb; acb; acb = acb->next) {
    112         (*acb->callback)(unit, attached, cpuent, cpuunit);
    113     }
    114 #ifdef BCM_RPC_SUPPORT
    115     /* notify rpc to fail any queued requests */
    116     if (!attached) {
    117         bcm_rpc_detach(unit);
    118     }
    119 #endif /* BCM_RPC_SUPPORT */
    120 }
    121 
    122 /*
    123  * Detach bcm units to match the cpu database.
    124  */
    125 int
    126 bcm_stack_detach(cpudb_ref_t db_ref)
    127 {
    128     int            ismaster;
    129     cpudb_entry_t  *nent;
    130     cpudb_entry_t  oent;
    131     int            unit, dunit, rv;
    132     cpudb_key_t    *key;
    133 
    134     AT_LOCK;
    135     ismaster = db_ref->local_entry == db_ref->master_entry;
    136 
    137     /* find any dispatch entries that need to be deleted */
    138     sal_memset(&oent, 0, sizeof(oent));
    139 
    140     for (unit = 0; unit < BCM_CONTROL_MAX; unit++) {
    141         if (BCM_CONTROL(unit) == NULL) {
    142             continue;
    143         }
    144         if (BCM_IS_REMOTE(unit)) {
    145             key = (cpudb_key_t *)BCM_CONTROL(unit)->drv_control;
    146             CPUDB_KEY_SEARCH(db_ref, *key, nent);
    147             if (nent != NULL && ismaster) {
    148                 continue;
    149             }
    150             dunit = BCM_CONTROL(unit)->unit;
    151             sal_memcpy(&oent.base.key, key, sizeof(cpudb_key_t));
    152             oent.flags = 0;
    153             rv = bcm_detach(unit);
    154         } else if (BCM_IS_LOCAL(unit)) {
    155             if (ismaster) {
    156                 continue;
    157             }
    158             if (!(BCM_CAPABILITY(unit) & BCM_CAPA_CALLBACK)) {
    159                 continue;
    160             }
    161             dunit = unit;
    162             rv = 0;
    163             BCM_CAPABILITY(unit) &= ~BCM_CAPA_CALLBACK;
    164             sal_memset(&oent.base.key, 0, sizeof(cpudb_key_t));
    165             oent.flags = CPUDB_F_IS_LOCAL;
    166         } else {
    167             continue;
    168         }
    169         if (rv >= 0) {
    170             _bcm_stack_attach_cb_run(unit, 0, &oent, dunit);
    171         }
    172     }
    173     AT_UNLOCK;
    174 
    175     return BCM_E_NONE;
    176 }
    177 
    178 /*
    179  * Attach bcm units to match the cpu database.
    180  */
    181 int
    182 bcm_stack_attach(cpudb_ref_t db_ref)
    183 {
    184     int            ismaster;
    185     cpudb_entry_t  *nent;
    186     int            dunit, rv;
    187     char           keybuf[CPUDB_KEY_STRING_LEN];
    188     char           *dtype, *dsubtype;
    189     int            terminate;
    190 
    191     AT_LOCK;
    192     ismaster = db_ref->local_entry == db_ref->master_entry;
    193 
    194     /* add any new cpu units */
    195     if (ismaster) {
    196         terminate = 0;
    197 
    198         /* attach local units first */
    199         CPUDB_FOREACH_ENTRY(db_ref, nent) {
    200             if (terminate) {
    201                 break;
    202             }
    203             if (!(nent->flags & CPUDB_F_IS_LOCAL)) {
    204                 continue;
    205             }
    206             dtype = NULL;
    207             dsubtype = NULL;
    208             rv = 0;
    209             for (dunit = 0; dunit < nent->base.num_units; dunit++) {
    210                 rv = bcm_find(dtype, dsubtype, dunit);
    211                 if (rv < 0) {
    212                     rv = bcm_attach(-1, dtype, dsubtype, dunit);
    213                 }
    214                 if (rv < 0) {
    215                     terminate = 1;
    216                     break;
    217                 }
    218                 if (rv >= 0 && !(BCM_CAPABILITY(rv) & BCM_CAPA_CALLBACK)) {
    219                     _bcm_stack_attach_cb_run(rv, 1, nent, dunit);
    220                     BCM_CAPABILITY(rv) |= BCM_CAPA_CALLBACK;
    221                 }
    222             }
    223         }
    224 
    225         /* attach remote units */
    226         CPUDB_FOREACH_ENTRY(db_ref, nent) {
    227             if (terminate) {
    228                 break;
    229             }
    230             if (nent->flags & CPUDB_F_IS_LOCAL) {
    231                 continue;
    232             }
    233             cpudb_key_format(nent->base.key, keybuf, sizeof(keybuf));
    234             dtype = "client";
    235             dsubtype = keybuf;
    236             rv = 0;
    237             for (dunit = 0; dunit < nent->base.num_units; dunit++) {
    238                 rv = bcm_find(dtype, dsubtype, dunit);
    239                 if (rv < 0) {
    240                     rv = bcm_attach(-1, dtype, dsubtype, dunit);
    241                 }
    242                 if (rv < 0) {
    243                     terminate = 1;
    244                     break;
    245                 }
    246                 if (rv >= 0 && !(BCM_CAPABILITY(rv) & BCM_CAPA_CALLBACK)) {
    247                     _bcm_stack_attach_cb_run(rv, 1, nent, dunit);
    248                     BCM_CAPABILITY(rv) |= BCM_CAPA_CALLBACK;
    249                 }
    250             }
    251         }
    252     }
    253     AT_UNLOCK;
    254 
    255     return BCM_E_NONE;
    256 }
    257 
    258 
    259 /*
    260  * Detach and attach bcm units to match the cpu database.
    261  */
    262 
    263 #ifdef BROADCOM_DEBUG
    264 
    265 /* Variables and callback for diagnostics */
    266 static int dt_unit, at_unit, at_cpu;
    267 static cpudb_entry_t *at_cpuent;
    268 
    269 static void
    270 _bcm_stack_at_dt_update(int unit,
    271                         int attach,
    272                         cpudb_entry_t *cpuent,
    273                         int cpuunit)
    274 {
    275     COMPILER_REFERENCE(unit);
    276     COMPILER_REFERENCE(cpuunit);
    277     if (attach) {
    278         at_unit++;
    279         /* count number of unique CPUs */
    280         if (cpuent != at_cpuent) {
    281             at_cpu++;
    282             at_cpuent = cpuent;
    283         }
    284     } else {
    285         dt_unit++;
    286     }
    287 }
    288 
    289 /* Debug version */
    290 
    291 STATIC void
    292 _bcm_stack_detach_attach(cpudb_ref_t db_ref)
    293 {
    294     int rv;
    295     char           keybuf[CPUDB_KEY_STRING_LEN];
    296     int            dbg_unit;
    297     cpudb_entry_t  *nent;
    298 
    299     AT_LOCK;
    300 
    301     dbg_unit = 0;
    302     CPUDB_FOREACH_ENTRY(db_ref, nent) {
    303         dbg_unit += nent->base.num_units;
    304     }
    305 
    306     rv = bcm_stack_attach_register(_bcm_stack_at_dt_update);
    307     if (BCM_SUCCESS(rv)) {
    308         dt_unit = at_unit = at_cpu = 0;
    309         at_cpuent = NULL;
    310         bcm_stack_detach(db_ref);
    311         bcm_stack_attach(db_ref);
    312         bcm_stack_attach_unregister(_bcm_stack_at_dt_update);
    313     }
    314     AT_UNLOCK;
    315 
    316     bcm_st_event_send(BCM_SUCCESS(rv) ?
    317                       BCM_STE_ATTACH_SUCCESS : BCM_STE_ATTACH_FAILURE);
    318     
    319     cpudb_key_format(db_ref->local_entry->base.key, keybuf, sizeof(keybuf));
    320     if (db_ref->local_entry == db_ref->master_entry) {
    321         LOG_INFO(BSL_LS_TKS_COMMON,
    322                  (BSL_META("STACK: master on %s (%d cpu%s, %d unit%s)\n"),
    323                   keybuf,
    324                   db_ref->num_cpus, db_ref->num_cpus == 1 ? "" : "s",
    325                   dbg_unit, dbg_unit == 1 ? "" : "s"));
    326     } else {
    327         char  keymast[CPUDB_KEY_STRING_LEN];
    328 
    329         cpudb_key_format(db_ref->master_entry->base.key,
    330                          keymast, sizeof(keymast));
    331         LOG_INFO(BSL_LS_TKS_COMMON,
    332                  (BSL_META("STACK: slave on %s (%d cpus, master %s)\n"),
    333                   keybuf, db_ref->num_cpus, keymast));
    334     }
    335 
    336     if (dt_unit > 0) {
    337         LOG_INFO(BSL_LS_TKS_COMMON,
    338                  (BSL_META("STACK: detach %d unit%s\n"),
    339                   dt_unit, dt_unit == 1 ? "" : "s"));
    340     }
    341 
    342     if (at_cpu > 0) {
    343         LOG_INFO(BSL_LS_TKS_COMMON,
    344                  (BSL_META("STACK: attach %d unit%s on %d cpu%s\n"),
    345                   at_unit, at_unit == 1 ? "" : "s",
    346                   at_cpu, at_cpu == 1 ? "" : "s"));
    347     }
    348 }
    349 
    350 #else
    351 
    352 /* Non-debug version */
    353 
    354 STATIC void
    355 _bcm_stack_detach_attach(cpudb_ref_t db_ref)
    356 {
    357     AT_LOCK;
    358     bcm_stack_detach(db_ref);
    359     bcm_stack_attach(db_ref);
    360     AT_UNLOCK;
    361 
    362     bcm_st_event_send(BCM_STE_ATTACH_SUCCESS);
    363 }
    364 
    365 #endif /* BROADCOM_DEBUG */
    366 
    367 /*
    368  *   asynchronous _bcm_stack_attach()
    369  */
    370 
    371 STATIC void
    372 _bcm_stack_attach_thread(void *cookie)
    373 {
    374     cpudb_ref_t db_ref = (cpudb_ref_t)cookie;
    375 
    376     _bcm_stack_attach_thread_active++;
    377 
    378     _bcm_stack_detach_attach(db_ref);
    379 
    380     _bcm_stack_attach_thread_active--;
    381 
    382     sal_thread_exit(0);
    383 
    384 }
    385 
    386 /*
    387  * The actual callout routine that the stack task calls.
    388  *
    389  * The stack attach update call takes place in the ATP RX thread
    390  * context.  Any attach callback might require the use of packet
    391  * services that would need to use the RX thread (BCM RPC calls for
    392  * example using ATP), so those callbacks are done in a new thread
    393  * context.
    394  */
    395 int
    396 bcm_stack_attach_update(cpudb_ref_t db_ref)
    397 {
    398     if (at_lock == NULL) {
    399         return BCM_E_INIT;
    400     }
    401 
    402     if (_attach_cb != NULL) {
    403 
    404         (void) sal_thread_create("bcmATTACH",
    405                                  ATTACH_THREAD_STACK,
    406                                  ATTACH_THREAD_PRIO,
    407                                  _bcm_stack_attach_thread,
    408                                  (void *)db_ref);
    409     } else {
    410         _bcm_stack_detach_attach((void *)db_ref);
    411     }
    412     return BCM_E_NONE;
    413 }
    414 
    415 /*
    416  * Return TRUE if the attach process is running
    417  */
    418 int
    419 bcm_stack_attach_running(void)
    420 {
    421     if ((_bcm_stack_attach_thread_active < 0) ||
    422         (_bcm_stack_attach_thread_active >= 2)) {
    423         assert(0);
    424     }
    425     return _bcm_stack_attach_thread_active != 0;
    426 }
    427 
    428 /*
    429  * Initialize resources needed by the attach process.
    430  */
    431 int
    432 bcm_stack_attach_init(void)
    433 {
    434     if (at_lock == NULL) {
    435         at_lock = sal_mutex_create("bcm_attach");
    436         if (at_lock == NULL) {
    437             return BCM_E_MEMORY;
    438         }
    439     }
    440     return BCM_E_NONE;
    441 }
    442