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

l2x.c (12310B)


      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  * Tomahawk switch doesn't completely support the hardware based l2 aging 
      8  * mechanism. Although it provides the l2 aging function, it doesn't have
      9  * a periodic timer to trigger the function. 
     10  * This file implements a timer thread to support the software triggered 
     11  * L2 aging. The thread periodically performs the aging function through 
     12  * the L2_BULK_CONTROL register at the user configured time interval.
     13  * The aging action checkes the hit bit of each entry in the l2 table.
     14  * If the hit bit is not set, the entry is deleted. If it is set, the
     15  * hit bit is cleared and the entry remains. Only static entries are 
     16  * excluded from l2 aging.
     17  */
     18 
     19 #include <shared/bsl.h>
     20 
     21 #include <sal/core/libc.h>
     22 
     23 #include <soc/drv.h>
     24 #include <soc/l2x.h>
     25 #include <soc/ptable.h>
     26 #include <soc/debug.h>
     27 #include <soc/util.h>
     28 #include <soc/mem.h>
     29 #include <soc/tomahawk.h>
     30 #include <bcm_int/esw/l2.h>
     31 
     32 #ifdef BCM_XGS_SWITCH_SUPPORT
     33 
     34 #define _SOC_TH_L2_BULK_BURST_MIN  0
     35 
     36 static int _soc_th_l2_bulk_age_iter[SOC_MAX_NUM_DEVICES] = {0};
     37 STATIC int
     38 _soc_th_l2_bulk_age_entries_delete(int unit, int *retry)
     39 {
     40     int rv;
     41     l2_bulk_entry_t match_mask;
     42     l2_bulk_entry_t match_data;
     43     l2_bulk_entry_t new_mask;
     44     l2_bulk_entry_t new_data;
     45     uint32 rval = 0;
     46     uint32 start = 0;
     47     uint32 complete = 0;
     48     soc_field_t valid_f = VALIDf;
     49     if (soc_feature(unit, soc_feature_base_valid)) {
     50         valid_f = BASE_VALIDf;
     51     }
     52 
     53     *retry = 0;
     54     sal_memset(&match_mask, 0, sizeof(match_mask));
     55     sal_memset(&match_data, 0, sizeof(match_data));
     56 
     57     soc_mem_field32_set(unit, L2_BULKm, &match_mask, valid_f, 1);
     58     soc_mem_field32_set(unit, L2_BULKm, &match_data, valid_f, 1);
     59 
     60     soc_mem_field32_set(unit, L2_BULKm, &match_mask, STATIC_BITf, 1);
     61     soc_mem_field32_set(unit, L2_BULKm, &match_mask, HITSAf, 1);
     62     soc_mem_field32_set(unit, L2_BULKm, &match_mask, HITDAf, 1);
     63 
     64     sal_memset(&new_data, 0, sizeof(l2_bulk_entry_t));
     65     sal_memset(&new_mask, 0, sizeof(l2_bulk_entry_t));
     66 
     67     soc_mem_lock(unit, L2Xm);
     68     rv = READ_L2_BULK_CONTROLr(unit, &rval);
     69     start = soc_reg_field_get(unit, L2_BULK_CONTROLr, rval, STARTf);
     70     complete = soc_reg_field_get(unit, L2_BULK_CONTROLr, rval, COMPLETEf);
     71 
     72     if ((start == 1) && (complete == 0)) {
     73         *retry = 1;
     74         soc_mem_unlock(unit, L2Xm);
     75         return SOC_E_BUSY;
     76     }
     77 
     78     if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) {
     79         soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 1);
     80         soc_mem_field32_set(unit, L2_BULKm, &new_mask, valid_f, 1);
     81     } else {
     82         soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 0);
     83         sal_memset(&new_mask, 0xff, sizeof(l2_bulk_entry_t));
     84     }
     85     soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 2);
     86     soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, BURST_ENTRIESf, 
     87                       _SOC_TH_L2_BULK_BURST_MIN);
     88     soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 
     89                       soc_mem_index_count(unit, L2Xm));
     90 
     91     /* write to bulk mask entry, valid bit and static bit */
     92     rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
     93                         _BCM_L2_BULK_MATCH_MASK_INX, &match_mask);
     94     /* write to bulk data entry, valid=1 and static=0 */
     95     rv |= WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
     96                          _BCM_L2_BULK_MATCH_DATA_INX, &match_data);
     97     rv |= WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
     98                          _BCM_L2_BULK_REPLACE_DATA_INX, &new_data);
     99     rv |= WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
    100                          _BCM_L2_BULK_REPLACE_MASK_INX, &new_mask);
    101     if (SOC_SUCCESS(rv)) {
    102         rv = WRITE_L2_BULK_CONTROLr(unit, rval);
    103     }
    104     if (SOC_SUCCESS(rv)) {
    105         rv = soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr);
    106         if (rv == SOC_E_TIMEOUT) {
    107             *retry = 1;
    108         }
    109     }
    110     soc_mem_unlock(unit, L2Xm);
    111     return rv;
    112 }
    113 
    114 STATIC int
    115 _soc_th_l2_bulk_age_entries_hit_clear(int unit, int *retry)
    116 {
    117     int rv;
    118     l2_bulk_entry_t match_mask;
    119     l2_bulk_entry_t match_data;
    120     l2_bulk_entry_t new_mask;
    121     l2_bulk_entry_t new_data;
    122     uint32 rval = 0;
    123     uint32 start = 0;
    124     uint32 complete = 0;
    125     soc_field_t valid_f = VALIDf;
    126     if (soc_feature(unit, soc_feature_base_valid)) {
    127         valid_f = BASE_VALIDf;
    128     }
    129 
    130     *retry = 0;
    131     sal_memset(&match_mask, 0, sizeof(match_mask));
    132     sal_memset(&match_data, 0, sizeof(match_data));
    133 
    134     /* Match VALIDf=1, HITSAf=1, HITDAf=1 */
    135     /* Set match data */
    136     sal_memset(&match_data, 0, sizeof(l2_bulk_entry_t));
    137     soc_mem_field32_set(unit, L2_BULKm, &match_data, valid_f, 1);
    138     
    139     /* Set match mask */
    140     sal_memset(&match_mask, 0, sizeof(l2_bulk_entry_t));
    141     soc_mem_field32_set(unit, L2_BULKm, &match_mask, valid_f, 1);
    142 
    143     sal_memset(&new_data, 0, sizeof(l2_bulk_entry_t));
    144     /* Clear HIT bits */
    145     sal_memset(&new_mask, 0, sizeof(l2_bulk_entry_t));
    146     soc_mem_field32_set(unit, L2_BULKm, &new_mask, HITSAf, 1);
    147     soc_mem_field32_set(unit, L2_BULKm, &new_mask, HITDAf, 1);
    148     soc_mem_field32_set(unit, L2_BULKm, &new_mask, LOCAL_SAf, 1);
    149 
    150     soc_mem_lock(unit, L2Xm);
    151     rv = READ_L2_BULK_CONTROLr(unit, &rval);
    152     start = soc_reg_field_get(unit, L2_BULK_CONTROLr, rval, STARTf);
    153     complete = soc_reg_field_get(unit, L2_BULK_CONTROLr, rval, COMPLETEf);
    154 
    155     if ((start == 1) && (complete == 0)) {
    156         *retry = 1;
    157         soc_mem_unlock(unit, L2Xm);
    158         return SOC_E_BUSY;
    159     }
    160 
    161     if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) {
    162         soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 0);
    163     }
    164     soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 2);
    165     soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, BURST_ENTRIESf, 
    166                       _SOC_TH_L2_BULK_BURST_MIN);
    167     soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 
    168                       soc_mem_index_count(unit, L2Xm));
    169 
    170     rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
    171                         _BCM_L2_BULK_MATCH_MASK_INX, &match_mask);
    172     rv |= WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
    173                          _BCM_L2_BULK_MATCH_DATA_INX, &match_data);
    174     rv |= WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
    175                          _BCM_L2_BULK_REPLACE_DATA_INX, &new_data);
    176     rv |= WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
    177                          _BCM_L2_BULK_REPLACE_MASK_INX, &new_mask);
    178     if (SOC_SUCCESS(rv)) {
    179         rv = WRITE_L2_BULK_CONTROLr(unit, rval);
    180     }
    181     if (SOC_SUCCESS(rv)) {
    182         rv = soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr);
    183         if (rv == SOC_E_TIMEOUT) {
    184             *retry = 1;
    185         }
    186     }
    187     soc_mem_unlock(unit, L2Xm);
    188     return rv;
    189 }
    190 
    191 /*
    192  * Function:
    193  * 	_soc_tr3_l2_bulk_age
    194  * Purpose:
    195  *   	l2 bulk age thread
    196  * Parameters:
    197  *	unit - unit number.
    198  * Returns:
    199  *	none
    200  */
    201 STATIC void
    202 _soc_th_l2_bulk_age(void *unit_vp)
    203 {
    204     int unit = PTR_TO_INT(unit_vp);
    205     int c, m, r, rv, iter = 0, retry = 0;
    206     soc_control_t *soc = SOC_CONTROL(unit);
    207     sal_usecs_t interval;
    208     sal_usecs_t stime, etime;
    209 
    210     while((interval = soc->l2x_age_interval) != 0) {
    211         if (!iter) {
    212             goto age_delay;
    213         }
    214         LOG_VERBOSE(BSL_LS_SOC_ARL,
    215                     (BSL_META_U(unit,
    216                                 "l2_bulk_age_thread: "
    217                                 "Process iters(total:%d, this run:%d\n"),
    218                      ++_soc_th_l2_bulk_age_iter[unit], iter));
    219         stime = sal_time_usecs();
    220 
    221         if (!soc->l2x_age_enable) {
    222             goto age_delay;
    223         }
    224 
    225         if (soc_mem_index_count(unit, L2Xm) == 0) {
    226             goto cleanup_exit;
    227         }
    228 
    229         rv = _soc_th_l2_bulk_age_entries_delete(unit, &retry);
    230 
    231         if (!SOC_SUCCESS(rv)) {
    232             if (retry) {
    233                 goto age_delay;
    234             }
    235             goto cleanup_exit;
    236         }
    237         rv = _soc_th_l2_bulk_age_entries_hit_clear(unit, &retry);
    238 
    239         if (!SOC_SUCCESS(rv)) {
    240             if (retry) {
    241                 goto age_delay;
    242             }
    243             goto cleanup_exit;
    244         }
    245         etime = sal_time_usecs();
    246         LOG_VERBOSE(BSL_LS_SOC_ARL,
    247                     (BSL_META_U(unit,
    248                                 "l2_bulk_age_thread: unit=%d: done in %d usec\n"),
    249                      unit, SAL_USECS_SUB(etime, stime)));
    250 age_delay:
    251         rv = -1; /* timeout */
    252         if (interval > 2147) {
    253             m = (interval / 2147) * 1000;
    254             r = (interval % 2147) * 1000000;
    255             for (c = 0; c < m; c++) {
    256                 rv = sal_sem_take(soc->l2x_age_notify, 2147000);
    257                 /* age interval is changed */
    258                 if (rv == 0 || interval != soc->l2x_age_interval) {
    259                     break;
    260                 }
    261             }
    262             if (soc->l2x_age_interval) {
    263                 if (rv == 0 || interval != soc->l2x_age_interval) {
    264                     /* age interval is changed */
    265                     interval = soc->l2x_age_interval;
    266                     goto age_delay;
    267                 } else if (r) {
    268                      /* age interval is not changed */
    269                     (void)sal_sem_take(soc->l2x_age_notify, r);
    270                 }
    271             }
    272         } else {
    273             rv = sal_sem_take(soc->l2x_age_notify, interval * 1000000);
    274             /* age interval is changed */
    275             if (soc->l2x_age_interval && (rv == 0 || interval != soc->l2x_age_interval)) {
    276                 interval = soc->l2x_age_interval;
    277                 goto age_delay;
    278             }
    279         }
    280         iter++;
    281     }
    282 
    283 cleanup_exit:
    284     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    285                 (BSL_META_U(unit,
    286                             "l2_bulk_age_thread: exiting\n")));
    287     soc->l2x_age_pid = SAL_THREAD_ERROR;
    288     sal_thread_exit(0);
    289 }
    290 
    291 /*
    292  * Function:
    293  * 	soc_th_l2_bulk_age_start
    294  * Purpose:
    295  *   	Start l2 bulk age thread
    296  * Parameters:
    297  *	unit - unit number.
    298  * Returns:
    299  *	SOC_E_XXX
    300  */
    301 int
    302 soc_th_l2_bulk_age_start(int unit, int interval)
    303 {
    304     int cfg_interval;
    305     soc_control_t *soc = SOC_CONTROL(unit);
    306 
    307     cfg_interval = soc_property_get(unit, spn_L2_SW_AGING_INTERVAL, 
    308                                     SAL_BOOT_QUICKTURN ? 30 : 10);
    309     SOC_CONTROL_LOCK(unit);
    310     soc->l2x_age_interval = interval ? interval : cfg_interval;
    311     sal_snprintf(soc->l2x_age_name, sizeof (soc->l2x_age_name),
    312                  "bcmL2age.%d", unit);
    313     soc->l2x_age_pid = sal_thread_create(soc->l2x_age_name, SAL_THREAD_STKSZ,
    314                                          soc_property_get(unit, spn_L2AGE_THREAD_PRI, 50),
    315                                          _soc_th_l2_bulk_age, INT_TO_PTR(unit));
    316     if (soc->l2x_age_pid == SAL_THREAD_ERROR) {
    317         LOG_ERROR(BSL_LS_SOC_COMMON,
    318                   (BSL_META_U(unit,
    319                               "bcm_esw_l2_init: Could not start L2 bulk age thread\n")));
    320         SOC_CONTROL_UNLOCK(unit);
    321         return SOC_E_MEMORY;
    322     }
    323     SOC_CONTROL_UNLOCK(unit);
    324     return SOC_E_NONE;
    325 }
    326 
    327 /*
    328  * Function:
    329  * 	soc_th_l2_bulk_age_stop
    330  * Purpose:
    331  *   	Stop l2 bulk age thread
    332  * Parameters:
    333  *	unit - unit number.
    334  * Returns:
    335  *	SOC_E_XXX
    336  */
    337 int
    338 soc_th_l2_bulk_age_stop(int unit)
    339 {
    340     soc_control_t *soc = SOC_CONTROL(unit);
    341     int           rv = SOC_E_NONE;
    342     soc_timeout_t to;
    343 
    344     SOC_CONTROL_LOCK(unit);
    345     soc->l2x_age_interval = 0;  /* Request exit */
    346     SOC_CONTROL_UNLOCK(unit);
    347 
    348     if (soc->l2x_age_pid && (soc->l2x_age_pid != SAL_THREAD_ERROR)) {
    349         /* Wake up thread so it will check the exit flag */
    350         sal_sem_give(soc->l2x_age_notify);
    351 
    352         /* Give thread a few seconds to wake up and exit */
    353         if (SAL_BOOT_SIMULATION) {
    354             soc_timeout_init(&to, 300 * 1000000, 0);
    355         } else {
    356             soc_timeout_init(&to, 60 * 1000000, 0);
    357         }
    358 
    359         while (soc->l2x_age_pid != SAL_THREAD_ERROR) {
    360             if (soc_timeout_check(&to)) {
    361                 LOG_ERROR(BSL_LS_SOC_COMMON,
    362                           (BSL_META_U(unit,
    363                                       "thread will not exit\n")));
    364                 rv = SOC_E_INTERNAL;
    365                 break;
    366             }
    367         }
    368     }
    369     return rv;
    370 }
    371 
    372 #endif /* BCM_XGS_SWITCH_SUPPORT */