hgoe.c (28872B)
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 * Higig Over Ethernet 8 */ 9 10 #include <shared/bsl.h> 11 12 #include <soc/defs.h> 13 #include <sal/core/libc.h> 14 15 #include <soc/drv.h> 16 #include <soc/mem.h> 17 #include <soc/debug.h> 18 #include <soc/higig.h> 19 #include <soc/trident3.h> 20 21 #include <bcm/debug.h> 22 #include <bcm/error.h> 23 #include <bcm/cosq.h> 24 #include <bcm/pkt.h> 25 #include <bcm/port.h> 26 #include <bcm_int/esw_dispatch.h> 27 #include <bcm_int/esw/mbcm.h> 28 #include <bcm_int/control.h> 29 #include <bcm_int/common/tx.h> 30 #include <bcm_int/esw/cosq.h> 31 #include <bcm_int/esw/trident3.h> 32 33 #ifdef BCM_TRIDENT3_SUPPORT 34 #define _BCM_TD3_HGOE_INITIAL_SHIFT 7 35 36 typedef struct bcm_tx_hgoe_cookie_s { 37 bcm_pkt_cb_f chain_cb; 38 bcm_pkt_cb_f pkt_cb; 39 bcm_pkt_t *org_pkt; 40 void *org_cookie; 41 int encap; 42 uint32 org_pkt_flags; 43 bcm_pkt_blk_t *org_pkt_blk_addr; 44 bcm_pkt_blk_t *new_pkt_blk_addr; 45 } bcm_tx_hgoe_cookie_t; 46 47 typedef struct bcm_tx_hgoe_chain_cb_cookie_s { 48 bcm_pkt_cb_f user_given_chain_cb; 49 void *user_given_cookie; 50 uint32 pkt_cnt; 51 bcm_tx_hgoe_cookie_t *pkt_cookie_arr; 52 } bcm_tx_hgoe_chain_cb_cookie_t; 53 54 STATIC void 55 _bcm_td3_tx_hgoe_pkt_cb(int unit, bcm_pkt_t *pkt, void *cookie) { 56 bcm_tx_hgoe_cookie_t *my_cookie = (bcm_tx_hgoe_cookie_t *)cookie; 57 58 if (my_cookie) { 59 60 if (my_cookie->pkt_cb || !my_cookie->chain_cb) { 61 /* Revert the changes done to the original pkt blk data */ 62 pkt->pkt_data = my_cookie->org_pkt_blk_addr; 63 pkt->blk_count--; 64 pkt->flags |= 65 (my_cookie->org_pkt_flags & (BCM_TX_ETHER | BCM_TX_HG_READY)); 66 pkt->call_back = my_cookie->pkt_cb; 67 } 68 69 if (my_cookie->pkt_cb) { 70 /* Now call the org call back*/ 71 my_cookie->pkt_cb(unit, pkt, my_cookie->org_cookie); 72 } 73 74 /* If chain cb is not defined then release the pkt blk related 75 * memories, otherwise let chain_cb take care of releasing them. 76 */ 77 if (!my_cookie->chain_cb) { 78 if (my_cookie->new_pkt_blk_addr) { 79 if (my_cookie->new_pkt_blk_addr->data) { 80 sal_dma_free(my_cookie->new_pkt_blk_addr->data); 81 } 82 sal_free(my_cookie->new_pkt_blk_addr); 83 } 84 sal_free(my_cookie); 85 } 86 } 87 } 88 89 STATIC void * 90 _bcm_td3_tx_hgoe_cb_cookie_set(bcm_pkt_t *pkt, 91 bcm_pkt_cb_f chain_cb, 92 void *org_cookie, 93 uint32 org_flags, 94 bcm_pkt_blk_t *org_blk_addr) { 95 96 if (pkt->call_back || chain_cb) { 97 98 bcm_tx_hgoe_cookie_t *cookie = sal_alloc(sizeof(*cookie), "hgoecookie"); 99 100 if (cookie) { 101 sal_memset(cookie, 0, sizeof(bcm_tx_hgoe_cookie_t)); 102 cookie->pkt_cb = pkt->call_back; 103 cookie->chain_cb = chain_cb; 104 cookie->org_pkt = pkt; 105 cookie->org_cookie = org_cookie; 106 cookie->org_pkt_flags = org_flags; 107 cookie->org_pkt_blk_addr = org_blk_addr; 108 cookie->new_pkt_blk_addr = pkt->pkt_data; 109 pkt->call_back = pkt->call_back ? _bcm_td3_tx_hgoe_pkt_cb : NULL; 110 } 111 return (void *)cookie; 112 } else { 113 return org_cookie; 114 } 115 } 116 117 STATIC void 118 _bcm_td3_tx_hgoe_manual_cleanup(bcm_pkt_t *pkt, 119 uint32 org_flags, bcm_pkt_blk_t *org_blk_addr, bcm_pkt_cb_f org_pkt_cb) { 120 121 if (pkt->pkt_data) { 122 if (pkt->pkt_data[0].data) { 123 sal_dma_free(pkt->pkt_data[0].data); 124 } 125 sal_free(pkt->pkt_data); 126 } 127 pkt->pkt_data = org_blk_addr; 128 pkt->flags |= (org_flags & (BCM_TX_ETHER | BCM_TX_HG_READY)); 129 pkt->blk_count--; 130 pkt->call_back = org_pkt_cb; 131 return; 132 } 133 134 STATIC void 135 _bcm_td3_tx_hgoe_chain_cb(int unit, bcm_pkt_t *pkt, void *cookie) { 136 uint32 pkt_idx; 137 bcm_tx_hgoe_cookie_t *per_pkt_info = NULL; 138 bcm_tx_hgoe_chain_cb_cookie_t *my_cookie = 139 (bcm_tx_hgoe_chain_cb_cookie_t *) cookie; 140 141 if (my_cookie) { 142 per_pkt_info = my_cookie->pkt_cookie_arr; 143 if (per_pkt_info) { 144 /* Revert the pkt data blk changes for eack packet in the chain */ 145 for (pkt_idx = 0 ; pkt_idx < my_cookie->pkt_cnt; pkt_idx++) { 146 if (per_pkt_info[pkt_idx].chain_cb 147 && per_pkt_info[pkt_idx].encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 148 _bcm_td3_tx_hgoe_manual_cleanup( 149 per_pkt_info[pkt_idx].org_pkt, 150 per_pkt_info[pkt_idx].org_pkt_flags, 151 per_pkt_info[pkt_idx].org_pkt_blk_addr, 152 per_pkt_info[pkt_idx].pkt_cb); 153 } 154 } 155 156 /* Call any user given pkt cb for eack packet */ 157 for (pkt_idx = 0 ; pkt_idx < my_cookie->pkt_cnt ; pkt_idx++) { 158 if (per_pkt_info[pkt_idx].pkt_cb) { 159 (per_pkt_info[pkt_idx].pkt_cb)(unit, 160 per_pkt_info[pkt_idx].org_pkt, 161 per_pkt_info[pkt_idx].org_cookie); 162 } 163 } 164 165 /* Remove the per packet info/cookie */ 166 sal_free(per_pkt_info); 167 } 168 169 /* Call user given chain cb, if any */ 170 if (my_cookie->user_given_chain_cb) { 171 my_cookie->user_given_chain_cb(unit, pkt, 172 my_cookie->user_given_cookie); 173 } 174 175 /* Remove the master cookie */ 176 sal_free(my_cookie); 177 } 178 return; 179 } 180 181 STATIC int 182 _bcm_td3_hgoe_pkt_prepare(int unit, 183 bcm_pkt_t *pkt, 184 uint32 *org_flags, 185 bcm_pkt_blk_t **org_blk_start, 186 bcm_port_encap_config_t *encap_cfg) 187 { 188 int rv = BCM_E_NONE; 189 int blk_idx = 0; 190 uint8 vlan_adj = 0; 191 bcm_pkt_blk_t *tmp_pkt_blk_arr = NULL; 192 uint8 *dma_buffer = NULL; 193 uint16 htons_val = 0; 194 195 if (!pkt || !org_blk_start || !org_flags) { 196 return BCM_E_PARAM; 197 } 198 199 /* Re-Adjust the size for VLAN tag */ 200 if (!BCM_PKT_NO_VLAN_TAG(pkt)) { 201 vlan_adj = 4; 202 } 203 204 /* Blk 0 should have DMAC, SMAC and VLAN (if VLAN tag exists) */ 205 if (pkt->pkt_data[0].len < (12 + vlan_adj)) { 206 return (BCM_E_FAIL); 207 } 208 209 /* Create a HG2 hdr if not provided */ 210 if(!BCM_PKT_TX_HG_READY(pkt)) { 211 rv = bcm_common_tx_pkt_setup(unit, pkt); 212 213 /* If HG Hdr build fails then bail out as HGoE requires the HG Hdr. */ 214 if (BCM_FAILURE(rv)) { 215 return rv; 216 } 217 /* If HG Hdr was not built return back error. */ 218 if (SOC_HIGIG2_START != *BCM_PKT_HG_HDR(pkt)) { 219 return (BCM_E_FAIL); 220 } 221 } 222 223 /* Create a dma'able block of memory */ 224 dma_buffer = sal_dma_alloc(42, "HgoeHeader"); 225 if (!dma_buffer) { 226 return BCM_E_MEMORY; 227 } 228 229 /* Create a pkt data block */ 230 tmp_pkt_blk_arr = 231 sal_alloc(sizeof(bcm_pkt_blk_t) * (pkt->blk_count + 1), "HgoeBlocks"); 232 if (!tmp_pkt_blk_arr) { 233 sal_dma_free(dma_buffer); 234 return BCM_E_MEMORY; 235 } 236 237 /* Fill in the block details */ 238 tmp_pkt_blk_arr[0].data = dma_buffer; 239 tmp_pkt_blk_arr[0].len = 42; 240 for (blk_idx = 0 ; blk_idx < pkt->blk_count; blk_idx++ ) { 241 tmp_pkt_blk_arr[blk_idx + 1] = pkt->pkt_data[blk_idx]; 242 } 243 244 /* Create and copy 42 byte HGoE HDR (DA, SA, EtherType, HG, DA, SA) */ 245 sal_memcpy(dma_buffer, pkt->pkt_data[0].data, 12); 246 htons_val = bcm_htons(encap_cfg->higig_ethertype); 247 sal_memcpy(dma_buffer + 12, &htons_val, 2); 248 249 /* Copy 16 byte HG2 HDR */ 250 sal_memcpy(dma_buffer + 14, BCM_PKT_HG_HDR(pkt), 16); 251 if (!BCM_PKT_TX_HG_READY(pkt)) { 252 /* Rewrite the SOP as HGoE requires the SOP to be 0xFB */ 253 dma_buffer[14] = SOC_HIGIG_START; 254 } 255 sal_memcpy(dma_buffer + 30, pkt->pkt_data[0].data, 12); 256 /* Keep hold of the start of the org blk address */ 257 *org_blk_start = pkt->pkt_data; 258 259 /* Replace the block list with new blk list */ 260 pkt->pkt_data = tmp_pkt_blk_arr; 261 pkt->blk_count++; 262 263 /* Readjust the len of org payload as SMAC/DMAC are already in HGoE Hdr */ 264 tmp_pkt_blk_arr[1].len -= (12 + vlan_adj); 265 tmp_pkt_blk_arr[1].data += (12 + vlan_adj); 266 267 /* Store the org flags */ 268 *org_flags = pkt->flags; 269 270 /* Mark the packet as SoBMH */ 271 pkt->flags &= ~BCM_TX_ETHER; 272 pkt->flags |= BCM_TX_HG_READY; /* HG header is ready */ 273 274 return rv; 275 } 276 277 int 278 bcm_td3_port_hgoe_mode_set(int unit, bcm_port_t port) { 279 280 soc_mem_t mem = INVALIDm; 281 ing_device_port_entry_t ing_entry; 282 egr_ing_port_entry_t egr_ing_entry; 283 egr_port_entry_t egr_entry; 284 if (!(SOC_PORT_VALID(unit, port))) { 285 return BCM_E_PORT; 286 } 287 if (IS_CPU_PORT(unit, port) || IS_LB_PORT(unit, port)) { 288 return BCM_E_PORT; 289 } 290 291 /* config ingress port */ 292 mem = ING_DEVICE_PORTm; 293 SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem, 294 MEM_BLOCK_ANY, port, &ing_entry)); 295 soc_mem_field32_set(unit, mem, &ing_entry, PARSE_CONTEXT_ID_0f, 2); 296 soc_mem_field32_set(unit, mem, &ing_entry, HDR_TYPE_0f, 297 BCM_TD3_HGOE_HDR_TYPE); 298 soc_mem_field32_set(unit, mem, &ing_entry, INITIAL_SHIFT_AMOUNT_0f, 299 _BCM_TD3_HGOE_INITIAL_SHIFT); 300 SOC_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 301 port, &ing_entry)); 302 303 mem = EGR_ING_PORTm; 304 SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem, 305 MEM_BLOCK_ANY, port, &egr_ing_entry)); 306 soc_mem_field32_set(unit, mem, &egr_ing_entry, PORT_TYPEf, 1); 307 SOC_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 308 port, &egr_ing_entry)); 309 310 mem = EGR_PORTm; 311 SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem, 312 MEM_BLOCK_ANY, port, &egr_entry)); 313 soc_mem_field32_set(unit, mem, &egr_entry, EDIT_CTRL_IDf, 4); 314 soc_mem_field32_set(unit, mem, &egr_entry, PORT_TYPEf, 1); 315 soc_mem_field32_set(unit, mem, &egr_entry, EGR_PORT_CTRL_IDf, 8); 316 SOC_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 317 port, &egr_entry)); 318 return BCM_E_NONE; 319 } 320 321 int bcm_td3_port_hgoe_mode_get(int unit, bcm_port_t port, uint8 *is_hgoe) { 322 323 ing_device_port_entry_t ing_entry; 324 soc_mem_t mem = ING_DEVICE_PORTm; 325 uint32 hdr_type, initial_shift; 326 *is_hgoe = 0; 327 328 if (IS_CPU_PORT(unit, port)) { 329 return BCM_E_NONE; 330 } 331 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, 332 MEM_BLOCK_ANY, port, &ing_entry)); 333 hdr_type = soc_mem_field32_get(unit, mem, &ing_entry, HDR_TYPE_0f); 334 initial_shift = soc_mem_field32_get(unit, mem, 335 &ing_entry, INITIAL_SHIFT_AMOUNT_0f); 336 if (hdr_type == BCM_TD3_HGOE_HDR_TYPE && 337 initial_shift == _BCM_TD3_HGOE_INITIAL_SHIFT) { 338 *is_hgoe = 1; 339 } 340 return BCM_E_NONE; 341 } 342 343 int bcm_td3_tx_hgoe_pkt(int unit, bcm_pkt_t *pkt, 344 bcm_port_encap_config_t *encap_cfg, void *cookie, 345 bcm_tx_f tx_f) 346 { 347 void *my_cookie = NULL; 348 int rv = BCM_E_NONE; 349 uint32 org_pkt_flags = 0; 350 bcm_pkt_cb_f pkt_org_cb = NULL; 351 bcm_pkt_blk_t *org_pkt_blk_addr = NULL; 352 rv = _bcm_td3_hgoe_pkt_prepare(unit, pkt, 353 &org_pkt_flags, &org_pkt_blk_addr, encap_cfg); 354 if (!BCM_FAILURE(rv)) { 355 pkt_org_cb = pkt->call_back; 356 357 /* cookie setup*/ 358 my_cookie = 359 _bcm_td3_tx_hgoe_cb_cookie_set(pkt, NULL, 360 cookie, org_pkt_flags, org_pkt_blk_addr); 361 362 /* Send the pkt if the cookie creation succeeded */ 363 if (my_cookie || !pkt_org_cb) { 364 rv = tx_f(unit, pkt, my_cookie); 365 } else { /* cookie alloc err */ 366 rv = BCM_E_MEMORY; 367 } 368 369 /* Cookie cleanup in an event of failure */ 370 if (BCM_FAILURE(rv) 371 && my_cookie && cookie != my_cookie) { 372 sal_free(my_cookie); 373 } 374 375 /* Pkt cleanup if no callback or failure to send */ 376 if (BCM_FAILURE(rv) || !pkt_org_cb) { 377 _bcm_td3_tx_hgoe_manual_cleanup(pkt, 378 org_pkt_flags, 379 org_pkt_blk_addr, 380 pkt_org_cb); 381 } 382 } 383 return rv; 384 } 385 386 int 387 bcm_td3_tx_hgoe_array(int unit, bcm_pkt_t **pkt_arr, int count, 388 bcm_pkt_cb_f all_done_cb, void *cookie) 389 { 390 int rv = BCM_E_NONE; 391 int port_cnt = 0; 392 bcm_pbmp_t pbmp; 393 uint32 pkt_idx = 0; 394 uint32 prt_idx = 0; 395 uint8 is_pkt_cb = 0; 396 uint8 use_hgoe = 0; 397 bcm_port_t tx_port = 0; 398 uint32 org_pkt_flags = 0; 399 uint8 use_dflt_method = 1; 400 bcm_pkt_t *cur_pkt = NULL; 401 bcm_pkt_blk_t *org_pkt_blk_addr = NULL; 402 bcm_port_encap_config_t encapcfg = {0}; 403 bcm_tx_hgoe_cookie_t *pkt_info_arr = NULL; 404 bcm_tx_hgoe_chain_cb_cookie_t *master_cookie = NULL; 405 typedef struct { 406 bcm_port_t port; 407 uint16 ether_type; 408 uint16 encap; 409 } hgoe_port_info_t; 410 hgoe_port_info_t *port_info_arr = NULL; 411 412 /* Input paramter check */ 413 if (!pkt_arr || count < 1 || !*pkt_arr) { 414 return BCM_E_PARAM; 415 } 416 417 if (!BCM_UNIT_VALID(unit) || !SOC_UNIT_VALID(unit)) { 418 return BCM_E_UNIT; 419 } 420 421 if (!BCM_IS_LOCAL(unit)) { /* Tunnel the packet to the remote CPU */ 422 LOG_ERROR(BSL_LS_BCM_TX, 423 (BSL_META_U(unit, 424 "bcm_tx_array ERROR: Cannot tunnel\n"))); 425 return BCM_E_PARAM; 426 } 427 428 BCM_PBMP_CLEAR(pbmp); 429 /* Do fast check if the HGoE logic can be invoked or not */ 430 for ( pkt_idx = 0 ; pkt_idx < count; pkt_idx++) { 431 432 /* Get hold of the current packet */ 433 cur_pkt = pkt_arr[pkt_idx]; 434 435 /* If even a single pkt is smart switched then go default route */ 436 if (BCM_PKT_TX_ETHER(cur_pkt)) { 437 break; 438 } 439 /* If pkt has to be sent on multiple ports then go default route */ 440 BCM_PBMP_COUNT(cur_pkt->tx_pbmp, port_cnt); 441 if (1 != port_cnt) { 442 break; 443 } 444 445 BCM_PBMP_OR(pbmp, cur_pkt->tx_pbmp); 446 447 /* Mark if individual pkt call back exists. */ 448 if (!is_pkt_cb && cur_pkt->call_back) { 449 is_pkt_cb = 1; 450 } 451 } 452 453 /* If previous loop did not complete successfully or there is a case 454 * where individual pkt callback esists but chain done callback not then 455 * the HGoE logic cannot be invoked as it wont handle the said scenario. 456 * Hence send the pkt using default way and hope TX happens successfully 457 */ 458 if ((pkt_idx >= count) && !(is_pkt_cb && !all_done_cb) ) { 459 use_dflt_method = 0; 460 } 461 462 if (use_dflt_method) { 463 return bcm_common_tx_array(unit, pkt_arr, count, all_done_cb, cookie); 464 } 465 466 /*** Check for port encapsulation type ***/ 467 /* Create a buffer to hold HGoE tag to be used later */ 468 BCM_PBMP_COUNT(pbmp, port_cnt); 469 port_info_arr = sal_alloc(sizeof(hgoe_port_info_t) * port_cnt, "HGoEPrtInfo"); 470 if (!port_info_arr) { 471 return (BCM_E_MEMORY); 472 } 473 474 /* If all tx ports are HGoE then go through the trouble of 475 * forming a sobmh pkt otherwise just use the default way 476 */ 477 prt_idx = 0; 478 rv = BCM_E_NONE; 479 BCM_PBMP_ITER(pbmp, tx_port) 480 { 481 if (prt_idx >= port_cnt) { 482 rv = BCM_E_FAIL; 483 break; 484 } 485 486 rv = bcm_esw_port_encap_config_get(unit, tx_port, &encapcfg); 487 488 if (BCM_FAILURE(rv)) { 489 rv = BCM_E_FAIL; 490 break; 491 } else { 492 if (encapcfg.encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 493 use_hgoe = 1; 494 } 495 port_info_arr[prt_idx].port = tx_port; 496 port_info_arr[prt_idx].ether_type = encapcfg.higig_ethertype; 497 port_info_arr[prt_idx++].encap = encapcfg.encap; 498 } 499 } 500 501 if (BCM_FAILURE(rv) || !use_hgoe) { 502 /* Error in getting the port encap. info or port is non HGoE */ 503 sal_free(port_info_arr); 504 return bcm_common_tx_array(unit, pkt_arr, count, all_done_cb, cookie); 505 } 506 507 /*** Past this point the pkt tx has to go through HGoE logic ***/ 508 509 /* Allocate memory to hold per pkt cookie */ 510 pkt_info_arr = 511 sal_alloc(sizeof(bcm_tx_hgoe_cookie_t) * count, "PerPktCkArr"); 512 if (!pkt_info_arr) { 513 sal_free(port_info_arr); 514 return BCM_E_MEMORY; 515 } 516 517 /* Allocate memory for master cookie */ 518 master_cookie = 519 sal_alloc(sizeof(bcm_tx_hgoe_chain_cb_cookie_t), "ChainCBCk"); 520 if (!master_cookie) { 521 sal_free(port_info_arr); 522 sal_free(pkt_info_arr); 523 return BCM_E_MEMORY; 524 } 525 /* Fill in master cookie */ 526 master_cookie->pkt_cnt = count; 527 master_cookie->user_given_chain_cb = all_done_cb; 528 master_cookie->user_given_cookie = cookie; 529 master_cookie->pkt_cookie_arr = pkt_info_arr; 530 531 /* Initialize the per pkt cookie arr */ 532 sal_memset(pkt_info_arr, 0, sizeof(bcm_tx_hgoe_cookie_t) * count); 533 534 for (pkt_idx = 0, rv = BCM_E_NONE; pkt_idx < count; pkt_idx++) { 535 uint8 is_hgoe = 0; 536 org_pkt_flags = 0; 537 org_pkt_blk_addr = NULL; 538 539 /* Get hold of the current packet */ 540 cur_pkt = pkt_arr[pkt_idx]; 541 542 /* Find out the appr. HGoE tag from the cached copy. It is sure that the 543 * information will be retrieved succesfully every time as the logic 544 * dictates no failure, hence no need to worry if hgoe tag is not found 545 */ 546 sal_memset(&encapcfg, 0, sizeof(encapcfg)); 547 BCM_PBMP_ITER(cur_pkt->tx_pbmp, tx_port) 548 { 549 for (prt_idx = 0; prt_idx < port_cnt; prt_idx++) { 550 if (port_info_arr[prt_idx].port == tx_port) { 551 if (port_info_arr[prt_idx].encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 552 is_hgoe = 1; 553 } 554 encapcfg.higig_ethertype =port_info_arr[prt_idx].ether_type; 555 encapcfg.encap = port_info_arr[prt_idx].encap; 556 break; 557 } 558 } 559 break; /* Only one TX port limitation */ 560 } 561 if (!is_hgoe) { 562 pkt_info_arr[pkt_idx].chain_cb = _bcm_td3_tx_hgoe_chain_cb; 563 pkt_info_arr[pkt_idx].org_cookie = cookie; 564 pkt_info_arr[pkt_idx].pkt_cb = cur_pkt->call_back; 565 pkt_info_arr[pkt_idx].org_pkt = cur_pkt; 566 continue; 567 } 568 /* Prepare the packet */ 569 rv = _bcm_td3_hgoe_pkt_prepare( 570 unit, cur_pkt, &org_pkt_flags, &org_pkt_blk_addr, &encapcfg); 571 572 if (BCM_FAILURE(rv)) { 573 break; 574 } 575 576 /* Fill in the per packet callback info*/ 577 pkt_info_arr[pkt_idx].encap = BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET; 578 pkt_info_arr[pkt_idx].chain_cb = _bcm_td3_tx_hgoe_chain_cb; 579 pkt_info_arr[pkt_idx].org_cookie = cookie; 580 pkt_info_arr[pkt_idx].org_pkt = cur_pkt; 581 pkt_info_arr[pkt_idx].pkt_cb = cur_pkt->call_back; 582 pkt_info_arr[pkt_idx].org_pkt_flags = org_pkt_flags; 583 pkt_info_arr[pkt_idx].org_pkt_blk_addr = org_pkt_blk_addr; 584 pkt_info_arr[pkt_idx].new_pkt_blk_addr = cur_pkt->pkt_data; 585 586 /* Remove the call back from the pkt */ 587 cur_pkt->call_back = NULL; 588 } 589 590 if (!BCM_FAILURE(rv)) { 591 /* All packets processed, now send the call down */ 592 if (all_done_cb) { 593 rv = bcm_common_tx_array(unit, pkt_arr, 594 count, _bcm_td3_tx_hgoe_chain_cb, master_cookie); 595 } else { 596 rv = bcm_common_tx_array(unit, pkt_arr, count, NULL, cookie); 597 } 598 } 599 600 if (BCM_FAILURE(rv) || !all_done_cb) { 601 /* Something went wrong or no callback requested, cleanup */ 602 for (pkt_idx=0 ; pkt_idx<count ; pkt_idx++) { 603 if (pkt_info_arr[pkt_idx].chain_cb) { 604 if (pkt_info_arr[pkt_idx].encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 605 _bcm_td3_tx_hgoe_manual_cleanup( 606 pkt_info_arr[pkt_idx].org_pkt, 607 pkt_info_arr[pkt_idx].org_pkt_flags, 608 pkt_info_arr[pkt_idx].org_pkt_blk_addr, 609 pkt_info_arr[pkt_idx].pkt_cb); 610 } 611 } 612 } 613 sal_free(pkt_info_arr); 614 sal_free(master_cookie); 615 } 616 sal_free(port_info_arr); 617 618 return rv; 619 } 620 621 int 622 bcm_td3_tx_hgoe_list(int unit, bcm_pkt_t *pkt, 623 bcm_pkt_cb_f all_done_cb, void *cookie) { 624 625 int rv = BCM_E_NONE; 626 int port_cnt = 0; 627 bcm_pbmp_t pbmp; 628 uint32 pkt_cnt = 0; 629 uint32 pkt_idx = 0; 630 uint32 prt_idx = 0; 631 uint8 is_pkt_cb = 0; 632 uint8 use_hgoe = 0; 633 bcm_port_t tx_port = 0; 634 uint32 org_pkt_flags = 0; 635 uint8 use_dflt_method = 1; 636 bcm_pkt_t *cur_pkt = NULL; 637 bcm_pkt_blk_t *org_pkt_blk_addr = NULL; 638 bcm_port_encap_config_t encapcfg = {0}; 639 bcm_tx_hgoe_cookie_t *pkt_info_arr = NULL; 640 bcm_tx_hgoe_chain_cb_cookie_t *master_cookie = NULL; 641 typedef struct { 642 bcm_port_t port; 643 uint16 ether_type; 644 uint16 encap; 645 } hgoe_port_info_t; 646 hgoe_port_info_t *port_info_arr = NULL; 647 648 /* Input parameter check */ 649 if (!pkt) { 650 return BCM_E_PARAM; 651 } 652 653 if (!BCM_UNIT_VALID(unit)) { 654 return BCM_E_UNIT; 655 } 656 657 if (!SOC_UNIT_VALID(unit)) { 658 return BCM_E_UNIT; 659 } 660 661 if (!BCM_IS_LOCAL(unit)) { /* Tunnel the packet to the remote CPU */ 662 LOG_ERROR(BSL_LS_BCM_TX, 663 (BSL_META_U(unit, 664 "bcm_tx_list ERROR: Cannot tunnel\n"))); 665 return BCM_E_PARAM; 666 } 667 668 669 BCM_PBMP_CLEAR(pbmp); 670 /* Do fast check if the HGoE logic can be invoked or not */ 671 for (cur_pkt = pkt; cur_pkt; cur_pkt = cur_pkt->next, pkt_cnt++) { 672 673 /* If even a single pkt is smart switched then go default route */ 674 if (BCM_PKT_TX_ETHER(cur_pkt)) { 675 break; 676 } 677 678 /* If pkt has to be sent on multiple ports then go default route */ 679 BCM_PBMP_COUNT(cur_pkt->tx_pbmp, port_cnt); 680 if (1 != port_cnt) { 681 break; 682 } 683 684 BCM_PBMP_OR(pbmp, cur_pkt->tx_pbmp); 685 686 /* Mark if individual pkt call back exists. */ 687 if (!is_pkt_cb && cur_pkt->call_back) { 688 is_pkt_cb = 1; 689 } 690 } 691 692 /* If previous loop did not complete successfully or there is a case 693 * where individual pkt callback esists but chain done callback not then 694 * the HGoE logic cannot be invoked as it wont handle the said scenario. 695 * Hence send the pkt using default way and hope TX happens successfully 696 */ 697 if (!cur_pkt && !(is_pkt_cb && !all_done_cb) ) { 698 use_dflt_method = 0; 699 } 700 701 if (use_dflt_method) { 702 rv = bcm_common_tx_list(unit, pkt, all_done_cb, cookie); 703 return rv; 704 } 705 /* Check for port encapsulation type */ 706 707 /* Create a buffer to hold HGoE tag to be used later */ 708 BCM_PBMP_COUNT(pbmp, port_cnt); 709 port_info_arr=sal_alloc(sizeof(hgoe_port_info_t) * port_cnt, "HGoEPrtInfo"); 710 if (!port_info_arr) { 711 return (BCM_E_MEMORY); 712 } 713 714 /* If all tx ports are HGoE then go through the trouble of 715 * forming a sobmh pkt otherwise just use the default way 716 */ 717 prt_idx = 0; 718 rv = BCM_E_NONE; 719 BCM_PBMP_ITER(pbmp, tx_port) 720 { 721 if (prt_idx >= port_cnt) { 722 rv = BCM_E_FAIL; 723 break; 724 } 725 726 rv = bcm_esw_port_encap_config_get(unit, tx_port, &encapcfg); 727 728 if (BCM_FAILURE(rv)) { 729 rv = BCM_E_FAIL; 730 break; 731 } else { 732 if (encapcfg.encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 733 use_hgoe = 1; 734 } 735 port_info_arr[prt_idx].port = tx_port; 736 port_info_arr[prt_idx].ether_type = encapcfg.higig_ethertype; 737 port_info_arr[prt_idx++].encap = encapcfg.encap; 738 } 739 } 740 741 if (BCM_FAILURE(rv) || !use_hgoe) { 742 /* Error in getting the port encap. info or port is non HGoE */ 743 sal_free(port_info_arr); 744 return(bcm_common_tx_list(unit, pkt, all_done_cb, cookie)); 745 } 746 747 /* Past this point the pkt tx has to go through HGoE logic */ 748 749 /* Allocate memory to hold per pkt cookie */ 750 pkt_info_arr = 751 sal_alloc(sizeof(bcm_tx_hgoe_cookie_t) * pkt_cnt, "PerPktCkArr"); 752 if (!pkt_info_arr) { 753 sal_free(port_info_arr); 754 return (BCM_E_MEMORY); 755 } 756 757 /* Allocate memory for master cookie */ 758 master_cookie = 759 sal_alloc(sizeof(bcm_tx_hgoe_chain_cb_cookie_t), "ChainCBCk"); 760 if (!master_cookie) { 761 sal_free(port_info_arr); 762 sal_free(pkt_info_arr); 763 return (BCM_E_MEMORY); 764 } 765 766 /* Fill in master cookie */ 767 master_cookie->pkt_cnt = pkt_cnt; 768 master_cookie->user_given_chain_cb = all_done_cb; 769 master_cookie->user_given_cookie = cookie; 770 master_cookie->pkt_cookie_arr = pkt_info_arr; 771 772 /* Initialize the per pkt cookie arr */ 773 sal_memset(pkt_info_arr, 0, sizeof(bcm_tx_hgoe_cookie_t) * pkt_cnt); 774 775 for (cur_pkt = pkt, rv = BCM_E_NONE, pkt_idx=0; 776 cur_pkt; cur_pkt=cur_pkt->next, pkt_idx++) { 777 uint8 is_hgoe = 0; 778 org_pkt_flags = 0; 779 org_pkt_blk_addr = NULL; 780 781 /* Find out the appr. HGoE tag from the cached copy. It is sure that the 782 * information will be retrieved succesfully every time as the logic 783 * dictates no failure, hence no need to worry if hgoe tag is not found 784 */ 785 sal_memset(&encapcfg, 0, sizeof(encapcfg)); 786 BCM_PBMP_ITER(cur_pkt->tx_pbmp, tx_port) 787 { 788 for (prt_idx=0 ; prt_idx<port_cnt ;prt_idx++) { 789 if (port_info_arr[prt_idx].port == tx_port) { 790 if (port_info_arr[prt_idx].encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 791 is_hgoe = 1; 792 } 793 encapcfg.higig_ethertype = port_info_arr[prt_idx].ether_type; 794 encapcfg.encap = port_info_arr[prt_idx].encap; 795 break; 796 } 797 } 798 break; /* Only one TX port limitation */ 799 } 800 if (!is_hgoe) { 801 pkt_info_arr[pkt_idx].chain_cb = _bcm_td3_tx_hgoe_chain_cb; 802 pkt_info_arr[pkt_idx].org_cookie = cookie; 803 pkt_info_arr[pkt_idx].org_pkt = cur_pkt; 804 pkt_info_arr[pkt_idx].pkt_cb = cur_pkt->call_back; 805 continue; 806 } 807 808 /* Prepare the packet */ 809 rv = _bcm_td3_hgoe_pkt_prepare( 810 unit, cur_pkt, &org_pkt_flags, &org_pkt_blk_addr, &encapcfg); 811 812 if (BCM_FAILURE(rv)) { 813 break; 814 } 815 816 /* Fill in the per packet callback info*/ 817 pkt_info_arr[pkt_idx].encap = BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET; 818 pkt_info_arr[pkt_idx].chain_cb = _bcm_td3_tx_hgoe_chain_cb; 819 pkt_info_arr[pkt_idx].org_cookie = cookie; 820 pkt_info_arr[pkt_idx].org_pkt = cur_pkt; 821 pkt_info_arr[pkt_idx].pkt_cb = cur_pkt->call_back; 822 pkt_info_arr[pkt_idx].org_pkt_flags = org_pkt_flags; 823 pkt_info_arr[pkt_idx].org_pkt_blk_addr = org_pkt_blk_addr; 824 pkt_info_arr[pkt_idx].new_pkt_blk_addr = cur_pkt->pkt_data; 825 826 /* Remove the call back from the pkt */ 827 cur_pkt->call_back = NULL; 828 } 829 830 if (!BCM_FAILURE(rv)) { 831 /* All packets processed, now send the call down */ 832 if (all_done_cb) { 833 rv = bcm_common_tx_list(unit, 834 pkt, _bcm_td3_tx_hgoe_chain_cb, master_cookie); 835 } else { 836 rv = bcm_common_tx_list(unit, pkt, NULL, cookie); 837 } 838 } 839 840 if (BCM_FAILURE(rv) || !all_done_cb) { 841 /* Something went wrong or no callback requested, cleanup */ 842 for (pkt_idx=0 ; pkt_idx<pkt_cnt ; pkt_idx++) { 843 if (pkt_info_arr[pkt_idx].chain_cb 844 && pkt_info_arr[pkt_idx].encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 845 _bcm_td3_tx_hgoe_manual_cleanup( 846 pkt_info_arr[pkt_idx].org_pkt, 847 pkt_info_arr[pkt_idx].org_pkt_flags, 848 pkt_info_arr[pkt_idx].org_pkt_blk_addr, 849 pkt_info_arr[pkt_idx].pkt_cb); 850 } 851 } 852 sal_free(pkt_info_arr); 853 sal_free(master_cookie); 854 } 855 sal_free(port_info_arr); 856 857 return rv; 858 } 859 #endif 860