l2mod.c (51733B)
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 8 #include <shared/bsl.h> 9 10 #include <sal/core/libc.h> 11 #include <shared/alloc.h> 12 #include <sal/core/spl.h> 13 #include <sal/core/time.h> 14 #include <shared/bsl.h> 15 #include <soc/mem.h> 16 #include <soc/debug.h> 17 #include <soc/cm.h> 18 #include <soc/drv.h> 19 #include <soc/l2x.h> 20 #if defined(BCM_TRX_SUPPORT) 21 #include <soc/triumph.h> 22 #endif /* BCM_TRX_SUPPORT */ 23 24 #ifdef BCM_CMICM_SUPPORT 25 #include <soc/cmicm.h> 26 #endif 27 28 #ifdef BCM_XGS3_SWITCH_SUPPORT 29 30 /**************************************************************************** 31 * 32 * L2MOD Message Registration 33 */ 34 35 #define OPER_WRITE 0 36 #define OPER_PPA 2 37 #define OPER_DELETE 3 38 39 #define REASON_CPU 0 40 #define REASON_AGE 1 41 #define REASON_PPA 3 42 43 #define REASON_CPU 0 44 #define REASON_LEARN 1 45 #define REASON_STAT_MOVE 2 46 #define REASON_PPA 3 47 48 #if defined(BCM_TRX_SUPPORT) 49 STATIC int 50 soc_l2_overflow_event_record_set(int unit, int enable) { 51 52 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_HURRICANE3_SUPPORT) 53 uint32 reg; 54 55 if (SOC_IS_TRIDENT(unit) || SOC_IS_HURRICANE3(unit) || 56 SOC_IS_GREYHOUND2(unit)) { 57 SOC_IF_ERROR_RETURN(READ_L2_LEARN_CONTROLr(unit, ®)); 58 soc_reg_field_set(unit, L2_LEARN_CONTROLr, ®, 59 L2_RECORD_OVERFLOW_ENABLEf, enable & 1); 60 SOC_IF_ERROR_RETURN(WRITE_L2_LEARN_CONTROLr(unit, reg)); 61 return SOC_E_NONE; 62 } 63 #endif 64 return SOC_E_NONE; 65 } 66 #endif /*defined(BCM_TRX_SUPPORT)*/ 67 STATIC int 68 _soc_l2mod_fifo_enable(int unit, int val) 69 { 70 uint32 reg; 71 #ifdef BCM_TRX_SUPPORT 72 if (SOC_IS_TRX(unit)) { 73 SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, ®)); 74 /* Does application cares about MEMWR, L2_INSERT, L2_DELETE ? */ 75 soc_reg_field_set(unit, AUX_ARB_CONTROLr, ®, 76 L2_MOD_FIFO_ENABLE_AGEf, val); 77 soc_reg_field_set(unit, AUX_ARB_CONTROLr, ®, 78 L2_MOD_FIFO_ENABLE_LEARNf, val); 79 soc_reg_field_set(unit, AUX_ARB_CONTROLr, ®, 80 L2_MOD_FIFO_ENABLE_L2_DELETEf, val); 81 if (!soc_feature(unit, soc_feature_l2_bulk_control)) { 82 soc_reg_field_set(unit, AUX_ARB_CONTROLr, ®, 83 L2_MOD_FIFO_ENABLE_PPA_DELETEf, val); 84 soc_reg_field_set(unit, AUX_ARB_CONTROLr, ®, 85 L2_MOD_FIFO_ENABLE_PPA_REPLACEf, val); 86 } 87 SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, reg)); 88 89 if (soc_feature(unit, soc_feature_l2_bulk_control)) { 90 SOC_IF_ERROR_RETURN(READ_L2_BULK_CONTROLr(unit, ®)); 91 soc_reg_field_set(unit, L2_BULK_CONTROLr, ®, 92 L2_MOD_FIFO_RECORDf, 1); 93 SOC_IF_ERROR_RETURN(WRITE_L2_BULK_CONTROLr(unit, reg)); 94 } 95 96 if (SOC_IS_TRIDENT(unit) || SOC_IS_HURRICANE3(unit) || 97 SOC_IS_GREYHOUND2(unit)) { 98 SOC_IF_ERROR_RETURN(soc_l2_overflow_event_record_set(unit, 1)); 99 } 100 101 return SOC_E_NONE; 102 } 103 #endif /* BCM_TRX_SUPPORT */ 104 #ifdef BCM_FIREBOLT_SUPPORT 105 if (SOC_IS_FBX(unit)) { 106 SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, ®)); 107 soc_reg_field_set(unit, AUX_ARB_CONTROLr, ®, L2_MOD_FIFO_ENABLEf, val); 108 SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, reg)); 109 } 110 #endif 111 return SOC_E_NONE; 112 } 113 114 STATIC int 115 _soc_l2mod_fifo_lock(int unit, int val) 116 { 117 uint32 reg; 118 #ifdef BCM_FIREBOLT_SUPPORT 119 if (SOC_IS_FBX(unit)) { 120 SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, ®)); 121 soc_reg_field_set(unit, AUX_ARB_CONTROLr, ®, L2_MOD_FIFO_LOCKf, val); 122 SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, reg)); 123 } 124 #endif 125 return SOC_E_NONE; 126 } 127 128 STATIC int 129 _soc_l2mod_fifo_get_count(int unit, int * cnt) 130 { 131 uint32 reg; 132 #ifdef BCM_FIREBOLT_SUPPORT 133 if (SOC_IS_FBX(unit)) { 134 SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_CNTr(unit, ®)); 135 *cnt = soc_reg_field_get(unit, L2_MOD_FIFO_CNTr, reg, NUM_OF_ENTRIESf); 136 } 137 #endif 138 return SOC_E_NONE; 139 } 140 141 142 #ifdef BCM_KATANA_SUPPORT 143 void 144 _soc_kt_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry) 145 { 146 int operation; 147 l2x_entry_t l2x_entry, old_l2x_entry; 148 uint32 fval[SOC_MAX_MEM_FIELD_WORDS]; 149 int len; 150 151 operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf); 152 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf, 153 l2x_entry.entry_data); 154 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 155 sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry)); 156 soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry, 157 REPLACED_ASSOC_DATAf, fval); 158 len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf); 159 if (len & 0x1f) { 160 fval[len / 32] &= (1 << (len & 0x1f)) - 1; 161 } 162 soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry, 163 ASSOCIATED_DATAf, fval); 164 } 165 166 switch (operation) { 167 case 0: /* L2_DELETE */ 168 case 1: /* PPA DELETE */ 169 case 2: /* AGE */ 170 case 9: /* L2_BULK_DELETE */ 171 case 11: /* L2_BULK_AGE */ 172 soc_l2x_callback(unit, 0, &l2x_entry, NULL); 173 break; 174 case 10: /* L2_BULK_REPLACE */ 175 case 4: /* PPA REPLACE */ 176 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 177 break; 178 case 3: /* L2_INSERT */ 179 case 5: /* LEARN */ 180 181 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 182 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 183 } else { 184 soc_l2x_callback(unit, 0, NULL, &l2x_entry); 185 } 186 187 break; 188 case 6: /* MEMWR, S/W mark for the end of matched traverse */ 189 soc_l2x_callback(unit, SOC_L2X_ENTRY_DUMMY, NULL, NULL); 190 break; 191 case 8: /* L2_BULK_NO_ACTION */ 192 soc_l2x_callback(unit, SOC_L2X_ENTRY_NO_ACTION, NULL, &l2x_entry); 193 break; 194 case 7: /* OVERFLOW */ 195 case 12: /* MAC_LIMIT_DELETE_FOR_INSERT */ 196 case 13: /* MAC_LIMIT_DELETE_FOR_PPA_REPLACE */ 197 case 14: /* MAC_LIMIT_DELETE_FOR_LEARN */ 198 default: 199 break; 200 } 201 202 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) { 203 soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA); 204 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n"))); 205 } 206 } 207 #endif /* BCM_KATANA_SUPPORT */ 208 209 #ifdef BCM_TRIDENT2_SUPPORT 210 void 211 _soc_td2_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry) 212 { 213 int operation; 214 l2x_entry_t l2x_entry, old_l2x_entry; 215 uint32 fval[SOC_MAX_MEM_FIELD_WORDS]; 216 int len; 217 soc_field_t vld_fld = VALIDf; 218 soc_field_t data_fld = ASSOCIATED_DATAf; 219 220 #ifdef BCM_TOMAHAWK_SUPPORT 221 if (SOC_IS_TOMAHAWKX(unit)) { 222 data_fld = L2__ASSOCIATED_DATAf; 223 } 224 #endif 225 226 if (soc_feature(unit, soc_feature_base_valid)) { 227 vld_fld = BASE_VALIDf; 228 } 229 230 operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf); 231 if (SOC_MEM_FIELD_VALID(unit, L2_MOD_FIFOm, L2_ENTRY_DATAf)) { 232 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf, 233 l2x_entry.entry_data); 234 } else { 235 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf, 236 l2x_entry.entry_data); 237 } 238 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 239 sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry)); 240 soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry, 241 REPLACED_ASSOC_DATAf, fval); 242 len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf); 243 if (len & 0x1f) { 244 fval[len / 32] &= (1 << (len & 0x1f)) - 1; 245 } 246 soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry, 247 data_fld, fval); 248 } 249 250 switch (operation) { 251 case 0: /* L2_DELETE */ 252 case 4: /* AGE */ 253 case 6: /* L2_BULK_DELETE */ 254 case 8: /* L2_BULK_AGE */ 255 soc_l2x_callback(unit, 0, &l2x_entry, NULL); 256 break; 257 case 7: /* L2_BULK_REPLACE */ 258 if (SOC_IS_TD2_TT2(unit) && 259 (!soc_mem_field32_get(unit, L2Xm, &l2x_entry, vld_fld) && 260 sal_memcmp(&l2x_entry, soc_mem_entry_null(unit, L2Xm), sizeof(l2x_entry_t)))) { /* L2_BULK_REPLACE FOR DELETE/AGE */ 261 soc_l2x_callback(unit, 0, &l2x_entry, NULL); 262 } else { 263 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 264 } 265 break; 266 case 1: /* L2_INSERT */ 267 case 2: /* LEARN */ 268 269 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 270 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 271 } else { 272 soc_l2x_callback(unit, 0, NULL, &l2x_entry); 273 } 274 275 break; 276 case 3: /* MEMWR, S/W mark for the end of matched traverse */ 277 soc_l2x_callback(unit, SOC_L2X_ENTRY_DUMMY, NULL, NULL); 278 break; 279 case 5: /* L2_BULK_NO_ACTION */ 280 soc_l2x_callback(unit, SOC_L2X_ENTRY_NO_ACTION, NULL, &l2x_entry); 281 break; 282 default: 283 break; 284 } 285 286 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) { 287 soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA); 288 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n"))); 289 } 290 } 291 #endif /* BCM_TRIDENT2_SUPPORT */ 292 293 #ifdef BCM_TRIDENT_SUPPORT 294 STATIC void 295 _soc_td_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry, 296 uint32 *poverflow_event_counter, uint32 overflow_event_threshhold) 297 { 298 int operation; 299 l2x_entry_t l2x_entry, old_l2x_entry; 300 uint32 fval[SOC_MAX_MEM_FIELD_WORDS]; 301 int len; 302 303 operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf); 304 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf, 305 l2x_entry.entry_data); 306 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 307 sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry)); 308 soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry, 309 REPLACED_ASSOC_DATAf, fval); 310 len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf); 311 if (len & 0x1f) { 312 fval[len / 32] &= (1 << (len & 0x1f)) - 1; 313 } 314 soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry, 315 ASSOCIATED_DATAf, fval); 316 } 317 318 switch (operation) { 319 case 0: /* L2_DELETE */ 320 case 1: /* AGE */ 321 case 7: /* L2_BULK_DELETE */ 322 case 9: /* L2_BULK_AGE */ 323 soc_l2x_callback(unit, 0, &l2x_entry, NULL); 324 break; 325 case 8: /* L2_BULK_REPLACE */ 326 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 327 break; 328 case 2: /* L2_INSERT */ 329 case 3: /* LEARN */ 330 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 331 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 332 } else { 333 soc_l2x_callback(unit, 0, NULL, &l2x_entry); 334 } 335 break; 336 case 4: /* MEMWR, S/W mark for the end of matched traverse */ 337 soc_l2x_callback(unit, SOC_L2X_ENTRY_DUMMY, NULL, NULL); 338 break; 339 case 5: /* OVERFLOW */ 340 if (SOC_IS_TRIDENT(unit)) { 341 (*poverflow_event_counter)++; 342 if (*poverflow_event_counter < overflow_event_threshhold) { 343 soc_l2x_callback(unit, SOC_L2X_ENTRY_OVERFLOW, NULL, &l2x_entry); 344 } else if (*poverflow_event_counter == overflow_event_threshhold) { 345 (void)soc_l2_overflow_event_record_set(unit, 0); 346 } 347 } 348 break; 349 case 6: /* L2_BULK_NO_ACTION */ 350 soc_l2x_callback(unit, SOC_L2X_ENTRY_NO_ACTION, NULL, &l2x_entry); 351 break; 352 default: 353 break; 354 } 355 356 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) { 357 soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA); 358 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n"))); 359 } 360 } 361 #endif /* BCM_TRIDENT_SUPPORT */ 362 363 #if defined(BCM_TRX_SUPPORT) 364 STATIC void 365 _soc_tr_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry) 366 { 367 int operation; 368 l2x_entry_t l2x_entry, old_l2x_entry; 369 uint32 fval[SOC_MAX_MEM_FIELD_WORDS]; 370 int len = 0; 371 #ifdef BCM_TRIUMPH_SUPPORT 372 int rv, rv1; 373 int index; 374 ext_l2_entry_entry_t ext_l2_entry, old_ext_l2_entry; 375 #endif /* BCM_TRIUMPH_SUPPORT */ 376 377 operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf); 378 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf, 379 l2x_entry.entry_data); 380 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 381 sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry)); 382 soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry, 383 REPLACED_ASSOC_DATAf, fval); 384 len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf); 385 if (len & 0x1f) { 386 fval[len / 32] &= (1 << (len & 0x1f)) - 1; 387 } 388 soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry, 389 ASSOCIATED_DATAf, fval); 390 } 391 392 switch (operation) { 393 case 1: /* PPA_DELETE */ 394 case 2: /* AGE */ 395 soc_l2x_callback(unit, 0, &l2x_entry, NULL); 396 break; 397 case 4: /* PPA_REPLACE */ 398 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 399 break; 400 case 5: /* LEARN */ 401 #ifdef BCM_TRIUMPH_SUPPORT 402 /* Check if it is a FALSE station move */ 403 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 404 uint32 fval_new[SOC_MAX_MEM_FIELD_WORDS]; 405 406 /* Get associated data of new entry, 407 we already have assc data of old_entry in fval from above */ 408 soc_mem_field_get(unit, L2Xm, (uint32 *)&l2x_entry, 409 ASSOCIATED_DATAf, fval_new); 410 if (!(sal_memcmp(fval, fval_new, BITS2BYTES(len)))) { 411 /* If old data is same as new data the its a FALSE move */ 412 break; 413 } 414 } 415 416 if (soc_mem_is_valid(unit, EXT_L2_ENTRYm) && 417 soc_mem_index_count(unit, EXT_L2_ENTRYm) > 0 && 418 !soc_mem_field32_get(unit, L2Xm, &l2x_entry, PENDINGf)) { 419 soc_triumph_l2x_to_ext_l2(unit, &l2x_entry, &ext_l2_entry); 420 421 soc_mem_lock(unit, L2Xm); 422 soc_mem_lock(unit, EXT_L2_ENTRYm); 423 rv = soc_mem_generic_lookup(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 0, 424 &ext_l2_entry, &old_ext_l2_entry, 425 NULL); 426 if (SOC_SUCCESS(rv)) { 427 if (soc_mem_field32_get(unit, EXT_L2_ENTRYm, 428 &old_ext_l2_entry, STATIC_BITf)) { 429 /* 430 * If an static entry for the same lookup key has been 431 * inserted to external table before we have chance to 432 * process the learn event. 433 * Ignore the learn event, no call back. 434 */ 435 soc_mem_unlock(unit, L2Xm); 436 soc_mem_unlock(unit, EXT_L2_ENTRYm); 437 break; 438 } 439 } 440 rv = soc_mem_generic_insert(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 0, 441 &ext_l2_entry, &old_ext_l2_entry, 442 NULL); 443 if (SOC_SUCCESS(rv) || rv == SOC_E_EXISTS) { 444 int is_static; 445 rv1 = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, 446 &l2x_entry, &old_l2x_entry, 447 &index); 448 is_static = soc_mem_field32_get(unit, L2Xm, &old_l2x_entry, 449 STATIC_BITf); 450 if ((SOC_SUCCESS(rv1) && is_static) || 451 ((rv1 == SOC_E_NOT_FOUND) && SOC_SUCCESS(rv))) { 452 /* 453 * If either an static entry for the same lookup key has 454 * been inserted to internal table or the entry has been 455 * delete from internal table before we have chance to 456 * process the mod fifo learn event. 457 * Ignore the learn event (undo insert), no call back. 458 */ 459 soc_mem_generic_delete(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 460 0, &ext_l2_entry, NULL, NULL); 461 soc_mem_unlock(unit, L2Xm); 462 soc_mem_unlock(unit, EXT_L2_ENTRYm); 463 break; 464 } 465 if (SOC_SUCCESS(rv1)) { 466 (void)soc_mem_field32_modify(unit, L2Xm, index, 467 LIMIT_COUNTEDf, 0); 468 (void)soc_mem_generic_delete(unit, L2Xm, MEM_BLOCK_ANY, 469 0, &l2x_entry, NULL, NULL); 470 if (rv == SOC_E_EXISTS ) { 471 /* Update counts as its a move (while using ESM) */ 472 soc_triumph_learn_count_update(unit, &old_ext_l2_entry, 473 FALSE, -1); 474 } 475 } 476 soc_mem_unlock(unit, L2Xm); 477 soc_mem_unlock(unit, EXT_L2_ENTRYm); 478 479 if (rv == SOC_E_EXISTS) { 480 /* Do extra delete callback if the entry exists in ext 481 * table but has "deleted" mark. */ 482 if (!soc_mem_field32_get(unit, EXT_L2_ENTRYm, 483 &old_ext_l2_entry, VALIDf)) { 484 soc_triumph_ext_l2_to_l2x(unit, &old_ext_l2_entry, 485 &old_l2x_entry); 486 soc_l2x_callback(unit, 0, &old_l2x_entry, NULL); 487 } 488 } 489 } else { 490 soc_mem_unlock(unit, L2Xm); 491 soc_mem_unlock(unit, EXT_L2_ENTRYm); 492 } 493 } 494 #endif /* BCM_TRIUMPH_SUPPORT */ 495 if (soc_feature(unit, soc_feature_ppa_bypass)) { 496 if (SOC_CONTROL(unit)->l2x_ppa_bypass == FALSE && 497 soc_mem_field32_get(unit, L2Xm, &l2x_entry, KEY_TYPEf) != 498 TR_L2_HASH_KEY_TYPE_BRIDGE) { 499 SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE; 500 } 501 } 502 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 503 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 504 } else { 505 soc_l2x_callback(unit, 0, NULL, &l2x_entry); 506 } 507 break; 508 case 0: /* L2_DELETE */ 509 soc_l2x_callback(unit, 0, &l2x_entry, NULL); 510 break; 511 case 3: /* L2_INSERT */ 512 case 6: /* MEMWR */ 513 case 7: /* OVERFLOW */ 514 case 11: /* MAC_LIMIT_DELETE_FOR_INSERT */ 515 case 12: /* MAC_LIMIT_DELETE_FOR_PPA_REPLACE */ 516 case 13: /* MAC_LIMIT_DELETE_FOR_LEARN */ 517 default: 518 break; 519 } 520 521 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) { 522 soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA); 523 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n"))); 524 } 525 } 526 527 #ifdef BCM_TRIUMPH_SUPPORT 528 STATIC void 529 _soc_tr_ext_l2mod_fifo_process(int unit, uint32 flags, 530 ext_l2_mod_fifo_entry_t *entry) 531 { 532 int rv, typ; 533 l2x_entry_t l2x_entry, old_l2x_entry; 534 ext_l2_entry_entry_t ext_l2_entry, old_ext_l2_entry; 535 ext_l2_entry_tcam_entry_t tcam_entry; 536 uint32 rval, index; 537 sal_mac_addr_t mac; 538 static uint32 repl_t = 0, repl_dest = 0; 539 540 soc_mem_field_get(unit, EXT_L2_MOD_FIFOm, (uint32 *)entry, WR_DATAf, 541 (uint32 *)&ext_l2_entry); 542 index = soc_mem_field32_get(unit, EXT_L2_MOD_FIFOm, entry, ENTRY_ADRf); 543 544 /* 545 * ESM_L2_AGE_CTL.EN_RD_TCAM and ESM_PER_PORTREPL_CONTROL.EN_RD_TCAM 546 * are required to be set to same value (even if aging is disable) 547 */ 548 if (SOC_FAILURE(READ_ESM_L2_AGE_CTLr(unit, &rval))) { 549 return; 550 } 551 if (!soc_reg_field_get(unit, ESM_L2_AGE_CTLr, rval, EN_RD_TCAMf)) { 552 if (SOC_FAILURE(soc_mem_read(unit, EXT_L2_ENTRY_TCAMm, 553 MEM_BLOCK_ANY, index, &tcam_entry))) { 554 return; 555 } 556 soc_mem_mac_addr_get(unit, EXT_L2_ENTRY_TCAMm, &tcam_entry, MAC_ADDRf, 557 mac); 558 soc_mem_mac_addr_set(unit, EXT_L2_ENTRYm, &ext_l2_entry, MAC_ADDRf, 559 mac); 560 } 561 562 typ = soc_mem_field32_get(unit, EXT_L2_MOD_FIFOm, entry, TYPf); 563 switch (typ) { 564 case 3: /* special PPA REPL marker by software */ 565 repl_t = soc_mem_field32_get(unit, EXT_L2_ENTRYm, &ext_l2_entry, Tf); 566 repl_dest = soc_mem_field32_get(unit, EXT_L2_ENTRYm, &ext_l2_entry, 567 DESTINATIONf); 568 break; 569 case 4: /* REPLACED */ 570 sal_memcpy(&old_ext_l2_entry, &ext_l2_entry, 571 soc_mem_entry_words(unit, EXT_L2_ENTRYm) * 4); 572 soc_mem_field32_set(unit, EXT_L2_ENTRYm, &ext_l2_entry, Tf, repl_t); 573 soc_mem_field32_set(unit, EXT_L2_ENTRYm, &ext_l2_entry, DESTINATIONf, 574 repl_dest); 575 soc_mem_lock(unit, EXT_L2_ENTRYm); 576 soc_triumph_learn_count_update(unit, &ext_l2_entry, FALSE, 1); 577 578 soc_triumph_ext_l2_entry_update(unit, index, &ext_l2_entry); 579 soc_triumph_learn_count_update(unit, &old_ext_l2_entry, FALSE, -1); 580 soc_mem_unlock(unit, EXT_L2_ENTRYm); 581 soc_triumph_ext_l2_to_l2x(unit, &old_ext_l2_entry, &old_l2x_entry); 582 soc_triumph_ext_l2_to_l2x(unit, &ext_l2_entry, &l2x_entry); 583 soc_l2x_callback(unit, 0, &old_l2x_entry, &l2x_entry); 584 break; 585 case 5: /* DELETED */ 586 case 6: /* ENTRY_IS_OLD */ 587 soc_mem_lock(unit, EXT_L2_ENTRYm); 588 soc_triumph_ext_l2_entry_update(unit, index, NULL); 589 soc_triumph_learn_count_update(unit, &ext_l2_entry, TRUE, -1); 590 soc_mem_unlock(unit, EXT_L2_ENTRYm); 591 soc_triumph_ext_l2_to_l2x(unit, &ext_l2_entry, &l2x_entry); 592 soc_l2x_callback(unit, 0, &l2x_entry, NULL); 593 break; 594 case 7: /* CLEARED_VALID */ 595 rv = soc_mem_generic_lookup(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 0, 596 &ext_l2_entry, &old_ext_l2_entry, 0); 597 if (rv != SOC_E_NONE) { 598 return; 599 } 600 601 /* delete only if the VALID bit is cleared */ 602 if (soc_mem_field32_get(unit, EXT_L2_ENTRYm, &old_ext_l2_entry, 603 VALIDf)) { 604 return; 605 } 606 607 soc_mem_generic_delete(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 0, 608 &ext_l2_entry, NULL, 0); 609 soc_triumph_learn_count_update(unit, &ext_l2_entry, TRUE, -1); 610 soc_triumph_ext_l2_to_l2x(unit, &ext_l2_entry, &l2x_entry); 611 soc_l2x_callback(unit, 0, &l2x_entry, NULL); 612 break; 613 default: 614 break; 615 } 616 } 617 #endif /* BCM_TRIUMPH_SUPPORT */ 618 #endif /* BCM_TRX_SUPPORT */ 619 620 #if defined(BCM_TSN_SUPPORT) 621 void 622 _soc_gh2_tsn_l2mod_fifo_process( 623 int unit, 624 uint32 flags, 625 l2_mod_fifo_entry_t *entry) 626 { 627 int operation; 628 l2x_entry_t l2x_entry, old_l2x_entry; 629 uint32 fval[SOC_MAX_MEM_FIELD_WORDS]; 630 int len; 631 l2x_entry_t l2x_entry_sr; 632 int is_tsn_or_sr_flow = FALSE; /* TSN or SR related flow */ 633 634 operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf); 635 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf, 636 l2x_entry.entry_data); 637 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 638 sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry)); 639 soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry, 640 REPLACED_ASSOC_DATAf, fval); 641 len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf); 642 if (len & 0x1f) { 643 fval[len / 32] &= (1 << (len & 0x1f)) - 1; 644 } 645 soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry, 646 ASSOCIATED_DATAf, fval); 647 } 648 649 /* Need to get SR_L2_ENTRY_DATA for TSN/SR L2MOD FIFO support */ 650 sal_memcpy(&l2x_entry_sr, &l2x_entry, sizeof(l2x_entry)); 651 soc_L2_MOD_FIFOm_field_get(unit, entry, 652 SR_L2_ENTRY_DATAf, fval); 653 len = soc_mem_field_length(unit, L2Xm, SR_ASSOCIATED_DATAf); 654 if (len & 0x1f) { 655 fval[len / 32] &= (1 << (len & 0x1f)) - 1; 656 } 657 soc_L2Xm_field_set(unit, &l2x_entry_sr, 658 SR_ASSOCIATED_DATAf, fval); 659 660 if ((soc_L2Xm_field32_get(unit, &l2x_entry_sr, TSN_CIRCUIT_IDf) != 0) || 661 (soc_L2Xm_field32_get(unit, &l2x_entry_sr, SR_FLOW_IDf) != 0)) { 662 is_tsn_or_sr_flow = TRUE; 663 } 664 665 switch (operation) { 666 case 0: /* L2_DELETE */ 667 case 1: /* PPA DELETE */ 668 soc_l2x_callback(unit, SOC_L2X_ENTRY_DELETE, &l2x_entry, NULL); 669 break; 670 case 2: /* AGE */ 671 if (is_tsn_or_sr_flow == TRUE) { 672 /* Decrease TSN/SR flowset reference count for PPA/AGE deletion */ 673 soc_l2x_callback(unit, 674 SOC_L2X_ENTRY_TSN_SR_FLOWSET_REF_CNT, 675 &l2x_entry_sr, NULL); 676 } 677 soc_l2x_callback(unit, SOC_L2X_ENTRY_AGE, &l2x_entry, NULL); 678 break; 679 case 4: /* PPA REPLACE */ 680 soc_l2x_callback(unit, SOC_L2X_ENTRY_DELETE, &old_l2x_entry, 681 &l2x_entry); 682 break; 683 case 3: /* L2_INSERT */ 684 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, 685 entry, STATION_MOVEf)) { 686 soc_l2x_callback(unit, SOC_L2X_ENTRY_INSERT, &old_l2x_entry, 687 &l2x_entry); 688 } else { 689 soc_l2x_callback(unit, SOC_L2X_ENTRY_INSERT, NULL, &l2x_entry); 690 } 691 break; 692 case 5: /* LEARN */ 693 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, 694 entry, STATION_MOVEf)) { 695 soc_l2x_callback(unit, SOC_L2X_ENTRY_LEARN, &old_l2x_entry, 696 &l2x_entry); 697 } else { 698 if (is_tsn_or_sr_flow == TRUE) { 699 /* Increase TSN/SR flowset reference count for addition */ 700 soc_l2x_callback(unit, 701 SOC_L2X_ENTRY_TSN_SR_FLOWSET_REF_CNT, 702 NULL, &l2x_entry_sr); 703 } 704 soc_l2x_callback(unit, SOC_L2X_ENTRY_LEARN, NULL, &l2x_entry); 705 } 706 break; 707 case 7: /* OVERFLOW */ 708 soc_l2x_callback(unit, SOC_L2X_ENTRY_OVERFLOW, NULL, &l2x_entry); 709 break; 710 case 6: /* MEMWR */ 711 case 11: /* MAC_LIMIT_DELETE_FOR_INSERT */ 712 case 12: /* MAC_LIMIT_DELETE_FOR_PPA_REPLACE */ 713 case 13: /* MAC_LIMIT_DELETE_FOR_LEARN */ 714 default: 715 break; 716 } 717 718 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) { 719 soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA); 720 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, 721 "\n"))); 722 } 723 } 724 #endif /* BCM_TSN_SUPPORT */ 725 726 #ifdef BCM_HURRICANE2_SUPPORT 727 void 728 _soc_hu2_l2mod_fifo_process(int unit, uint32 flags, 729 l2_mod_fifo_entry_t *entry) 730 { 731 int operation; 732 l2x_entry_t l2x_entry, old_l2x_entry; 733 uint32 fval[SOC_MAX_MEM_FIELD_WORDS]; 734 int len; 735 736 #if defined(BCM_TSN_SUPPORT) 737 if (soc_feature(unit, soc_feature_tsn)) { 738 _soc_gh2_tsn_l2mod_fifo_process(unit, flags, entry); 739 } else 740 #endif /* BCM_TSN_SUPPORT */ 741 { 742 operation = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf); 743 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRY_DATAf, 744 l2x_entry.entry_data); 745 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, entry, STATION_MOVEf)) { 746 sal_memcpy(&old_l2x_entry, &l2x_entry, sizeof(l2x_entry)); 747 soc_mem_field_get(unit, L2_MOD_FIFOm, (uint32 *)entry, 748 REPLACED_ASSOC_DATAf, fval); 749 len = soc_mem_field_length(unit, L2Xm, ASSOCIATED_DATAf); 750 if (len & 0x1f) { 751 fval[len / 32] &= (1 << (len & 0x1f)) - 1; 752 } 753 soc_mem_field_set(unit, L2Xm, (uint32 *)&old_l2x_entry, 754 ASSOCIATED_DATAf, fval); 755 } 756 757 switch (operation) { 758 case 0: /* L2_DELETE */ 759 case 1: /* PPA DELETE */ 760 soc_l2x_callback(unit, SOC_L2X_ENTRY_DELETE, &l2x_entry, NULL); 761 break; 762 case 2: /* AGE */ 763 soc_l2x_callback(unit, SOC_L2X_ENTRY_AGE, &l2x_entry, NULL); 764 break; 765 case 4: /* PPA REPLACE */ 766 soc_l2x_callback(unit, SOC_L2X_ENTRY_DELETE, &old_l2x_entry, 767 &l2x_entry); 768 break; 769 case 3: /* L2_INSERT */ 770 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, 771 entry, STATION_MOVEf)) { 772 soc_l2x_callback(unit, SOC_L2X_ENTRY_INSERT, 773 &old_l2x_entry, &l2x_entry); 774 } else { 775 soc_l2x_callback(unit, SOC_L2X_ENTRY_INSERT, 776 NULL, &l2x_entry); 777 } 778 break; 779 case 5: /* LEARN */ 780 if (soc_mem_field32_get(unit, L2_MOD_FIFOm, 781 entry, STATION_MOVEf)) { 782 soc_l2x_callback(unit, SOC_L2X_ENTRY_LEARN, 783 &old_l2x_entry, &l2x_entry); 784 } else { 785 soc_l2x_callback(unit, SOC_L2X_ENTRY_LEARN, 786 NULL, &l2x_entry); 787 } 788 break; 789 case 7: /* OVERFLOW */ 790 soc_l2x_callback(unit, SOC_L2X_ENTRY_OVERFLOW, 791 NULL, &l2x_entry); 792 break; 793 case 6: /* MEMWR */ 794 case 11: /* MAC_LIMIT_DELETE_FOR_INSERT */ 795 case 12: /* MAC_LIMIT_DELETE_FOR_PPA_REPLACE */ 796 case 13: /* MAC_LIMIT_DELETE_FOR_LEARN */ 797 default: 798 break; 799 } 800 801 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) { 802 soc_mem_entry_dump(unit, L2_MOD_FIFOm, 803 entry, (BSL_VERBOSE | BSL_LS_SOC_DMA)); 804 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n"))); 805 } 806 } 807 } 808 #endif /* BCM_HURRICANE2_SUPPORT */ 809 810 STATIC void 811 _soc_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t * entry) 812 { 813 int op; 814 l2x_entry_t wr_data; 815 816 op = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERf); 817 818 soc_L2_MOD_FIFOm_field_get(unit, entry, WR_DATAf, wr_data.entry_data); 819 820 /* 821 * No need to translate. A callback expects an l2x_entry_t, and 822 * does the translation itselt via mbcm. 823 */ 824 825 /* 826 * The l2mod_fifo_thread gets _changes_, and doesn't need the shadow 827 * table; therefore no processing happens here. Just call the callback. 828 */ 829 switch (op) { 830 case OPER_DELETE: 831 soc_l2x_callback(unit, 0, &wr_data, NULL); 832 break; 833 case OPER_PPA: 834 soc_l2x_callback(unit, 0, &wr_data, &wr_data); 835 break; 836 case OPER_WRITE: 837 soc_l2x_callback(unit, 0, NULL, &wr_data); 838 break; 839 default: 840 LOG_ERROR(BSL_LS_SOC_L2, 841 (BSL_META_U(unit, 842 "soc_l2mod_fifo_thread: invalid operation\n"))); 843 break; 844 } 845 } 846 847 STATIC void 848 _soc_l2mod_thread(void * unit_vp) 849 { 850 int unit = PTR_TO_INT(unit_vp); 851 soc_control_t * soc = SOC_CONTROL(unit); 852 uint32 *fifo; 853 int mfifo_words = soc_mem_entry_words(unit, L2_MOD_FIFOm); 854 int count; 855 uint32 i; 856 int interval; 857 int rv; 858 uint32 index_min, index_max; 859 860 count = soc_mem_index_count(unit, L2_MOD_FIFOm); 861 index_min = soc_mem_index_min(unit, L2_MOD_FIFOm); 862 index_max = soc_mem_index_max(unit, L2_MOD_FIFOm); 863 fifo = soc_cm_salloc(unit, 864 WORDS2BYTES(mfifo_words) * count, 865 "L2_MOD_FIFOm"); 866 if (fifo == NULL) { 867 soc->l2x_pid = SAL_THREAD_ERROR; 868 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 869 SOC_SWITCH_EVENT_THREAD_L2MOD, __LINE__, 870 SOC_E_MEMORY); 871 sal_thread_exit(0); 872 return; 873 } 874 875 soc_intr_enable(unit, IRQ_L2_MOD_FIFO_NOT_EMPTY); 876 _soc_l2mod_fifo_enable(unit, 1); 877 878 while ((interval = soc->l2x_interval) != 0) { 879 /* 880 * Post the semaphore -- it will be signalled by the ISR when 881 * new data appear in MOD_FIFO. 882 */ 883 sal_sem_take(soc->arl_notify, interval); 884 885 /* Lock the fifo */ 886 _soc_l2mod_fifo_lock(unit, 1); 887 888 /* Get the number of entries */ 889 _soc_l2mod_fifo_get_count(unit, &count); 890 891 if (count == 0) { 892 _soc_l2mod_fifo_lock(unit, 0); 893 continue; 894 } 895 896 /* Read in the fifo contents */ 897 if ((rv = soc_mem_read_range(unit, L2_MOD_FIFOm, MEM_BLOCK_ANY, 898 index_min, index_max, fifo)) < 0) { 899 LOG_ERROR(BSL_LS_SOC_L2, 900 (BSL_META_U(unit, 901 "AbnormalThreadExit:soc_l2mod_fifo_thread,DMA failed: %s\n"), 902 soc_errmsg(rv))); 903 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 904 SOC_SWITCH_EVENT_THREAD_L2MOD, __LINE__, rv); 905 goto cleanup_exit; 906 } 907 /* Unlock (and clear) the fifo */ 908 _soc_l2mod_fifo_lock(unit, 0); 909 910 /* Do the callback for each entry */ 911 for (i = index_min; i < (index_min + count); i++) { 912 if (!soc->l2x_interval) { 913 goto cleanup_exit; 914 } 915 _soc_l2mod_fifo_process( 916 unit, 917 soc->l2x_flags, 918 (l2_mod_fifo_entry_t *)(fifo + i * mfifo_words)); 919 } 920 /* 921 * Re-enable the interrupt for 922 * L2MOD FIFO not empty events, disabled in ISR. 923 * Reset arl_notified before waiting 924 * on the arl_notify semaphore. 925 */ 926 soc->arl_notified = 0; 927 soc_intr_enable(unit, IRQ_L2_MOD_FIFO_NOT_EMPTY); 928 } 929 cleanup_exit: 930 soc_cm_sfree(unit, fifo); 931 soc->l2x_pid = SAL_THREAD_ERROR; 932 sal_thread_exit(0); 933 } 934 935 extern uint32 soc_mem_fifo_delay_value; 936 937 #ifdef BCM_TRX_SUPPORT 938 STATIC void 939 _soc_l2mod_dma_thread(void *unit_vp) 940 { 941 int unit = PTR_TO_INT(unit_vp); 942 soc_control_t *soc = SOC_CONTROL(unit); 943 int rv, entries_per_buf, adv_threshold, interval, count, i, non_empty; 944 int chan[2], entry_words[2]; 945 void *host_buf[2], *host_entry; 946 soc_mem_t mem[2]; 947 uint32 intr_mask; 948 #ifdef BCM_CMICM_SUPPORT 949 uint32 rval = 0; 950 uint8 overflow = 0, timeout = 0; 951 int cmc = SOC_PCI_CMC(unit); 952 #endif /* BCM_CMICM_SUPPORT */ 953 #ifdef BCM_TRIDENT_SUPPORT 954 uint32 overflow_event_threshhold; 955 uint32 overflow_event_counter; 956 sal_usecs_t cur_time, clear_time, time_diff; 957 #endif 958 959 chan[1] = -1; 960 mem[1] = INVALIDm; 961 entry_words[1] = 0; 962 host_buf[1] = NULL; 963 964 entries_per_buf = soc_property_get(unit, spn_L2XMSG_HOSTBUF_SIZE, 1024); 965 adv_threshold = entries_per_buf / 2; 966 967 chan[0] = SOC_MEM_FIFO_DMA_CHANNEL_1; 968 mem[0] = L2_MOD_FIFOm; 969 entry_words[0] = soc_mem_entry_words(unit, mem[0]); 970 intr_mask = IRQ_FIFO_CH1_DMA; 971 host_buf[0] = 972 soc_cm_salloc(unit, entries_per_buf * entry_words[0] * sizeof(uint32), 973 "L2_MOD DMA Buffer"); 974 if (host_buf[0] == NULL) { 975 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 976 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, 977 SOC_E_MEMORY); 978 goto cleanup_exit; 979 } 980 981 #if defined (BCM_TRIUMPH_SUPPORT) 982 if (soc_feature(unit, soc_feature_esm_support)) { 983 chan[1] = SOC_MEM_FIFO_DMA_CHANNEL_2; 984 mem[1] = EXT_L2_MOD_FIFOm; 985 entry_words[1] = soc_mem_entry_words(unit, mem[1]); 986 intr_mask |= IRQ_FIFO_CH2_DMA; 987 host_buf[1] = 988 soc_cm_salloc(unit, entries_per_buf * entry_words[1] * 989 sizeof(uint32), "EXT_L2_MOD DMA Buffer"); 990 if (host_buf[1] == NULL) { 991 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 992 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, 993 SOC_E_MEMORY); 994 goto cleanup_exit; 995 } 996 } 997 #endif /* BCM_TRIUMPH_SUPPORT */ 998 (void)soc_mem_fifo_dma_stop(unit, chan[0]); 999 rv = soc_mem_fifo_dma_start(unit, chan[0], mem[0], MEM_BLOCK_ANY, 1000 entries_per_buf, host_buf[0]); 1001 if (SOC_FAILURE(rv)) { 1002 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1003 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv); 1004 goto cleanup_exit; 1005 } 1006 1007 #if defined (BCM_TRIUMPH_SUPPORT) 1008 if (mem[1] != INVALIDm) { 1009 rv = soc_reg_field32_modify(unit, ESM_L2_AGE_CTLr, REG_PORT_ANY, 1010 CPU_NOTIFYf, 1); 1011 if (SOC_FAILURE(rv)) { 1012 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1013 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv); 1014 goto cleanup_exit; 1015 } 1016 rv = soc_reg_field32_modify(unit, ESM_PER_PORT_REPL_CONTROLr, 1017 REG_PORT_ANY, CPU_NOTIFYf, 1); 1018 if (SOC_FAILURE(rv)) { 1019 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1020 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv); 1021 goto cleanup_exit; 1022 } 1023 rv = soc_reg_field32_modify(unit, ESM_CTLr, REG_PORT_ANY, 1024 L2MODFIFO_PUSH_ENf, 1); 1025 if (SOC_FAILURE(rv)) { 1026 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1027 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv); 1028 goto cleanup_exit; 1029 } 1030 rv = soc_mem_fifo_dma_start(unit, chan[1], mem[1], MEM_BLOCK_ANY, 1031 entries_per_buf, host_buf[1]); 1032 if (SOC_FAILURE(rv)) { 1033 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1034 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv); 1035 goto cleanup_exit; 1036 } 1037 } 1038 #endif /* BCM_TRIUMPH_SUPPORT */ 1039 soc_mem_fifo_delay_value = 1040 soc_property_get(unit, spn_FIFO_DELAY_VALUE, (15 * MILLISECOND_USEC)); 1041 1042 #ifdef BCM_TRIDENT_SUPPORT 1043 overflow_event_threshhold = soc_property_get(unit, "fifo_overflow_threshhold", 100); 1044 overflow_event_counter = 0; 1045 clear_time = sal_time_usecs(); 1046 #endif 1047 1048 _soc_l2mod_fifo_enable(unit, 1); 1049 1050 while ((interval = soc->l2x_interval)) { 1051 if (soc->l2modDmaIntrEnb) { 1052 #ifdef BCM_CMICM_SUPPORT 1053 if (SOC_IS_KATANA(unit)) { 1054 soc_cmicm_intr0_enable(unit, 1055 IRQ_CMCx_FIFO_CH_DMA(SOC_MEM_FIFO_DMA_CHANNEL_1)); 1056 } else 1057 #endif /* BCM_CMICM_SUPPORT */ 1058 { 1059 soc_intr_enable(unit, intr_mask); 1060 } 1061 if (sal_sem_take(soc->arl_notify, interval) < 0) { 1062 LOG_VERBOSE(BSL_LS_SOC_ARL, 1063 (BSL_META_U(unit, 1064 "%s polling timeout soc_mem_fifo_delay_value=%d\n"), 1065 soc->l2x_name, soc_mem_fifo_delay_value)); 1066 1067 #ifdef BCM_TRIDENT_SUPPORT 1068 if (SOC_IS_TRIDENT(unit)) { 1069 overflow_event_counter = 0; 1070 (void)soc_l2_overflow_event_record_set(unit, 1); 1071 } 1072 #endif 1073 } else { 1074 LOG_VERBOSE(BSL_LS_SOC_ARL, 1075 (BSL_META_U(unit, 1076 "%s woken up soc_mem_fifo_delay_value=%d\n"), 1077 soc->l2x_name, soc_mem_fifo_delay_value)); 1078 #ifdef BCM_CMICM_SUPPORT 1079 if (SOC_IS_KATANA(unit)) { 1080 /* check for timeout & overflow */ 1081 rval = soc_pci_read(unit, 1082 CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, 1083 SOC_MEM_FIFO_DMA_CHANNEL_1)); 1084 overflow = soc_reg_field_get(unit, 1085 CMIC_CMC0_FIFO_CH1_RD_DMA_STATr, rval, 1086 FIFO_CH1_DMA_HOSTMEM_TIMEOUTf); 1087 if (overflow) { 1088 timeout = soc_reg_field_get(unit, 1089 CMIC_CMC0_FIFO_CH1_RD_DMA_STATr, 1090 rval, FIFO_CH1_DMA_HOSTMEM_OVERFLOWf); 1091 overflow |= timeout; 1092 } 1093 } 1094 #endif /* BCM_CMICM_SUPPORT */ 1095 #ifdef BCM_TRIDENT_SUPPORT 1096 if (SOC_IS_TRIDENT(unit)) { 1097 cur_time = sal_time_usecs(); 1098 time_diff = SAL_USECS_SUB( cur_time, clear_time ); 1099 if (time_diff > interval) { 1100 overflow_event_counter = 0; 1101 (void)soc_l2_overflow_event_record_set(unit, 1); 1102 clear_time = sal_time_usecs(); 1103 } 1104 } 1105 #endif 1106 } 1107 } else { 1108 sal_usleep(interval); 1109 #ifdef BCM_TRIDENT_SUPPORT 1110 if (SOC_IS_TRIDENT(unit)) { 1111 overflow_event_counter = 0; 1112 (void)soc_l2_overflow_event_record_set(unit, 1); 1113 clear_time = sal_time_usecs(); 1114 } 1115 #endif 1116 } 1117 1118 do { 1119 non_empty = FALSE; 1120 rv = soc_mem_fifo_dma_get_read_ptr(unit, chan[0], &host_entry, 1121 &count); 1122 if (SOC_SUCCESS(rv)) { 1123 non_empty = TRUE; 1124 if (count > adv_threshold) { 1125 count = adv_threshold; 1126 } 1127 for (i = 0; i < count; i++) { 1128 if(!soc->l2x_interval) { 1129 goto cleanup_exit; 1130 } 1131 #ifdef BCM_TRIDENT_SUPPORT 1132 if (soc_feature(unit, soc_feature_l2_bulk_control)) { 1133 #ifdef BCM_KATANA_SUPPORT 1134 if (SOC_IS_KATANA(unit)) { 1135 _soc_kt_l2mod_fifo_process(unit, soc->l2x_flags, 1136 host_entry); 1137 1138 } else 1139 #endif /* BCM_KATANA_SUPPORT */ 1140 { 1141 _soc_td_l2mod_fifo_process(unit, soc->l2x_flags, 1142 host_entry, 1143 &overflow_event_counter, 1144 overflow_event_threshhold); 1145 } 1146 } else 1147 #endif /* BCM_TRIDENT_SUPPORT */ 1148 { 1149 _soc_tr_l2mod_fifo_process(unit, soc->l2x_flags, 1150 host_entry); 1151 } 1152 host_entry = (uint32 *)host_entry + entry_words[0]; 1153 /* 1154 * PPA may wait for available space in mod_fifo, lower the 1155 * threshold when ppa is running, therefore read point can 1156 * be updated sooner. 1157 */ 1158 if (SOC_CONTROL(unit)->l2x_ppa_in_progress && i >= 63) { 1159 i++; 1160 break; 1161 } 1162 } 1163 (void)soc_mem_fifo_dma_advance_read_ptr(unit, chan[0], i); 1164 } 1165 #if defined(BCM_TRIUMPH_SUPPORT) 1166 if (mem[1] == INVALIDm) { 1167 if (!SOC_CONTROL(unit)->l2x_ppa_in_progress) { 1168 sal_thread_yield(); 1169 } 1170 continue; 1171 } 1172 1173 rv = soc_mem_fifo_dma_get_read_ptr(unit, chan[1], &host_entry, 1174 &count); 1175 if (SOC_SUCCESS(rv)) { 1176 non_empty = TRUE; 1177 if (count > adv_threshold) { 1178 count = adv_threshold; 1179 } 1180 for (i = 0; i < count; i++) { 1181 if(!soc->l2x_interval) { 1182 goto cleanup_exit; 1183 } 1184 _soc_tr_ext_l2mod_fifo_process(unit, soc->l2x_flags, 1185 host_entry); 1186 host_entry = (uint32 *)host_entry + entry_words[1]; 1187 /* 1188 * PPA may wait for available space in mod_fifo, lower the 1189 * threshold when ppa is running, therefore read point can 1190 * be updated sooner. 1191 */ 1192 if (SOC_CONTROL(unit)->l2x_ppa_in_progress && i >= 63) { 1193 i++; 1194 break; 1195 } 1196 } 1197 (void)soc_mem_fifo_dma_advance_read_ptr(unit, chan[1], i); 1198 } 1199 #endif /* BCM_TRIUMPH_SUPPORT */ 1200 1201 if (!SOC_CONTROL(unit)->l2x_ppa_in_progress) { 1202 sal_thread_yield(); 1203 } 1204 } while (non_empty); 1205 /* clearing of the FIFO_CH_DMA_INT interrupt by resetring 1206 overflow & timeout status in FIFO_CHx_RD_DMA_STAT_CLR reg */ 1207 #ifdef BCM_CMICM_SUPPORT 1208 if (SOC_IS_KATANA(unit)) { 1209 if (overflow) { 1210 rval = 0; 1211 soc_reg_field_set(unit, 1212 CMIC_CMC0_FIFO_CH1_RD_DMA_STAT_CLRr, &rval, 1213 FIFO_CH1_DMA_HOSTMEM_OVERFLOWf, 1); 1214 soc_reg_field_set(unit, 1215 CMIC_CMC0_FIFO_CH1_RD_DMA_STAT_CLRr, &rval, 1216 FIFO_CH1_DMA_HOSTMEM_TIMEOUTf, 1); 1217 soc_pci_write(unit, 1218 CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_CLR_OFFSET(cmc, 1219 SOC_MEM_FIFO_DMA_CHANNEL_1), rval); 1220 } 1221 } 1222 #endif /* BCM_CMICM_SUPPORT */ 1223 } 1224 1225 cleanup_exit: 1226 (void)soc_mem_fifo_dma_stop(unit, chan[0]); 1227 #if defined (BCM_TRIUMPH_SUPPORT) 1228 if (mem[1] != INVALIDm) { 1229 (void)soc_mem_fifo_dma_stop(unit, chan[1]); 1230 (void)soc_reg_field32_modify(unit, ESM_CTLr, REG_PORT_ANY, 1231 L2MODFIFO_PUSH_ENf, 0); 1232 } 1233 #endif /* BCM_TRIUMPH_SUPPORT */ 1234 1235 if (host_buf[0] != NULL) { 1236 soc_cm_sfree(unit, host_buf[0]); 1237 } 1238 if (mem[1] != INVALIDm && host_buf[1] != NULL) { 1239 soc_cm_sfree(unit, host_buf[1]); 1240 } 1241 /* Exiting L2_MOD_FIFO drain thread, disable recording into L2_MOD_FIFO */ 1242 _soc_l2mod_fifo_enable(unit, 0); 1243 soc->l2x_pid = SAL_THREAD_ERROR; 1244 sal_thread_exit(0); 1245 } 1246 #endif /* BCM_TRX_SUPPORT */ 1247 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 1248 1249 /* 1250 * Function: 1251 * soc_l2mod_running 1252 * Purpose: 1253 * Determine the L2MOD sync thread running parameters 1254 * Parameters: 1255 * unit - unit number. 1256 * flags (OUT) - if non-NULL, receives the current flag settings 1257 * interval (OUT) - if non-NULL, receives the current pass interval 1258 * Returns: 1259 * Boolean; TRUE if L2MOD sync thread is running 1260 */ 1261 1262 int 1263 soc_l2mod_running(int unit, uint32 *flags, sal_usecs_t *interval) 1264 { 1265 #ifdef BCM_XGS3_SWITCH_SUPPORT 1266 soc_control_t *soc = SOC_CONTROL(unit); 1267 1268 if (SOC_IS_XGS3_SWITCH(unit)) { 1269 if (soc->l2x_pid != SAL_THREAD_ERROR) { 1270 if (flags != NULL) { 1271 *flags = soc->l2x_flags; 1272 } 1273 if (interval != NULL) { 1274 *interval = soc->l2x_interval; 1275 } 1276 } 1277 1278 return (soc->l2x_pid != SAL_THREAD_ERROR); 1279 } 1280 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 1281 return SOC_E_UNAVAIL; 1282 } 1283 1284 /* 1285 * Function: 1286 * soc_l2mod_stop 1287 * Purpose: 1288 * Stop L2MOD-related thread 1289 * Parameters: 1290 * unit - unit number. 1291 * Returns: 1292 * SOC_E_XXX 1293 */ 1294 1295 int 1296 soc_l2mod_stop(int unit) 1297 { 1298 #ifdef BCM_XGS3_SWITCH_SUPPORT 1299 soc_control_t * soc = SOC_CONTROL(unit); 1300 int rv = SOC_E_NONE; 1301 1302 if (SOC_IS_XGS3_SWITCH(unit)) { 1303 LOG_INFO(BSL_LS_SOC_ARL, 1304 (BSL_META_U(unit, 1305 "soc_l2mod_stop: unit=%d\n"), unit)); 1306 1307 _soc_l2mod_fifo_enable(unit, 0); 1308 if (!soc_feature(unit, soc_feature_fifo_dma)) { 1309 soc_intr_disable(unit, IRQ_L2_MOD_FIFO_NOT_EMPTY); 1310 /* Wake up thread so it will check the exit flag */ 1311 sal_sem_give(soc->arl_notify); 1312 } 1313 #if defined (BCM_TRIUMPH_SUPPORT) 1314 if (soc_feature(unit, soc_feature_esm_support)) { 1315 SOC_IF_ERROR_RETURN 1316 (soc_reg_field32_modify(unit, ESM_L2_AGE_CTLr, REG_PORT_ANY, 1317 CPU_NOTIFYf, 0)); 1318 SOC_IF_ERROR_RETURN 1319 (soc_reg_field32_modify(unit, ESM_PER_PORT_REPL_CONTROLr, 1320 REG_PORT_ANY, CPU_NOTIFYf, 0)); 1321 } 1322 #endif /* BCM_TRIUMPH_SUPPORT */ 1323 return rv; 1324 } 1325 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 1326 return SOC_E_UNAVAIL; 1327 } 1328 1329 int 1330 soc_l2mod_start(int unit, uint32 flags, sal_usecs_t interval) 1331 { 1332 #ifdef BCM_XGS3_SWITCH_SUPPORT 1333 soc_control_t * soc = SOC_CONTROL(unit); 1334 int pri; 1335 1336 if (SOC_IS_XGS3_SWITCH(unit)) { 1337 if (!soc_feature(unit, soc_feature_arl_hashed)) { 1338 return SOC_E_UNAVAIL; 1339 } 1340 1341 if (soc->l2x_interval != 0) { 1342 SOC_IF_ERROR_RETURN(soc_l2mod_stop(unit)); 1343 } 1344 1345 sal_snprintf(soc->l2x_name, sizeof (soc->l2x_name), "bcmL2MOD.%d", unit); 1346 1347 soc->l2x_flags = flags; 1348 soc->l2x_interval = interval; 1349 1350 if (interval == 0) { 1351 return SOC_E_NONE; 1352 } 1353 1354 if (soc->l2x_pid == SAL_THREAD_ERROR) { 1355 pri = soc_property_get(unit, spn_L2XMSG_THREAD_PRI, 50); 1356 1357 #ifdef BCM_TRX_SUPPORT 1358 if (soc_feature(unit, soc_feature_fifo_dma)) { 1359 soc->l2x_pid = 1360 sal_thread_create(soc->l2x_name, SAL_THREAD_STKSZ, pri, 1361 _soc_l2mod_dma_thread, INT_TO_PTR(unit)); 1362 } else 1363 #endif /* BCM_TRX_SUPPORT */ 1364 { 1365 soc->l2x_pid = 1366 sal_thread_create(soc->l2x_name, SAL_THREAD_STKSZ, pri, 1367 _soc_l2mod_thread, INT_TO_PTR(unit)); 1368 } 1369 if (soc->l2x_pid == SAL_THREAD_ERROR) { 1370 LOG_ERROR(BSL_LS_SOC_L2, 1371 (BSL_META_U(unit, 1372 "soc_l2mod_start: Could not start L2MOD thread\n"))); 1373 return SOC_E_MEMORY; 1374 } 1375 } 1376 1377 return SOC_E_NONE; 1378 } 1379 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 1380 return SOC_E_UNAVAIL; 1381 }