l2x.c (9856B)
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 * XGS TD2 Bulk Aging Management. 8 */ 9 10 #include <sal/core/libc.h> 11 #include <shared/bsl.h> 12 #include <soc/drv.h> 13 #include <soc/l2x.h> 14 #include <soc/ptable.h> 15 #include <soc/debug.h> 16 #include <soc/util.h> 17 #include <soc/mem.h> 18 19 #ifdef BCM_XGS_SWITCH_SUPPORT 20 #ifdef BCM_TRIDENT2_SUPPORT 21 22 #define _SOC_IF_ERROR_UNLOCK_EXIT(rv) \ 23 if (!SOC_SUCCESS(rv)) { \ 24 soc_mem_unlock(unit, L2Xm); \ 25 sal_sem_give(soc->l2x_age_sync); \ 26 LOG_ERROR(BSL_LS_SOC_L2, \ 27 (BSL_META_U(unit, \ 28 "rv: %d\n"), rv)); \ 29 goto thread_exit; \ 30 } 31 32 static int _soc_td2_l2_bulk_age_iter[SOC_MAX_NUM_DEVICES] = {0}; 33 34 /* 35 * Function: 36 * _soc_td2_l2_bulk_age 37 * Purpose: 38 * l2 bulk age thread 39 * Parameters: 40 * unit - unit number. 41 * Returns: 42 * none 43 */ 44 STATIC void 45 _soc_td2_l2_bulk_age(void *unit_vp) 46 { 47 int unit = PTR_TO_INT(unit_vp); 48 soc_control_t *soc = SOC_CONTROL(unit); 49 sal_usecs_t interval, cfg_interval, stime, etime; 50 l2x_entry_t match_data; 51 l2x_entry_t match_mask; 52 l2x_entry_t new_data; 53 l2x_entry_t new_mask; 54 uint32 rval; 55 int i, rv, iter = 0; 56 57 cfg_interval = soc_property_get(unit, spn_L2_SW_AGING_INTERVAL, 300); 58 59 while ((interval = soc->l2x_age_interval) != 0) { 60 if (!iter) { 61 goto age_delay; 62 } 63 64 LOG_VERBOSE(BSL_LS_SOC_ARL, 65 (BSL_META_U(unit, 66 "l2_bulk_age_thread: " 67 "Process iters(total:%d, this run:%d\n"), 68 ++_soc_td2_l2_bulk_age_iter[unit], iter)); 69 70 stime = sal_time_usecs(); 71 72 if (!soc->l2x_age_enable) { 73 goto age_delay; 74 } 75 76 sal_sem_take(soc->l2x_age_sync, sal_sem_FOREVER); 77 soc_mem_lock(unit, L2Xm); 78 79 /* Match VALIDf=1, STATICf=0, HITSAf=0, HITDAf=0 */ 80 /* Set match data */ 81 sal_memset(&match_data, 0, sizeof(l2x_entry_t)); 82 soc_mem_field32_set(unit, L2Xm, &match_data, VALIDf, 1); 83 84 /* Set match mask */ 85 sal_memset(&match_mask, 0, sizeof(l2x_entry_t)); 86 soc_mem_field32_set(unit, L2Xm, &match_mask, VALIDf, 1); 87 soc_mem_field32_set(unit, L2Xm, &match_mask, STATIC_BITf, 1); 88 soc_mem_field32_set(unit, L2Xm, &match_mask, HITSAf, 1); 89 soc_mem_field32_set(unit, L2Xm, &match_mask, HITDAf, 1); 90 91 _SOC_IF_ERROR_UNLOCK_EXIT 92 (WRITE_L2_BULK_MATCH_DATAm(unit, MEM_BLOCK_ALL, 0, &match_data)); 93 _SOC_IF_ERROR_UNLOCK_EXIT 94 (WRITE_L2_BULK_MATCH_MASKm(unit, MEM_BLOCK_ALL, 0, &match_mask)); 95 96 sal_memset(&new_data, 0, sizeof(l2x_entry_t)); 97 if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) { /* Clear VALIDf */ 98 sal_memset(&new_mask, 0, sizeof(l2x_entry_t)); 99 soc_mem_field32_set(unit, L2Xm, &new_mask, VALIDf, 1); 100 } else { /* Clear All Fields */ 101 sal_memset(&new_mask, 0xff, sizeof(l2x_entry_t)); 102 } 103 104 _SOC_IF_ERROR_UNLOCK_EXIT 105 (WRITE_L2_BULK_REPLACE_DATAm(unit, MEM_BLOCK_ALL, 0, &new_data)); 106 _SOC_IF_ERROR_UNLOCK_EXIT 107 (WRITE_L2_BULK_REPLACE_MASKm(unit, MEM_BLOCK_ALL, 0, &new_mask)); 108 109 /* Set bulk control action */ 110 _SOC_IF_ERROR_UNLOCK_EXIT(READ_L2_BULK_CONTROLr(unit, &rval)); 111 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 2); 112 if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) { 113 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, 114 L2_MOD_FIFO_RECORDf, 1); 115 } 116 _SOC_IF_ERROR_UNLOCK_EXIT(WRITE_L2_BULK_CONTROLr(unit, rval)); 117 118 rv = soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 119 if (rv == SOC_E_TIMEOUT) { 120 goto age_exit; 121 } 122 _SOC_IF_ERROR_UNLOCK_EXIT(rv); 123 124 /* Match VALIDf=1, HITSAf=1, HITDAf=1 */ 125 /* Set match data */ 126 sal_memset(&match_data, 0, sizeof(l2x_entry_t)); 127 soc_mem_field32_set(unit, L2Xm, &match_data, VALIDf, 1); 128 129 /* Set match mask */ 130 sal_memset(&match_mask, 0, sizeof(l2x_entry_t)); 131 soc_mem_field32_set(unit, L2Xm, &match_mask, VALIDf, 1); 132 /* soc_mem_field32_set(unit, L2Xm, &match_mask, STATIC_BITf, 1); */ 133 134 _SOC_IF_ERROR_UNLOCK_EXIT 135 (WRITE_L2_BULK_MATCH_DATAm(unit, MEM_BLOCK_ALL, 0, &match_data)); 136 _SOC_IF_ERROR_UNLOCK_EXIT 137 (WRITE_L2_BULK_MATCH_MASKm(unit, MEM_BLOCK_ALL, 0, &match_mask)); 138 139 sal_memset(&new_data, 0, sizeof(l2x_entry_t)); 140 /* Clear HIT bits */ 141 sal_memset(&new_mask, 0, sizeof(l2x_entry_t)); 142 soc_mem_field32_set(unit, L2Xm, &new_mask, HITSAf, 1); 143 soc_mem_field32_set(unit, L2Xm, &new_mask, HITDAf, 1); 144 soc_mem_field32_set(unit, L2Xm, &new_mask, LOCAL_SAf, 1); 145 146 _SOC_IF_ERROR_UNLOCK_EXIT 147 (WRITE_L2_BULK_REPLACE_DATAm(unit, MEM_BLOCK_ALL, 0, &new_data)); 148 _SOC_IF_ERROR_UNLOCK_EXIT 149 (WRITE_L2_BULK_REPLACE_MASKm(unit, MEM_BLOCK_ALL, 0, &new_mask)); 150 151 /* Set bulk control action */ 152 _SOC_IF_ERROR_UNLOCK_EXIT(READ_L2_BULK_CONTROLr(unit, &rval)); 153 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 2); 154 if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) { 155 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, 156 L2_MOD_FIFO_RECORDf, 0); 157 } 158 _SOC_IF_ERROR_UNLOCK_EXIT(WRITE_L2_BULK_CONTROLr(unit, rval)); 159 160 rv = soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 161 if (rv == SOC_E_TIMEOUT) { 162 goto age_exit; 163 } 164 _SOC_IF_ERROR_UNLOCK_EXIT(rv); 165 166 age_exit: 167 soc_mem_unlock(unit, L2Xm); 168 sal_sem_give(soc->l2x_age_sync); 169 170 etime = sal_time_usecs(); 171 LOG_VERBOSE(BSL_LS_SOC_ARL, 172 (BSL_META_U(unit, 173 "l2_bulk_age_thread: unit=%d: done in %d usec with rv=%d\n"), 174 unit, SAL_USECS_SUB(etime, stime), rv)); 175 176 age_delay: 177 rv = -1; 178 for (i = 0; i < interval / cfg_interval; i++) { 179 rv = sal_sem_take(soc->l2x_age_notify, cfg_interval * 1000000); 180 if (interval != soc->l2x_age_interval || rv == 0) { 181 break; 182 } 183 } 184 /* age interval is not changed */ 185 if (rv != 0 && interval == soc->l2x_age_interval && interval % cfg_interval) { 186 rv = sal_sem_take(soc->l2x_age_notify, interval % cfg_interval * 1000000); 187 } 188 /* age interval is changed */ 189 if (soc->l2x_age_interval && (interval != soc->l2x_age_interval || rv == 0)) { 190 interval = soc->l2x_age_interval; 191 goto age_delay; 192 } 193 194 iter++; 195 } 196 197 thread_exit: 198 LOG_VERBOSE(BSL_LS_SOC_L2, 199 (BSL_META_U(unit, 200 "l2_bulk_age_thread: exiting\n"))); 201 202 soc->l2x_age_pid = SAL_THREAD_ERROR; 203 soc->l2x_age_interval = 0; 204 soc->l2x_age_enable = 0; 205 206 sal_thread_exit(0); 207 } 208 209 /* 210 * Function: 211 * soc_td2_l2_bulk_age_start 212 * Purpose: 213 * Start l2 bulk age thread 214 * Parameters: 215 * unit - unit number. 216 * Returns: 217 * SOC_E_XXX 218 */ 219 int 220 soc_td2_l2_bulk_age_start(int unit, int interval) 221 { 222 soc_control_t *soc = SOC_CONTROL(unit); 223 int cfg_interval; 224 int thread_prio; 225 226 if (soc->l2x_age_pid && soc->l2x_age_pid != SAL_THREAD_ERROR) { 227 return SOC_E_NONE; 228 } 229 230 cfg_interval = soc_property_get(unit, spn_L2_SW_AGING_INTERVAL, 300); 231 232 SOC_CONTROL_LOCK(unit); 233 soc->l2x_age_interval = interval ? interval : cfg_interval; 234 soc->l2x_age_enable = interval ? 1 : 0; 235 sal_snprintf(soc->l2x_age_name, sizeof(soc->l2x_age_name), "bcmL2age.%d", unit); 236 thread_prio = 50; 237 if (soc_feature(unit, soc_feature_l2_hw_aging_bug)) { 238 /* Real-time threads not permitted in simulation environments */ 239 if (!SAL_BOOT_SIMULATION) { 240 thread_prio = SAL_THREAD_PRIO_NO_PREEMPT; 241 } 242 } 243 soc->l2x_age_pid = sal_thread_create(soc->l2x_age_name, SAL_THREAD_STKSZ, 244 soc_property_get(unit, spn_L2AGE_THREAD_PRI, thread_prio), 245 _soc_td2_l2_bulk_age, INT_TO_PTR(unit)); 246 if (soc->l2x_age_pid == SAL_THREAD_ERROR) { 247 LOG_ERROR(BSL_LS_SOC_L2, 248 (BSL_META_U(unit, 249 "Could not start L2 bulk age thread\n"))); 250 SOC_CONTROL_UNLOCK(unit); 251 return SOC_E_MEMORY; 252 } 253 SOC_CONTROL_UNLOCK(unit); 254 255 return SOC_E_NONE; 256 } 257 258 /* 259 * Function: 260 * soc_td2_l2_bulk_age_stop 261 * Purpose: 262 * Stop l2 bulk age thread 263 * Parameters: 264 * unit - unit number. 265 * Returns: 266 * SOC_E_XXX 267 */ 268 int 269 soc_td2_l2_bulk_age_stop(int unit) 270 { 271 soc_control_t *soc = SOC_CONTROL(unit); 272 soc_timeout_t to; 273 int rv = SOC_E_NONE; 274 275 SOC_CONTROL_LOCK(unit); 276 soc->l2x_age_interval = 0; 277 soc->l2x_age_enable = 0; 278 SOC_CONTROL_UNLOCK(unit); 279 280 if (soc->l2x_age_pid && soc->l2x_age_pid != SAL_THREAD_ERROR) { 281 sal_sem_give(soc->l2x_age_notify); 282 283 if (SAL_BOOT_SIMULATION) { 284 soc_timeout_init(&to, 300 * 1000000, 0); 285 } else { 286 soc_timeout_init(&to, 60 * 1000000, 0); 287 } 288 289 while (soc->l2x_age_pid != SAL_THREAD_ERROR) { 290 if (soc_timeout_check(&to)) { 291 LOG_ERROR(BSL_LS_SOC_L2, 292 (BSL_META_U(unit, 293 "thread will not exit\n"))); 294 rv = SOC_E_INTERNAL; 295 break; 296 } 297 } 298 } 299 300 return rv; 301 } 302 303 #endif /* BCM_TRIDENT2_SUPPORT */ 304 #endif /* BCM_XGS_SWITCH_SUPPORT */