ipmc.c (18262B)
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 * File: ipmc.c 8 * Purpose: Tomahawk3 multicast replication implementation. 9 */ 10 #ifdef BCM_TOMAHAWK3_SUPPORT 11 12 #include <shared/bsl.h> 13 14 #include <soc/defs.h> 15 #include <sal/core/libc.h> 16 17 #include <soc/drv.h> 18 #include <soc/mem.h> 19 20 #include <bcm/types.h> 21 #include <bcm/error.h> 22 23 #include <bcm_int/esw_dispatch.h> 24 #include <bcm_int/esw/ipmc.h> 25 #include <bcm_int/esw/tomahawk.h> 26 #include <bcm_int/esw/tomahawk3.h> 27 #include <bcm_int/esw/firebolt.h> 28 29 #include <bcm_int/esw/stack.h> 30 #include <bcm_int/esw/l3.h> 31 #include <soc/tomahawk.h> 32 #include <soc/tomahawk3.h> 33 #include <soc/flexport/tomahawk3_mmu_flexport.h> 34 35 STATIC int 36 _bcm_th3_repl_head_tbl_read(int unit, int index, uint32 *entry, uint32 *head_ptr) 37 { 38 soc_mem_t repl_hd_tbl; 39 40 repl_hd_tbl = MMU_REPL_HEAD_TBLm; 41 SOC_IF_ERROR_RETURN(soc_mem_read(unit, repl_hd_tbl, MEM_BLOCK_ALL, 42 index, entry)); 43 if (head_ptr) { 44 *head_ptr = soc_mem_field32_get(unit, repl_hd_tbl, entry, HEAD_PTRf); 45 } 46 47 return BCM_E_NONE; 48 } 49 50 51 STATIC int 52 _bcm_th3_repl_head_tbl_write(int unit, int index, uint32 *entry) 53 { 54 soc_mem_t repl_hd_tbl; 55 repl_hd_tbl = MMU_REPL_HEAD_TBLm; 56 SOC_IF_ERROR_RETURN(soc_mem_write(unit, repl_hd_tbl, MEM_BLOCK_ALL, 57 index, entry)); 58 59 return BCM_E_NONE; 60 } 61 62 /* 63 * Function: 64 * bcm_th3_repl_list_start_ptr_get 65 * Purpose: 66 * Get replication list start pointer for given (repl_group, port). 67 * Parameters: 68 * unit - StrataSwitch PCI device unit number. 69 * repl_group - The replication group number. 70 * port - Port. 71 * start_ptr - (OUT) Replication list's start pointer to 72 * REPL_LIST table. 73 * Returns: 74 * BCM_E_XXX 75 */ 76 int 77 bcm_th3_repl_list_start_ptr_get(int unit, int repl_group, bcm_port_t port, 78 int *start_ptr) 79 { 80 soc_mem_t repl_group_table; 81 soc_field_t member_bitmap_f, head_index_f; 82 int member_bitmap_index; 83 mmu_repl_group_info_tbl_entry_t repl_group_entry; 84 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 85 int i; 86 soc_pbmp_t member_bitmap; 87 int member_id, member; 88 int head_index; 89 uint32 repl_head_entry[SOC_MAX_MEM_FIELD_WORDS]; 90 91 member_bitmap_f = MEMBER_BMPf; 92 head_index_f = BASE_PTRf; 93 94 #ifdef INCLUDE_L3 95 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 96 BCM_IF_ERROR_RETURN(bcm_th_port_to_aggid(unit, port, &member_bitmap_index)); 97 } else 98 #endif 99 { 100 /* Get member bitmap index */ 101 member_bitmap_index = port; 102 } 103 104 /* Get member bitmap */ 105 repl_group_table = MMU_REPL_GROUP_INFO_TBLm; 106 107 SOC_IF_ERROR_RETURN 108 (soc_mem_read(unit, repl_group_table, MEM_BLOCK_ANY, 109 repl_group, &repl_group_entry)); 110 sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32)); 111 soc_mem_field_get(unit, repl_group_table, (uint32 *)&repl_group_entry, 112 member_bitmap_f, fldbuf); 113 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 114 SOC_PBMP_WORD_SET(member_bitmap, i, fldbuf[i]); 115 } 116 117 /* Check if port is in member bitmap */ 118 if (!SOC_PBMP_MEMBER(member_bitmap, member_bitmap_index)) { 119 *start_ptr = 0; 120 return BCM_E_NONE; 121 } 122 123 /* Get replication list start pointer */ 124 member_id = 0; 125 SOC_PBMP_ITER(member_bitmap, member) { 126 if (member == member_bitmap_index) { 127 break; 128 } 129 member_id++; 130 } 131 head_index = member_id + soc_mem_field32_get(unit, repl_group_table, 132 &repl_group_entry, head_index_f); 133 134 SOC_IF_ERROR_RETURN 135 (_bcm_th3_repl_head_tbl_read(unit, head_index, 136 repl_head_entry, (uint32 *)start_ptr)); 137 138 139 return BCM_E_NONE; 140 } 141 142 STATIC int 143 _bcm_th3_initial_copy_count_set(int unit, int repl_head_ptr, int intf_count) 144 { 145 /* each replication head entry is associated with a ICC entry*/ 146 int icc_entry_ptr; 147 int icc_field_index; 148 mmu_repl_member_icc_entry_t entry; 149 soc_mem_t mem; 150 int icc_val; 151 soc_field_t icc_fields[] = { 152 ICC_VAL0f, ICC_VAL1f, ICC_VAL2f, ICC_VAL3f, 153 ICC_VAL4f, ICC_VAL5f, ICC_VAL6f, ICC_VAL7f, 154 ICC_VAL8f, ICC_VAL9f, ICC_VAL10f, ICC_VAL11f, 155 ICC_VAL12f, ICC_VAL13f, ICC_VAL14f, ICC_VAL15f, 156 ICC_VAL16f, ICC_VAL17f, ICC_VAL18f, ICC_VAL19f, 157 ICC_VAL20f, ICC_VAL21f, ICC_VAL22f, ICC_VAL23f, 158 ICC_VAL24f, ICC_VAL25f, ICC_VAL26f, ICC_VAL27f, 159 ICC_VAL28f, ICC_VAL29f, ICC_VAL30f, ICC_VAL31f, 160 ICC_VAL32f, ICC_VAL33f, ICC_VAL34f, ICC_VAL35f, 161 ICC_VAL36f, ICC_VAL37f, ICC_VAL38f, ICC_VAL39f, 162 ICC_VAL40f, ICC_VAL41f, ICC_VAL42f, ICC_VAL43f, 163 ICC_VAL44f, ICC_VAL45f, ICC_VAL46f, ICC_VAL47f, 164 ICC_VAL48f, ICC_VAL49f, ICC_VAL50f, ICC_VAL51f, 165 ICC_VAL52f, ICC_VAL53f, ICC_VAL54f, ICC_VAL55f, 166 ICC_VAL56f, ICC_VAL57f, ICC_VAL58f, ICC_VAL59f, 167 ICC_VAL60f, ICC_VAL61f, ICC_VAL62f, ICC_VAL63f, 168 169 }; 170 icc_entry_ptr = repl_head_ptr / TH3_IPMC_MAX_INTF_COUNT_PER_ENTRY; 171 icc_field_index = repl_head_ptr % TH3_IPMC_MAX_INTF_COUNT_PER_ENTRY; 172 /* ICC value is equal to inft_count for repl counts 1-31 */ 173 /* ICC value will be 0 for repl_count = 0 or > 31*/ 174 icc_val = intf_count > 31 ? 0 : intf_count; 175 mem = MMU_REPL_MEMBER_ICCm; 176 SOC_IF_ERROR_RETURN 177 (soc_mem_read(unit, mem, MEM_BLOCK_ANY, icc_entry_ptr, &entry)); 178 soc_MMU_REPL_MEMBER_ICCm_field32_set(unit, &entry, 179 icc_fields[icc_field_index], icc_val); 180 181 SOC_IF_ERROR_RETURN 182 (soc_mem_write(unit, mem, MEM_BLOCK_ALL, icc_entry_ptr, &entry)); 183 184 return BCM_E_NONE; 185 } 186 187 STATIC int 188 _bcm_th3_initial_copy_count_get(int unit, int repl_head_ptr, int *intf_count) 189 { 190 /* each replication head entry is associated with a ICC entry*/ 191 int icc_entry_ptr; 192 int icc_field_index; 193 mmu_repl_member_icc_entry_t entry; 194 soc_mem_t mem; 195 soc_field_t icc_fields[] = { 196 ICC_VAL0f, ICC_VAL1f, ICC_VAL2f, ICC_VAL3f, 197 ICC_VAL4f, ICC_VAL5f, ICC_VAL6f, ICC_VAL7f, 198 ICC_VAL8f, ICC_VAL9f, ICC_VAL10f, ICC_VAL11f, 199 ICC_VAL12f, ICC_VAL13f, ICC_VAL14f, ICC_VAL15f, 200 ICC_VAL16f, ICC_VAL17f, ICC_VAL18f, ICC_VAL19f, 201 ICC_VAL20f, ICC_VAL21f, ICC_VAL22f, ICC_VAL23f, 202 ICC_VAL24f, ICC_VAL25f, ICC_VAL26f, ICC_VAL27f, 203 ICC_VAL28f, ICC_VAL29f, ICC_VAL30f, ICC_VAL31f, 204 ICC_VAL32f, ICC_VAL33f, ICC_VAL34f, ICC_VAL35f, 205 ICC_VAL36f, ICC_VAL37f, ICC_VAL38f, ICC_VAL39f, 206 ICC_VAL40f, ICC_VAL41f, ICC_VAL42f, ICC_VAL43f, 207 ICC_VAL44f, ICC_VAL45f, ICC_VAL46f, ICC_VAL47f, 208 ICC_VAL48f, ICC_VAL49f, ICC_VAL50f, ICC_VAL51f, 209 ICC_VAL52f, ICC_VAL53f, ICC_VAL54f, ICC_VAL55f, 210 ICC_VAL56f, ICC_VAL57f, ICC_VAL58f, ICC_VAL59f, 211 ICC_VAL60f, ICC_VAL61f, ICC_VAL62f, ICC_VAL63f, 212 213 }; 214 215 if(intf_count == NULL) { 216 return BCM_E_PARAM; 217 } 218 icc_entry_ptr = repl_head_ptr / TH3_IPMC_MAX_INTF_COUNT_PER_ENTRY; 219 icc_field_index = repl_head_ptr % TH3_IPMC_MAX_INTF_COUNT_PER_ENTRY; 220 221 mem = MMU_REPL_MEMBER_ICCm; 222 SOC_IF_ERROR_RETURN 223 (soc_mem_read(unit, mem, MEM_BLOCK_ANY, icc_entry_ptr, &entry)); 224 *intf_count = soc_MMU_REPL_MEMBER_ICCm_field32_get(unit, &entry, 225 icc_fields[icc_field_index]); 226 227 return BCM_E_NONE; 228 } 229 230 /* Function: 231 * bcm_th3_repl_list_start_ptr_set 232 * Purpose: 233 * Set replication list start pointer for given (repl_group, port). 234 * Parameters: 235 * unit - StrataSwitch PCI device unit number. 236 * repl_group - The replication group number. 237 * port - Port. 238 * start_ptr - Replication list's start pointer. 239 * intf_count - Replication list's interface count. 240 * Returns: 241 * BCM_E_XXX 242 */ 243 int 244 bcm_th3_repl_list_start_ptr_set(int unit, int repl_group, bcm_port_t port, 245 int start_ptr, int intf_count) 246 { 247 int add_member; 248 soc_mem_t repl_group_table; 249 soc_mem_t repl_head_table; 250 soc_field_t member_bitmap_f, head_index_f; 251 int member_bitmap_index; 252 int pipe; 253 mmu_repl_group_info_tbl_entry_t repl_group_entry; 254 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 255 int i; 256 soc_pbmp_t old_member_bitmap; 257 soc_pbmp_t new_member_bitmap; 258 int old_member_count, new_member_count; 259 int old_head_index, new_head_index; 260 int member_id, member, old_member_id, new_member_id; 261 uint32 repl_head_entry[SOC_MAX_MEM_FIELD_WORDS]; 262 uint32 old_repl_head_entry[SOC_MAX_MEM_FIELD_WORDS]; 263 int member_bitmap_len; 264 soc_info_t *si = &SOC_INFO(unit); 265 uint32 itm_map = si->itm_map; 266 int itm, rv; 267 268 if (start_ptr > 0) { 269 add_member = TRUE; 270 } else { 271 add_member = FALSE; 272 } 273 274 member_bitmap_f = MEMBER_BMPf; 275 head_index_f = BASE_PTRf; 276 277 #ifdef INCLUDE_L3 278 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 279 BCM_IF_ERROR_RETURN(bcm_th_port_to_aggid(unit, port, &member_bitmap_index)); 280 } else 281 #endif 282 { 283 /* Get member bitmap index */ 284 member_bitmap_index = port; 285 } 286 287 member_bitmap_len = soc_mem_field_length(unit, MMU_REPL_GROUP_INFO_TBLm, 288 member_bitmap_f); 289 if (member_bitmap_index >= member_bitmap_len) { 290 return BCM_E_PARAM; 291 } 292 293 /* Get old member bitmap and old head index */ 294 pipe = 0; 295 296 repl_head_table = MMU_REPL_HEAD_TBLm; 297 298 repl_group_table = MMU_REPL_GROUP_INFO_TBLm; 299 300 SOC_IF_ERROR_RETURN 301 (soc_mem_read(unit, repl_group_table, MEM_BLOCK_ANY, 302 repl_group, &repl_group_entry)); 303 sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32)); 304 soc_mem_field_get(unit, repl_group_table, (uint32 *)&repl_group_entry, 305 member_bitmap_f, fldbuf); 306 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 307 SOC_PBMP_WORD_SET(old_member_bitmap, i, fldbuf[i]); 308 } 309 SOC_PBMP_ASSIGN(new_member_bitmap, old_member_bitmap); 310 SOC_PBMP_COUNT(old_member_bitmap, old_member_count); 311 old_head_index = soc_mem_field32_get(unit, repl_group_table, 312 &repl_group_entry, head_index_f); 313 314 if (add_member) { 315 /* Update REPL_HEAD table */ 316 sal_memset(repl_head_entry, 0, sizeof(repl_head_entry)); 317 soc_mem_field32_set(unit, repl_head_table, repl_head_entry, 318 HEAD_PTRf, start_ptr); 319 if (SOC_PBMP_MEMBER(old_member_bitmap, member_bitmap_index)) { 320 /* Port is already a member of the group */ 321 member_id = 0; 322 SOC_PBMP_ITER(old_member_bitmap, member) { 323 if (member == member_bitmap_index) { 324 break; 325 } 326 member_id++; 327 } 328 SOC_IF_ERROR_RETURN 329 (_bcm_th3_repl_head_tbl_write(unit, 330 (old_head_index + member_id), repl_head_entry)); 331 BCM_IF_ERROR_RETURN 332 (_bcm_th3_initial_copy_count_set(unit, 333 (old_head_index + member_id), intf_count)); 334 new_head_index = old_head_index; 335 } else { 336 SOC_PBMP_PORT_ADD(new_member_bitmap, member_bitmap_index); 337 new_member_count = old_member_count + 1; 338 BCM_IF_ERROR_RETURN(bcm_th3_repl_head_alloc(unit, 339 0, new_member_count, &new_head_index)); 340 old_member_id = 0; 341 new_member_id = 0; 342 SOC_PBMP_ITER(new_member_bitmap, member) { 343 int old_icc = 0; 344 if (member == member_bitmap_index) { 345 SOC_IF_ERROR_RETURN 346 (_bcm_th3_repl_head_tbl_write(unit, 347 (new_head_index + new_member_id), 348 repl_head_entry)); 349 BCM_IF_ERROR_RETURN 350 (_bcm_th3_initial_copy_count_set(unit, 351 (new_head_index + new_member_id), intf_count)); 352 } else { 353 SOC_IF_ERROR_RETURN 354 (_bcm_th3_repl_head_tbl_read(unit, 355 (old_head_index + old_member_id), 356 old_repl_head_entry, NULL)); 357 SOC_IF_ERROR_RETURN(_bcm_th3_initial_copy_count_get(unit, 358 (old_head_index + old_member_id), &old_icc)); 359 SOC_IF_ERROR_RETURN 360 (_bcm_th3_repl_head_tbl_write(unit, 361 (new_head_index + new_member_id), 362 old_repl_head_entry)); 363 BCM_IF_ERROR_RETURN 364 (_bcm_th3_initial_copy_count_set(unit, 365 (new_head_index + new_member_id), old_icc)); 366 old_member_id++; 367 } 368 new_member_id++; 369 } 370 } 371 372 /* Update REPL_GROUP entry */ 373 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 374 fldbuf[i] = SOC_PBMP_WORD_GET(new_member_bitmap, i); 375 } 376 soc_mem_field_set(unit, repl_group_table, (uint32 *)&repl_group_entry, 377 member_bitmap_f, fldbuf); 378 soc_mem_field32_set(unit, repl_group_table, &repl_group_entry, 379 head_index_f, new_head_index); 380 381 SOC_IF_ERROR_RETURN 382 (soc_mem_write(unit, repl_group_table, MEM_BLOCK_ALL, 383 repl_group, &repl_group_entry)); 384 if (!SAL_BOOT_SIMULATION) { 385 /* mmu rqe Flush*/ 386 for (itm = 0; itm < NUM_ITM(unit); itm++) { 387 if (itm_map & (1 << itm)) { 388 /* Issue RQE flush twice per each ITM*/ 389 rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 1); 390 if (rv != BCM_E_NONE) { 391 return BCM_E_INTERNAL; 392 } 393 rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 2); 394 if (rv != BCM_E_NONE) { 395 return BCM_E_INTERNAL; 396 } 397 } 398 } 399 } 400 401 /* Release old block of REPL_HEAD entries */ 402 if (old_member_count > 0 && old_head_index != new_head_index) { 403 BCM_IF_ERROR_RETURN(bcm_th3_repl_head_free(unit, 404 pipe, old_head_index, old_member_count)); 405 } 406 407 408 } else { /* Remove member from replication group */ 409 410 if (!SOC_PBMP_MEMBER(old_member_bitmap, member_bitmap_index)) { 411 /* Port is not a member. Nothing more to do. */ 412 return BCM_E_NONE; 413 } 414 415 /* Update REPL_HEAD table */ 416 new_member_count = old_member_count - 1; 417 if (new_member_count > 0) { 418 BCM_IF_ERROR_RETURN(bcm_th3_repl_head_alloc(unit, 419 0, new_member_count, &new_head_index)); 420 old_member_id = 0; 421 new_member_id = 0; 422 SOC_PBMP_ITER(old_member_bitmap, member) { 423 if (member != member_bitmap_index) { 424 int old_icc = 0; 425 SOC_IF_ERROR_RETURN 426 (_bcm_th3_repl_head_tbl_read(unit, 427 (old_head_index + old_member_id), 428 old_repl_head_entry, NULL)); 429 SOC_IF_ERROR_RETURN(_bcm_th3_initial_copy_count_get(unit, 430 (old_head_index + old_member_id), &old_icc)); 431 SOC_IF_ERROR_RETURN 432 (_bcm_th3_repl_head_tbl_write(unit, 433 (new_head_index + new_member_id), 434 old_repl_head_entry)); 435 BCM_IF_ERROR_RETURN 436 (_bcm_th3_initial_copy_count_set(unit, 437 (new_head_index + new_member_id), old_icc)); 438 new_member_id++; 439 } 440 old_member_id++; 441 } 442 } else { 443 new_head_index = 0; 444 } 445 446 /* Update REPL_GROUP entry */ 447 SOC_PBMP_PORT_REMOVE(new_member_bitmap, member_bitmap_index); 448 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 449 fldbuf[i] = SOC_PBMP_WORD_GET(new_member_bitmap, i); 450 } 451 soc_mem_field_set(unit, repl_group_table, (uint32 *)&repl_group_entry, 452 member_bitmap_f, fldbuf); 453 soc_mem_field32_set(unit, repl_group_table, &repl_group_entry, 454 head_index_f, new_head_index); 455 456 SOC_IF_ERROR_RETURN 457 (soc_mem_write(unit, repl_group_table, MEM_BLOCK_ALL, 458 repl_group, &repl_group_entry)); 459 460 if (!SAL_BOOT_SIMULATION) { 461 /* mmu rqe Flush*/ 462 for (itm = 0; itm < NUM_ITM(unit); itm++) { 463 if (itm_map & (1 << itm)) { 464 /* Issue RQE flush twice per each ITM*/ 465 rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 1); 466 if (rv != BCM_E_NONE) { 467 return BCM_E_INTERNAL; 468 } 469 rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 2); 470 if (rv != BCM_E_NONE) { 471 return BCM_E_INTERNAL; 472 } 473 } 474 } 475 } 476 /* Release old block of REPL_HEAD entries */ 477 BCM_IF_ERROR_RETURN(bcm_th3_repl_head_free(unit, 478 pipe, old_head_index, old_member_count)); 479 } 480 481 return BCM_E_NONE; 482 } 483 484 #endif