niv.c (16376B)
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: niv.c 8 * Purpose: Implements bcm_niv_forward_* APIs for Triumph3. 9 */ 10 11 #include <soc/defs.h> 12 #include <sal/core/libc.h> 13 14 #if defined(BCM_TRIUMPH3_SUPPORT) && defined(INCLUDE_L3) 15 16 #include <soc/mem.h> 17 #include <soc/ism_hash.h> 18 19 #include <bcm/error.h> 20 21 #include <bcm_int/common/multicast.h> 22 #include <bcm_int/esw/triumph3.h> 23 24 /* 25 * Purpose: 26 * Create NIV Forwarding table entry 27 * Parameters: 28 * unit - (IN) Device Number 29 * iv_fwd_entry - (IN) NIV Forwarding table entry 30 */ 31 int 32 bcm_tr3_niv_forward_add(int unit, bcm_niv_forward_t *iv_fwd_entry) 33 { 34 int rv = BCM_E_NONE; 35 bcm_module_t mod_out; 36 bcm_port_t port_out; 37 bcm_trunk_t tgid_out; 38 int id_out; 39 l2_entry_1_entry_t l2_entry; 40 41 if (iv_fwd_entry->name_space > 0xfff) { 42 return BCM_E_PARAM; 43 } 44 45 if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_MULTICAST)) { 46 if (iv_fwd_entry->virtual_interface_id > 0xfff) { 47 return BCM_E_PARAM; 48 } 49 50 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, 51 iv_fwd_entry->dest_port, 52 &mod_out, &port_out, &tgid_out, &id_out)); 53 if (-1 != id_out) { 54 return BCM_E_PARAM; 55 } 56 57 sal_memset(&l2_entry, 0, sizeof(l2_entry)); 58 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VALIDf, 1); 59 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, KEY_TYPEf, 60 SOC_MEM_KEY_L2_ENTRY_1_VIF_VIF); 61 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__NAMESPACEf, 62 iv_fwd_entry->name_space); 63 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__Pf, 0); 64 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__DST_VIFf, 65 iv_fwd_entry->virtual_interface_id); 66 if (-1 != tgid_out) { 67 BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, tgid_out)); 68 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__DEST_TYPEf, 1); 69 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__TGIDf, tgid_out); 70 } else { 71 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__MODULE_IDf, mod_out); 72 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__PORT_NUMf, port_out); 73 } 74 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, STATIC_BITf, 1); 75 76 } else { /* Multicast forward entry */ 77 if (iv_fwd_entry->virtual_interface_id > 0x3fff) { 78 return BCM_E_PARAM; 79 } 80 if (!_BCM_MULTICAST_IS_L2(iv_fwd_entry->dest_multicast)) { 81 return BCM_E_PARAM; 82 } 83 84 sal_memset(&l2_entry, 0, sizeof(l2_entry)); 85 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VALIDf, 1); 86 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, KEY_TYPEf, 87 SOC_MEM_KEY_L2_ENTRY_1_VIF_VIF); 88 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__NAMESPACEf, 89 iv_fwd_entry->name_space); 90 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__Pf, 1); 91 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__DST_VIFf, 92 iv_fwd_entry->virtual_interface_id); 93 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__L2MC_PTRf, 94 _BCM_MULTICAST_ID_GET(iv_fwd_entry->dest_multicast)); 95 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, STATIC_BITf, 1); 96 } 97 98 soc_mem_lock(unit, L2_ENTRY_1m); 99 100 if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_REPLACE)) { 101 l2_entry_1_entry_t l2x_lookup; 102 int l2_index; 103 104 /* See if the entry already exists */ 105 rv = soc_mem_generic_lookup(unit, L2_ENTRY_1m, MEM_BLOCK_ANY, 0, 106 &l2_entry, &l2x_lookup, &l2_index); 107 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 108 soc_mem_unlock(unit, L2_ENTRY_1m); 109 return rv; 110 } 111 if (BCM_SUCCESS(rv)) { 112 soc_mem_unlock(unit, L2_ENTRY_1m); 113 return BCM_E_EXISTS; 114 } 115 116 rv = soc_mem_insert(unit, L2_ENTRY_1m, MEM_BLOCK_ALL, &l2_entry); 117 if (SOC_FAILURE(rv)) { 118 soc_mem_unlock(unit, L2_ENTRY_1m); 119 return rv; 120 } 121 } else { /* Replace existing entry */ 122 rv = soc_mem_delete(unit, L2_ENTRY_1m, MEM_BLOCK_ALL, &l2_entry); 123 if (SOC_FAILURE(rv)) { 124 soc_mem_unlock(unit, L2_ENTRY_1m); 125 return rv; 126 } 127 rv = soc_mem_insert(unit, L2_ENTRY_1m, MEM_BLOCK_ALL, &l2_entry); 128 if (SOC_FAILURE(rv)) { 129 soc_mem_unlock(unit, L2_ENTRY_1m); 130 return rv; 131 } 132 } 133 134 soc_mem_unlock(unit, L2_ENTRY_1m); 135 136 return rv; 137 } 138 139 /* 140 * Purpose: 141 * Delete NIV Forwarding table entry 142 * Parameters: 143 * unit - (IN) Device Number 144 * iv_fwd_entry - (IN) NIV Forwarding table entry 145 */ 146 int 147 bcm_tr3_niv_forward_delete(int unit, bcm_niv_forward_t *iv_fwd_entry) 148 { 149 int rv = BCM_E_NONE; 150 l2_entry_1_entry_t l2_entry; 151 152 if (iv_fwd_entry->name_space > 0xfff) { 153 return BCM_E_PARAM; 154 } 155 156 if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_MULTICAST)) { 157 if (iv_fwd_entry->virtual_interface_id > 0xfff) { 158 return BCM_E_PARAM; 159 } 160 161 sal_memset(&l2_entry, 0, sizeof(l2_entry)); 162 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, KEY_TYPEf, 163 SOC_MEM_KEY_L2_ENTRY_1_VIF_VIF); 164 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__NAMESPACEf, 165 iv_fwd_entry->name_space); 166 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__Pf, 0); 167 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__DST_VIFf, 168 iv_fwd_entry->virtual_interface_id); 169 170 } else { /* Multicast forward entry */ 171 if (iv_fwd_entry->virtual_interface_id > 0x3fff) { 172 return BCM_E_PARAM; 173 } 174 175 sal_memset(&l2_entry, 0, sizeof(l2_entry)); 176 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, KEY_TYPEf, 177 SOC_MEM_KEY_L2_ENTRY_1_VIF_VIF); 178 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__NAMESPACEf, 179 iv_fwd_entry->name_space); 180 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__Pf, 1); 181 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__DST_VIFf, 182 iv_fwd_entry->virtual_interface_id); 183 } 184 185 soc_mem_lock(unit, L2_ENTRY_1m); 186 rv = soc_mem_delete(unit, L2_ENTRY_1m, MEM_BLOCK_ALL, &l2_entry); 187 soc_mem_unlock(unit, L2_ENTRY_1m); 188 189 return rv; 190 } 191 192 /* 193 * Purpose: 194 * Delete all NIV Forwarding table entries 195 * Parameters: 196 * unit - Device Number 197 */ 198 int 199 bcm_tr3_niv_forward_delete_all(int unit) 200 { 201 int rv = BCM_E_NONE; 202 int seconds, enabled; 203 l2_entry_1_entry_t match_mask; 204 l2_entry_1_entry_t match_data; 205 l2_bulk_entry_t l2_bulk; 206 int match_mask_index, match_data_index; 207 uint32 rval; 208 int field_len; 209 210 SOC_IF_ERROR_RETURN 211 (SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, &seconds, &enabled)); 212 if (enabled) { 213 SOC_IF_ERROR_RETURN(soc_tr3_l2_bulk_age_stop(unit)); 214 } 215 216 soc_mem_lock(unit, L2_ENTRY_1m); 217 218 /* Set match mask and data */ 219 sal_memset(&match_mask, 0, sizeof(match_mask)); 220 sal_memset(&match_data, 0, sizeof(match_data)); 221 222 soc_mem_field32_set(unit, L2_ENTRY_1m, &match_mask, VALIDf, 1); 223 soc_mem_field32_set(unit, L2_ENTRY_1m, &match_data, VALIDf, 1); 224 225 soc_mem_field32_set(unit, L2_ENTRY_1m, &match_mask, WIDEf, 1); 226 soc_mem_field32_set(unit, L2_ENTRY_1m, &match_data, WIDEf, 0); 227 228 field_len = soc_mem_field_length(unit, L2_ENTRY_1m, KEY_TYPEf); 229 soc_mem_field32_set(unit, L2_ENTRY_1m, &match_mask, KEY_TYPEf, 230 (1 << field_len) - 1); 231 soc_mem_field32_set(unit, L2_ENTRY_1m, &match_data, KEY_TYPEf, 232 SOC_MEM_KEY_L2_ENTRY_1_VIF_VIF); 233 234 sal_memset(&l2_bulk, 0, sizeof(l2_bulk)); 235 sal_memcpy(&l2_bulk, &match_mask, sizeof(match_mask)); 236 match_mask_index = 1; 237 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, match_mask_index, &l2_bulk); 238 if (BCM_SUCCESS(rv)) { 239 sal_memset(&l2_bulk, 0, sizeof(l2_bulk)); 240 sal_memcpy(&l2_bulk, &match_data, sizeof(match_data)); 241 match_data_index = 0; 242 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, match_data_index, &l2_bulk); 243 } 244 245 /* Set bulk control */ 246 rval = 0; 247 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 0); 248 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 1); 249 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, BURST_ENTRIESf, 250 _SOC_TR3_L2_BULK_BURST_MAX); 251 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ENTRY_WIDTHf, 0); 252 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 253 soc_mem_index_count(unit, L2_ENTRY_1m)); 254 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, EXTERNAL_L2_ENTRYf, 0); 255 if (BCM_SUCCESS(rv)) { 256 rv = WRITE_L2_BULK_CONTROLr(unit, rval); 257 } 258 if (BCM_SUCCESS(rv)) { 259 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 260 } 261 262 soc_mem_unlock(unit, L2_ENTRY_1m); 263 264 if(enabled) { 265 SOC_IF_ERROR_RETURN(soc_tr3_l2_bulk_age_start(unit, seconds)); 266 } 267 268 return rv; 269 } 270 271 /* 272 * Purpose: 273 * Get NIV Forwarding table entry 274 * Parameters: 275 * unit - (IN) Device Number 276 * iv_fwd_entry - (IN/OUT) NIV forwarding table info 277 */ 278 int 279 bcm_tr3_niv_forward_get(int unit, bcm_niv_forward_t *iv_fwd_entry) 280 { 281 int rv = BCM_E_NONE; 282 l2_entry_1_entry_t l2_entry, l2_entry_out; 283 int idx; 284 _bcm_gport_dest_t dest; 285 int l2mc_index; 286 287 if (iv_fwd_entry->name_space > 0xfff) { 288 return BCM_E_PARAM; 289 } 290 291 if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_MULTICAST)) { 292 if (iv_fwd_entry->virtual_interface_id > 0xfff) { 293 return BCM_E_PARAM; 294 } 295 296 sal_memset(&l2_entry, 0, sizeof(l2_entry)); 297 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, KEY_TYPEf, 298 SOC_MEM_KEY_L2_ENTRY_1_VIF_VIF); 299 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__NAMESPACEf, 300 iv_fwd_entry->name_space); 301 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__Pf, 0); 302 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__DST_VIFf, 303 iv_fwd_entry->virtual_interface_id); 304 305 } else { /* Multicast forward entry */ 306 if (iv_fwd_entry->virtual_interface_id > 0x3fff) { 307 return BCM_E_PARAM; 308 } 309 310 sal_memset(&l2_entry, 0, sizeof(l2_entry)); 311 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, KEY_TYPEf, 312 SOC_MEM_KEY_L2_ENTRY_1_VIF_VIF); 313 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__NAMESPACEf, 314 iv_fwd_entry->name_space); 315 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__Pf, 1); 316 soc_L2_ENTRY_1m_field32_set(unit, &l2_entry, VIF__DST_VIFf, 317 iv_fwd_entry->virtual_interface_id); 318 } 319 320 soc_mem_lock(unit, L2_ENTRY_1m); 321 rv = soc_mem_search(unit, L2_ENTRY_1m, MEM_BLOCK_ALL, &idx, &l2_entry, 322 &l2_entry_out, 0); 323 soc_mem_unlock(unit, L2_ENTRY_1m); 324 325 if (SOC_SUCCESS(rv)) { 326 if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_MULTICAST)) { 327 if (soc_L2_ENTRY_1m_field32_get(unit, &l2_entry_out, 328 VIF__DEST_TYPEf)) { 329 dest.tgid = soc_L2_ENTRY_1m_field32_get(unit, &l2_entry_out, 330 VIF__TGIDf); 331 dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 332 } else { 333 dest.modid = soc_L2_ENTRY_1m_field32_get(unit, &l2_entry_out, 334 VIF__MODULE_IDf); 335 dest.port = soc_L2_ENTRY_1m_field32_get(unit, &l2_entry_out, 336 VIF__PORT_NUMf); 337 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 338 } 339 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, 340 &(iv_fwd_entry->dest_port))); 341 } else { 342 l2mc_index = soc_L2_ENTRY_1m_field32_get(unit, &l2_entry_out, 343 VIF__L2MC_PTRf); 344 _BCM_MULTICAST_GROUP_SET(iv_fwd_entry->dest_multicast, 345 _BCM_MULTICAST_TYPE_L2, l2mc_index); 346 } 347 } 348 349 return rv; 350 } 351 352 /* 353 * Purpose: 354 * Traverse all valid NIV forward entries and call the 355 * supplied callback routine. 356 * Parameters: 357 * unit - Device Number 358 * cb - User callback function, called once per NIV forward entry. 359 * user_data - cookie 360 * Returns: 361 * BCM_E_XXX 362 */ 363 int 364 bcm_tr3_niv_forward_traverse(int unit, 365 bcm_niv_forward_traverse_cb cb, 366 void *user_data) 367 { 368 int rv = BCM_E_NONE; 369 int chunk_entries, chunk_bytes; 370 uint8 *l2_tbl_chunk = NULL; 371 int chunk_idx_min, chunk_idx_max, chunk_end; 372 int ent_idx, mem_idx_min, mem_idx_max; 373 l2_entry_1_entry_t *l2_entry; 374 bcm_niv_forward_t iv_fwd_entry; 375 int l2mc_index; 376 _bcm_gport_dest_t dest; 377 378 chunk_entries = soc_property_get(unit, spn_L2DELETE_CHUNKS, 379 L2_MEM_CHUNKS_DEFAULT); 380 chunk_bytes = 4 * SOC_MEM_WORDS(unit, L2_ENTRY_1m) * chunk_entries; 381 l2_tbl_chunk = soc_cm_salloc(unit, chunk_bytes, "niv forward traverse"); 382 if (NULL == l2_tbl_chunk) { 383 return BCM_E_MEMORY; 384 } 385 386 mem_idx_min = soc_mem_index_min(unit, L2_ENTRY_1m); 387 mem_idx_max = soc_mem_index_max(unit, L2_ENTRY_1m); 388 for (chunk_idx_min = mem_idx_min; chunk_idx_min <= mem_idx_max; 389 chunk_idx_min += chunk_entries) { 390 sal_memset(l2_tbl_chunk, 0, chunk_bytes); 391 392 chunk_idx_max = chunk_idx_min + chunk_entries - 1; 393 if (chunk_idx_max > mem_idx_max) { 394 chunk_idx_max = mem_idx_max; 395 } 396 397 rv = soc_mem_read_range(unit, L2_ENTRY_1m, MEM_BLOCK_ANY, 398 chunk_idx_min, chunk_idx_max, l2_tbl_chunk); 399 if (SOC_FAILURE(rv)) { 400 break; 401 } 402 403 chunk_end = (chunk_idx_max - chunk_idx_min); 404 for (ent_idx = 0; ent_idx <= chunk_end; ent_idx++) { 405 l2_entry = soc_mem_table_idx_to_pointer(unit, L2_ENTRY_1m, 406 l2_entry_1_entry_t *, l2_tbl_chunk, ent_idx); 407 408 if (soc_L2_ENTRY_1m_field32_get(unit, l2_entry, VALIDf) == 0) { 409 continue; 410 } 411 412 if (soc_L2_ENTRY_1m_field32_get(unit, l2_entry, KEY_TYPEf) != 413 SOC_MEM_KEY_L2_ENTRY_1_VIF_VIF) { 414 continue; 415 } 416 417 bcm_niv_forward_t_init(&iv_fwd_entry); 418 419 iv_fwd_entry.name_space = soc_L2_ENTRY_1m_field32_get(unit, 420 l2_entry, VIF__NAMESPACEf); 421 iv_fwd_entry.virtual_interface_id = soc_L2_ENTRY_1m_field32_get(unit, 422 l2_entry, VIF__DST_VIFf); 423 424 if (soc_L2_ENTRY_1m_field32_get(unit, l2_entry, VIF__Pf)) { 425 /* Multicast NIV forward entry */ 426 iv_fwd_entry.flags |= BCM_NIV_FORWARD_MULTICAST; 427 l2mc_index = soc_L2_ENTRY_1m_field32_get(unit, l2_entry, 428 VIF__L2MC_PTRf); 429 _BCM_MULTICAST_GROUP_SET(iv_fwd_entry.dest_multicast, 430 _BCM_MULTICAST_TYPE_L2, l2mc_index); 431 } else { 432 if (soc_L2_ENTRY_1m_field32_get(unit, l2_entry, 433 VIF__DEST_TYPEf)) { 434 dest.tgid = soc_L2_ENTRY_1m_field32_get(unit, l2_entry, 435 VIF__TGIDf); 436 dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 437 } else { 438 dest.modid = soc_L2_ENTRY_1m_field32_get(unit, l2_entry, 439 VIF__MODULE_IDf); 440 dest.port = soc_L2_ENTRY_1m_field32_get(unit, l2_entry, 441 VIF__PORT_NUMf); 442 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 443 } 444 rv = _bcm_esw_gport_construct(unit, &dest, 445 &(iv_fwd_entry.dest_port)); 446 if (BCM_FAILURE(rv)) { 447 break; 448 } 449 } 450 451 rv = cb(unit, &iv_fwd_entry, user_data); 452 if (BCM_FAILURE(rv)) { 453 break; 454 } 455 } 456 if (BCM_FAILURE(rv)) { 457 break; 458 } 459 } 460 soc_cm_sfree(unit, l2_tbl_chunk); 461 462 return rv; 463 } 464 465 #endif /* BCM_TRIUMPH3_SUPPORT && INCLUDE_L3 */