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

alpm_hit.c (17472B)


      1 /*
      2  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      3  * 
      4  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      5  * 
      6  * File:    alpm_hit.c
      7  * Purpose: ALPM Distributed HITBIT (device independent implementation).
      8  * Requires:
      9  */
     10 
     11 /* Implementation notes:
     12  */
     13 #include <shared/bsl.h>
     14 
     15 #include <soc/mem.h>
     16 #include <soc/drv.h>
     17 #include <soc/debug.h>
     18 #include <soc/error.h>
     19 #include <soc/lpm.h>
     20 #include <soc/trident2.h>
     21 #include <soc/tomahawk.h>
     22 #include <shared/bsl.h>
     23 
     24 #include <shared/util.h>
     25 #include <shared/l3.h>
     26 
     27 #if defined(ALPM_ENABLE)
     28 
     29 #include <bcm/l3.h>
     30 
     31 #include <bcm_int/esw/l3.h>
     32 #include <bcm_int/esw/firebolt.h>
     33 #include <bcm_int/esw/alpm.h>
     34 #include <bcm_int/esw/alpm_util.h>
     35 
     36 _alpm_dist_hitbit_t *alpm_dist_hitbit[SOC_MAX_NUM_DEVICES];
     37 
     38 /* Find the mem Hw location in upper CB bucket (upr_bkt_node->ent_idx)
     39  * for a pivot in current CB
     40  */
     41 int
     42 alpm_pvt_ent_idx_get(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node,
     43                      int *ent_idx)
     44 {
     45     int rv = BCM_E_NONE;
     46     _bcm_defip_cfg_t lpm_cfg;
     47     _alpm_pvt_node_t *upr_pvt_node = NULL;
     48     _alpm_bkt_node_t *upr_bkt_node = NULL;
     49 
     50     if (ACB_HAS_TCAM(acb)) { /* skip top CB */
     51         return BCM_E_INTERNAL;
     52     }
     53 
     54     sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg));
     55 
     56     /* defip_flags */
     57     if (PVT_BKT_TRIE(pvt_node) &&
     58         PVT_BKT_TRIE(pvt_node)->v6_key) {
     59         lpm_cfg.defip_flags |= BCM_L3_IP6;
     60     }
     61 
     62     /* Key & Length (lpm_cfg.user_data will be used in _alpm_find()) */
     63     alpm_trie_pfx_to_cfg(u, pvt_node->key, pvt_node->key_len, &lpm_cfg);
     64     sal_memcpy(lpm_cfg.user_data, pvt_node->key, sizeof(pvt_node->key));
     65     lpm_cfg.defip_vrf = ALPM_VRF_ID_TO_VRF(u, PVT_BKT_VRF(pvt_node));
     66 
     67     /* Find corresponding upper CB pivot and bucket */
     68     rv = alpm_cb_find(u, ACB_UPR(u, acb), &lpm_cfg,
     69                     &upr_pvt_node, &upr_bkt_node);
     70 
     71     if (BCM_SUCCESS(rv)) {
     72         *ent_idx = (int)upr_bkt_node->ent_idx;
     73     }
     74 
     75     return rv;
     76 }
     77 
     78 /*
     79  * Function:
     80  *      alpm_rte_hit_get
     81  * Purpose:
     82  *      Get ALPM route hitbit status via hitbit cache sync with Hw
     83  *      and gathering pivot hitbit status whose BPM is the route.
     84  * Parameters:
     85  *      u       - Device unit #.
     86  *      vrf_id  - VRF ID for logic hit table PID in Parallel/Mixed Mode
     87  *      idx     - ALPM route bucket level table index
     88  *      ent     - Route entry ID (0-15)
     89  * Returns:
     90  *      Route hit bit (0 or 1)
     91  */
     92 int
     93 alpm_rte_hit_get(int u, int vrf_id, _alpm_tbl_t tbl, int idx, int ent)
     94 {
     95     int rv = BCM_E_UNAVAIL;
     96     rv = ALPM_DRV(u)->alpm_bkt_hit_get(u, vrf_id, ACB_VRF_BTM(u, vrf_id),
     97                                        tbl, idx, ent);
     98     return rv;
     99 }
    100 
    101 /* Get bucket entry hitbit status from cached Hit table in ent_idx */
    102 int
    103 alpm_bkt_hit_get(int u, int vrf_id, _alpm_cb_t *acb, _alpm_tbl_t tbl, int ent_idx)
    104 {
    105     int rv = BCM_E_UNAVAIL;
    106     int idx, ent;
    107 
    108     ent = ALPM_IDX_TO_ENT(ent_idx);
    109     idx = ALPM_TAB_IDX_GET(ent_idx);
    110 
    111     rv = ALPM_DRV(u)->alpm_bkt_hit_get(u, vrf_id, acb, tbl, idx, ent);
    112     return rv;
    113 }
    114 
    115 /* Set ALPM route hitbit=1 via cached Hit table by idx and ent */
    116 int
    117 alpm_rte_hit_set(int u, int vrf_id, _alpm_tbl_t tbl, int idx, int ent)
    118 {
    119     int rv = BCM_E_UNAVAIL;
    120     rv = ALPM_DRV(u)->alpm_bkt_hit_set(u, vrf_id, ACB_VRF_BTM(u, vrf_id),
    121                                        tbl, idx, ent, 1);
    122     return rv;
    123 }
    124 
    125 /* Set ALPM bucket entry hitbit status to cached Hit table
    126    in ent_idx with hit_val */
    127 int
    128 alpm_bkt_hit_set(int u, int vrf_id, _alpm_cb_t *acb,
    129                  _alpm_tbl_t tbl, int ent_idx, int hit_val)
    130 {
    131     int rv = BCM_E_UNAVAIL;
    132     int idx, ent;
    133 
    134     ent = ALPM_IDX_TO_ENT(ent_idx);
    135     idx = ALPM_TAB_IDX_GET(ent_idx);
    136 
    137     rv = ALPM_DRV(u)->alpm_bkt_hit_set(u, vrf_id, acb, tbl, idx, ent, hit_val);
    138 
    139     return rv;
    140 }
    141 
    142 /* Set ALPM bucket entry hitbit status to hitbit table cache
    143    and write to Hw (by setting Entry Move & Mask to trigger write to Hw
    144    in next Dist Hitbit thread clycle). */
    145 int
    146 alpm_bkt_hit_write_hw(int u, int vrf_id, _alpm_cb_t *acb,
    147                       _alpm_tbl_t tbl, int ent_idx, int hit_val)
    148 {
    149     int rv = BCM_E_UNAVAIL;
    150     rv = ALPM_DRV(u)->alpm_bkt_hit_write(u, vrf_id, acb, tbl, ent_idx, hit_val);
    151     return rv;
    152 }
    153 
    154 /* Get ALPM pivot hitbit status from cached Hit table */
    155 int
    156 alpm_pvt_hit_get(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node)
    157 {
    158     int         rv = BCM_E_NONE;
    159     int         tcam_idx, ent_idx, vrf_id;
    160     _alpm_tbl_t tbl = alpmTblInvalid;
    161 
    162     if (ACB_HAS_TCAM(acb)) { /* TCAM pre-pivot cb=0 */
    163         int pkm, ipt = PVT_BKT_IPT(pvt_node);
    164         tcam_idx = PVT_IDX(pvt_node);
    165         pkm = ALPM_PKM_RECOVER(u, ipt);
    166         rv = tcam_cache_hit_get(u, pkm, tcam_idx);
    167 
    168     } else { /* Pivot cb=1 */
    169         vrf_id = PVT_BKT_VRF(pvt_node);
    170         /* Get upper CB bucket ent_idx for the pivot */
    171         ALPM_IER(alpm_pvt_ent_idx_get(u, acb, pvt_node, &ent_idx));
    172         rv = alpm_bkt_hit_get(u, vrf_id, ACB_UPR(u, acb), tbl, ent_idx);
    173     }
    174 
    175     return rv;
    176 }
    177 
    178 /* ALPM pivot dist hitbit gathering to BPM route */
    179 int
    180 alpm_pvt_hit_cb(int u, _alpm_cb_t *acb,
    181                 _alpm_pvt_node_t *pvt_node, void *user_data)
    182 {
    183     int rv = BCM_E_NONE;
    184     int idx, ent;
    185     int vrf_id = PVT_BKT_VRF(pvt_node);
    186     _alpm_bkt_node_t *def_node = PVT_BKT_DEF(pvt_node);
    187     _alpm_tbl_t tbl = alpmTblInvalid;
    188 
    189     if (def_node != NULL) { /* pivot BPM route exists */
    190         ent = ALPM_IDX_TO_ENT(def_node->ent_idx);
    191         idx = ALPM_TAB_IDX_GET(def_node->ent_idx);
    192 
    193         rv = alpm_rte_hit_get(u, vrf_id, tbl, idx, ent);
    194         if (rv) { /* continue if route hit=0 */
    195             return rv;
    196         }
    197 
    198         rv = alpm_pvt_hit_get(u, acb, pvt_node);
    199         if (rv <= 0) { /* continue if pivot hit=1 */
    200             return rv;
    201         }
    202 
    203         /* Set route hit to 1 if BPM pivot hit=1 */
    204         rv = alpm_rte_hit_set(u, vrf_id, tbl, idx, ent);
    205     }
    206 
    207     return BCM_E_NONE;
    208 }
    209 
    210 /* Walk pivot tries and gather hitbit to BPM route */
    211 int
    212 alpm_hitbit_gather(int u)
    213 {
    214     int         i, vrf_id, ipt;
    215     int         rv = BCM_E_NONE;
    216     _alpm_cb_t  *acb;
    217 
    218     for (i = 0; i < ACB_CNT(u); i++) {
    219         acb = ACB(u, i);
    220         for (vrf_id = 0; vrf_id <= ALPM_VRF_ID_MAX(u); vrf_id++) {
    221             for (ipt = 0; ipt < ALPM_IPT_CNT; ipt++) {
    222                 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) {
    223                     continue;
    224                 }
    225                 rv = bcm_esw_alpm_pvt_traverse(u, i, vrf_id, ipt,
    226                                                alpm_pvt_hit_cb, NULL);
    227             }
    228         }
    229     }
    230 
    231     return rv;
    232 }
    233 
    234 /* Sync ALPM non-TCAM level (i:0/1 for level 2/3) hitbit cache with Hw */
    235 int
    236 alpm_hitbit_sync_cache(int u, int i, int pid)
    237 {
    238     int rv = BCM_E_UNAVAIL;
    239     rv = ALPM_DRV(u)->alpm_hit_cache_sync(u, i, pid);
    240 
    241     return rv;
    242 }
    243 
    244 /* Write ALPM non-TCAM level (i:0/1 for level 2/3) hitbit cache to Hw */
    245 int
    246 alpm_hitbit_write_hw(int u, int i, int pid)
    247 {
    248     int rv = BCM_E_UNAVAIL;
    249     rv = ALPM_DRV(u)->alpm_hit_hw_write(u, i, pid);
    250 
    251     return rv;
    252 }
    253 
    254 /* Update hitbit for entry move on level i by
    255  * hit_cache = (hit_cache & ~hit_move_mask) | (hit_move & hit_move_mask)
    256  */
    257 int
    258 alpm_hitbit_ent_move_update(int u, int i, int pid)
    259 {
    260     int rv = BCM_E_UNAVAIL;
    261     rv = ALPM_DRV(u)->alpm_hit_move_update(u, i, pid);
    262 
    263     return rv;
    264 }
    265 
    266 /* Reset hitbit ent move, move mask and moved flag
    267  * for next cycle of dist hitbit thread
    268  */
    269 int
    270 alpm_hitbit_ent_move_reset(int u, int i, int pid)
    271 {
    272     int alloc_sz = ALPM_HTBL_SIZE(u, i, pid);
    273 
    274     sal_memset(ALPM_HTBL_MOVE(u, i, pid), 0, alloc_sz);
    275     sal_memset(ALPM_HTBL_MOVE_MASK(u, i, pid), 0, alloc_sz);
    276 
    277     ALPM_HTBL_ENT_MOVED(u, i, pid) = FALSE;
    278     ALPM_HTBL_ENT_MOVED_CNT(u, i, pid) = 0;
    279     return BCM_E_NONE;
    280 }
    281 
    282 /* Get TCAM hitbit status from a TCAM entry */
    283 int
    284 tcam_entry_hit_get(int u, int pkm, void *e, int sub_idx)
    285 {
    286     int         rv = BCM_E_UNAVAIL;
    287 
    288     rv = ALPM_DRV(u)->tcam_entry_hit_get(u, pkm, e, sub_idx);
    289 
    290     return rv;
    291 }
    292 
    293 /* Get TCAM cached entry hitbit status from pivot's tcam_idx */
    294 int
    295 tcam_cache_hit_get(int u, int pkm, int tcam_idx)
    296 {
    297     int         rv = BCM_E_UNAVAIL;
    298 
    299     rv = ALPM_DRV(u)->tcam_cache_hit_get(u, pkm, tcam_idx);
    300 
    301     return rv;
    302 }
    303 
    304 /* Sync TCAM hitbit cache with Hw */
    305 int
    306 tcam_hitbit_sync_cache(int u)
    307 {
    308     int         rv = BCM_E_UNAVAIL;
    309 
    310     rv = ALPM_DRV(u)->tcam_hit_cache_sync(u);
    311 
    312     return rv;
    313 }
    314 
    315 /*
    316  * Function:
    317  *      bcm_esw_alpm_clear_hit
    318  * Purpose:
    319  *      Clear ALPM route hit bit from found lpm_cfg->bkt_node->ent_idx.
    320  * Parameters:
    321  *      u       - (IN)SOC unit number.
    322  *      lpm_cfg - (IN)Found lpm defip_cfg info
    323  * Returns:
    324  *      BCM_E_XXX
    325  */
    326 int
    327 bcm_esw_alpm_clear_hit(int u, _bcm_defip_cfg_t *lpm_cfg)
    328 {
    329     int rv = BCM_E_NONE;
    330 
    331     _alpm_pvt_node_t *pvt_node = (_alpm_pvt_node_t *)lpm_cfg->pvt_node;
    332     _alpm_bkt_node_t *bkt_node = (_alpm_bkt_node_t *)lpm_cfg->bkt_node;
    333     _alpm_cb_t  *acb;
    334     int vrf_id;
    335     _alpm_tbl_t tbl;
    336 
    337     vrf_id = PVT_BKT_VRF(pvt_node);
    338     acb = ACB_VRF_BTM(u, vrf_id);
    339     tbl = BPC_BKT_TBL(ACB_BKT_VRF_POOL(acb, vrf_id));
    340 
    341     if (ALPM_HIT_SKIP(u)) {
    342         return rv;
    343     }
    344 
    345     if (pvt_node && bkt_node) {
    346         rv = alpm_bkt_hit_write_hw(u, vrf_id, acb, tbl, bkt_node->ent_idx, 0);
    347     } else {
    348         rv = BCM_E_NOT_FOUND;
    349     }
    350 
    351     return rv;
    352 }
    353 
    354 /*
    355  * Function:
    356  *      alpm_dist_hitbit_thread
    357  * Purpose:
    358  *      ALPM distributed hitbit thread running periodically
    359  *      to sync hitbit cache with Hw, gathering pivot hitbit status
    360  *      to BPM route, and write hitbit entry move to Hw.
    361  * Parameters:
    362  *      u - Device unit #.
    363  * Returns:
    364  *      Nothing
    365  */
    366 STATIC void
    367 alpm_dist_hitbit_thread(int u)
    368 {
    369     int i, pid;
    370     _alpm_cb_t *acb;
    371     sal_usecs_t t0, t1, t2, t3, t4, t5;
    372 
    373     ALPM_INFO(("thread starting on unit %d\n", u));
    374     ALPMDH(u)->thread = sal_thread_self();
    375 
    376     while (ALPMDH(u)->interval != 0) {
    377         ALPM_HIT_LOCK(u);
    378         t0 = sal_time_usecs();
    379         if (soc_feature(u, soc_feature_distributed_hit_bits)) {
    380             /* Sync TCAM hitbit cache with Hw */
    381             tcam_hitbit_sync_cache(u);
    382         }
    383 
    384         t1 = sal_time_usecs();
    385         /* Sync Bucket level hitbit caches with Hw */
    386         for (i = 0; i < ACB_CNT(u); i++) {
    387             acb = ACB(u, i);
    388             for (pid = 0; pid < ACB_PID_CNT(acb); pid++) {
    389                 alpm_hitbit_sync_cache(u, i, pid);
    390             }
    391         }
    392 
    393         t2 = sal_time_usecs();
    394         /* Entry move hitbits handling for bucket levels.
    395            TCAM entry move writes hitbit in combined view
    396            directly to cache/Hw by soc_mem_write() */
    397         for (i = 0; i < ACB_CNT(u); i++) {
    398             acb = ACB(u, i);
    399             for (pid = 0; pid < ACB_PID_CNT(acb); pid++) {
    400                 alpm_hitbit_ent_move_update(u, i, pid);
    401             }
    402         }
    403 
    404         t3 = sal_time_usecs();
    405         if (soc_feature(u, soc_feature_distributed_hit_bits)) {
    406             alpm_hitbit_gather(u);
    407         }
    408         t4 = sal_time_usecs();
    409         /* Wtite to Hw if moved and reset ent move and move mask */
    410         for (i = 0; i < ACB_CNT(u); i++) {
    411             acb = ACB(u, i);
    412             for (pid = 0; pid < ACB_PID_CNT(acb); pid++) {
    413                 if (ALPM_HTBL_ENT_MOVED(u, i, pid)) {
    414                     if (ALPMC(u)->_alpm_dbg_info_bmp & _ALPM_DBG_INFO_HIT) {
    415                         LOG_CLI(("Writes to L%d PID %d hit table: %d (entries)\n",
    416                                  i+2, pid, ALPM_HTBL_ENT_MOVED_CNT(u, i, pid)));
    417                     }
    418                     t5 = sal_time_usecs();
    419                     alpm_hitbit_write_hw(u, i, pid);
    420                     if (ALPMC(u)->_alpm_dbg_info_bmp & _ALPM_DBG_INFO_HIT) {
    421                         LOG_CLI(("Hit table L%d PID %d write latency: %u (us).\n", i+2, pid,
    422                                  sal_time_usecs() - t5));
    423                     }
    424                 }
    425                 alpm_hitbit_ent_move_reset(u, i, pid);
    426             }
    427         }
    428 
    429         if (ALPMC(u)->_alpm_dbg_info_bmp & _ALPM_DBG_INFO_HIT) {
    430             t5 = sal_time_usecs();
    431             ALPM_INFO(("\nTime: %lu (sec), latency: %d %d %d %d %d (us)\n",
    432                        sal_time(), t1-t0, t2-t1, t3-t2, t4-t3, t5-t4));
    433         }
    434         ALPM_HIT_UNLOCK(u);
    435         /* wait for next cycle after interval time */
    436         (void)sal_sem_take(ALPMDH(u)->sema, ALPMDH(u)->interval);
    437     }
    438 
    439     ALPM_INFO(("thread exiting on unit %d\n", u));
    440 
    441     ALPMDH(u)->thread = NULL;
    442     sal_thread_exit(0);
    443 }
    444 
    445 /*
    446  * Function:
    447  *      alpm_dist_hitbit_enable_set
    448  * Purpose:
    449  *      Enable or disable the ALPM distributed hitbits
    450  *      background thread feature.
    451  * Parameters:
    452  *      u  - Device unit #.
    453  *      us - Specifies the software polling interval in micro-seconds;
    454  *           the value 0 disables Dist hitbits thread.
    455  * Returns:
    456  *      BCM_E_XXX
    457  */
    458 
    459 int
    460 alpm_dist_hitbit_enable_set(int u, int us)
    461 {
    462     int                 rv = BCM_E_NONE;
    463     soc_timeout_t       to;
    464     sal_usecs_t         wait_usec;
    465 
    466     /* Time to wait for thread to start/end (longer for BCMSIM) */
    467     wait_usec = (SAL_BOOT_BCMSIM || SAL_BOOT_QUICKTURN) ? 30000000 : 10000000;
    468 
    469     if (ALPMDH(u) == NULL) { /* No error to disable if not inited */
    470         return(BCM_E_NONE);
    471     }
    472 
    473     sal_snprintf(ALPMDH(u)->taskname, sizeof(ALPMDH(u)->taskname),
    474                  "bcmALPMDH.%d", u);
    475 
    476     if (us) {
    477         ALPMDH(u)->interval = us;
    478 
    479         if (ALPMDH(u)->thread != NULL) {
    480             /* Dist hit thread is already running; just update the period */
    481             sal_sem_give(ALPMDH(u)->sema);
    482             return BCM_E_NONE;
    483         }
    484 
    485         if (sal_thread_create(ALPMDH(u)->taskname,
    486                               SAL_THREAD_STKSZ,
    487                               ALPMDH(u)->priority,
    488                               (void (*)(void*))alpm_dist_hitbit_thread,
    489                               INT_TO_PTR(u)) == SAL_THREAD_ERROR) {
    490             ALPM_ERR(("%s: Thread create error\n", ALPMDH(u)->taskname));
    491             ALPMDH(u)->interval = 0;
    492             rv = BCM_E_MEMORY;
    493         } else {
    494             soc_timeout_init(&to, wait_usec, 0);
    495 
    496             while (ALPMDH(u)->thread == NULL) {
    497                 if (soc_timeout_check(&to)) {
    498                     ALPM_ERR(("%s: Thread did not start\n",
    499                               ALPMDH(u)->taskname));
    500                     ALPMDH(u)->interval = 0;
    501                     rv = BCM_E_INTERNAL;
    502                     break;
    503                 }
    504             }
    505 
    506             if (BCM_SUCCESS(rv)) {
    507                 LOG_CLI(("ALPM Distributed HITBIT thread enabled (interval %d us)\n", us));
    508             }
    509         }
    510     } else if (ALPMDH(u)->thread != NULL) {
    511         ALPMDH(u)->interval = 0;
    512 
    513         sal_sem_give(ALPMDH(u)->sema);
    514         soc_timeout_init(&to, 5 * wait_usec, 0);
    515 
    516         while (ALPMDH(u)->thread != NULL) {
    517             if (soc_timeout_check(&to)) {
    518                 ALPM_ERR(("%s: Thread did not exit\n", ALPMDH(u)->taskname));
    519                 rv = BCM_E_INTERNAL;
    520                 break;
    521             }
    522         }
    523 
    524         if (BCM_SUCCESS(rv)) {
    525             LOG_CLI(("ALPM Distributed HITBIT thread disabled\n"));
    526         }
    527     }
    528 
    529     return rv;
    530 }
    531 
    532 int
    533 alpm_dist_hitbit_interval_get(int u)
    534 {
    535     if (ALPMDH(u)) {
    536         return ALPMDH(u)->interval;
    537     } else {
    538         return 0;
    539     }
    540 }
    541 
    542 /* Deinit ALPM distributed hitbit */
    543 int
    544 bcm_esw_alpm_hit_deinit(int u)
    545 {
    546     int rv = BCM_E_NONE;
    547 
    548     if (ALPM_HIT_SKIP(u)) {
    549         return rv;
    550     }
    551 
    552     if (ALPMDH(u) != NULL) {
    553         ALPM_INFO(("ALPM distributed hitbits thread end\n"));
    554         rv = alpm_dist_hitbit_enable_set(u, 0);
    555 
    556         if (ALPMDH(u)->sema != NULL) {
    557             sal_sem_destroy(ALPMDH(u)->sema);
    558             ALPMDH(u)->sema = NULL;
    559         }
    560 
    561         ALPM_DRV(u)->alpm_hit_deinit(u);
    562 
    563         alpm_util_free(ALPMDH(u));
    564         ALPMDH(u) = NULL;
    565     }
    566 
    567     return rv;
    568 }
    569 
    570 /* Initialize ALPM distributed hitbit */
    571 int
    572 bcm_esw_alpm_hit_init(int u)
    573 {
    574     int         rv = BCM_E_NONE;
    575     sal_usecs_t usec, def;
    576 
    577     if (ALPM_HIT_SKIP(u)) {
    578         return rv;
    579     }
    580 
    581     if (ALPMDH(u) != NULL) {
    582         bcm_esw_alpm_hit_deinit(u);
    583     }
    584 
    585     ALPM_ALLOC_EG(ALPMDH(u), sizeof(_alpm_dist_hitbit_t), "ALPMDH");
    586 
    587     ALPM_IEG(ALPM_DRV(u)->alpm_hit_init(u));
    588 
    589     /* Initialize ALPM dist hitbit thread */
    590 
    591     def = (SAL_BOOT_BCMSIM || SAL_BOOT_QUICKTURN) ? 30000000 : ALPM_HIT_INTERVAL_DEF;
    592     usec = soc_property_get(u, "alpm_dist_hit_interval_us", def);
    593     /* Set usec=0 to disable thread */
    594     if ((usec < ALPM_HIT_INTERVAL_MIN) && (usec > 0)) {
    595         usec = ALPM_HIT_INTERVAL_MIN;
    596     }
    597     if (usec > ALPM_HIT_INTERVAL_MAX) {
    598         usec = ALPM_HIT_INTERVAL_MAX;
    599     }
    600     ALPMDH(u)->priority = soc_property_get(u, "alpm_dist_hit_priority",
    601                                            ALPM_HIT_PRIORITY_DEF);
    602     ALPMDH(u)->sema = sal_sem_create("bcmHit_SLEEP", sal_sem_BINARY, 0);
    603     if (ALPMDH(u)->sema == NULL) {
    604         ALPM_IEG(BCM_E_MEMORY);
    605     }
    606 
    607     ALPM_IEG(alpm_dist_hitbit_enable_set(u, usec));
    608 
    609     return rv;
    610 
    611 bad:
    612     bcm_esw_alpm_hit_deinit(u);
    613     return rv;
    614 }
    615 
    616 /*
    617  * Function:
    618  *      alpm_dist_hitbit_thread_stop
    619  * Purpose:
    620  *      Stop the ALPM distributed hitbits thread
    621  * Parameters:
    622  *      u  - Device unit #.
    623  * Returns:
    624  *      BCM_E_XXX
    625  */
    626 int
    627 alpm_dist_hitbit_thread_stop(int unit)
    628 {
    629     int rv = BCM_E_NONE;
    630     if (ALPMC(unit) && !ALPM_HIT_SKIP(unit)) {
    631         rv = alpm_dist_hitbit_enable_set(unit, 0);
    632     }
    633     return rv;
    634 }
    635 
    636 #endif /* ALPM_ENABLE */
    637