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 */