l2x.c (16372B)
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 GH L2 Table Manipulation API routines. 8 * 9 * A low-level L2 shadow table is optionally kept in soc->arlShadow by 10 * using a callback to get all inserts/deletes from the l2xmsg task. It 11 * can be disabled by setting the l2xmsg_avl property to 0. 12 */ 13 14 #include <sal/core/libc.h> 15 #include <shared/bsl.h> 16 #include <soc/drv.h> 17 #include <soc/l2x.h> 18 #include <soc/ptable.h> 19 #include <soc/debug.h> 20 #include <soc/util.h> 21 #include <soc/mem.h> 22 #include <soc/greyhound.h> 23 24 #ifdef BCM_GREYHOUND_SUPPORT 25 26 #define _SOC_GH_L2_TABLE_DMA_CHUNK_SIZE 1024 27 28 /* 29 * Function: 30 * _soc_gh_l2_entry_limit_update 31 * Purpose: 32 * Update the mac limits per l2 entry 33 * Parameters: 34 * unit - unit number 35 * l2_entry - l2 entry 36 * ptm_tbl - port or trumk mac limit table 37 * ptm_entry_dw - entry length of port or trumk mac limit table 38 * vvm_tbl - vlan or vfi mac limit table 39 * vvm_entry_dw - entry length of vlan or vfi mac limit table 40 * s_count - system mac limit count 41 * Returns: 42 * SOC_E_XXX. 43 */ 44 STATIC int 45 _soc_gh_l2_entry_limit_update( 46 int unit, 47 uint32 *l2_entry, 48 uint32 *ptm_tbl, 49 uint32 ptm_entry_dw, 50 uint32 *vvm_tbl, 51 uint32 vvm_entry_dw, 52 uint32 *s_count) 53 { 54 uint32 dest_type, key_type; 55 uint32 is_valid, is_limit_counted = 0; 56 soc_mem_t mem; 57 uint32 entry[SOC_MAX_MEM_WORDS]; 58 int32 v_index = -1; /* vlan index */ 59 int32 p_index = -1; /* port index */ 60 uint32 p_count = 0; /* port or trunk mac count */ 61 uint32 v_count = 0; /* vlan or vfi mac count */ 62 uint32 *v_entry; /* vlan or vfi count entry */ 63 uint32 *p_entry; /* port or trunk count entry */ 64 65 mem = L2Xm; 66 67 /* check if entry is valid */ 68 is_valid = soc_mem_field32_get(unit, mem, l2_entry, VALIDf); 69 if (!is_valid) { 70 /* not valid entry skip it */ 71 return SOC_E_NONE; 72 } 73 74 /* check if entry is limit counted */ 75 if (soc_mem_field_valid(unit, mem, LIMIT_COUNTEDf)) { 76 is_limit_counted = soc_mem_field32_get(unit, mem, l2_entry, 77 LIMIT_COUNTEDf); 78 if (!is_limit_counted) { 79 /* entry not limit counted skip it */ 80 return SOC_E_NONE; 81 } 82 } 83 84 /* 85 * Get the key type of the entries. Process entries with only key_type 86 * GH_L2_HASH_KEY_TYPE_BRIDGE 87 */ 88 key_type = soc_mem_field32_get(unit, mem, l2_entry, KEY_TYPEf); 89 90 if (key_type != GH_L2_HASH_KEY_TYPE_BRIDGE) { 91 return SOC_E_NONE; 92 } 93 94 dest_type = soc_mem_field32_get(unit, mem, l2_entry, L2__DEST_TYPEf); 95 96 switch (dest_type) { 97 case 0: /* mod port */ 98 SOC_IF_ERROR_RETURN(soc_mem_read(unit, PORT_TABm, 99 MEM_BLOCK_ANY, 0, &entry)); 100 if (soc_mem_field32_get(unit, PORT_TABm, &entry, MY_MODIDf) == 101 soc_mem_field32_get(unit, mem, l2_entry, L2__MODULE_IDf)) { 102 p_index = soc_mem_field32_get(unit, mem, l2_entry, PORT_NUMf) + 103 soc_mem_index_count(unit, TRUNK_GROUPm); 104 } 105 break; 106 case 1: /* trunk */ 107 p_index = soc_mem_field32_get(unit, mem, l2_entry, L2__TGIDf); 108 break; 109 default: 110 /* if VFI based key then break else continue? */ 111 break; 112 } 113 114 /* 115 * based on key_type get vlan or vfi 116 * to index into VLAN_OR_VFI_MAC_COUNTm 117 */ 118 v_index = soc_mem_field32_get(unit, mem, l2_entry, L2__VLAN_IDf); 119 120 /* 121 * read and update vlan or vfi mac count 122 * in buffer also update the sys mac count. 123 */ 124 v_count = 0; 125 if (v_index >= 0) { 126 v_entry = (vvm_tbl + (v_index * vvm_entry_dw)); 127 v_count = soc_mem_field32_get(unit, VLAN_OR_VFI_MAC_COUNTm, 128 v_entry, COUNTf); 129 *s_count = *s_count + 1; 130 v_count++; 131 soc_mem_field32_set(unit, VLAN_OR_VFI_MAC_COUNTm, 132 v_entry, COUNTf, v_count); 133 } 134 135 /* read and update port or trunk mac count in buffer. */ 136 p_count = 0; 137 if (p_index >= 0) { 138 p_entry = ptm_tbl + (p_index * ptm_entry_dw); 139 p_count = soc_mem_field32_get(unit, PORT_OR_TRUNK_MAC_COUNTm, 140 p_entry, COUNTf); 141 p_count++; 142 soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_COUNTm, 143 p_entry, COUNTf, p_count); 144 } 145 146 return SOC_E_NONE; 147 } 148 149 150 /************************************************** 151 * @function soc_gh_l2_entry_limit_count_update 152 * 153 * 154 * @purpose Read L2 table from hardware, calculate 155 * and restore port/trunk and vlan/vfi 156 * mac counts. 157 * 158 * @param unit @b{(input)} unit number 159 * 160 * @returns BCM_E_NONE 161 * @returns BCM_E_FAIL 162 * 163 * @comments This rountine gets called for an 164 * L2 table SER event, if any of the 165 * mac limits(system, port, vlan) are 166 * enabled on the device. 167 * 168 * @end 169 */ 170 int 171 soc_gh_l2_entry_limit_count_update(int unit) 172 { 173 uint32 rval; 174 uint32 *l2_entry; /* l2 entry */ 175 uint32 s_count = 0; /* system mac count */ 176 177 /* l2 table */ 178 int index_min, index_max; 179 int entry_dw, entry_sz; 180 int chnk_idx, chnk_idx_max, table_chnk_sz, idx; 181 int chunk_size = _SOC_GH_L2_TABLE_DMA_CHUNK_SIZE; 182 183 /* port or trunk mac count table */ 184 int ptm_index_min, ptm_index_max; 185 int ptm_table_sz, ptm_entry_dw, ptm_entry_sz; 186 187 /* vlan or vfi mac count table */ 188 int vvm_index_min, vvm_index_max; 189 int vvm_table_sz, vvm_entry_dw, vvm_entry_sz; 190 191 uint32 *l2_buf = NULL; 192 uint32 *ptm_buf = NULL; 193 uint32 *vvm_buf = NULL; 194 195 soc_mem_t mem; 196 int rv; 197 #ifdef BCM_HURRICANE3_SUPPORT 198 uint32 l2_learn; 199 #endif /* BCM_HURRICANE3_SUPPORT */ 200 201 /* If MAC learn limit not enabled do nothing */ 202 SOC_IF_ERROR_RETURN(READ_SYS_MAC_LIMIT_CONTROLr(unit, &rval)); 203 if (!soc_reg_field_get(unit, SYS_MAC_LIMIT_CONTROLr, 204 rval, ENABLEf)) { 205 LOG_VERBOSE(BSL_LS_SOC_COMMON, 206 (BSL_META_U(unit, 207 "\nMAC limits not enabled.\n"))); 208 return SOC_E_NONE; 209 } 210 211 /* 212 * Mac limits are enabled. 213 * 1. Read (DMA) L2 table to recalculate mac count 214 * 2. Iterate through all the entries. 215 * 3. if the entry is limit_counted 216 * Check if KEY_TYPE is BRIDGE, VLAN or VFI 217 * based on DEST_TYPE determine if Trunk or ModPort 218 * Get port index into port_or_trunk_mac_count table 219 * Get vlan/vfi index into vlan_or_vfi_mac_count table 220 * update the port, vlan/vfi, system mac count. 221 * Write(slam) port_or_trunk_mac count and 222 * vlan_or_vfi_mac_count tables. 223 */ 224 225 /* 226 * Allocate memory for port/trunk mac count table to store 227 * the updated count. 228 */ 229 mem = PORT_OR_TRUNK_MAC_COUNTm; 230 ptm_entry_dw = soc_mem_entry_words(unit, mem); 231 ptm_entry_sz = ptm_entry_dw * sizeof(uint32); 232 ptm_index_min = soc_mem_index_min(unit, mem); 233 ptm_index_max = soc_mem_index_max(unit, mem); 234 ptm_table_sz = (ptm_index_max - ptm_index_min + 1) * ptm_entry_sz; 235 236 ptm_buf = soc_cm_salloc(unit, ptm_table_sz, "ptm_tmp"); 237 if (ptm_buf == NULL) { 238 LOG_ERROR(BSL_LS_SOC_L2, 239 (BSL_META_U(unit, 240 "soc_gh_l2_entry_limit_count_update: " 241 "Memory allocation failed for %s\n"), 242 SOC_MEM_NAME(unit, mem))); 243 return SOC_E_MEMORY; 244 } 245 246 sal_memset(ptm_buf, 0, ptm_table_sz); 247 248 /* 249 * Allocate memory for vlan/vfi mac count table to store 250 * the updated count. 251 */ 252 mem = VLAN_OR_VFI_MAC_COUNTm; 253 vvm_entry_dw = soc_mem_entry_words(unit, mem); 254 vvm_entry_sz = vvm_entry_dw * sizeof(uint32); 255 vvm_index_min = soc_mem_index_min(unit, mem); 256 vvm_index_max = soc_mem_index_max(unit, mem); 257 vvm_table_sz = (vvm_index_max - vvm_index_min + 1) * vvm_entry_sz; 258 259 vvm_buf = soc_cm_salloc(unit, vvm_table_sz, "vvm_tmp"); 260 if (vvm_buf == NULL) { 261 soc_cm_sfree(unit, ptm_buf); 262 LOG_ERROR(BSL_LS_SOC_L2, 263 (BSL_META_U(unit, 264 "soc_gh_l2_entry_limit_count_update: " 265 "Memory allocation failed for %s\n"), 266 SOC_MEM_NAME(unit, mem))); 267 return SOC_E_MEMORY; 268 } 269 270 sal_memset(vvm_buf, 0, vvm_table_sz); 271 272 /* Create a copy L2Xm table for calculating mac count */ 273 mem = L2Xm; 274 entry_dw = soc_mem_entry_words(unit, mem); 275 entry_sz = entry_dw * sizeof(uint32); 276 index_min = soc_mem_index_min(unit, mem); 277 index_max = soc_mem_index_max(unit, mem); 278 table_chnk_sz = chunk_size * entry_sz; 279 280 l2_buf = soc_cm_salloc(unit, table_chnk_sz, "l2x_tmp"); 281 if (l2_buf == NULL) { 282 soc_cm_sfree(unit, ptm_buf); 283 soc_cm_sfree(unit, vvm_buf); 284 LOG_ERROR(BSL_LS_SOC_L2, 285 (BSL_META_U(unit, 286 "soc_gh_l2_entry_limit_count_update: " 287 "Memory allocation failed for %s\n"), 288 SOC_MEM_NAME(unit, mem))); 289 return SOC_E_MEMORY; 290 } 291 292 SOC_L2X_MEM_LOCK(unit); 293 for (chnk_idx = index_min; chnk_idx <= index_max; chnk_idx += chunk_size) { 294 sal_memset(l2_buf, 0, table_chnk_sz); 295 296 chnk_idx_max = ((chnk_idx + chunk_size) <= index_max) ? 297 (chnk_idx + chunk_size - 1) : index_max; 298 299 /* DMA L2 Table */ 300 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, chnk_idx, 301 chnk_idx_max, l2_buf); 302 if (SOC_FAILURE(rv)) { 303 soc_cm_sfree(unit, ptm_buf); 304 soc_cm_sfree(unit, vvm_buf); 305 soc_cm_sfree(unit, l2_buf); 306 SOC_L2X_MEM_UNLOCK(unit); 307 LOG_ERROR(BSL_LS_SOC_L2, 308 (BSL_META_U(unit, 309 "DMA failed: %s, mac limts not synced!\n"), 310 soc_errmsg(rv))); 311 return SOC_E_FAIL; 312 } 313 314 /* Iter through all l2 entries in the chunk */ 315 for (idx = 0; idx <= (chnk_idx_max - chnk_idx); idx++) { 316 l2_entry = (l2_buf + (idx * entry_dw)); 317 318 rv = _soc_gh_l2_entry_limit_update(unit, l2_entry, 319 ptm_buf, ptm_entry_dw, 320 vvm_buf, vvm_entry_dw, 321 &s_count); 322 if (SOC_FAILURE(rv)) { 323 soc_cm_sfree(unit, ptm_buf); 324 soc_cm_sfree(unit, vvm_buf); 325 soc_cm_sfree(unit, l2_buf); 326 SOC_L2X_MEM_UNLOCK(unit); 327 LOG_ERROR(BSL_LS_SOC_L2, 328 (BSL_META_U(unit, 329 "L2 MAC count update failed: %s, " 330 "for L2 Entry\n"), 331 soc_errmsg(rv))); 332 return SOC_E_FAIL; 333 } 334 } /* End for index */ 335 } /* End for chnk_idx */ 336 337 /* Free memory */ 338 soc_cm_sfree(unit, l2_buf); 339 340 #ifdef BCM_HURRICANE3_SUPPORT 341 if (soc_feature(unit, soc_feature_l2_overflow_bucket)) { 342 /* check if l2 overflow table is enabled */ 343 rv = READ_L2_LEARN_CONTROLr(unit, &l2_learn); 344 if (SOC_FAILURE(rv)) { 345 soc_cm_sfree(unit, ptm_buf); 346 soc_cm_sfree(unit, vvm_buf); 347 SOC_L2X_MEM_UNLOCK(unit); 348 LOG_ERROR(BSL_LS_SOC_L2, 349 (BSL_META_U(unit, 350 "Register read failed: %s, " 351 "for L2 Learn Control\n"), 352 soc_errmsg(rv))); 353 return SOC_E_FAIL; 354 } 355 if (soc_reg_field_get(unit, L2_LEARN_CONTROLr, 356 l2_learn, OVERFLOW_BUCKET_ENABLEf)) { 357 /* L2 overflow table is enabled */ 358 mem = L2_ENTRY_OVERFLOWm; 359 entry_dw = soc_mem_entry_words(unit, mem); 360 entry_sz = entry_dw * sizeof(uint32); 361 index_min = soc_mem_index_min(unit, mem); 362 index_max = soc_mem_index_max(unit, mem); 363 table_chnk_sz = (index_max + 1) * entry_sz; 364 365 l2_buf = soc_cm_salloc(unit, table_chnk_sz, "l2x_overflow"); 366 if (l2_buf == NULL) { 367 soc_cm_sfree(unit, ptm_buf); 368 soc_cm_sfree(unit, vvm_buf); 369 SOC_L2X_MEM_UNLOCK(unit); 370 LOG_ERROR(BSL_LS_SOC_L2, 371 (BSL_META_U(unit, 372 "soc_gh_l2_entry_limit_count_update: " 373 "Memory allocation failed for %s\n"), 374 SOC_MEM_NAME(unit, mem))); 375 return SOC_E_MEMORY; 376 } 377 378 sal_memset(l2_buf, 0, table_chnk_sz); 379 380 /* DMA L2 overflow Table */ 381 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 382 index_min, index_max, l2_buf); 383 if (SOC_FAILURE(rv)) { 384 soc_cm_sfree(unit, ptm_buf); 385 soc_cm_sfree(unit, vvm_buf); 386 soc_cm_sfree(unit, l2_buf); 387 SOC_L2X_MEM_UNLOCK(unit); 388 LOG_ERROR(BSL_LS_SOC_L2, 389 (BSL_META_U(unit, 390 "DMA failed: %s, " 391 "mac limts not synced!\n"), 392 soc_errmsg(rv))); 393 return SOC_E_FAIL; 394 } 395 396 /* Iter through all l2 overflow entries */ 397 for (idx = 0; idx <= index_max; idx++) { 398 l2_entry = (l2_buf + (idx * entry_dw)); 399 400 rv = _soc_gh_l2_entry_limit_update(unit, l2_entry, 401 ptm_buf, ptm_entry_dw, 402 vvm_buf, vvm_entry_dw, 403 &s_count); 404 if (SOC_FAILURE(rv)) { 405 soc_cm_sfree(unit, ptm_buf); 406 soc_cm_sfree(unit, vvm_buf); 407 soc_cm_sfree(unit, l2_buf); 408 SOC_L2X_MEM_UNLOCK(unit); 409 LOG_ERROR(BSL_LS_SOC_L2, 410 (BSL_META_U(unit, 411 "L2 MAC count update failed: %s, " 412 "for L2 Overflow Entry\n"), 413 soc_errmsg(rv))); 414 return SOC_E_FAIL; 415 } 416 } 417 418 /* Free memory */ 419 soc_cm_sfree(unit, l2_buf); 420 } 421 } 422 #endif /* BCM_HURRICANE3_SUPPORT */ 423 424 /* Write the tables to hardware */ 425 mem = PORT_OR_TRUNK_MAC_COUNTm; 426 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY, 427 ptm_index_min, ptm_index_max, (void *)ptm_buf); 428 if (SOC_FAILURE(rv)) { 429 soc_cm_sfree(unit, ptm_buf); 430 soc_cm_sfree(unit, vvm_buf); 431 SOC_L2X_MEM_UNLOCK(unit); 432 LOG_ERROR(BSL_LS_SOC_L2, 433 (BSL_META_U(unit, 434 "PORT_OR_TRUNK_MAC_COUNT write failed: " 435 "%s, mac limts not synced!\n"), 436 soc_errmsg(rv))); 437 return SOC_E_FAIL; 438 } 439 440 mem = VLAN_OR_VFI_MAC_COUNTm; 441 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY, 442 vvm_index_min, vvm_index_max, (void *)vvm_buf); 443 if (SOC_FAILURE(rv)) { 444 soc_cm_sfree(unit, ptm_buf); 445 soc_cm_sfree(unit, vvm_buf); 446 SOC_L2X_MEM_UNLOCK(unit); 447 LOG_ERROR(BSL_LS_SOC_L2, 448 (BSL_META_U(unit, 449 "VLAN_OR_VFI_MAC_COUNT write failed: " 450 "%s, mac limts not synced!\n"), 451 soc_errmsg(rv))); 452 return SOC_E_FAIL; 453 } 454 455 /* Update system count */ 456 soc_reg_field_set(unit, SYS_MAC_COUNTr, &rval, COUNTf, s_count); 457 rv = WRITE_SYS_MAC_COUNTr(unit, rval); 458 459 /* Free memory */ 460 soc_cm_sfree(unit, ptm_buf); 461 soc_cm_sfree(unit, vvm_buf); 462 463 SOC_L2X_MEM_UNLOCK(unit); 464 465 return rv; 466 } 467 468 #endif /* BCM_GREYHOUND_SUPPORT */