openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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