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

cpu2cpu.c (30231B)


      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:        cpu2cpu.c
      8  * Purpose:     Provides CPU to CPU packet transmit
      9  * Requires:    CPU keys for destination; cputrans for pkt alloc
     10  * Notes:
     11  *     Applications must directly register with some RX to receive packets.
     12  *     They may then use c2c_pkt_recognize to determine if a packet
     13  *     is a cpu-to-cpu packet.
     14  *
     15  *     Since RX is not a service of CPU-to-CPU, loopback is not
     16  *     supported at this level.
     17  *
     18  *     CPU indexing is managed by a local cpudb.  That module must be properly
     19  *     initialized before using cpu2cpu transport including calls to
     20  *     add CPU keys and other info to the local CPU.
     21  *
     22  *     This module uses the tx packet allocation routines implemented in
     23  *     cputrans.
     24  */
     25 
     26 #include <shared/bsl.h>
     27 
     28 #include <assert.h>
     29 
     30 #include <shared/idents.h>
     31 
     32 #include <sal/core/sync.h>
     33 #include <sal/core/libc.h>
     34 #include <shared/alloc.h>
     35 
     36 #include <bcm/types.h>
     37 #include <bcm/pkt.h>
     38 #include <bcm/tx.h>
     39 #include <bcm/rx.h>
     40 #include <bcm/error.h>
     41 
     42 #include <appl/cpudb/cpudb.h>
     43 
     44 #include <appl/cputrans/cpu2cpu.h>
     45 #include <appl/cputrans/cputrans.h>
     46 
     47 #include "t_util.h"
     48 
     49 /****************************************************************
     50  *
     51  * Configurable parameters
     52  */
     53 static bcm_trans_ptr_t *c2c_trans_ptr   = C2C_TRANS_PTR_DEFAULT;
     54 static uint16           c2c_snap_type   = C2C_SNAP_TYPE_DEFAULT;
     55 static uint16           c2c_trans_type  = C2C_TRANS_TYPE_DEFAULT;
     56 static bcm_mac_t        c2c_snap_mac    = C2C_SNAP_MAC_DEFAULT;
     57 static uint32           c2c_flags;
     58 static int              c2c_src_modid = C2C_SRC_MODID_DEFAULT;
     59 
     60 #define C2C_LOCAL_MAC (c2c_db_ref->local_entry->base.mac)
     61 
     62 static sal_mutex_t c2c_mutex;
     63 static int init_done;
     64 
     65 static cpudb_ref_t c2c_db_ref = CPUDB_REF_NULL;
     66 
     67 #define C2C_INIT if (!init_done) BCM_IF_ERROR_RETURN(c2c_init())
     68 
     69 #define C2C_LOCK sal_mutex_take(c2c_mutex, sal_sem_FOREVER)
     70 #define C2C_UNLOCK sal_mutex_give(c2c_mutex)
     71 
     72 #define PKT_TRANS_PTR(pkt) ((bcm_trans_ptr_t *)((pkt)->trans_ptr))
     73 
     74 typedef struct {
     75     c2c_cb_f callback;
     76 } c2c_cb_cookie_t;
     77 
     78 STATIC void *
     79 _c2c_callback_cookie_set(c2c_cb_f callback)
     80 {
     81     c2c_cb_cookie_t *cookie = sal_alloc(sizeof(*cookie), "c2c_cookie");
     82 
     83     if (cookie) {
     84         cookie->callback = callback;
     85     }
     86 
     87     return (void *)cookie;
     88 }
     89 
     90 STATIC void
     91 _c2c_callback_cookie_get(void *cookie, c2c_cb_f *cb)
     92 {
     93     if (cookie) {
     94         c2c_cb_cookie_t *c2c_cookie = (c2c_cb_cookie_t *)cookie;
     95         *cb = c2c_cookie->callback;
     96         sal_free(c2c_cookie);
     97     } else {
     98         *cb = NULL;
     99     }
    100 }
    101 
    102 int
    103 c2c_src_mod_set(int src_mod)
    104 {
    105     c2c_src_modid = src_mod;
    106 
    107     return BCM_E_NONE;
    108 }
    109 
    110 int
    111 c2c_src_mod_get(int *src_mod)
    112 {
    113     *src_mod = c2c_src_modid;
    114 
    115     return BCM_E_NONE;
    116 }
    117 
    118 static INLINE int
    119 c2c_src_mod(void)
    120 {
    121     return (c2c_src_modid < 0) ?
    122         c2c_db_ref->local_entry->dest_mod : c2c_src_modid;
    123 }
    124 
    125 STATIC int
    126 c2c_init(void)
    127 {
    128     if (c2c_mutex == NULL) {
    129         c2c_mutex = sal_mutex_create("C2C_mutex");
    130         if (c2c_mutex == NULL) {
    131             return BCM_E_MEMORY;
    132         }
    133     }
    134 
    135     if (c2c_db_ref == CPUDB_REF_NULL) {
    136         c2c_db_ref = cpudb_create();
    137         if (c2c_db_ref == CPUDB_REF_NULL) {
    138             return BCM_E_MEMORY;
    139         }
    140     }
    141 
    142     init_done = TRUE;
    143 
    144     return BCM_E_NONE;
    145 }
    146 
    147 /* Assumes lock held */
    148 STATIC int
    149 _c2c_cpu_add(const cpudb_entry_t *db_ent)
    150 {
    151     cpudb_entry_t *ent;
    152 
    153     LOG_INFO(BSL_LS_TKS_C2C,
    154              (BSL_META("C2C: add key " CPUDB_KEY_FMT ", flags 0x%x (%d,%d,%d,%d)\n"),
    155               CPUDB_KEY_DISP(db_ent->base.key), db_ent->flags,
    156               db_ent->tx_unit,db_ent->tx_port,
    157               db_ent->dest_mod,db_ent->dest_port));
    158 
    159     CPUDB_KEY_SEARCH(c2c_db_ref, db_ent->base.key, ent);
    160     if (ent == NULL) {
    161         ent = cpudb_entry_create(c2c_db_ref, db_ent->base.key, FALSE);
    162         if (ent == NULL) {
    163             return BCM_E_MEMORY;
    164         }
    165     }
    166 
    167     sal_memcpy(&ent->base, &db_ent->base, sizeof(cpudb_base_t));
    168     ent->tx_unit = db_ent->tx_unit;
    169     ent->tx_port = db_ent->tx_port;
    170     ent->dest_mod = db_ent->dest_mod;
    171     ent->dest_port = db_ent->dest_port;
    172     ent->flags = db_ent->flags;
    173     ent->trans_ptr = db_ent->trans_ptr;
    174 
    175     if (ent->flags & CPUDB_F_IS_LOCAL) {
    176         c2c_db_ref->local_entry = ent;
    177     }
    178 
    179     return BCM_E_NONE;
    180 }
    181 
    182 int
    183 c2c_cpu_add(const cpudb_entry_t *db_ent)
    184 {
    185     int rv;
    186 
    187     C2C_INIT;
    188     LOG_INFO(BSL_LS_TKS_C2C,
    189              (BSL_META("C2C added " CPUDB_KEY_FMT_EOLN),
    190               CPUDB_KEY_DISP(db_ent->base.key)));
    191 
    192     C2C_LOCK;
    193     rv = _c2c_cpu_add(db_ent);
    194     C2C_UNLOCK;
    195 
    196     return rv;
    197 }
    198 
    199 int
    200 c2c_cpu_remove(const cpudb_key_t key)
    201 {
    202     int rv;
    203 
    204     C2C_INIT;
    205     LOG_INFO(BSL_LS_TKS_C2C,
    206              (BSL_META("C2C removed " CPUDB_KEY_FMT_EOLN),
    207               CPUDB_KEY_DISP(key)));
    208 
    209     C2C_LOCK;
    210     rv = cpudb_entry_remove(c2c_db_ref, key);
    211     C2C_UNLOCK;
    212 
    213     return rv;
    214 }
    215 
    216 int
    217 c2c_cpu_clear(void)
    218 {
    219     int rv;
    220 
    221     C2C_INIT;
    222     C2C_LOCK;
    223     rv = cpudb_clear(c2c_db_ref, FALSE);
    224     C2C_UNLOCK;
    225 
    226     return rv;
    227 }
    228 
    229 /* Assumes local entry does not change */
    230 int
    231 c2c_cpu_update(cpudb_ref_t db_ref)
    232 {
    233     cpudb_entry_t *entry, *new_ref_entry;
    234     int rv = BCM_E_NONE;
    235     static cpudb_key_t del_keys[CPUDB_CPU_MAX];
    236     int count, i;
    237 
    238     LOG_INFO(BSL_LS_TKS_C2C,
    239              (BSL_META("C2C CPU DB %s\n"),
    240               (db_ref==NULL) ? "clear" : "update"));
    241     C2C_INIT;
    242 
    243     C2C_LOCK;
    244     if (db_ref == CPUDB_REF_NULL) { /* Clear out DB completely */
    245         rv = cpudb_clear(c2c_db_ref, FALSE);
    246     } else {
    247         /*
    248          * Remove entries from c2c db that are not in new DB;
    249          * Can't remove entries while looping over entries, so accumulate
    250          * in del_keys structure
    251          */
    252         count = 0;
    253         CPUDB_FOREACH_ENTRY(c2c_db_ref, entry) {
    254             CPUDB_KEY_SEARCH(db_ref, entry->base.key, new_ref_entry);
    255             if (new_ref_entry == NULL) {
    256                 if (entry == c2c_db_ref->local_entry) {
    257                     LOG_INFO(BSL_LS_TKS_C2C,
    258                              (BSL_META("C2C: Update error, can't remove local\n")));
    259                     continue;
    260                 }
    261                 CPUDB_KEY_COPY(del_keys[count], entry->base.key);
    262                 if (++count >= CPUDB_CPU_MAX) {
    263                     break;
    264                 }
    265             }
    266         }
    267         for (i = 0; i < count; i++) {
    268             rv = cpudb_entry_remove(c2c_db_ref, del_keys[i]);
    269             if (rv < 0) {
    270                 LOG_INFO(BSL_LS_TKS_C2C,
    271                          (BSL_META("C2C: Failed to remove entry on update\n")));
    272                 break;
    273             }
    274         }
    275 
    276         /* Add entries that are in new DB */
    277         CPUDB_FOREACH_ENTRY(db_ref, entry) {
    278             rv = _c2c_cpu_add(entry);
    279             if (rv < 0) {
    280                 LOG_INFO(BSL_LS_TKS_C2C,
    281                          (BSL_META("C2C: Failed to remove entry on update\n")));
    282                 break;
    283             }
    284         }
    285     }
    286     C2C_UNLOCK;
    287 
    288     return rv;
    289 }
    290 
    291 
    292 /****************************************************************
    293  *
    294  * Forward declarations
    295  */
    296 
    297 STATIC void c2c_send_callback(int unit, bcm_pkt_t *pkt, void *cookie);
    298 STATIC void c2c_send_callback_nofree(int unit, bcm_pkt_t *pkt, void *cookie);
    299 
    300 STATIC int           good_c2c_pkt(uint8 *pkt_data,
    301                                   cpudb_key_t *src_key,
    302                                   uint16 *mplx_num);
    303 STATIC void          c2c_l2_hdr_pack(const bcm_mac_t dest_mac,
    304                                      const bcm_mac_t src_mac,
    305                                      uint8 *pkt_buf,
    306                                      uint16 mplx_num,
    307                                      uint16 vlan);
    308 
    309 
    310 /****************************************************************
    311  *
    312  * Configuration functions
    313  */
    314 
    315 /*
    316  * Function:
    317  *      c2c_config_set
    318  * Purpose:
    319  *      Set the configurable parameters for CPU to CPU config
    320  * Parameters:
    321  *      trans_ptr       - Tranport pointer structure
    322  *      local_mac       - Local MAC address  IGNORED
    323  * Returns:
    324  *      BCM_E_XXX
    325  */
    326 
    327 int
    328 c2c_config_set(
    329     bcm_trans_ptr_t *trans_ptr,
    330     bcm_mac_t local_mac,
    331     uint32 flags)
    332 {
    333     if (trans_ptr->tp_tx == NULL ||
    334             trans_ptr->tp_setup_tx == NULL) {
    335         return BCM_E_PARAM;
    336     }
    337 
    338     c2c_trans_ptr = trans_ptr;
    339 
    340     if (local_mac != NULL) {
    341         LOG_INFO(BSL_LS_TKS_C2C,
    342                  (BSL_META("c2c local mac set is deprecated.\n")));
    343     }
    344 
    345     c2c_flags = flags;
    346 
    347     return BCM_E_NONE;
    348 }
    349 
    350 
    351 /*
    352  * Function:
    353  *      c2c_config_get
    354  * Purpose:
    355  *      Get the configurable parameters for CPU to CPU config
    356  * Parameters:
    357  *      trans_ptr       - (OUT) Pointer to tranport pointer structure
    358  *      local_mac       - (OUT) Local MAC address
    359  * Returns:
    360  *      BCM_E_XXX
    361  * Notes:
    362  */
    363 
    364 int
    365 c2c_config_get(
    366     bcm_trans_ptr_t **trans_ptr,
    367     bcm_mac_t local_mac,
    368     uint32 *flags)
    369 {
    370     C2C_LOCK;
    371     *trans_ptr = c2c_trans_ptr;
    372     if (c2c_db_ref != NULL && c2c_db_ref->local_entry != NULL) {
    373         sal_memcpy(local_mac, C2C_LOCAL_MAC, sizeof(bcm_mac_t));
    374     } else {
    375         sal_memset(local_mac, 0, sizeof(bcm_mac_t));
    376     }
    377     *flags = c2c_flags;
    378     C2C_UNLOCK;
    379 
    380     return BCM_E_NONE;
    381 }
    382 
    383 
    384 /*
    385  * Function:
    386  *      c2c_snap_set
    387  * Purpose:
    388  *      Set the SNAP mac and type ID
    389  * Parameters:
    390  *      new_mac   - MAC to use
    391  *      new_type  - Type ID to use; host order
    392  * Returns:
    393  *      BCM_E_XXX
    394  * Notes:
    395  *      It defaults to Broadcom, so generally not required
    396  */
    397 
    398 int
    399 c2c_snap_set(bcm_mac_t new_mac, uint16 new_type, uint16 new_trans_type)
    400 {
    401     sal_memcpy(c2c_snap_mac, new_mac, sizeof(bcm_mac_t));
    402     c2c_snap_type = new_type;
    403     c2c_trans_type = new_trans_type;
    404 
    405     return BCM_E_NONE;
    406 }
    407 
    408 
    409 /*
    410  * Function:
    411  *      c2c_snap_get
    412  * Purpose:
    413  *      Get the SNAP mac and type ID
    414  * Parameters:
    415  *      snap_mac   - (OUT) MAC to use
    416  *      snap_type  - (OUT) Type ID to use; host order
    417  * Returns:
    418  *      BCM_E_XXX
    419  * Notes:
    420  *      It defaults to Broadcom, so generally not required
    421  */
    422 
    423 int
    424 c2c_snap_get(bcm_mac_t snap_mac, uint16 *snap_type, uint16 *trans_type)
    425 {
    426     sal_memcpy(snap_mac, c2c_snap_mac, sizeof(bcm_mac_t));
    427     *snap_type = c2c_snap_type;
    428     *trans_type = c2c_trans_type;
    429 
    430     return BCM_E_NONE;
    431 }
    432 
    433 
    434 
    435 /****************************************************************
    436  *
    437  * CPU to CPU transmit routines
    438  *
    439  *    There are two choices here:
    440  *       c2c_tx:          Allocate a bcm packet, send it, deallocate it
    441  *    Or:
    442  *       c2c_pkt_create:  Create a c2c pkt that can be sent multiple times
    443  *       c2c_pkt_update:  Update pkt info according to current cpudb
    444  *       c2c_pkt_send:    Send a pkt created with c2c_pkt_create
    445  *       c2c_pkt_destroy: Deallocate a c2c packet.
    446  */
    447 
    448 /*
    449  * Function:
    450  *      c2c_pkt_create
    451  * Purpose:
    452  *      Returns a bcm_pkt_t that can be sent by c2c
    453  * Parameters:
    454  *      See c2c_tx below
    455  * Returns:
    456  *      BCM_E_XXX
    457  * Notes:
    458  *      The buffer should include C2C_DATA_OFFSET bytes for the
    459  *      packet headers.
    460  *
    461  *      This routine is meant to create a packet which is repeatedly
    462  *      sent without being changed.  It is not meant to allocate
    463  *      a packet which is updated and sent out for different
    464  *      reasons or to different CPUs.
    465  *
    466  *      The 'cos' parameter contains the cos and internal priority
    467  *      values encoded.   Use CPUTRANS_COS_SET() CPUTRANS_INT_PRIO_SET()
    468  *      to set values accordingly.  The internal priority is optional;
    469  *      if this is not provided, the cos value is used for internal priority.
    470  */
    471 
    472 bcm_pkt_t *
    473 c2c_pkt_create(
    474     cpudb_key_t dest_key,
    475     uint8 *pkt_buf,
    476     int len,
    477     int cos,
    478     int vlan,
    479     int seg_len,
    480     uint16 mplx_num,
    481     uint32 ct_flags,
    482     int *tot_segs,
    483     int *rvp)
    484 {
    485     bcm_pkt_t *pkt, *cur_pkt;
    486     const cpudb_entry_t *db_ent;
    487     uint8 *pkt_data;
    488     int src_mod, src_port, dest_mod, dest_port;
    489     int tx_unit, tx_port;
    490     cpudb_key_t local_key;
    491     bcm_mac_t dest_mac, src_mac;
    492     int pkt_cos, pkt_int_prio;
    493     int rv;
    494 
    495     if (!init_done) {
    496         if ((rv = c2c_init()) != BCM_E_NONE) {
    497             LOG_INFO(BSL_LS_TKS_C2C,
    498                      (BSL_META("c2c pc. init failed\n")));
    499             *rvp = rv;
    500             return NULL;
    501         }
    502     }
    503 
    504     C2C_LOCK;
    505     CPUDB_KEY_SEARCH(c2c_db_ref, dest_key, db_ent);
    506     if (db_ent == NULL || c2c_db_ref->local_entry == NULL) {
    507         LOG_INFO(BSL_LS_TKS_C2C,
    508                  (BSL_META("c2c: Could not find %s%s%s for "
    509                            CPUDB_KEY_FMT_EOLN),
    510                   db_ent == NULL ? "db entry" : "",
    511                   db_ent || c2c_db_ref->local_entry ? "" : ",",
    512                   c2c_db_ref->local_entry == NULL ? "local entry" : "",
    513                   CPUDB_KEY_DISP(dest_key)));
    514         *rvp = (db_ent == NULL) ? BCM_E_NOT_FOUND : BCM_E_EMPTY;
    515         C2C_UNLOCK;
    516         return NULL;
    517     }
    518 #if defined(BROADCOM_DEBUG)
    519     if (!(db_ent->flags & CPUDB_F_TX_KNOWN)) {
    520         C2C_UNLOCK;
    521         LOG_INFO(BSL_LS_TKS_C2C,
    522                  (BSL_META("c2c: Unknown transmit port (flags 0x%x) for dest key "
    523                            CPUDB_KEY_FMT_EOLN),
    524                   db_ent->flags,
    525                   CPUDB_KEY_DISP(dest_key)));
    526         *rvp = BCM_E_INTERNAL;
    527         return NULL;
    528     }
    529 #endif /* BROADCOM_DEBUG */
    530 
    531     /* Get needed info from db entries */
    532     src_mod        = c2c_src_mod();
    533     src_port       = c2c_db_ref->local_entry->dest_port;
    534     CPUDB_KEY_COPY(local_key, c2c_db_ref->local_entry->base.key);
    535     dest_mod = db_ent->dest_mod;
    536     dest_port = db_ent->dest_port;
    537     tx_unit = db_ent->tx_unit;
    538     tx_port = db_ent->tx_port;
    539     sal_memcpy(&dest_mac, db_ent->base.mac, sizeof(bcm_mac_t));
    540     sal_memcpy(&src_mac, c2c_db_ref->local_entry->base.mac, sizeof(bcm_mac_t));
    541     C2C_UNLOCK;
    542 
    543     pkt = cputrans_tx_pkt_list_alloc(pkt_buf, len, seg_len, ct_flags,
    544                                      tot_segs);
    545     if (pkt == NULL) {
    546         LOG_INFO(BSL_LS_TKS_C2C,
    547                  (BSL_META("c2c: Could not alloc cputrans pkt\n")));
    548         *rvp = BCM_E_MEMORY;
    549         return NULL;
    550     }
    551 #if defined(BROADCOM_DEBUG)
    552     assert(pkt->next != pkt);
    553 #endif   /* BROADCOM_DEBUG */
    554 
    555 #if defined(BCM_C2C_TRANSPORT_SWITCHING)
    556     /* Record the current entry in packet meta-data */
    557     pkt->trans_ptr = (void *)(db_ent->trans_ptr);
    558 #endif
    559 
    560     /* If internal priority is not provided, set value to cos */
    561     pkt_cos = CPUTRANS_COS_GET(cos);
    562     if (cos & CPUTRANS_INT_PRIO_VALID) {
    563         pkt_int_prio = CPUTRANS_INT_PRIO_GET(cos);
    564     } else {
    565         pkt_int_prio = pkt_cos;
    566     }
    567 
    568     /* Set up packet data in each segment */
    569     for (cur_pkt = pkt; cur_pkt != NULL; cur_pkt = cur_pkt->next) {
    570 
    571         cur_pkt->unit           = tx_unit;
    572         BCM_PBMP_PORT_SET(cur_pkt->tx_pbmp, tx_port);
    573         cur_pkt->dest_mod       = dest_mod;
    574         cur_pkt->dest_port      = dest_port;
    575 
    576         
    577         cur_pkt->flags          |= (BCM_TX_SRC_MOD|BCM_TX_SRC_PORT);
    578         cur_pkt->src_mod        = src_mod;
    579         cur_pkt->src_port       = src_port;
    580         cur_pkt->opcode         = BCM_HG_OPCODE_UC;
    581         cur_pkt->cos            = pkt_cos;
    582         cur_pkt->prio_int       = pkt_int_prio;
    583         cur_pkt->flags         |= BCM_TX_PRIO_INT;
    584 
    585         /* L2 header is always in block 0 */
    586         pkt_data = cur_pkt->pkt_data[0].data;
    587         c2c_l2_hdr_pack(dest_mac, src_mac, pkt_data,
    588                         mplx_num, BCM_VLAN_CTRL(cos, 0, vlan));
    589         CPUDB_KEY_PACK(&pkt_data[CPUTRANS_SRC_KEY_OFS], local_key);
    590     }
    591 
    592     LOG_DEBUG(BSL_LS_TKS_C2C,
    593               (BSL_META("c2c: pkt from (%d.%d) to (%d.%d) "
    594                         "op %d cos %d int_prio %d\n"),
    595                pkt->src_mod, pkt->src_port, 
    596                pkt->dest_mod, pkt->dest_port,
    597                pkt->opcode, pkt_cos, pkt_int_prio));
    598 
    599     *rvp = BCM_E_NONE;
    600     return pkt;
    601 }
    602 
    603 /*
    604  * Function:
    605  *      c2c_pkt_update
    606  * Purpose:
    607  *      Update the routing information in a packet created by c2c_pkt_create
    608  * Parameters:
    609  *      pkt   - Returned by c2c_pkt_create
    610  * Returns:
    611  *      BCM_E_XXX
    612  * Notes:
    613  *      If topology info in the system changes, this can be used
    614  *      to update packets to reflect that.
    615  */
    616 
    617 int
    618 c2c_pkt_update(
    619     bcm_pkt_t *pkt,
    620     cpudb_key_t dest_key)
    621 {
    622     bcm_pkt_t *cur_pkt;
    623     const cpudb_entry_t *db_ent;
    624     int src_mod, src_port, dest_mod, dest_port;
    625     int tx_unit, tx_port;
    626 
    627     if (!init_done) {
    628         if (c2c_init() != BCM_E_NONE) {
    629             LOG_INFO(BSL_LS_TKS_C2C,
    630                      (BSL_META("c2c update. init failed\n")));
    631             return BCM_E_INIT;
    632         }
    633     }
    634 
    635     C2C_LOCK;
    636     CPUDB_KEY_SEARCH(c2c_db_ref, dest_key, db_ent);
    637 #if defined(BROADCOM_DEBUG)
    638     if (db_ent == NULL || c2c_db_ref->local_entry == NULL) {
    639         C2C_UNLOCK;
    640         LOG_INFO(BSL_LS_TKS_C2C,
    641                  (BSL_META("c2c update: key %sfound, local_entry %sNULL, dest key "
    642                            CPUDB_KEY_FMT_EOLN),
    643                   (db_ent == NULL) ? "not " : "",
    644                   (c2c_db_ref->local_entry) == NULL ? "" : "not ",
    645                   CPUDB_KEY_DISP(dest_key)));
    646         return BCM_E_NOT_FOUND;
    647     }
    648     if (!(db_ent->flags & CPUDB_F_TX_KNOWN)) {
    649         C2C_UNLOCK;
    650         LOG_INFO(BSL_LS_TKS_C2C,
    651                  (BSL_META("c2c update: Unknown tx port (flags 0x%x) for dest key "
    652                            CPUDB_KEY_FMT_EOLN),
    653                   db_ent->flags,
    654                   CPUDB_KEY_DISP(dest_key)));
    655         return BCM_E_NOT_FOUND;
    656     }
    657 #else
    658     if (db_ent == NULL) {
    659         C2C_UNLOCK;
    660         return BCM_E_NOT_FOUND;
    661     }
    662 #endif /* BROADCOM_DEBUG */
    663 
    664     /* Get needed info from db entries */
    665     src_mod        = c2c_src_mod();
    666     src_port       = c2c_db_ref->local_entry->dest_port;
    667     dest_mod = db_ent->dest_mod;
    668     dest_port = db_ent->dest_port;
    669     tx_unit = db_ent->tx_unit;
    670     tx_port = db_ent->tx_port;
    671     C2C_UNLOCK;
    672 
    673     /* Set up topology packet data in each segment */
    674     for (cur_pkt = pkt; cur_pkt != NULL; cur_pkt = cur_pkt->next) {
    675         cur_pkt->unit           = tx_unit;
    676         BCM_PBMP_PORT_SET(cur_pkt->tx_pbmp, tx_port);
    677         cur_pkt->dest_mod       = dest_mod;
    678         cur_pkt->dest_port      = dest_port;
    679 
    680         
    681         cur_pkt->flags          |= (BCM_TX_SRC_MOD|BCM_TX_SRC_PORT);
    682         cur_pkt->src_mod        = src_mod;
    683         cur_pkt->src_port       = src_port;
    684         /* Assume mac/key for local box haven't changed */
    685     }
    686 
    687     return BCM_E_NONE;
    688 }
    689 
    690 #if defined(BCM_C2C_TRANSPORT_SWITCHING)
    691 #define SETUP_TX_RESOLVE(_pkt, _setup, _tx_list) do {                       \
    692         bcm_trans_ptr_t *_tp;                                               \
    693         _setup = c2c_trans_ptr->tp_setup_tx;                                \
    694         _tx_list = c2c_trans_ptr->tp_tx_list;                               \
    695         _tp = PKT_TRANS_PTR(_pkt);                                          \
    696         if (_tp != NULL) {                                                  \
    697             if (_tp->tp_setup_tx != NULL) {                                 \
    698                 _setup = _tp->tp_setup_tx;                                  \
    699             }                                                               \
    700             if (_tp->tp_tx_list != NULL) {                                  \
    701                 _tx_list = _tp->tp_tx_list;                                 \
    702             }                                                               \
    703         }                                                                   \
    704     } while (0)
    705 #else
    706 #define SETUP_TX_RESOLVE(_pkt, _setup, _tx_list) do {                       \
    707         _setup = c2c_trans_ptr->tp_setup_tx;                                \
    708         _tx_list = c2c_trans_ptr->tp_tx_list;                               \
    709     } while (0)
    710 #endif  /* Transport switching */
    711 
    712 /*
    713  * Function:
    714  *      c2c_pkt_send
    715  * Purpose:
    716  *      Send a packet prepared by c2c_pkt_create.  Will not
    717  *      deallocate on completion.
    718  * Parameters:
    719  *      pkt        - The packet or list of packets to send
    720  *      callback   - If non-NULL, send async and make callback
    721  *      cookie     - Passed on callback
    722  * Returns:
    723  *      BCM_E_XXX
    724  * Notes:
    725  *      This function may be called multiple times on the same
    726  *      packet(s).  The header of the packet should not be altered.
    727  *      If callback is non-NULL, it will be made after the last packet
    728  *      is sent.
    729  */
    730 
    731 int
    732 c2c_pkt_send(
    733     bcm_pkt_t *pkt,
    734     c2c_cb_f callback,
    735     void *cookie)
    736 {
    737     int rv;
    738     bcm_pkt_cb_f  local_callback = NULL;
    739     bcm_tx_pkt_setup_f setup_fn;
    740     bcm_tx_list_f tx_list_fn;
    741     c2c_cb_cookie_t *c2c_cookie = NULL;
    742 
    743     C2C_INIT;
    744 
    745     SETUP_TX_RESOLVE(pkt, setup_fn, tx_list_fn);
    746 
    747     if (setup_fn != NULL) {
    748         rv = setup_fn(pkt->unit, pkt);    /* Set up the packet */
    749         if (rv < 0) {  /* Problem packet configuration */
    750             LOG_INFO(BSL_LS_TKS_C2C,
    751                      (BSL_META("c2c tx: Error setting up packet\n")));
    752             return rv;
    753         }
    754     }
    755 
    756     if (callback != NULL) {    /* Async send; but don't free after call */
    757         local_callback = c2c_send_callback_nofree;
    758         pkt->_last_pkt->cookie = cookie;
    759         c2c_cookie = _c2c_callback_cookie_set(callback);
    760         if (c2c_cookie == NULL) {
    761             return BCM_E_MEMORY;
    762         }
    763     }
    764 
    765     assert(tx_list_fn != NULL);
    766     rv = tx_list_fn(pkt->unit, pkt, local_callback, c2c_cookie);
    767     return rv;
    768 }
    769 
    770 
    771 /*
    772  * Function:
    773  *      c2c_pkt_destroy
    774  * Purpose:
    775  *      Deallocate a packet created with c2c_pkt_create
    776  * Parameters:
    777  *      pkt     - The packet to deallocate
    778  * Returns:
    779  *      BCM_E_XXX
    780  * Notes:
    781  */
    782 
    783 void
    784 c2c_pkt_destroy(bcm_pkt_t *pkt)
    785 {
    786     assert(pkt->next != pkt);
    787     cputrans_tx_pkt_list_free(pkt);
    788 }
    789 
    790 /*
    791  * Function:
    792  *      c2c_tx
    793  * Purpose:
    794  *      Transmit a (single) packet to a CPU given by index.
    795  * Parameters:
    796  *      dest_key    - To what CPU is this being sent
    797  *      pkt_buf     - DMA-able buffer to be sent
    798  *      len         - Total bytes in packet
    799  *      vlan        - VLAN id (12 bits)
    800  *      cos         - COS and internal priority to use
    801  *      seg_len     - Bytes per data segment
    802  *      mplx_num    - (TCP-like) multiplexing number for packet
    803  *      ct_flags    - Indicate if packet contains space for header:
    804  *      callback    - If non-null, send async and make callback
    805  *      cookie      - Passed to callback when complete
    806  * Returns:
    807  *      BCM_E_XXX
    808  * Notes:
    809  *      The length field in the L2 header of the packet is not touched.
    810  *      Does not support segmentation/reassembly.
    811  *
    812  *      The 'cos' parameter contains the cos and internal priority
    813  *      values encoded.   Use CPUTRANS_COS_SET() CPUTRANS_INT_PRIO_SET()
    814  *      to set values accordingly.  The internal priority is optional;
    815  *      if this is not provided, the cos value is used for internal priority.
    816  */
    817 
    818 int
    819 c2c_tx(
    820     cpudb_key_t dest_key,
    821     uint8 *pkt_buf,
    822     int len,
    823     int cos,
    824     int vlan,
    825     int seg_len,
    826     uint16 mplx_num,
    827     uint32 ct_flags,
    828     c2c_cb_f callback,
    829     void *cookie)
    830 {
    831     bcm_pkt_t *pkt, *cur_pkt;
    832     int rv;
    833     bcm_pkt_cb_f  local_callback = NULL;
    834     bcm_tx_pkt_setup_f setup_fn;
    835     bcm_tx_list_f tx_list_fn;
    836     c2c_cb_cookie_t *c2c_cookie = NULL;
    837 
    838     C2C_INIT;
    839 
    840     pkt = c2c_pkt_create(dest_key, pkt_buf, len, cos, vlan,
    841                          seg_len, mplx_num, ct_flags, NULL, &rv);
    842     if (rv != BCM_E_NONE) {
    843         LOG_INFO(BSL_LS_TKS_C2C,
    844                  (BSL_META("c2c send. can't create (%s)\n"),
    845                   bcm_errmsg(rv)));
    846         return rv;
    847     }
    848 
    849     SETUP_TX_RESOLVE(pkt, setup_fn, tx_list_fn);
    850 
    851     /* Set up the packet */
    852     for (cur_pkt = pkt; cur_pkt != NULL; cur_pkt = cur_pkt->next) {
    853         rv = setup_fn(pkt->unit, cur_pkt);
    854         if (rv < 0) {  /* Problem packet configuration */
    855             LOG_INFO(BSL_LS_TKS_C2C,
    856                      (BSL_META("c2c tx: Error setting up packet\n")));
    857             cputrans_tx_pkt_list_free(pkt);
    858             return rv;
    859         }
    860     }
    861 
    862     /* Callback should deallocate packet when called */
    863     if (callback != NULL) {    /* Async send */
    864         local_callback = c2c_send_callback;
    865         pkt->_last_pkt->cookie = cookie;
    866         c2c_cookie = _c2c_callback_cookie_set(callback);
    867         if (c2c_cookie == NULL) {
    868             cputrans_tx_pkt_list_free(pkt);
    869             return BCM_E_MEMORY;
    870         }
    871     }
    872 
    873     rv = tx_list_fn(pkt->unit, pkt, local_callback, c2c_cookie);
    874 
    875     /* Free packet if sending sync, or if an error occurs */
    876     if (callback == NULL || rv != BCM_E_NONE) {
    877         cputrans_tx_pkt_list_free(pkt);
    878     }
    879 
    880     return rv;
    881 }
    882 
    883 
    884 /*
    885  * Function:
    886  *      c2c_pkt_recognize
    887  * Purpose:
    888  *      Check if the given packet is a CPU2CPU packet and
    889  *      get the index if it is.
    890  * Parameters:
    891  *      pkt_data    - The buffer to examine, from start of L2 hdr
    892  *      src_key     - (OUT) Source KEY
    893  *      mplx_num    - (OUT) Packet multiplexing value, if packet recognized
    894  * Returns:
    895  *      BCM_E_NONE if it is a CPU 2 CPU packet; sets cpu_idx.
    896  *      BCM_E_NOT_FOUND if not a CPU 2 CPU packet.
    897  * Notes:
    898  *      If the DB reference is non-NULL, then it is searched for the source
    899  *      MAC address of the packet as well.
    900  *
    901  *      If src_key is non-NULL as well, it is filled in with a pointer
    902  *      to the found entry.
    903  */
    904 
    905 int
    906 c2c_pkt_recognize(uint8 *pkt_data,
    907                   cpudb_key_t *src_key,
    908                   uint16 *mplx_num)
    909 {
    910     int is_good;
    911 
    912     if (!pkt_data) {
    913         return 0;
    914     }
    915 
    916     C2C_INIT;
    917 
    918     C2C_LOCK;
    919     is_good = good_c2c_pkt(pkt_data, src_key, mplx_num);
    920     C2C_UNLOCK;
    921 
    922     LOG_DEBUG(BSL_LS_TKS_C2C,
    923               (BSL_META("c2c: pkt is %srecognized. type, %d\n"),
    924                is_good ? "" : "not ", mplx_num ? *mplx_num : -1));
    925 
    926     return is_good ? BCM_E_NONE : BCM_E_NOT_FOUND;
    927 }
    928 
    929 
    930 /*
    931  * Boolean function that returns true if the packet is recognized
    932  * as cpu-to-cpu transport packet.
    933  * If the DB reference is non-NULL, then it is searched for the source
    934  * MAC address of the packet as well.
    935  */
    936 
    937 STATIC int
    938 good_c2c_pkt(uint8 *pkt_data,
    939              cpudb_key_t *src_key,
    940              uint16 *mplx_num)
    941 {
    942     uint16 snap_type, trans_type;
    943 
    944     /* Dest MAC is ours? */
    945     if (c2c_flags & C2C_F_DEST_MAC_CHECK_ENABLE) {
    946         if (c2c_db_ref != NULL && c2c_db_ref->local_entry != NULL) {
    947             if (sal_memcmp(pkt_data, C2C_LOCAL_MAC, sizeof(bcm_mac_t))) {
    948                 return 0;
    949             }
    950         }
    951     }
    952 
    953     
    954 
    955     /* SNAP pkt? */
    956     if (sal_memcmp(&pkt_data[CPUTRANS_SNAP_OFS], c2c_snap_mac,
    957                    sizeof(bcm_mac_t))) {
    958         LOG_DEBUG(BSL_LS_TKS_C2C,
    959                   (BSL_META("c2c: Not SNAP mac\n")));
    960         return 0;
    961     }
    962 
    963     /* SNAP type correct? */
    964     UNPACK_SHORT(&pkt_data[CPUTRANS_SNAP_TYPE_OFS], snap_type);
    965     if (snap_type != c2c_snap_type) {
    966         LOG_DEBUG(BSL_LS_TKS_C2C,
    967                   (BSL_META("c2c: Wrong SNAP type 0x%04x\n"),
    968                    snap_type));
    969         return 0;
    970     }
    971 
    972     /* SNAP local type correct? */
    973     UNPACK_SHORT(&pkt_data[CPUTRANS_TR_TYPE_OFS], trans_type);
    974     if (trans_type != c2c_trans_type) {
    975         LOG_DEBUG(BSL_LS_TKS_C2C,
    976                   (BSL_META("c2c: Wrong trans type 0x%04x\n"),
    977                    trans_type));
    978         return 0;
    979     }
    980 
    981     /* It is a c2c packet; get application packet type and source key */
    982     if (src_key != NULL) {
    983         CPUDB_KEY_UNPACK(&pkt_data[CPUTRANS_SRC_KEY_OFS], *src_key);
    984     }
    985     if (mplx_num != NULL) {
    986         /* Get the local packet type from the next short in the pkt */
    987         UNPACK_SHORT(&pkt_data[CPUTRANS_TR_MULT_OFS], (*mplx_num));
    988     }
    989 
    990     return 1;
    991 }
    992 
    993 STATIC void
    994 _do_callback(bcm_pkt_t *pkt, void *cookie)
    995 {
    996     c2c_cb_f cb;
    997     int pkt_data_blk;
    998     /* Grab the callback from the packet */
    999     _c2c_callback_cookie_get(cookie, &cb);
   1000     /* Check where packet data is; see cputrans for more info */
   1001     pkt_data_blk = 1;
   1002     if (pkt->blk_count == 1) {
   1003         pkt_data_blk = 0;
   1004     }
   1005     if (cb) {
   1006         cb(pkt->pkt_data[pkt_data_blk].data, pkt->cookie);
   1007     }
   1008 }
   1009 
   1010 /* Callback and deallocate packet after being sent.  Does not touch
   1011  * user data linked into the packet.
   1012  */
   1013 STATIC void
   1014 c2c_send_callback(int unit, bcm_pkt_t *pkt, void *cookie)
   1015 {
   1016     _do_callback(pkt, cookie);
   1017     assert(pkt->next != pkt);
   1018     cputrans_tx_pkt_list_free(pkt);
   1019 }
   1020 
   1021 
   1022 /* Callback and don't deallocate packet; appl must call pkt_destroy. */
   1023 STATIC void
   1024 c2c_send_callback_nofree(int unit, bcm_pkt_t *pkt, void *cookie)
   1025 {
   1026     _do_callback(pkt, cookie);
   1027 }
   1028 
   1029 /* Set up the L2 header for the CPU to CPU packet; destination is in cm */
   1030 
   1031 STATIC void
   1032 c2c_l2_hdr_pack(const bcm_mac_t dest_mac,
   1033                 const bcm_mac_t src_mac,
   1034                 uint8 *pkt_buf,
   1035                 uint16 mplx_num,
   1036                 uint16 vlan)
   1037 {
   1038     /* Set up the L2 header in the packet */
   1039     sal_memcpy(pkt_buf, dest_mac, sizeof(bcm_mac_t));
   1040     sal_memcpy(&pkt_buf[CPUTRANS_SMAC_OFS], src_mac, sizeof(bcm_mac_t));
   1041     PACK_SHORT(&pkt_buf[CPUTRANS_VTAG_OFS], 0x8100);
   1042     PACK_SHORT(&pkt_buf[CPUTRANS_VTAG_OFS + sizeof(uint16)], vlan);
   1043     /* Skip type/len field */
   1044     /* Following three "packs" could be combined */
   1045     sal_memcpy(&pkt_buf[CPUTRANS_SNAP_OFS], c2c_snap_mac, sizeof(bcm_mac_t));
   1046     PACK_SHORT(&pkt_buf[CPUTRANS_SNAP_TYPE_OFS], c2c_snap_type);
   1047     PACK_SHORT(&pkt_buf[CPUTRANS_TR_TYPE_OFS], c2c_trans_type);
   1048     PACK_SHORT(&pkt_buf[CPUTRANS_TR_MULT_OFS], mplx_num);
   1049 }
   1050 
   1051 #if defined(BROADCOM_DEBUG)
   1052 void
   1053 c2c_dump(void)
   1054 {
   1055     cpudb_entry_t *entry;
   1056 
   1057     if (!init_done) {
   1058         return;
   1059     }
   1060     
   1061     LOG_INFO(BSL_LS_TKS_C2C,
   1062              (BSL_META("C2C Database\n")));
   1063 
   1064     C2C_LOCK;
   1065 
   1066     if (c2c_db_ref == CPUDB_REF_NULL) {
   1067         LOG_INFO(BSL_LS_TKS_C2C,
   1068                  (BSL_META("    Empty\n")));
   1069     } else {
   1070         CPUDB_FOREACH_ENTRY(c2c_db_ref, entry) {
   1071             LOG_INFO(BSL_LS_TKS_C2C,
   1072                      (BSL_META("    CPU Key " CPUDB_KEY_FMT ", flags 0x%x\n"),
   1073                       CPUDB_KEY_DISP(entry->base.key), entry->flags));
   1074         }
   1075     }
   1076     
   1077     C2C_UNLOCK;
   1078 
   1079     return;
   1080 }
   1081 #endif  /* BROADCOM_DEBUG */