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

dma.c (128495B)


      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  * Purpose:     SOC DMA LLC (Link Layer) driver; used for sending
      8  *              and receiving packets over PCI (and later, the uplink).
      9  *
     10  * NOTE:  DV chains are different than hardware chains. The hardware
     11  * chain bit is used to keep DMA going through multiple packets.
     12  * This corresponds to the sequence of DCBs (and usually multiple
     13  * packets) of one DV.  DVs are chained in a linked list in software.
     14  * The dv->dv_chain member (and dv_chain parameters) implement this
     15  * linked list.
     16  *   To improve the performance of packets receiving, we introduced the
     17  * method to mitigate descriptor done interrupts. When we detect the
     18  * packet storm is coming, we will disable descriptor done interrupt and
     19  * simultaneously start the monitor timer which will reenable the disabled
     20  * interrupt while storm is stopped.
     21  *
     22  * Starting with CMICDv2 devices, the DCB reload support has been
     23  * improved to allow DCB chains to be appended safely without
     24  * stopping the DMA channel. This feature is called Continuous
     25  * DMA mode and works like this: When initially added, each DCB
     26  * chain will end with a reload DCB pointing to itself. To
     27  * prevent it from reloading over and over, a new CMIC DMA HALT
     28  * register is programmed with the address of the reload DCB. The
     29  * DMA process will suspend itself when the DCB at the HALT
     30  * address is reached. When a new DCB chain is added, the
     31  * previous reload DCB is updated with the address of the new DCB
     32  * chain. If the DMA process has already been suspended when the
     33  * new DCB chain is added, it will automatically resume when the
     34  * HALT register is updated with the address of the reload DCB at
     35  * the end of the new DCB chain. The major difference between
     36  * reload and non-reload mode is that in reload mode, the last DCB
     37  * chain cannot be discarded (freed) when processing is done because
     38  * the reload DCB is needed until the next DCB chain is started.
     39  */
     40 
     41 #include <shared/bsl.h>
     42 
     43 #include <sal/core/boot.h>
     44 #include <sal/core/libc.h>
     45 
     46 #include <shared/alloc.h>
     47 #include <shared/bsl.h>
     48 
     49 #include <soc/drv.h>
     50 #include <soc/dcb.h>
     51 #include <soc/dcbformats.h>     /* only for 5670 crc erratum warning */
     52 #include <soc/pbsmh.h>
     53 #include <soc/higig.h>
     54 #include <soc/debug.h>
     55 #include <soc/cm.h>
     56 #ifdef BCM_CMICM_SUPPORT
     57 #include <soc/cmicm.h>
     58 #endif
     59 
     60 #ifdef INCLUDE_KNET
     61 #include <soc/knet.h>
     62 #endif
     63 
     64 #ifdef BCM_CMIC_SUPPORT
     65 
     66 #define DV_MAGIC_NUMBER 0xba5eba11
     67 
     68 #define DMA_CHAIN_DONE_TIMEOUT_USEC         (4000)
     69 #define DMA_CHAIN_DONE_INTERVAL_USEC        (1000)
     70 
     71 
     72 #define DMA_LAST_DESC_DONE_CTN(unit, dv_chain)\
     73     ((SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) &&\
     74      (dv_chain->dv_vcnt - dv_chain->dv_dcnt == 2))
     75 
     76 #define DMA_LAST_DESC_DONE_NON_CTN(unit, dv_chain)\
     77     ((SOC_DMA_MODE(unit) != SOC_DMA_MODE_CONTINUOUS) &&\
     78       (dv_chain->dv_vcnt - dv_chain->dv_dcnt == 1))
     79           
     80 #define DMA_LAST_DESC_DONE(unit, dv_chain)\
     81     (DMA_LAST_DESC_DONE_CTN(unit, dv_chain) ||\
     82      DMA_LAST_DESC_DONE_NON_CTN(unit, dv_chain))
     83 
     84 typedef struct sdc_intr_mitigate_s {
     85     uint32        rx_chain_intr;
     86     uint32        rx_chain_intr_prev;
     87     sal_usecs_t   cur_tm;
     88     sal_usecs_t   prev_tm;
     89     char          sem_name[16];
     90     sal_sem_t     thread_sem;
     91     sal_thread_t  thread_id;
     92     int           thread_running;
     93     int           mitigation_started;
     94 } sdc_intr_mitigate_t;
     95 
     96 typedef struct soc_dma_intr_mitigate_s {
     97     int                 enabled;
     98     sdc_intr_mitigate_t chans_intr_mitigation[MAX_N_DMA_CHAN * SOC_CMCS_NUM_MAX];
     99 } soc_dma_intr_mitigate_t;
    100 
    101 static soc_dma_intr_mitigate_t soc_dma_intr_mitigation[SOC_MAX_NUM_DEVICES];
    102 
    103 STATIC soc_cmic_dma_drv_t cmic_drv[SOC_MAX_NUM_DEVICES];
    104 
    105 #if (defined(BCM_ESW_SUPPORT) || defined (BCM_PETRA_SUPPORT))
    106 extern void tx_dv_free_cb(int unit, dv_t *dv) __attribute__ ((weak)); 
    107 extern void rx_dv_free_cb(int unit, dv_t *dv) __attribute__ ((weak));
    108 #else
    109 static void (*tx_dv_free_cb)(int unit, dv_t *dv) = NULL; 
    110 static void (*rx_dv_free_cb)(int unit, dv_t *dv) = NULL;
    111 #endif
    112 
    113 STATIC void
    114 soc_dma_monitor_thread(void *p)
    115 {
    116     uint32 param = PTR_TO_INT(p);
    117     int unit = param >> 16 & 0xffff;
    118     int vchan = param & 0xffff;
    119     sdc_intr_mitigate_t *sdc_mtg =
    120         &soc_dma_intr_mitigation[unit].chans_intr_mitigation[vchan];
    121 
    122     while (1) {
    123         if (sdc_mtg->thread_running == 0) {
    124             sal_sem_destroy(sdc_mtg->thread_sem);
    125             sal_memset(sdc_mtg, 0, sizeof(* sdc_mtg));
    126             break;
    127         }
    128         if (!sdc_mtg->mitigation_started) {
    129             sal_sem_take(sdc_mtg->thread_sem, sal_sem_FOREVER);
    130             continue;
    131         }
    132         sal_usleep(DMA_CHAIN_DONE_TIMEOUT_USEC);
    133         if (sdc_mtg->rx_chain_intr != sdc_mtg->rx_chain_intr_prev) {
    134             sdc_mtg->rx_chain_intr_prev = sdc_mtg->rx_chain_intr;
    135         } else {
    136             sdc_mtg->mitigation_started = 0;
    137             /* Enable descriptor done interrupt */
    138             cmic_drv[unit].chan_desc_done_intr_enable(unit, vchan);
    139 
    140             sdc_mtg->rx_chain_intr_prev = sdc_mtg->rx_chain_intr = 0;
    141         }
    142     }
    143 }
    144 
    145 /*
    146  * Function:
    147  *      soc_dma_channel
    148  * Purpose:
    149  *      Choose a channel to send a DMA request over.
    150  * Parameters:
    151  *      unit - StrataSwitch Unit #.
    152  *      vchan - -1 --> choose any virtual channel.
    153  *                0-11 --> select given channel.
    154  * Returns:
    155  *      Pointer to soc_dma_start structure to use, NULL if failed.
    156  * Notes:
    157  *      If no channel is specified then the default channel for that
    158  *      operation type is chosen.
    159  */
    160 
    161 STATIC sdc_t *
    162 soc_dma_channel(int unit, dma_chan_t vchan, dv_t *dv_chain)
    163 {
    164     soc_control_t       *soc = SOC_CONTROL(unit);
    165     sdc_t               *cd;
    166 
    167     if (vchan < 0) {                  /* Choose a channel */
    168         switch(dv_chain->dv_op) {
    169         case DV_TX:     return(soc->soc_dma_default_tx);
    170         case DV_RX:     return(soc->soc_dma_default_rx);
    171         default:        return(NULL);
    172         }
    173     } else if (vchan < 0 || vchan >= soc->soc_dma_channels) {
    174         return NULL;
    175     } else {
    176         cd = &soc->soc_channels[vchan];
    177         return((cd->sc_type == dv_chain->dv_op) ? cd : NULL);
    178     }
    179 }
    180 
    181 /*
    182  * Function:
    183  *      soc_dma_start_channel
    184  *
    185  * Purpose:
    186  *      Start the next queued DMA (ignoring channel state)
    187  * Parameters:
    188  *      unit - StrataSwitch unit #
    189  *      sc - pointer to channel to start operation on.
    190  * Returns:
    191  *      nothing.
    192  * Notes:
    193  *      Assumes SOC_DMA_LOCK held on entry (or called from interrupt
    194  *      handler).
    195  *
    196  *      Sets sc_dv_active, but NOT sc_dv_q. Safe to call if
    197  *      no pending DMA to start, in which case sc_dv_active is set to NULL.
    198  */
    199 
    200 STATIC void
    201 soc_dma_start_channel(int unit, sdc_t *sc)
    202 {
    203     dv_t *dv;
    204 
    205     if ((dv = sc->sc_dv_active = sc->sc_q) == NULL) {
    206         sc->sc_q_tail = NULL;
    207         return;
    208     }
    209 
    210 #ifdef INCLUDE_KNET
    211     if (SOC_KNET_MODE(unit)) {
    212         return;
    213     }
    214 #endif
    215 
    216     LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
    217              (BSL_META_U(unit,
    218                          "Starting DMA channel: c=%d\n"), sc->sc_channel));
    219 
    220     cmic_drv[unit].chan_start(unit, sc);
    221 }
    222 
    223 #ifdef  BCM_XGS3_SWITCH_SUPPORT
    224 /*
    225  * Function:
    226  *      soc_dma_tx_purge
    227  * Purpose:
    228  *      Purge the partial packet from the Pipeline left from TX DMA abort.
    229  * Parameters:
    230  *      unit         - Unit on which being transmitted
    231  * Returns:
    232  *      SOC_E_XXX
    233  */
    234 int
    235 soc_dma_tx_purge(int unit, dma_chan_t vchan)
    236 {
    237     int         rv = SOC_E_NONE;
    238 
    239 #ifdef INCLUDE_KNET
    240     if (SOC_KNET_MODE(unit)) {
    241         return SOC_E_NONE;
    242     }
    243 #endif
    244 
    245     if (soc_feature(unit, soc_feature_txdma_purge)) {
    246         dv_t        dvs;
    247         dv_t        *dv = &dvs;
    248         dcb_t       *dcb;
    249         soc_control_t       *soc = SOC_CONTROL(unit);
    250 
    251         if (soc->tx_purge_pkt == NULL) {
    252             return SOC_E_NONE;
    253         }
    254         sal_memset(dv, 0, sizeof(*dv));
    255         dv->dv_unit    = unit;
    256         dcb = dv->dv_dcb = soc->tx_purge_pkt;
    257 
    258         dv->dv_op      = DV_TX;
    259         dv->dv_channel = vchan;
    260         dv->dv_cnt     = 1;
    261 
    262         rv = SOC_DCB_ADDTX(unit, dv,
    263             (sal_vaddr_t) SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, dv->dv_vcnt),
    264             64,             /* Some Non Zero Lenght */
    265             PBMP_ALL(unit), /* Not used */
    266             PBMP_ALL(unit), /* Not used */
    267             PBMP_ALL(unit), /* Not used */
    268             SOC_DMA_PURGE,  /* Purge packet */
    269             NULL            /* No Higig Header required */
    270             );
    271         /* Mark the end of the packet */
    272         SOC_DCB_SG_SET(dv->dv_unit, dcb, 0);
    273         if (rv >= 0) {
    274             soc_cm_sflush(unit, dv->dv_dcb, SOC_DCB_SIZE(unit));
    275 
    276             rv = cmic_drv[unit].chan_tx_purge(unit, vchan, dv);
    277 
    278             SDK_CONFIG_MEMORY_BARRIER; 
    279         }
    280     }
    281     return rv;
    282 }
    283 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
    284 
    285 /*
    286  * Function:
    287  *      soc_dma_abort_channel
    288  * Purpose:
    289  *      Abort currently active DMA on the specified channel.
    290  * Parameters:
    291  *      unit - SOC unit #
    292  *      vchan - Virtual channel number to abort.
    293  * Returns:
    294  *      SOC_E_NONE   - Success
    295  *      SOC_E_TIMEOUT - failed (Timeout)
    296  * Notes:
    297  *      This routine does not dequeue any operation, only
    298  *      terminate activity on the specified channel.
    299  *
    300  *      No check is made for active operation, but this
    301  *      routine should succeed regardless. Assumes SOC_DMA_LOCK
    302  *      held for manipulation of CMIC_DMA_CTRL.
    303  */
    304 
    305 STATIC int
    306 soc_dma_abort_channel(int unit, dma_chan_t vchan)
    307 {
    308 
    309     int                 rv = SOC_E_NONE;
    310 #ifdef INCLUDE_KNET
    311     uint8               shutdown_knet = TRUE;
    312 #endif
    313 
    314     LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
    315              (BSL_META_U(unit,
    316                          "soc_dma_abort_channel: c=%d\n"), vchan));
    317 
    318 #ifdef INCLUDE_KNET
    319     if (SOC_KNET_MODE(unit)) {
    320         if (soc_property_get(unit, spn_WARMBOOT_KNET_SHUTDOWN_MODE, 0)) {
    321             shutdown_knet = FALSE;
    322         }
    323         if (shutdown_knet) {
    324             return soc_knet_hw_reset(unit, vchan);
    325         } else {
    326             return soc_knet_wb_cleanup(unit);
    327         }
    328     }
    329 #endif
    330 
    331     /*
    332      * Write the abort, wait for active to clear, then clear abort.
    333      */
    334 
    335     rv = cmic_drv[unit].chan_abort(unit, vchan);
    336 
    337 #ifdef  BCM_XGS3_SWITCH_SUPPORT
    338     /*
    339      * Send a purge packet to flush any partial packet in the ingress
    340      * for TX DMA channel abvort
    341      */
    342     if (!(SAL_BOOT_SIMULATION) && (rv >= 0) &&
    343         (soc_dma_chan_dvt_get(unit, vchan) == DV_TX)) {
    344         rv = soc_dma_tx_purge(unit, vchan);
    345     }
    346 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
    347 
    348     return rv;
    349 }
    350 
    351 /*
    352  * Function:
    353  *      soc_dma_abort_dv
    354  * Purpose:
    355  *      Abort active DMA operations.
    356  * Parameters:
    357  *      unit - unit number to abort DMA on
    358  *      dv - dv chain to abort.
    359  * Returns:
    360  *      SOC_E_NONE - Operation aborted.
    361  *      SOC_E_TIMEOUT - operation not located, or time-out waiting
    362  *                      for abort.
    363  */
    364 
    365 int
    366 soc_dma_abort_dv(int unit, dv_t *dv_chain)
    367 {
    368     uint32        soc_dma_lock;
    369     soc_control_t *soc = SOC_CONTROL(unit);
    370     sdc_t         *sc;
    371     int           rv;
    372 
    373     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
    374                 (BSL_META_U(unit,
    375                             "Aborting DV: c=%d dv=%p\n"),
    376                  dv_chain->dv_channel, (void *)dv_chain));
    377 
    378     SOC_DMA_LOCK(soc_dma_lock); /* Be sure nothing changes */
    379     if ((dv_chain->dv_channel < 0) ||
    380         (dv_chain->dv_channel >= soc->soc_dma_channels)) {
    381         SOC_DMA_UNLOCK(soc_dma_lock);
    382         return (SOC_E_TIMEOUT);
    383     }
    384 
    385     sc = &soc->soc_channels[dv_chain->dv_channel];
    386 
    387     /*
    388      * Check if active operation. soc_dma_start_channel will update the
    389      * dv_active field if the operation is active, otherwise it is not
    390      * required to update it.
    391      */
    392     if (sc->sc_q == NULL) {
    393         rv = SOC_E_TIMEOUT;
    394     } else if (dv_chain == sc->sc_q) {
    395         rv = soc_dma_abort_channel(unit, sc->sc_channel);
    396         sc->sc_q = dv_chain->dv_next;   /* Remove from Queue */
    397         sc->sc_q_cnt--;                 /* Decrement current Q length */
    398         /* Updates state and active values */
    399         soc_dma_start_channel(unit, sc); /* Try to start next operation */
    400     } else {
    401         dv_t    *dv;
    402         /*
    403          * Look down list for operation, if not found, it may have completed
    404          * already.
    405          */
    406         for (dv = sc->sc_q;
    407              (dv->dv_next != dv_chain) && (dv->dv_next != NULL);
    408              dv = dv->dv_next)
    409             ;
    410         if (dv->dv_next == dv_chain) {
    411             dv->dv_next = dv->dv_next->dv_next; /* Off list */
    412             if (sc->sc_q_tail == dv_chain) { /* was on tail? */
    413                 sc->sc_q_tail = dv;          /* then make previous on tail */
    414             }
    415             sc->sc_q_cnt--;
    416             rv = SOC_E_NONE;
    417         } else {
    418             rv = SOC_E_TIMEOUT;
    419         }
    420     }
    421 
    422     SOC_DMA_UNLOCK(soc_dma_lock);
    423     return (rv);
    424 }
    425 
    426 /*
    427  * Function:
    428  *      soc_dma_abort_channel_total
    429  * Purpose:
    430  *      Abort ALL active DMA on the specified channel.
    431  * Parameters:
    432  *      unit - SOC unit #
    433  *      vchan - Virtual channel number to abort.
    434  * Returns:
    435  *      # of operations aborted.
    436  * Notes:
    437  *      This routine _does_ dequeue any operations on the channel.
    438  */
    439 int
    440 soc_dma_abort_channel_total(int unit, dma_chan_t vchan)
    441 {
    442     uint32        soc_dma_lock;
    443     soc_control_t *soc = SOC_CONTROL(unit);
    444     sdc_t         *sc;    /* Channel pointer */
    445     int           rv = 0; /* Return value */
    446 
    447     SOC_DMA_LOCK(soc_dma_lock); /* Be sure nothing changes */
    448     sc = &soc->soc_channels[vchan];
    449     soc_dma_abort_channel(unit, vchan);
    450 
    451     /* Clear up all queued DMA operations */
    452 
    453     while (sc->sc_q != NULL) {
    454         assert(sc->sc_q->dv_channel >= 0);
    455         sc->sc_q->dv_channel = -sc->sc_q->dv_channel;
    456         sc->sc_q = sc->sc_q->dv_next;
    457         sc->sc_q_cnt--;
    458         rv++;
    459     }
    460     sc->sc_dv_active = NULL;
    461     sc->sc_q_tail   = NULL;
    462     assert(sc->sc_q == NULL);
    463     assert(sc->sc_q_cnt == 0);
    464     SOC_DMA_UNLOCK(soc_dma_lock);
    465     return rv;
    466 }
    467 
    468 /*
    469  * Function:
    470  *      soc_dma_abort
    471  * Purpose:
    472  *      Abort ALL dma active on a CMIC.
    473  * Parameters:
    474  *      unit - unit #.
    475  * Returns:
    476  *      # of operations aborted.
    477  */
    478 
    479 int
    480 soc_dma_abort(int unit)
    481 {
    482     soc_control_t       *soc = SOC_CONTROL(unit);
    483     dma_chan_t          vchan;                     /* Channel # */
    484     int                 rv = 0;        /* Return value */
    485 
    486     for (vchan = 0; vchan < soc->soc_dma_channels; vchan++) {
    487         rv += soc_dma_abort_channel_total(unit, vchan);
    488     }
    489     return (rv);
    490 }
    491 
    492 #define DP_FMT  "%sdata[%04x]: "        /* dump line start format */
    493 #define DP_HDR  "%sheader[%04x]: "      /* dump header */
    494 #define DP_BPL  16                      /* dumped bytes per line */
    495 
    496 /*
    497  * Function:
    498  *      soc_dma_higig_dump
    499  * Purpose:
    500  *      Dump the HIGIG header of a packet in human readable form
    501  * Parameters:
    502  *      pfx - prefix for all output strings
    503  *      addr - pointer to data bytes of packet
    504  *      len - length of data to dump
    505  *      ether_offset - (OUT) return offset of start of ether packet
    506  * Returns:
    507  *      Nothing
    508  */
    509 
    510 #if defined(BCM_XGS_FABRIC_SUPPORT) || defined(BCM_XGS3_SWITCH_SUPPORT) || defined(BCM_PETRA_SUPPORT) || defined(BCM_DNX_SUPPORT)
    511 void
    512 soc_dma_higig_dump(int unit, char *pfx, uint8 *addr, int len, int pkt_len,
    513                    int *ether_offset)
    514 {
    515     soc_higig_hdr_t *xgh = (soc_higig_hdr_t *)addr;
    516 
    517     if (soc_higig_field_get(unit, xgh, HG_hgi) == SOC_HIGIG_HGI) {
    518         if (!len) {
    519             len = pkt_len + SOC_HIGIG_HDR_SIZE;
    520         }
    521         LOG_CLI((BSL_META_U(unit,
    522                             "%sHIGIG Frame:"
    523                  " len=%d (header=%d payload=%d)\n"),
    524                  pfx, len, SOC_HIGIG_HDR_SIZE,
    525                  len - SOC_HIGIG_HDR_SIZE));
    526         soc_higig_dump(unit, pfx, xgh);
    527         LOG_CLI((BSL_META_U(unit,
    528                             "%s802.3 Ether-II VLAN-Tagged Payload (%d bytes)\n"),
    529                  pfx, len - SOC_HIGIG_HDR_SIZE));
    530 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT)
    531     } else if ((SOC_IS_TRIUMPH3(unit) || SOC_IS_TD2_TT2(unit) ||
    532                         SOC_IS_HURRICANE2(unit) || SOC_IS_KATANA2(unit) ||
    533                         SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) ||
    534                         SOC_IS_GREYHOUND2(unit)) &&
    535                (soc_pbsmh_field_get(unit,
    536                     (soc_pbsmh_hdr_t *)xgh,
    537                      PBSMH_start) == SOC_PBSMH_START_INTERNAL)) {
    538 
    539         soc_pbsmh_dump(unit, pfx, (soc_pbsmh_hdr_t *)xgh);
    540 #endif  /* BCM_TRIUMPH3_SUPPORT */
    541 #ifdef  BCM_XGS3_SWITCH_SUPPORT
    542     } else if ((SOC_IS_XGS3_SWITCH(unit)) &&
    543                (soc_pbsmh_field_get(unit,
    544                                     (soc_pbsmh_hdr_t *)xgh,
    545                                     PBSMH_start) == SOC_PBSMH_START)) {
    546         soc_pbsmh_dump(unit, pfx, (soc_pbsmh_hdr_t *)xgh);
    547 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
    548 #ifdef BCM_HIGIG2_SUPPORT
    549     } else if (soc_feature(unit, soc_feature_higig2) ||
    550                soc_feature(unit, soc_feature_rx_pkt_hdr_format_higig2)) {
    551         /* Not Higig/Higig+/PBS - assume Higig2 */
    552         if (!len) {
    553             len = pkt_len + SOC_HIGIG2_HDR_SIZE;
    554         }
    555         LOG_CLI((BSL_META_U(unit,
    556                             "%sHIGIG2 Frame:"
    557                  " len=%d (header=%d payload=%d)\n"),
    558                  pfx, len, SOC_HIGIG2_HDR_SIZE,
    559                  len - SOC_HIGIG2_HDR_SIZE));
    560         soc_higig2_dump(unit, pfx, (soc_higig2_hdr_t *)xgh);
    561         LOG_CLI((BSL_META_U(unit,
    562                             "%s802.3 Ether-II VLAN-Tagged Payload (%d bytes)\n"),
    563                  pfx, len - SOC_HIGIG2_HDR_SIZE));
    564 #endif /* BCM_HIGIG2_SUPPORT */
    565 #ifdef BCM_XGS_SUPPORT
    566     } else if (xgh->overlay1.hgi == SOC_BCM5632_HGI) {
    567         soc_bcm5632_hdr_t *bhdr = (soc_bcm5632_hdr_t *)addr;
    568         if (!len) {
    569             len = pkt_len + SOC_BCM5632_HDR_SIZE;
    570         }
    571         /* BCM5632 format */
    572         LOG_CLI((BSL_META_U(unit,
    573                             "%sBCM5632 Frame:"
    574                  " len=%d (header=%d payload=%d)\n"),
    575                  pfx, len, SOC_BCM5632_HDR_SIZE,
    576                  len - SOC_BCM5632_HDR_SIZE));
    577         LOG_CLI((BSL_META_U(unit,
    578                             "%s0x%02x%02x%02x%02x <D_PORTID=%d>\n"),
    579                  pfx,
    580                  bhdr->overlay0.bytes[0],
    581                  bhdr->overlay0.bytes[1],
    582                  bhdr->overlay0.bytes[2],
    583                  bhdr->overlay0.bytes[3],
    584                  bhdr->overlay1.d_portid));
    585         LOG_CLI((BSL_META_U(unit,
    586                             "%s0x%02x%02x%02x%02x <S_PORTID=%d> "
    587                  "<LEN=%d> START=<0x%x>\n"),
    588                  pfx,
    589                  bhdr->overlay0.bytes[4],
    590                  bhdr->overlay0.bytes[5],
    591                  bhdr->overlay0.bytes[6],
    592                  bhdr->overlay0.bytes[7],
    593                  bhdr->overlay1.s_portid,
    594                  (bhdr->overlay1.length_hi << 8 |
    595                  bhdr->overlay1.length_lo),
    596                  bhdr->overlay1.start));
    597 #endif /* BCM_XGS_SUPPORT */
    598     }
    599 
    600     /* Calculate ether_offset if given */
    601     if (ether_offset) {
    602 #ifdef BCM_HIGIG2_SUPPORT
    603         if (soc_higig_field_get(unit, xgh, HG_start) == SOC_HIGIG2_START) {
    604             *ether_offset = sizeof(soc_higig2_hdr_t);
    605         } else
    606 #endif
    607         if (soc_higig_field_get(unit, xgh, HG_hgi) == SOC_HIGIG_HGI) {
    608             *ether_offset = sizeof(soc_higig_hdr_t);
    609 #ifdef BCM_XGS_SUPPORT
    610         } else if (xgh->overlay1.hgi == SOC_BCM5632_HGI) {
    611             *ether_offset = sizeof (soc_bcm5632_hdr_t);
    612 #endif /* BCM_XGS_SUPPORT */
    613         } else {
    614             *ether_offset = 0;
    615         }
    616     }
    617 }
    618 #endif /* defined(BCM_XGS_FABRIC_SUPPORT) || defined(BCM_XGS3_SWITCH_SUPPORT) */
    619 
    620 
    621 void
    622 soc_dma_ether_dump(int unit, char *pfx, uint8 *addr, int len, int offset)
    623 {
    624     int         i = 0, j;
    625 
    626 
    627     if (addr == 0) {
    628         LOG_CLI((BSL_META_U(unit,
    629                             "Bad packet ADDR!!\n")));
    630         return;
    631     }
    632 
    633     if (len > DP_BPL && (DP_BPL & 1) == 0) {
    634         char    linebuf[128], *s;
    635         /* Show first line with MAC addresses in curly braces */
    636         s = linebuf;
    637         sal_sprintf(s, DP_FMT "{", pfx, i);
    638         while (*s != 0) s++;
    639         for (i = offset; i < offset + 6; i++) {
    640             sal_sprintf(s, "%02x", addr[i]);
    641             while (*s != 0) s++;
    642         }
    643         sal_sprintf(s, "} {");
    644         while (*s != 0) s++;
    645         for (; i < offset + 12; i++) {
    646             sal_sprintf(s, "%02x", addr[i]);
    647             while (*s != 0) s++;
    648         }
    649         sal_sprintf(s, "}");
    650         while (*s != 0) s++;
    651         for (; i < offset + DP_BPL; i += 2) {
    652             sal_sprintf(s, " %02x%02x", addr[i], addr[i + 1]);
    653             while (*s != 0) s++;
    654         }
    655         LOG_CLI((BSL_META_U(unit,
    656                             "%s\n"), linebuf));
    657     }
    658 
    659     for (; i < len; i += DP_BPL) {
    660         char    linebuf[128], *s;
    661         s = linebuf;
    662         sal_sprintf(s, DP_FMT, pfx, i);
    663         while (*s != 0) s++;
    664         for (j = i; j < i + DP_BPL && j < len; j++) {
    665             sal_sprintf(s, "%02x%s", addr[j], j & 1 ? " " : "");
    666             while (*s != 0) s++;
    667         }
    668         LOG_CLI((BSL_META_U(unit,
    669                             "%s\n"), linebuf));
    670     }
    671 
    672 }
    673 
    674 void
    675 soc_dma_ep_to_cpu_hdr_dump(int unit, char *pfx, uint8 *addr, int len, int offset)
    676 {
    677     int         i, j;
    678     uint8       hdr[96];
    679 #ifdef  LE_HOST
    680     int         word = 0;
    681     uint8       temp = 0;
    682 #endif
    683 
    684     if (addr == 0) {
    685         LOG_CLI((BSL_META_U(unit,
    686                             "Bad Header ADDR!!\n")));
    687         return;
    688     }
    689 
    690     sal_memcpy(hdr, addr, len);
    691 #ifdef  LE_HOST
    692     for (word = 0; word < BYTES2WORDS(len); word++) {
    693         temp = hdr[(word * 4) + 0];
    694         hdr[(word * 4) + 0] = hdr[(word * 4) + 3];
    695         hdr[(word * 4) + 3] = temp;
    696 
    697         temp = hdr[(word * 4) + 1];
    698         hdr[(word * 4) + 1] = hdr[(word * 4) + 2];
    699         hdr[(word * 4) + 2] = temp;
    700 
    701     }
    702 #endif
    703 
    704     for (i = offset; i < len; i += DP_BPL) {
    705         char    linebuf[128], *s;
    706         s = linebuf;
    707         sal_sprintf(s, DP_HDR, pfx, i);
    708         while (*s != 0) s++;
    709         for (j = i; j < i + DP_BPL && j < len; j++) {
    710             sal_sprintf(s, "%02x%s", hdr[j], j & 1 ? " " : "");
    711             while (*s != 0) s++;
    712         }
    713         LOG_CLI((BSL_META_U(unit,
    714                             "%s\n"), linebuf));
    715     }
    716 
    717 }
    718 
    719 void
    720 soc_dma_usage_get(int unit)
    721 {
    722 #if !defined(__KERNEL__)
    723     int sz;
    724     extern int _dma_get_usage(void) __attribute__ ((weak));
    725 
    726     sz = _dma_get_usage();
    727 
    728     LOG_CLI((BSL_META_U(unit,
    729                        "DMA memory usage : %d (%dk)\n"), sz, sz/1024));
    730 #endif
    731 }
    732 
    733 /*
    734  * Function:
    735  *      soc_dma_dump_rx_pkt
    736  * Purpose:
    737  *      Dump packet data in human readable form with packet watch layout
    738  * Parameters:
    739  *      pfx - prefix for all output strings
    740  *      dcb     - dma control block
    741  * Returns:
    742  *      Nothing
    743  */
    744 
    745 void
    746 soc_dma_dump_rx_pkt(int unit, char *pfx, dcb_t *dcb)
    747 {
    748     /* for alignment packet watch packet format */
    749     char prefix[64];
    750     uint8 rx_untagged;                  /* The packet was untagged on ingress. */
    751     rx_untagged = SOC_DCB_RX_UNTAGGED_GET(unit, dcb);
    752 
    753     sal_sprintf(prefix, "%s Packet: ", pfx);
    754 
    755     LOG_CLI((BSL_META_U(unit,
    756                          "%s length %d. rx-port %d. cos %d. prio_int %d. vlan %d. reason 0x%x. %s.\n"),
    757                          prefix,
    758                          SOC_DCB_XFERCOUNT_GET(unit, dcb),
    759                          SOC_DCB_RX_INGPORT_GET(unit, dcb),
    760                          SOC_DCB_RX_COS_GET(unit, dcb),
    761                          SOC_DCB_RX_PRIO_GET(unit, dcb),
    762                          SOC_DCB_RX_OUTER_VID_GET(unit, dcb),
    763                          SOC_DCB_RX_REASON_GET(unit, dcb),
    764                          (rx_untagged & 0x1) ?
    765                          ((rx_untagged & 0x2) ? "Untagged" : "Inner tagged") :
    766                          ((rx_untagged & 0x2) ? "Outer tagged" : "Double tagged")
    767                          ));
    768     LOG_CLI((BSL_META_U(unit,
    769                          "%s dest-gport %d. dest-mod %d. src-gport %d. src-mod %d. opcode %d. matched %d. classification-tag %d.\n"),
    770                          prefix,
    771                          SOC_DCB_RX_DESTPORT_GET(unit, dcb),
    772                          SOC_DCB_RX_DESTMOD_GET(unit, dcb),
    773                          SOC_DCB_RX_SRCPORT_GET(unit, dcb),
    774                          SOC_DCB_RX_SRCMOD_GET(unit, dcb),
    775                          SOC_DCB_RX_OPCODE_GET(unit, dcb),
    776                          SOC_DCB_RX_MATCHRULE_GET(unit, dcb),
    777                          SOC_DCB_RX_CLASSTAG_GET(unit, dcb)
    778                          ));
    779     SOC_DCB_REASON_DUMP(unit, dcb, prefix);
    780 }
    781 
    782 /*
    783  * Function:
    784  *      soc_dma_dump_pkt
    785  * Purpose:
    786  *      Dump packet data in human readable form
    787  * Parameters:
    788  *      pfx - prefix for all output strings
    789  *      addr - pointer to data bytes of packet
    790  *      len - length of data to dump
    791  *      decode - assume this is start of packet and decode fields
    792  * Returns:
    793  *      Nothing
    794  */
    795 
    796 void
    797 soc_dma_dump_pkt(int unit, char *pfx, uint8 *addr, int len, int decode)
    798 {
    799     int ether_offset;
    800 
    801     COMPILER_REFERENCE(unit);
    802 
    803     if (!addr || !pfx) {
    804         LOG_CLI((BSL_META_U(unit,
    805                             "<ERROR>\n")));
    806         return;
    807     }
    808 
    809     if (len == 0) {
    810         LOG_CLI((BSL_META_U(unit,
    811                             DP_FMT "<NONE>\n"), pfx, 0));
    812     }
    813 
    814     ether_offset = 0;
    815 
    816 #ifdef BCM_HERCULES_SUPPORT
    817     /* All hercules chips have module header prepended to frame */
    818     if (SOC_IS_HERCULES(unit) && decode) {
    819         soc_dma_higig_dump(unit, pfx, addr, len, 0, &ether_offset);
    820     }
    821 #endif /* BCM_HERCULES_SUPPORT */
    822 
    823     soc_dma_ether_dump(unit, pfx, addr, len, ether_offset);
    824 }
    825 
    826 #undef DP_FMT
    827 #undef DP_BPL
    828 
    829 /*
    830  * Function:
    831  *      soc_dma_dv_valid
    832  * Purpose:
    833  *      Check if a DV is (probably) valid
    834  * Parameters:
    835  *      dv - The dv to examine
    836  * Returns:
    837  *      BCM_E_XXX
    838  * Notes:
    839  *      Does not guarantee a DV is valid, but will detect
    840  *      most _invalid_ DVs.
    841  */
    842 
    843 int
    844 soc_dma_dv_valid(dv_t *dv)
    845 {
    846     if (dv->dv_magic != DV_MAGIC_NUMBER) {
    847         return FALSE;
    848     }
    849 
    850     return TRUE;
    851 }
    852 
    853 /*
    854  * Function:
    855  *      soc_dma_dv_cnt_valid
    856  * Purpose:
    857  *      Check if the cnt of the dv are valid
    858  * Parameters:
    859  *      dv - The dv to examine
    860  * Returns:
    861  *      BCM_E_XXX
    862  */
    863 
    864 static int
    865 soc_dma_dv_cnt_valid(int unit, dv_t *dv)
    866 {
    867     assert(dv != NULL);
    868     if (dv->dv_cnt < 0 || dv->dv_dcnt < 0 || dv->dv_vcnt < 0 ||
    869         dv->dv_cnt < dv->dv_dcnt ||
    870         dv->dv_cnt < dv->dv_vcnt) {
    871         LOG_WARN(BSL_LS_SOC_COMMON,
    872                  (BSL_META_U(unit,
    873                              "unit=%d, "
    874                              "dv->dv_cnt=%d, dv->dv_dcnt=%d, dv->dv_vcnt=%d"),
    875                   unit, dv->dv_cnt, dv->dv_dcnt, dv->dv_vcnt));
    876         return FALSE;
    877     }
    878     return TRUE;
    879 }
    880 
    881 /*
    882  * Function:
    883  *      soc_dma_dump_dv
    884  * Purpose:
    885  *      Dump a "dv" structure and all the DCB fields.
    886  * Parameters:
    887  *      dv_chain - pointer to dv list to dump.
    888  * Returns:
    889  *      Nothing.
    890  */
    891 
    892 void
    893 soc_dma_dump_dv(int unit, char *pfx, dv_t *dv_chain)
    894 {
    895     static char *channel[] = {"0","1","2","3"};
    896     char        tmps[128];
    897     char        *op_name;
    898     int         i;
    899     dv_t        *dv;
    900     char *      chan_str;
    901     int len = 0;
    902     int len_tmps = 0;
    903 
    904     for (dv = dv_chain; dv; dv = dv->dv_chain) {
    905 
    906         if (!soc_dma_dv_valid(dv)) {
    907             LOG_CLI((BSL_META_U(unit,
    908                                 "%sdv@%p appears invalid\n"), pfx, (void *)dv));
    909             break;
    910         }
    911 
    912         switch(dv_chain->dv_op) {
    913         case DV_NONE:   op_name = "None";       break;
    914         case DV_TX:     op_name = "TX";         break;
    915         case DV_RX:     op_name = "RX";         break;
    916         default:        op_name = "*ERR*";      break;
    917         }
    918 
    919         tmps[0] = '\0';
    920         len_tmps = sal_strlen(tmps);
    921 
    922         if (dv_chain->dv_flags & DV_F_NOTIFY_DSC) {
    923             len = sal_strlen("notify-dsc ");
    924             sal_strncpy(tmps + len_tmps , "notify-dsc ", len);
    925             *(tmps + len_tmps + len) = '\0';
    926         }
    927         if (dv_chain->dv_flags & DV_F_NOTIFY_CHN) {
    928             len = sal_strlen("notify-chn ");
    929             sal_strncpy(tmps + len_tmps, "notify-chn ", len);
    930             *(tmps + len_tmps + len) = '\0';
    931         }
    932         if (dv_chain->dv_done_packet) {
    933             len = sal_strlen("notify-pkt ");
    934             sal_strncpy(tmps + len_tmps, "notify-pkt ", len);
    935             *(tmps + len_tmps + len) = '\0';
    936         }
    937         if (dv_chain->dv_flags & DV_F_COMBINE_DCB) {
    938             len = sal_strlen("combine-dcb ");
    939             sal_strncpy(tmps + len_tmps, "combine-dcb ", len);
    940             *(tmps + len_tmps + len) = '\0';
    941         }
    942 
    943         LOG_CLI((BSL_META_U(unit,
    944                             "%sdv@%p unit %d dcbtype-%d op=%s vcnt=%d dcnt=%d "
    945                  "cnt=%d\n"),
    946                  pfx, (void *)dv, unit, SOC_DCB_TYPE(unit),
    947                  op_name, dv->dv_vcnt, dv->dv_dcnt, dv->dv_cnt));
    948         if (dv->dv_channel == -1) {
    949             chan_str = "any";
    950         } else if  (dv->dv_channel < -1 || dv->dv_channel > 3) {
    951             chan_str = "illegal";
    952         } else {
    953             chan_str = channel[dv->dv_channel];
    954         }
    955         LOG_CLI((BSL_META_U(unit,
    956                             "%s    chan=%s chain=%p flags=0x%x-->%s\n"),
    957                  pfx, chan_str,
    958                  (void *)dv->dv_chain,
    959                  dv->dv_flags, tmps));
    960         LOG_CLI((BSL_META_U(unit,
    961                             "%s    user1 %p. user2 %p. user3 %p. user4 %p\n"),
    962                  pfx, dv->dv_public1.ptr, dv->dv_public2.ptr,
    963                  dv->dv_public3.ptr, dv->dv_public4.ptr));
    964         if (dv->tx_param.flags != 0) {
    965             soc_tx_param_t *prm = &dv->tx_param;
    966             LOG_CLI((BSL_META_U(unit,
    967                                 "%s    tx-param flags 0x%x cos %d sp.sm %d.%d\n"),
    968                      pfx, prm->flags, prm->cos, prm->src_port,
    969                      prm->src_mod));
    970         }
    971         for (i = 0; i < dv->dv_vcnt; i++) {
    972             dcb_t         *dcb;
    973             sal_vaddr_t   addr;
    974             int decode = 0;
    975 
    976             dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i);
    977             addr = SOC_DCB_ADDR_GET(unit, dcb);
    978             LOG_CLI((BSL_META_U(unit,
    979                                 "%sdcb[%d] @%p:\n"), pfx, i, dcb));
    980 #ifdef BROADCOM_DEBUG
    981             SOC_DCB_DUMP(dv->dv_unit, dcb, pfx,
    982                          (dv_chain->dv_op == DV_TX) ? 1 : 0);
    983 #endif /* BROADCOM_DEBUG */
    984             decode = (i == 0 ||
    985                       !SOC_DCB_SG_GET(dv->dv_unit,
    986                                       SOC_DCB_IDX2PTR(dv->dv_unit,
    987                                                       dv->dv_dcb, i - 1)));
    988 
    989             if (dv->dv_op == DV_TX) {
    990                 if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityNormal, unit)) {
    991                     LOG_VERBOSE(BSL_LS_SOC_TX,
    992                                 (BSL_META_U(unit,
    993                                             "soc_dma_dump_pkt: Tx DV infomation\n")));
    994                     soc_dma_dump_pkt(unit, pfx, (uint8 *) addr,
    995                                      SOC_DCB_REQCOUNT_GET(unit, dcb),
    996                                  decode);
    997                 }
    998             } else if (dv->dv_op == DV_RX && SOC_DCB_DONE_GET(unit, dcb)) {
    999                 if (bsl_check(bslLayerSoc, bslSourceRx, bslSeverityNormal, unit)) {
   1000                     LOG_VERBOSE(BSL_LS_SOC_RX,
   1001                                 (BSL_META_U(unit,
   1002                                             "soc_dma_dump_pkt: Rx DV infomation\n")));
   1003 
   1004 #if defined(BCM_CMICX_SUPPORT)
   1005                     if (soc_feature(unit, soc_feature_cmicx)) {
   1006                         uint32 hdr_size = 0;
   1007                         soc_dma_header_size_get(unit, &hdr_size);
   1008 
   1009                         soc_dma_ep_to_cpu_hdr_dump(unit, pfx, (uint8 *) addr, hdr_size, 0);
   1010 
   1011                         soc_dma_dump_pkt(unit, pfx, (uint8 *) (addr + hdr_size),
   1012                                      SOC_DCB_XFERCOUNT_GET(unit, dcb) - hdr_size,
   1013                                      decode);
   1014                     } else
   1015 #endif
   1016                     {
   1017                         soc_dma_dump_pkt(unit, pfx, (uint8 *) addr,
   1018                                      SOC_DCB_XFERCOUNT_GET(unit, dcb),
   1019                                      decode);
   1020                     }
   1021                     LOG_VERBOSE(BSL_LS_SOC_RX,
   1022                                 (BSL_META_U(unit,
   1023                                             "soc_dma_dump_rx_pkt: Rx packet infomation\n")));
   1024                     soc_dma_dump_rx_pkt(unit, pfx, dcb);
   1025                 }
   1026             }
   1027         }
   1028     }
   1029 }
   1030 
   1031 void
   1032 soc_dma_dump_dv_dcb(int unit, char *pfx, dv_t *dv_chain, int index) /* , dcb_t *dcb) */
   1033 {
   1034     static char *channel[] = {"0","1","2","3"};
   1035     char        tmps[128];
   1036     char        *op_name;
   1037     int         i;
   1038     dv_t        *dv;
   1039     char *      chan_str;
   1040     int len = 0;
   1041     int len_tmps = 0;
   1042 
   1043     dv = dv_chain;
   1044     {
   1045         if (!soc_dma_dv_valid(dv)) {
   1046             LOG_CLI((BSL_META_U(unit,
   1047                                 "%sdv@%p appears invalid\n"), pfx, (void *)dv));
   1048             return ;
   1049         }
   1050         switch(dv_chain->dv_op) {
   1051         case DV_NONE:   op_name = "None";       break;
   1052         case DV_TX:     op_name = "TX";         break;
   1053         case DV_RX:     op_name = "RX";         break;
   1054         default:        op_name = "*ERR*";      break;
   1055         }
   1056         tmps[0] = '\0';
   1057         len_tmps = sal_strlen(tmps);
   1058 
   1059         if (dv_chain->dv_flags & DV_F_NOTIFY_DSC) {
   1060             len = sal_strlen("notify-dsc ");
   1061             sal_strncpy(tmps + len_tmps , "notify-dsc ", len);
   1062             *(tmps + len_tmps + len) = '\0';
   1063         }
   1064         if (dv_chain->dv_flags & DV_F_NOTIFY_CHN) {
   1065             len = sal_strlen("notify-chn ");
   1066             sal_strncpy(tmps + len_tmps, "notify-chn ", len);
   1067             *(tmps + len_tmps + len) = '\0';
   1068         }
   1069         if (dv_chain->dv_done_packet) {
   1070             len = sal_strlen("notify-pkt ");
   1071             sal_strncpy(tmps + len_tmps, "notify-pkt ", len);
   1072             *(tmps + len_tmps + len) = '\0';
   1073         }
   1074         if (dv_chain->dv_flags & DV_F_COMBINE_DCB) {
   1075             len = sal_strlen("combine-dcb ");
   1076             sal_strncpy(tmps + len_tmps, "combine-dcb ", len);
   1077             *(tmps + len_tmps + len) = '\0';
   1078         }
   1079 
   1080         LOG_CLI((BSL_META_U(unit,
   1081                             "%sdv@%p unit %d dcbtype-%d op=%s vcnt=%d dcnt=%d "
   1082                  "cnt=%d\n"),
   1083                  pfx, (void *)dv, unit, SOC_DCB_TYPE(unit),
   1084                  op_name, dv->dv_vcnt, dv->dv_dcnt, dv->dv_cnt));
   1085         if (dv->dv_channel == -1) {
   1086             chan_str = "any";
   1087         } else if  (dv->dv_channel < -1 || dv->dv_channel > 3) {
   1088             chan_str = "illegal";
   1089         } else {
   1090             chan_str = channel[dv->dv_channel];
   1091         }
   1092         LOG_CLI((BSL_META_U(unit,
   1093                             "%s    chan=%s chain=%p flags=0x%x-->%s\n"),
   1094                  pfx, chan_str,
   1095                  (void *)dv->dv_chain,
   1096                  dv->dv_flags, tmps));
   1097         LOG_CLI((BSL_META_U(unit,
   1098                             "%s    user1 %p. user2 %p. user3 %p. user4 %p\n"),
   1099                  pfx, dv->dv_public1.ptr, dv->dv_public2.ptr,
   1100                  dv->dv_public3.ptr, dv->dv_public4.ptr));
   1101         if (dv->tx_param.flags != 0) {
   1102             soc_tx_param_t *prm = &dv->tx_param;
   1103             LOG_CLI((BSL_META_U(unit,
   1104                                 "%s    tx-param flags 0x%x cos %d sp.sm %d.%d\n"),
   1105                      pfx, prm->flags, prm->cos, prm->src_port,
   1106                      prm->src_mod));
   1107         }
   1108         i= index;
   1109         {
   1110             dcb_t         *dcb;
   1111             sal_vaddr_t   addr;
   1112             dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i);
   1113             addr = SOC_DCB_ADDR_GET(unit, dcb);
   1114             LOG_CLI((BSL_META_U(unit,
   1115                                 "%sdcb[%d] @%p:\n"), pfx, i, dcb));
   1116 #ifdef BROADCOM_DEBUG
   1117             SOC_DCB_DUMP(dv->dv_unit, dcb, pfx,
   1118                          (dv_chain->dv_op == DV_TX) ? 1 : 0);
   1119 #endif /* BROADCOM_DEBUG */
   1120             {
   1121                 int decode;
   1122                 decode = (i == 0 ||
   1123                           !SOC_DCB_SG_GET(dv->dv_unit,
   1124                                           SOC_DCB_IDX2PTR(dv->dv_unit,
   1125                                                           dv->dv_dcb, i - 1)));
   1126                 if (dv->dv_op == DV_TX) {
   1127                     if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityNormal, unit)) {
   1128                         LOG_VERBOSE(BSL_LS_SOC_TX,
   1129                                     (BSL_META_U(unit,
   1130                                                 "soc_dma_dump_pkt: DV_TX infomation\n")));
   1131                         soc_dma_dump_pkt(unit, pfx, (uint8 *) addr,
   1132                                          SOC_DCB_REQCOUNT_GET(unit, dcb),
   1133                                          decode);
   1134                     }
   1135                 } else if (dv->dv_op == DV_RX && SOC_DCB_DONE_GET(unit, dcb)) {
   1136                     if (bsl_check(bslLayerSoc, bslSourceRx, bslSeverityNormal, unit)) {
   1137                         LOG_VERBOSE(BSL_LS_SOC_RX,
   1138                                     (BSL_META_U(unit,
   1139                                                 "soc_dma_dump_pkt: DV_RX infomation\n")));
   1140                          soc_dma_dump_pkt(unit, pfx, (uint8 *) addr,
   1141                                           SOC_DCB_XFERCOUNT_GET(unit, dcb),
   1142                                           decode);
   1143                          LOG_VERBOSE(BSL_LS_SOC_RX,
   1144                                      (BSL_META_U(unit,
   1145                                                 "soc_dma_dump_rx_pkt: Rx packet infomation\n")));
   1146                          soc_dma_dump_rx_pkt(unit, pfx, dcb);
   1147                     }
   1148                 }
   1149             }
   1150         }
   1151     }
   1152 }
   1153 
   1154 /*
   1155  * Function:
   1156  *      soc_dma_start_dv (internal)
   1157  * Purpose:
   1158  *      Main part of soc_dma_start function.
   1159  * Parameters:
   1160  *      unit - StrataSwitch unit #.
   1161  *      sc - Pointer to channel structure to start
   1162  *      dv_chain - pointer to DV chain to start.
   1163  * Returns:
   1164  *      SOC_E_XXX.
   1165  */
   1166 
   1167 STATIC int
   1168 soc_dma_start_dv(int unit, sdc_t *sc, dv_t *dv_chain)
   1169 {
   1170     uint32        soc_dma_lock;
   1171     int           i;
   1172     dv_t          *dv;
   1173     dcb_t         *dcb;
   1174     int           rv = SOC_E_NONE;
   1175 
   1176     assert(sc->sc_type == dv_chain->dv_op);
   1177     assert(!(dv_chain->dv_flags & DV_F_NOTIFY_CHN) ||
   1178            dv_chain->dv_done_chain);
   1179     assert(!(dv_chain->dv_flags & DV_F_NOTIFY_DSC) ||
   1180            dv_chain->dv_done_desc);
   1181 
   1182 #if defined(BROADCOM_DEBUG)
   1183     /* Dump out info on request, before queued on channel */
   1184     if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityNormal, unit)) {
   1185         soc_dma_dump_dv(unit, "dma (before): ", dv_chain);
   1186     }
   1187 #endif /* BROADCOM_DEBUG */
   1188 
   1189     /* Clean cache of any dirty data */
   1190 
   1191     for (dv = dv_chain; dv; dv = dv->dv_chain) {
   1192         soc_cm_sflush(unit, dv->dv_dcb,
   1193 	                      dv->dv_vcnt * SOC_DCB_SIZE(unit));
   1194 
   1195         for (i = 0; i < dv->dv_vcnt; i++) {
   1196             uint32      cnt;
   1197             sal_vaddr_t addr;
   1198 
   1199             dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i);
   1200             cnt = SOC_DCB_REQCOUNT_GET(unit, dcb);
   1201             addr = SOC_DCB_ADDR_GET(unit, dcb);
   1202             if (dv_chain->dv_op == DV_TX) {
   1203                 soc_cm_sflush(unit, (void *)addr, cnt);
   1204             } else {
   1205                 assert(dv_chain->dv_op == DV_RX);
   1206             }
   1207         }
   1208     }
   1209 
   1210     /* Mark Channel # */
   1211 
   1212     dv_chain->dv_channel = sc->sc_channel;
   1213 
   1214     SOC_DMA_LOCK(soc_dma_lock);
   1215 
   1216     cmic_drv[unit].chan_dv_start(unit, sc, dv_chain);
   1217 
   1218     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   1219                 (BSL_META_U(unit,
   1220                             "Starting DV: c=%d dv=%p\n"),
   1221                  dv_chain->dv_channel, (void *)dv_chain));
   1222 
   1223 #ifdef INCLUDE_KNET
   1224     /*
   1225      * For KNET mode it is still required to hold the DMA lock while
   1226      * the DV chain is started. However, since this operation takes
   1227      * place at the kernel level (via the KCOM user/kernel messaging
   1228      * protocol,) it is critical that the DMA lock implementation does
   1229      * not block task scheduling or hardware interrupts (this is
   1230      * normally not possible to do from user mode anyway.)
   1231      */
   1232     if (SOC_KNET_MODE(unit)) {
   1233         kcom_msg_dma_info_t kmsg;
   1234         int wsize = BYTES2WORDS(SOC_DCB_SIZE(unit));
   1235         int len;
   1236 
   1237         for (dv = dv_chain; dv; dv = dv->dv_chain) {
   1238             sal_memset(&kmsg, 0, sizeof(kmsg));
   1239             kmsg.hdr.opcode = KCOM_M_DMA_INFO;
   1240             kmsg.hdr.unit = unit;
   1241             if (dv_chain->dv_op == DV_TX) {
   1242                 kmsg.dma_info.type = KCOM_DMA_INFO_T_TX_DCB;
   1243             } else {
   1244                 kmsg.dma_info.type = KCOM_DMA_INFO_T_RX_DCB;
   1245             }
   1246             kmsg.dma_info.cnt = dv->dv_vcnt;
   1247             kmsg.dma_info.size = wsize;
   1248             kmsg.dma_info.chan = dv_chain->dv_channel;
   1249             dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, 0);
   1250             kmsg.dma_info.data.dcb_start = soc_cm_l2p(unit, dcb);
   1251             len = sizeof(kmsg);
   1252             rv = soc_knet_cmd_req((kcom_msg_t *)&kmsg, len, sizeof(kmsg));
   1253         }
   1254     }
   1255 #endif
   1256 
   1257     SOC_DMA_UNLOCK(soc_dma_lock);
   1258     return rv;
   1259 }
   1260 
   1261 /*
   1262  * Function:
   1263  *      soc_dma_start
   1264  * Purpose:
   1265  *      Launch a SOC_DMA DMA operation.
   1266  * Parameters:
   1267  *      unit - unit number.
   1268  *      vchan - Virtual DMA channel to use (0-11) or -1 if any
   1269  *                      channel ok.
   1270  *      dv_chain - dma request description.
   1271  * Returns:
   1272  *      SOC_E_NONE - operation started.
   1273  *      SOC_E_TIMEOUT - operation failed to be queued.
   1274  */
   1275 
   1276 int
   1277 soc_dma_start(int unit, dma_chan_t vchan, dv_t *dv_chain)
   1278 {
   1279     sdc_t       *sc;                    /* Channel pointer */
   1280     int         rv = SOC_E_NONE;
   1281 
   1282     /* Fire off DMA operation, let interrupt handler free channel */
   1283 
   1284     sc = soc_dma_channel(unit, vchan, dv_chain);
   1285     if (sc == NULL) {
   1286         return(SOC_E_RESOURCE);
   1287     }
   1288 
   1289     rv = soc_dma_start_dv(unit, sc, dv_chain);
   1290     return rv;
   1291 }
   1292 
   1293 STATIC void
   1294 soc_dma_free_list(int unit);
   1295 
   1296 /*
   1297  * Function:
   1298  *      soc_dma_dv_alloc
   1299  * Purpose:
   1300  *      Allocate and initialize a dv struct.
   1301  * Parameters:
   1302  *      op - operations iov requested for.
   1303  *      cnt - number of DCBs required.
   1304  * Notes:
   1305  *      If a DV on the free list will accomodate the request,
   1306  *      satisfy it from there to avoid extra alloc/free calls.
   1307  */
   1308 
   1309 dv_t *
   1310 soc_dma_dv_alloc(int unit, dvt_t op, int cnt)
   1311 {
   1312     uint32        soc_dma_lock;
   1313     soc_control_t *soc = SOC_CONTROL(unit);
   1314     dv_t          *dv;
   1315     uint32        dmabuf_size;
   1316     int           *dv_free_cnt;
   1317     dv_t          **dv_free;
   1318     void          *info = NULL;
   1319 
   1320     assert(cnt > 0);
   1321 
   1322     /* Always bump up DCB count to free list size */
   1323 
   1324     if (cnt < soc->soc_dv_size) {
   1325         cnt = soc->soc_dv_size;
   1326     }
   1327 
   1328     /* Check if we can use one off the free list */
   1329 
   1330     SOC_DMA_LOCK(soc_dma_lock);
   1331     if (op == DV_TX) {
   1332     	dv_free_cnt = &(soc->soc_dv_tx_free_cnt);
   1333     	dv_free = &(soc->soc_dv_tx_free);
   1334     } else if (op == DV_RX) {
   1335     	dv_free_cnt = &(soc->soc_dv_rx_free_cnt);
   1336     	dv_free = &(soc->soc_dv_rx_free);
   1337     } else {
   1338     	SOC_DMA_UNLOCK(soc_dma_lock);
   1339     	return NULL;
   1340     }
   1341     soc->stat.dv_alloc++;
   1342     if ((cnt == soc->soc_dv_size) && ((*dv_free_cnt) > 0)) {
   1343         dv = *(dv_free);
   1344         *(dv_free) = dv->dv_chain;
   1345         (*dv_free_cnt)--;
   1346         soc->stat.dv_alloc_q++;
   1347         SOC_DMA_UNLOCK(soc_dma_lock);
   1348         info = dv->dv_public1.ptr;
   1349     } else {
   1350         SOC_DMA_UNLOCK(soc_dma_lock);
   1351         dv = soc_at_alloc(unit, sizeof(dv_t), "soc_dma_dv_alloc");
   1352         if (dv == NULL) {
   1353             /* to release the free list */
   1354         	soc_dma_free_list(unit);
   1355         	dv = soc_at_alloc(unit, sizeof(dv_t), "soc_dma_dv_alloc");
   1356         	if (dv == NULL) {
   1357 	            return(NULL);
   1358 	        }
   1359         }
   1360         dmabuf_size = SOC_DV_DMABUF_SIZE;
   1361         dv->dv_dma_buf_size = dmabuf_size;
   1362         /* Optionally allocate one word per DCB for Tx alignment */
   1363         if (soc_feature(unit, soc_feature_pkt_tx_align)) {
   1364             dmabuf_size += 4 * cnt;
   1365         }
   1366         dv->dv_dmabuf = soc_cm_salloc(unit, dmabuf_size,
   1367                                       "sdma_dmabuf_alloc");
   1368         if (dv->dv_dmabuf == NULL) {
   1369             /* to release the free list */
   1370         	soc_dma_free_list(unit);
   1371 
   1372         	dv->dv_dmabuf = soc_cm_salloc(unit, dmabuf_size,
   1373                                       "sdma_dmabuf_alloc");
   1374             if (dv->dv_dmabuf == NULL) {
   1375                 soc_at_free(unit, dv);
   1376                 return(NULL);
   1377             }
   1378         }
   1379         dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit) * cnt,
   1380                                    "sdma_dcb_alloc");
   1381         if (dv->dv_dcb == NULL) {
   1382             /* to release the free list */
   1383         	soc_dma_free_list(unit);
   1384 
   1385         	dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit) * cnt,
   1386                                    "sdma_dcb_alloc");
   1387             if (dv->dv_dcb == NULL) {
   1388                 soc_cm_sfree(unit, dv->dv_dmabuf);
   1389                 soc_at_free(unit, dv);
   1390                 return(NULL);
   1391             }
   1392         }
   1393         dv->dv_unit = unit;
   1394         dv->dv_cnt = cnt;
   1395         dv->dv_flags = ((op == DV_TX) ? DV_F_COMBINE_DCB : 0);
   1396 	}
   1397 
   1398 	dv->dv_done_packet = NULL;
   1399 	dv->dv_done_desc = NULL;
   1400 	dv->dv_done_chain = NULL;
   1401 	dv->dv_magic = DV_MAGIC_NUMBER;
   1402 	soc_dma_dv_reset(op, dv);   /* Reset standard fields */
   1403     dv->dv_public1.ptr = info;
   1404     return(dv);
   1405 }
   1406 
   1407 /*
   1408  * Function:
   1409  *      soc_dma_dv_alloc_by_port
   1410  * Purpose:
   1411  *      Allocate and initialize a dv struct.
   1412  * Parameters:
   1413  *      op - operations iov requested for.
   1414  *      cnt - number of DCBs required.
   1415  *      pkt_to_ports - number of ports to send to (specify if 
   1416  *                     sending more than SOC_DV_PKTS_MAX)
   1417  * Notes:
   1418  *      If a DV on the free list will accomodate the request,
   1419  *      satisfy it from there to avoid extra alloc/free calls.
   1420  */
   1421 
   1422 dv_t *
   1423 soc_dma_dv_alloc_by_port(int unit, dvt_t op, int cnt, int pkt_to_ports)
   1424 {
   1425     uint32        soc_dma_lock;
   1426     soc_control_t *soc = SOC_CONTROL(unit);
   1427     dv_t          *dv;
   1428     uint32        dmabuf_size;
   1429     int           *dv_free_cnt;
   1430     dv_t          **dv_free;
   1431     void          *info = NULL;
   1432 
   1433     if (pkt_to_ports <= 0) { /* not specified */
   1434         return soc_dma_dv_alloc(unit, op, cnt);
   1435     }
   1436     assert(cnt > 0);
   1437 
   1438     /* Always bump up DCB count to free list size */
   1439 
   1440     if (cnt < soc->soc_dv_size) {
   1441         cnt = soc->soc_dv_size;
   1442     }
   1443     if (pkt_to_ports < SOC_DV_PKTS_MAX) {
   1444     	pkt_to_ports = SOC_DV_PKTS_MAX;
   1445     }
   1446     /* Check if we can use one off the free list */
   1447 
   1448     SOC_DMA_LOCK(soc_dma_lock);
   1449     if (op == DV_TX) {
   1450     	dv_free_cnt = &(soc->soc_dv_tx_free_cnt);
   1451     	dv_free = &(soc->soc_dv_tx_free);
   1452     } else if (op == DV_RX) {
   1453     	dv_free_cnt = &(soc->soc_dv_rx_free_cnt);
   1454     	dv_free = &(soc->soc_dv_rx_free);
   1455     } else {
   1456     	SOC_DMA_UNLOCK(soc_dma_lock);
   1457     	return NULL;
   1458     }
   1459     soc->stat.dv_alloc++;
   1460     if ((cnt == soc->soc_dv_size) &&
   1461     	((*dv_free_cnt) > 0) &&
   1462     	(pkt_to_ports == SOC_DV_PKTS_MAX)) {
   1463         dv = (*dv_free);
   1464         (*dv_free) = dv->dv_chain;
   1465         (*dv_free_cnt)--;
   1466         soc->stat.dv_alloc_q++;
   1467         SOC_DMA_UNLOCK(soc_dma_lock);
   1468         info = dv->dv_public1.ptr;
   1469     } else {
   1470         SOC_DMA_UNLOCK(soc_dma_lock);
   1471         dv = soc_at_alloc(unit, sizeof(dv_t), "soc_dma_dv_alloc");
   1472         if (dv == NULL) {
   1473         	/* to release the free list */
   1474         	soc_dma_free_list(unit);
   1475         	dv = soc_at_alloc(unit, sizeof(dv_t), "soc_dma_dv_alloc");
   1476         	if (dv == NULL) {
   1477 	            return(NULL);
   1478 	        }
   1479         }
   1480         dmabuf_size = pkt_to_ports * SOC_DMA_BUF_LEN;
   1481         dv->dv_dma_buf_size = dmabuf_size;
   1482         /* Optionally allocate one word per DCB for Tx alignment */
   1483         if (soc_feature(unit, soc_feature_pkt_tx_align)) {
   1484             dmabuf_size += 4 * cnt;
   1485         }
   1486         dv->dv_dmabuf = soc_cm_salloc(unit, dmabuf_size,
   1487                                       "sdma_dmabuf_alloc");
   1488         if (dv->dv_dmabuf == NULL) {
   1489         	/* to release the free list */
   1490         	soc_dma_free_list(unit);
   1491 
   1492         	dv->dv_dmabuf = soc_cm_salloc(unit, dmabuf_size,
   1493                                       "sdma_dmabuf_alloc");
   1494             if (dv->dv_dmabuf == NULL) {
   1495                 soc_at_free(unit, dv);
   1496                 return(NULL);
   1497             }
   1498         }
   1499         dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit) * cnt,
   1500                                    "sdma_dcb_alloc");
   1501         if (dv->dv_dcb == NULL) {
   1502             /* to release the free list */
   1503             soc_dma_free_list(unit);
   1504         	dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit) * cnt,
   1505                                    "sdma_dcb_alloc");
   1506             if (dv->dv_dcb == NULL) {
   1507                 soc_cm_sfree(unit, dv->dv_dmabuf);
   1508                 soc_at_free(unit, dv);
   1509                 return(NULL);
   1510             }
   1511         }
   1512         dv->dv_unit = unit;
   1513         dv->dv_cnt = cnt;
   1514         dv->dv_flags = ((op == DV_TX) ? DV_F_COMBINE_DCB : 0);
   1515     }
   1516 	dv->dv_done_packet = NULL;
   1517 	dv->dv_done_desc = NULL;
   1518 	dv->dv_done_chain = NULL;
   1519 	dv->dv_magic = DV_MAGIC_NUMBER;
   1520 	soc_dma_dv_reset(op, dv);   /* Reset standard fields */
   1521     dv->dv_public1.ptr = info;
   1522     return(dv);
   1523 }
   1524 
   1525 /*
   1526  * Function:
   1527  *      soc_dma_dv_free
   1528  * Purpose:
   1529  *      Free a dv struct.
   1530  * Parameters:
   1531  *      dv - pointer to dv to free (NOT a dv chain).
   1532  * Returns:
   1533  *      Nothing.
   1534  */
   1535 
   1536 void
   1537 soc_dma_dv_free(int unit, dv_t *dv)
   1538 {
   1539     uint32        soc_dma_lock;
   1540     soc_control_t *soc = SOC_CONTROL(unit);
   1541     int           *dv_free_cnt;
   1542     dv_t          **dv_free;
   1543 
   1544     SOC_DMA_LOCK(soc_dma_lock);
   1545     if (dv->dv_op == DV_TX) {
   1546     	dv_free_cnt = &(soc->soc_dv_tx_free_cnt);
   1547     	dv_free = &(soc->soc_dv_tx_free);
   1548     } else {
   1549     	dv_free_cnt = &(soc->soc_dv_rx_free_cnt);
   1550     	dv_free = &(soc->soc_dv_rx_free);
   1551     }
   1552 
   1553     soc->stat.dv_free++;
   1554     assert(dv->dv_magic == DV_MAGIC_NUMBER);
   1555     if ((dv->dv_cnt == soc->soc_dv_size) &&
   1556         ((*dv_free_cnt) < soc->soc_dv_cnt)) {
   1557         assert(dv);
   1558         assert(dv->dv_dcb);
   1559         dv->dv_chain = (*dv_free);
   1560         (*dv_free) = dv;
   1561         (*dv_free_cnt)++;
   1562         SOC_DMA_UNLOCK(soc_dma_lock);
   1563     } else {
   1564     	dv->dv_magic = 0;
   1565         SOC_DMA_UNLOCK(soc_dma_lock);
   1566         if (dv->dv_dcb) {
   1567             soc_cm_sfree(unit, dv->dv_dcb);
   1568         }
   1569         soc_cm_sfree(unit, dv->dv_dmabuf);
   1570         soc_at_free(unit, dv);
   1571     }
   1572 }
   1573 
   1574 /*
   1575  * Function:
   1576  *      soc_dma_done_reload
   1577  * Purpose:
   1578  *      Process completion of a reload descriptor.
   1579  *      Continuous DMA only.
   1580  * Parameters:
   1581  *      unit - soc unit
   1582  *      vchan - Virtual channel number.
   1583  * Returns:
   1584  *      Nothing
   1585  */
   1586 
   1587 dv_t *
   1588 soc_dma_done_reload(int unit, uint32 vchan)
   1589 {
   1590     dma_chan_t    c = (dma_chan_t)vchan;
   1591     uint32        soc_dma_lock;
   1592     soc_control_t *soc = SOC_CONTROL(unit);
   1593     sdc_t         *sc = &soc->soc_channels[c];
   1594     dv_t          *dv_chain;  /* Head of current chain */
   1595 
   1596     SOC_DMA_LOCK(soc_dma_lock);
   1597 
   1598     assert(sc->sc_q_cnt > 0);           /* Be sure there is at least one */
   1599     assert(sc->sc_q != NULL);           /* And a pointer too */
   1600 
   1601     dv_chain    = sc->sc_q;             /* Pick up request */
   1602     sc->sc_q    = sc->sc_q->dv_next;    /* Unlink current DV */
   1603 
   1604     if (dv_chain->dv_done_reload == NULL) {
   1605         LOG_WARN(BSL_LS_SOC_COMMON,
   1606                  (BSL_META_U(unit,
   1607                              "_soc_dma_done_reload: NULL callback: "
   1608                              "unit=%d chain=%p\n"),
   1609                   unit, (void *)dv_chain));
   1610     } else {
   1611         dv_chain->dv_done_reload(unit, dv_chain);
   1612         LOG_DEBUG(BSL_LS_SOC_COMMON,
   1613                     (BSL_META_U(unit,
   1614                                 "_soc_dma_done_reload: calling dv_done_reload()"
   1615                                 " unit=%d chain=%p\n"),
   1616                      unit, (void *)dv_chain));
   1617     }
   1618     soc->stat.intr_reload++;
   1619     sc->sc_q_cnt--;                     /* Decrement */
   1620 
   1621     /* DMA followed reload descriptor set next as active */
   1622     sc->sc_dv_active = sc->sc_q;
   1623 
   1624     SOC_DMA_UNLOCK(soc_dma_lock);
   1625 
   1626     return(sc->sc_dv_active);
   1627 }
   1628 
   1629 /*
   1630  * Function:
   1631  *      soc_dma_process_done_desc
   1632  * Purpose:
   1633  *      Process and make callouts for completed descriptors.
   1634  * Parameters:
   1635  *      unit - SOC unit number
   1636  *      dv_chain - pointer to currently active dv chain
   1637  *      dv - pointer to next individual dv to process (MAY BE NULL).
   1638  * Returns:
   1639  *      Pointer to next descriptor that is not yet complete,
   1640  *      NULL if list is complete.
   1641  * Notes:
   1642  *      This is done at INTERRUPT LEVEL so we know no more
   1643  *      completion interrupts will arrive during processing.
   1644  */
   1645 
   1646 STATIC dv_t *
   1647 soc_dma_process_done_desc(int unit, dv_t *dv_chain, dv_t *dv)
   1648 {
   1649     dcb_t         *dcb;
   1650     int           i;
   1651     int           tx = (dv_chain->dv_op == DV_TX);
   1652     soc_stat_t    *stat = &SOC_CONTROL(unit)->stat;
   1653     uint32        flags, count;
   1654     int           is_rld_done;
   1655     dv_t *dv_next = NULL;
   1656 
   1657     /* Process all DCBs in the current DV */
   1658     while (dv != NULL) {
   1659 
   1660         LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   1661                     (BSL_META_U(unit,
   1662                                 "soc_dma_process_done_desc "
   1663                                 "dv_chain=%p dv_active=%p\n"),
   1664                      (void *)dv_chain, (void *)dv));
   1665 
   1666         /*
   1667          * Valid dv cnt checks
   1668          * To avoid SOC_DCB_IDX2PTR to get a invalid dcb address
   1669          */
   1670         assert(soc_dma_dv_cnt_valid(unit, dv) == TRUE);
   1671 
   1672         /* Store the next dv pointer of the chain */
   1673         if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) {
   1674             dv_next = dv->dv_next;
   1675         } else {
   1676             dv_next = dv->dv_chain;
   1677         }
   1678 
   1679         /* Clean cache of any dirty data */
   1680         soc_cm_sinval(unit, dv->dv_dcb,
   1681                       dv->dv_vcnt * SOC_DCB_SIZE(unit));
   1682 
   1683         for (i = dv->dv_dcnt; i < dv->dv_vcnt; i++) {
   1684             dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i);
   1685             flags = SOC_DCB_INTRINFO(unit, dcb, tx, &count);
   1686 
   1687             LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, /* VERBOSE */
   1688                         (BSL_META_U(unit,
   1689                                     "soc_dma_process_done_desc "
   1690                                     "at %p flags=0x%x dcnt = %d vcnt = %d\n"),
   1691                          (void *)dcb, (uint32)flags, dv->dv_dcnt, dv->dv_vcnt));
   1692 
   1693 #ifdef INCLUDE_KNET
   1694             if (SOC_KNET_MODE(unit) &&
   1695                 (!tx || (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS &&
   1696                          i == dv->dv_vcnt - 2))) {
   1697 
   1698                 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   1699                             (BSL_META_U(unit,
   1700                                         "soc_dma_process_done_desc"
   1701                                         "KNET dv=%p\n"),
   1702                              (void *)dv));
   1703 
   1704                 if ((count & SOC_DCB_KNET_DONE) == 0) {
   1705                     LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
   1706                              (BSL_META_U(unit,
   1707                                          "soc_dma_process_done_desc "
   1708                                          "KNET NOT_DONE dv_chain=%p\n"),
   1709                               (void *)dv_chain));
   1710                     /* Processing not complete in kernel */
   1711                     dv->dv_dcnt = i;
   1712                     return(dv);
   1713                 }
   1714                 /* Mask off indicator for kernel processing done */
   1715                 count &= ~SOC_DCB_KNET_DONE;
   1716                 LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
   1717                          (BSL_META_U(unit,
   1718                                      "soc_dma_process_done_desc "
   1719                                      "KNET DONE dv_chain=%p\n"),
   1720                           (void *)dv_chain));
   1721             }
   1722 #endif
   1723 
   1724             /* Check for reload DCB */
   1725             if (SOC_DCB_RELOAD_GET(unit, dcb)) {
   1726                 LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
   1727                           (BSL_META_U(unit,
   1728                                       "soc_dma_process_done_desc "
   1729                                       "(is rld) dv=%p dcb=%p\n"),
   1730                            (void *)dv, (void *)dcb));
   1731                 if (cmic_drv[unit].chan_reload_done) {
   1732                     is_rld_done = 0;
   1733                     if(cmic_drv[unit].chan_reload_done(unit,
   1734                                                        dv->dv_channel,
   1735                                                        dcb,
   1736                                                        &is_rld_done)) {
   1737                         /* Error processing reload */
   1738                         LOG_ERROR(BSL_LS_SOC_PACKETDMA,
   1739                                   (BSL_META_U(unit,
   1740                                               "Error procesing reload "
   1741                                               "descriptor: c=%d dv=%p\n"),
   1742                                    dv->dv_channel, (void *)dv));
   1743                     } else {
   1744                         if (is_rld_done) {
   1745                             dv->dv_dcnt = i + 1; /* Count it as done */
   1746 
   1747                             LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   1748                                         (BSL_META_U(unit,
   1749                                                     "soc_dma_process_done_desc "
   1750                                                     "(rld_done) dv=%p dcb=%p\n"),
   1751                                          (void *)dv, (void *)dcb));
   1752 
   1753                             soc_dma_done_reload(unit, dv->dv_channel);
   1754                             break;
   1755                         }
   1756                         else {
   1757                             dv->dv_dcnt = i;
   1758                             return(dv);
   1759                         }
   1760                     }
   1761                 }
   1762             }
   1763 
   1764             if (flags) {
   1765                 if ((dv->dv_flags & DV_F_NOTIFY_DSC) &&
   1766                     dv->dv_done_desc &&
   1767                     DMA_LAST_DESC_DONE(unit, dv)) {
   1768                     LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
   1769                                 (BSL_META_U(unit,
   1770                                             "soc_dma_process_done_desc "
   1771                                             "(notify desc) dv=%p dcb=%p\n"),
   1772                                  (void *)dv, (void *)dcb));
   1773                     dv->dv_done_desc(unit, dv, dcb);
   1774                 }
   1775 
   1776                 if (tx) {
   1777                     stat->dma_tbyt += count;
   1778                     if (flags & SOC_DCB_INFO_PKTEND) {
   1779                         if (dv->dv_done_packet) {
   1780                             dv->dv_done_packet(unit, dv, dcb);
   1781                         }
   1782                         stat->dma_tpkt++;
   1783                         LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
   1784                                     (BSL_META_U(unit,
   1785                                                 "soc_dma_process_done_desc "
   1786                                                 "(tpkt) dv=%p dcb=%p\n"),
   1787                                      (void *)dv, (void *)dcb));
   1788                     }
   1789                 } else {
   1790 
   1791                     sal_vaddr_t addr = SOC_DCB_ADDR_GET(unit, dcb);
   1792                     /* Clean cache lines associated with Rx buffer */
   1793                     soc_cm_sinval(unit, (void *)addr, count);
   1794 
   1795                     #define MIN_PAYLOAD_SIZE (64-4-12) /* 4:VLAN, 12: DA+SA */
   1796                     stat->dma_rbyt += count;
   1797                     if (flags & SOC_DCB_INFO_PKTEND) {
   1798                         if (dv->dv_done_packet) {
   1799                             dv->dv_done_packet(unit, dv, dcb);
   1800                         }
   1801                         stat->dma_rpkt++;
   1802                         LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
   1803                                     (BSL_META_U(unit,
   1804                                                 "soc_dma_process_done_desc "
   1805                                                 "(rpkt) dcb=%p\n"),
   1806                                      (void *)dcb));
   1807                     }
   1808                     /* pkt size > dma_len & !pkt_end */
   1809                     else if (count >= MIN_PAYLOAD_SIZE) {
   1810                         if (dv->dv_done_packet) {
   1811                             dv->dv_done_packet(unit, dv, dcb);
   1812                             LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
   1813                                         (BSL_META_U(unit,
   1814                                                     "soc_dma_process_done_desc "
   1815                                                     "(rpkt-partial) dcb=%p\n"),
   1816                                          (void *)dcb));
   1817                         }
   1818                     }
   1819                 }
   1820                 dv->dv_dcnt = i + 1;
   1821             } else { /* No flags */
   1822 
   1823                 dv->dv_dcnt = i;
   1824                 return(dv);
   1825             }
   1826         } /* for */
   1827 
   1828         LOG_DEBUG(BSL_LS_SOC_PACKETDMA,
   1829                     (BSL_META_U(unit,
   1830                                 "soc_dma_process_done_desc "
   1831                                 "dv_next = %p, dv_chain = %p, dcnt = %d, vcnt = %d\n"),
   1832                      (void *)dv->dv_next, (void *)dv->dv_chain, dv->dv_dcnt, dv->dv_vcnt));
   1833         /* Move to next dv */
   1834         dv = dv_next;
   1835     } /* while */
   1836 
   1837     return(dv);
   1838 }
   1839 
   1840 /*
   1841  * Function:
   1842  *      soc_dma_cmicx_done_desc
   1843  * Purpose:
   1844  *      Process a completion of a DMA descriptor in cmicx devices.
   1845  * Parameters:
   1846  *      unit - soc unit
   1847  *      vchan - Virtual channel number.
   1848  * Returns:
   1849  *      Nothing
   1850  * Notes:
   1851  *      INTERRUPT LEVEL ROUTINE
   1852  */
   1853 
   1854 void
   1855 soc_dma_cmicx_done_desc(int unit, uint32 vchan)
   1856 {
   1857     dma_chan_t          c = (dma_chan_t)vchan;
   1858     soc_control_t       *soc = SOC_CONTROL(unit);
   1859     sdc_t               *sc = &soc->soc_channels[c];
   1860     dv_t                *dv_chain = sc->sc_q;   /* Pick up request */
   1861     dv_t                *dv_active = sc->sc_dv_active;
   1862     int                 flag = 0;
   1863 
   1864 #ifdef INCLUDE_KNET
   1865     if (SOC_KNET_MODE(unit)) {
   1866         return;
   1867     }
   1868 #endif
   1869 
   1870     assert(sc->sc_q_cnt);               /* Be sure there is at least one */
   1871     assert(dv_chain);
   1872 
   1873     if (!dv_active) {
   1874         cmic_drv[unit].chan_desc_done(unit, vchan);
   1875         flag = 1;
   1876     }
   1877 
   1878     if (flag == 0) {
   1879         soc->stat.intr_desc++;
   1880 
   1881         /* Clear interrupt */
   1882         cmic_drv[unit].chan_desc_done(unit, vchan);
   1883 
   1884         /*
   1885          * Reap done descriptors, and possibly notify callers of descriptor
   1886          * completion.
   1887          */
   1888         sc->sc_dv_active =
   1889             soc_dma_process_done_desc(unit, dv_chain, dv_active);
   1890     }
   1891 
   1892     if (!(sc->sc_flags & SOC_DMA_F_POLL)) {
   1893         cmic_drv[unit].chan_desc_done_intr_enable(unit, vchan);
   1894     }
   1895 }
   1896 
   1897 /*
   1898  * Function:
   1899  *      soc_dma_done_desc
   1900  * Purpose:
   1901  *      Process a completion of a DMA descriptor.
   1902  * Parameters:
   1903  *      unit - soc unit
   1904  *      vchan - Virtual channel number.
   1905  * Returns:
   1906  *      Nothing
   1907  * Notes:
   1908  *      INTERRUPT LEVEL ROUTINE
   1909  */
   1910 
   1911 void
   1912 soc_dma_done_desc(int unit, uint32 vchan)
   1913 {
   1914     dma_chan_t          c = (dma_chan_t)vchan;
   1915     soc_control_t       *soc = SOC_CONTROL(unit);
   1916     sdc_t               *sc = &soc->soc_channels[c];
   1917     dv_t                *dv_chain = sc->sc_q;   /* Pick up request */
   1918     dv_t                *dv_active = sc->sc_dv_active;
   1919 
   1920 #ifdef INCLUDE_KNET
   1921     if (SOC_KNET_MODE(unit)) {
   1922         return;
   1923     }
   1924 #endif
   1925 
   1926     assert(sc->sc_q_cnt);               /* Be sure there is at least one */
   1927     assert(dv_chain);
   1928 
   1929     if (!dv_active) {
   1930         cmic_drv[unit].chan_desc_done(unit, vchan);
   1931         return;
   1932     }
   1933 
   1934     soc->stat.intr_desc++;
   1935 
   1936     /* Clear interrupt */
   1937     cmic_drv[unit].chan_desc_done(unit, vchan);
   1938 
   1939     /*
   1940      * Reap done descriptors, and possibly notify callers of descriptor
   1941      * completion.
   1942      */
   1943     sc->sc_dv_active =
   1944           soc_dma_process_done_desc(unit, dv_chain, dv_active);
   1945 }
   1946 
   1947 /*
   1948  * Function:
   1949  *      soc_dma_pci_timeout_handle
   1950  * Purpose:
   1951  *      Process PCI timeout error.
   1952  * Parameters:
   1953  *      unit number
   1954  *        data
   1955  * Returns:
   1956  *      Nothing
   1957  * Notes:
   1958  *      INTERRUPT LEVEL ROUTINE
   1959  */
   1960 void
   1961 soc_dma_pci_timeout_handle(int unit,  uint32 data)
   1962 {
   1963 #if defined(BCM_ESW_SUPPORT) && defined(BCM_IPROC_SUPPORT)
   1964     if (cmic_drv[unit].pci_timeout_handle != NULL) {
   1965         (void)cmic_drv[unit].pci_timeout_handle(unit);
   1966     }
   1967 #endif
   1968 }
   1969 
   1970 /*
   1971  * Function:
   1972  *      soc_dma_done_chain
   1973  * Purpose:
   1974  *      Process a completion of a DMA operation.
   1975  * Parameters:
   1976  *      s - pointer to socket structure.
   1977  *      vchan - Virtual channel number.
   1978  * Returns:
   1979  *      Nothing
   1980  * Notes:
   1981  *      INTERRUPT LEVEL ROUTINE
   1982  */
   1983 
   1984 void
   1985 soc_dma_done_chain(int unit, uint32 vchan)
   1986 {
   1987     dma_chan_t    c = (dma_chan_t)vchan;
   1988     uint32        soc_dma_lock;
   1989     soc_control_t *soc = SOC_CONTROL(unit);
   1990     sdc_t         *sc = &soc->soc_channels[c];
   1991     dv_t          *dv_chain;  /* Head of current chain */
   1992     dv_t          *dv_active; /* Current DV needed if DV chaining */
   1993     sdc_intr_mitigate_t *sdc_mtg;
   1994     int            diff;
   1995 
   1996 #ifdef INCLUDE_KNET
   1997     if (SOC_KNET_MODE(unit)) {
   1998         return;
   1999     }
   2000 #endif
   2001 
   2002     sdc_mtg = &soc_dma_intr_mitigation[unit].chans_intr_mitigation[c];
   2003     if (sdc_mtg->thread_running) {
   2004         if (sdc_mtg->mitigation_started) {
   2005             sdc_mtg->rx_chain_intr++;
   2006         } else {
   2007             sdc_mtg->cur_tm = sal_time_usecs();
   2008             diff = SAL_USECS_SUB(sdc_mtg->cur_tm, sdc_mtg->prev_tm);
   2009             if ((diff < DMA_CHAIN_DONE_INTERVAL_USEC) && (diff > 0)) {
   2010                 sdc_mtg->mitigation_started = 1;
   2011                 sdc_mtg->cur_tm = sdc_mtg->prev_tm = 0;
   2012                 sal_sem_give(sdc_mtg->thread_sem);
   2013             } else {
   2014                 sdc_mtg->prev_tm = sdc_mtg->cur_tm;
   2015             }
   2016         }
   2017     }
   2018 
   2019     assert(sc->sc_q_cnt > 0);           /* Be sure there is at least one */
   2020     assert(sc->sc_q != NULL);           /* And a pointer too */
   2021 
   2022     soc->stat.intr_chain++;
   2023 
   2024     cmic_drv[unit].chan_chain_done(unit, vchan, sdc_mtg->mitigation_started);
   2025 
   2026     SOC_DMA_LOCK(soc_dma_lock);
   2027 
   2028     dv_chain    = sc->sc_q;             /* Pick up request */
   2029     dv_active   = sc->sc_dv_active;     /* DV in processing - MAY BE NULL */
   2030     sc->sc_q    = dv_chain->dv_next;    /* Unlink current DV */
   2031     sc->sc_q_cnt--;                     /* Decrement */
   2032 
   2033     soc_dma_start_channel(unit, sc);
   2034 
   2035     SOC_DMA_UNLOCK(soc_dma_lock);
   2036 
   2037     soc_dma_process_done_desc(unit, dv_chain, dv_active);
   2038 
   2039     if (!soc_feature(unit, soc_feature_cmicx)) {
   2040         assert(dv_chain->dv_dcnt == dv_chain->dv_vcnt);
   2041     }
   2042 
   2043     if (dv_chain->dv_flags & DV_F_NOTIFY_CHN) {
   2044         if (dv_chain->dv_done_chain == NULL) {
   2045             LOG_WARN(BSL_LS_SOC_PACKETDMA,
   2046                      (BSL_META_U(unit,
   2047                                  "_soc_dma_done_chain: NULL callback: "
   2048                                  "unit=%d chain=%p\n"),
   2049                       unit, (void *)dv_chain));
   2050         } else {
   2051             dv_chain->dv_done_chain(unit, dv_chain);
   2052         }
   2053     }
   2054 }
   2055 
   2056 /*
   2057  * Function:
   2058  *      soc_dma_desc_end_packet
   2059  * Purpose:
   2060  *      Mark last descriptor in dv as end of packet.
   2061  * Parameters:
   2062  *      dv - pointer to DMA I/O Vector to be affected.
   2063  * Returns:
   2064  *      Nothing
   2065  */
   2066 
   2067 void
   2068 soc_dma_desc_end_packet(dv_t *dv)
   2069 {
   2070     dcb_t       *d;
   2071 
   2072     if (dv->dv_vcnt > 0) {
   2073         d = SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, dv->dv_vcnt - 1);
   2074         SOC_DCB_SG_SET(dv->dv_unit, d, 0);
   2075     }
   2076 }
   2077 
   2078 /* Initialize basic port bitmaps and cos/crc (used to be flags) for
   2079  * the SOC packet structure in the given DV.
   2080  */
   2081 void
   2082 soc_dma_dv_pkt_init(dv_t *dv, soc_pbmp_t pbmp, soc_pbmp_t ut_pbmp,
   2083                     soc_pbmp_t l3_pbmp, int cos, int crc)
   2084 {
   2085     sal_memset(&dv->tx_param, 0, sizeof(soc_tx_param_t));
   2086     dv->tx_param.cos = cos;
   2087     dv->tx_param.prio_int = cos;  /* By default, same as COS */
   2088     if (crc) {
   2089         dv->tx_param.flags |= SOC_DMA_CRC_REGEN;
   2090     }
   2091     SOC_PBMP_ASSIGN(dv->tx_param.tx_pbmp, pbmp);
   2092     SOC_PBMP_ASSIGN(dv->tx_param.tx_upbmp, ut_pbmp);
   2093     SOC_PBMP_ASSIGN(dv->tx_param.tx_l3pbmp, l3_pbmp);
   2094 
   2095     dv->tx_param.src_mod = SOC_DEFAULT_DMA_SRCMOD_GET(dv->dv_unit);
   2096     dv->tx_param.src_port = SOC_DEFAULT_DMA_SRCPORT_GET(dv->dv_unit);
   2097     dv->tx_param.pfm = SOC_DEFAULT_DMA_PFM_GET(dv->dv_unit);
   2098 }
   2099 
   2100 /*
   2101  * Function:
   2102  *      soc_dma_desc_add
   2103  * Purpose:
   2104  *      Add a DMA descriptor to a DMA chain independent of the
   2105  *      descriptor type.
   2106  * Parameters:
   2107  *      dv - pointer to DMA I/O Vector to be filled in.
   2108  *      addr/cnt/pbmp/ubmp/l3pbm - values to add to the DMA chain.
   2109  *      flags - COS/CRC/ etc.
   2110  * Returns:
   2111  *      < 0 - SOC_E_XXXX error code
   2112  *      >= 0 - # entries left that may be filled.
   2113  * Notes:
   2114  *      Calls the specific fastpath routine if it can, defaulting
   2115  *      to a general routine.
   2116  */
   2117 
   2118 int
   2119 soc_dma_desc_add(dv_t *dv, sal_vaddr_t addr, uint16 cnt, pbmp_t pbmp,
   2120                  pbmp_t ubmp, pbmp_t l3pbm, uint32 flags, uint32 *hgh)
   2121 {
   2122     if (dv->dv_op == DV_TX) {
   2123         return SOC_DCB_ADDTX(dv->dv_unit, dv, addr, cnt,
   2124                                 pbmp, ubmp, l3pbm, flags, hgh);
   2125     } else {
   2126         return SOC_DCB_ADDRX(dv->dv_unit, dv, addr, cnt, flags);
   2127     }
   2128 }
   2129 
   2130 /*
   2131  * Function:
   2132  *      soc_dma_rld_desc_add
   2133  * Puporse:
   2134  *      Append a RELOAD descriptor to the end of the given DV.
   2135  * Parameters:
   2136  *      dv - pointer to DV to add descriptor to.
   2137  *      addr - address to reload to. If 0, set to self.
   2138  * Returns:
   2139  *      < 0 - SOC_E_XXXX error code
   2140  *      >= 0 - # entries left that may be filled.
   2141  * Notes:
   2142  *      For legacy DMA, the reload operations addr will have a value
   2143  *      != 0. To add the reload descriptor in continuous mode this
   2144  *      function is called with addr=0. The addr is updated
   2145  *      to point to itself to match the DMA halt addr.
   2146  */
   2147 
   2148 int
   2149 soc_dma_rld_desc_add(dv_t *dv, sal_vaddr_t addr)
   2150 {
   2151     int         unit;
   2152     dcb_t       *d;
   2153     int         i = 0;
   2154 
   2155     /* Make sure there's room for a reload descriptor */
   2156     if (dv->dv_vcnt == dv->dv_cnt) {
   2157         return SOC_E_FULL;
   2158     }
   2159 
   2160     unit = dv->dv_unit;
   2161 
   2162     if (addr == 0) {
   2163         /* Setup chain for continuous mode */
   2164 
   2165         /* Set desc done intr bit in all dcbs */
   2166         for (i = 0; i < dv->dv_vcnt; i++) {
   2167             d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i);
   2168             /* No Chain Interrupt */
   2169             SOC_DCB_CHAIN_SET(unit, d, 1);
   2170             /* For TX- only set controlled desc done intr in last packet DCB */
   2171             if (dv->dv_op == DV_TX) {
   2172                 if (i == dv->dv_vcnt - 1) {
   2173                     SOC_DCB_DESC_INTR_SET(unit, d, SOC_DCB_CNTLD_DESC_INTR);
   2174                 }
   2175             } else {
   2176                 /* Set controlled desc done intr bit in all RX DCBs */
   2177                 SOC_DCB_DESC_INTR_SET(unit, d, SOC_DCB_CNTLD_DESC_INTR);
   2178             }
   2179 
   2180             if (soc_property_get(unit, spn_PDMA_DESCRIPTOR_PREFETCH_ENABLE, 0)) {
   2181                 if (soc_feature(unit, soc_feature_cmicx)) {
   2182                     if (i !=  dv->dv_vcnt) {
   2183                         if ((dv->dv_vcnt - i) >= CMICX_DMA_CONTIGUOUS_DESCS) {
   2184                             SOC_DCB_DESC_REMAINING_SET(unit, d, CMICX_DMA_CONTIGUOUS_DESCS);
   2185                         } else {
   2186                             SOC_DCB_DESC_REMAINING_SET(unit, d, (dv->dv_vcnt - i));
   2187                         }
   2188                     }
   2189                 }
   2190             }
   2191         }
   2192 
   2193         /* Find the reload DCB and configure it */
   2194         d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, dv->dv_vcnt);
   2195         SOC_DCB_INIT(unit, d);
   2196 
   2197         /* Set reload addr to self until next dv is concatenated */
   2198         addr = (sal_vaddr_t) d;
   2199         SOC_DCB_ADDR_SET(unit, d, (sal_vaddr_t)addr);
   2200 
   2201         /* Reload Bit */
   2202         SOC_DCB_RELOAD_SET(unit, d, 1);
   2203         /* No Chain Done Interrupt */
   2204         SOC_DCB_CHAIN_SET(unit, d, 1);
   2205         /* Controlled Desc Done Interrupt */
   2206         SOC_DCB_DESC_INTR_SET(unit, d, SOC_DCB_CNTLD_DESC_INTR);
   2207     } else {
   2208         /* Setup chain for legacy mode */
   2209 
   2210         if (dv->dv_vcnt > 0) {
   2211             /* Set chain bit in previous */
   2212             d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, dv->dv_vcnt - 1);
   2213             SOC_DCB_CHAIN_SET(unit, d, 1);
   2214         }
   2215 
   2216         if (soc_property_get(unit, spn_PDMA_DESCRIPTOR_PREFETCH_ENABLE, 0)) {
   2217             if (soc_feature(unit, soc_feature_cmicx)) {
   2218                 for (i = 0; i < dv->dv_vcnt; i++) {
   2219                     d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i);
   2220                     if (i !=  dv->dv_vcnt) {
   2221                         if ((dv->dv_vcnt - i) >= CMICX_DMA_CONTIGUOUS_DESCS) {
   2222                             SOC_DCB_DESC_REMAINING_SET(unit, d, CMICX_DMA_CONTIGUOUS_DESCS);
   2223                         } else {
   2224                             SOC_DCB_DESC_REMAINING_SET(unit, d, (dv->dv_vcnt - i));
   2225                         }
   2226                     }
   2227                 }
   2228             }
   2229         }
   2230 
   2231         d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, dv->dv_vcnt);
   2232         SOC_DCB_INIT(unit, d);
   2233         SOC_DCB_RELOAD_SET(unit, d, 1);
   2234         SOC_DCB_ADDR_SET(unit, d, addr);
   2235         LOG_DEBUG(BSL_LS_SOC_PACKETDMA, (BSL_META_U(unit, "reload address = %p\n"), d));
   2236     }
   2237 
   2238     dv->dv_vcnt++;
   2239     return (dv->dv_cnt - dv->dv_vcnt);
   2240 }
   2241 
   2242 /*
   2243  * Function:
   2244  *      soc_dma_contiguous_desc_add
   2245  * Puporse:
   2246  *      Setup contiguous descriptors in a DV.
   2247  * Parameters:
   2248  *      dv - pointer to DV to add descriptor to.
   2249  * Returns:
   2250  *      < 0 - SOC_E_XXXX error code
   2251  *      >= 0 - Success.
   2252  * Notes:
   2253  *      This is a new feature that is available in cmicx based devices.
   2254  */
   2255 
   2256 int
   2257 soc_dma_contiguous_desc_add(dv_t *dv)
   2258 {
   2259     int         unit;
   2260     dcb_t       *d = NULL;
   2261     int         i = 0;
   2262 
   2263     unit = dv->dv_unit;
   2264 
   2265     LOG_DEBUG(BSL_LS_SOC_PACKETDMA, (BSL_META_U(unit, "\n desc count = %d \n") ,dv->dv_vcnt));
   2266 
   2267     if (soc_property_get(unit, spn_PDMA_DESCRIPTOR_PREFETCH_ENABLE, 0)) {
   2268         if (soc_feature(unit, soc_feature_cmicx)) {
   2269             for (i = 0; i < dv->dv_vcnt; i++) {
   2270                 d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i);
   2271                 if ((dv->dv_vcnt - i) > CMICX_DMA_CONTIGUOUS_DESCS) {
   2272                     SOC_DCB_DESC_REMAINING_SET(unit, d, CMICX_DMA_CONTIGUOUS_DESCS);
   2273                 } else {
   2274                     SOC_DCB_DESC_REMAINING_SET(unit, d, (dv->dv_vcnt - i - 1));
   2275                 }
   2276             }
   2277         }
   2278     }
   2279 
   2280     LOG_DEBUG(BSL_LS_SOC_PACKETDMA, (BSL_META_U(unit, "\n contiguous address end = %p\n"), d));
   2281 
   2282     return 0;
   2283 }
   2284 
   2285 /*
   2286  * Function:
   2287  *      soc_dma_dv_join
   2288  * Purpose:
   2289  *      Append src_chain to the end of dv_chain
   2290  * Parameters:
   2291  *      dv_chain - pointer to DV chain to be appended to.
   2292  *      src_chain - pointer to DV chain to add.
   2293  * Returns:
   2294  *      SOC_E_NONE - success
   2295  *      SOC_E_XXXX - error code.
   2296  * Note:
   2297  *      src_chain is consumed and should not be further referenced.
   2298  *      If the last DCB in the chained list has the S/G
   2299  *      bit set, then the S/G bit is set in the RLD dcb.
   2300  *      The notification routines MUST be the same in all
   2301  *      elements of the list (this condition is asserted)
   2302  */
   2303 
   2304 int
   2305 soc_dma_dv_join(dv_t *dv_chain, dv_t *src_chain)
   2306 {
   2307     dcb_t       *d;
   2308     int         unit;
   2309 
   2310     assert(dv_chain);
   2311     assert(src_chain);
   2312 
   2313     unit = dv_chain->dv_unit;
   2314 
   2315     /* Go to last dv in chain */
   2316 
   2317     while (dv_chain->dv_chain) {
   2318         dv_chain = dv_chain->dv_chain;
   2319     }
   2320 
   2321     /* Make sure there's room for a reload descriptor */
   2322 
   2323     if (dv_chain->dv_vcnt == dv_chain->dv_cnt) {
   2324         return SOC_E_FULL;
   2325     }
   2326 
   2327     /* Ensure the same notification callbacks are used */
   2328 
   2329     assert(dv_chain->dv_done_chain == src_chain->dv_done_chain);
   2330     assert(dv_chain->dv_done_desc == src_chain->dv_done_desc);
   2331 
   2332     /* Add reload descriptor */
   2333 
   2334     d = SOC_DCB_IDX2PTR(unit, dv_chain->dv_dcb, dv_chain->dv_vcnt);
   2335 
   2336     SOC_DCB_INIT(unit, d);
   2337     SOC_DCB_ADDR_SET(src_chain->dv_unit, d, (sal_vaddr_t)src_chain->dv_dcb);
   2338     SOC_DCB_RELOAD_SET(unit, d, 1);             /* Reload */
   2339     SOC_DCB_CHAIN_SET(unit, d, 1);              /* Chain */
   2340 
   2341     /* Set chain bit in last DCB */
   2342 
   2343     if (dv_chain->dv_vcnt > 0) {
   2344         d = SOC_DCB_IDX2PTR(unit, dv_chain->dv_dcb, dv_chain->dv_vcnt - 1);
   2345         SOC_DCB_CHAIN_SET(unit, d, 1);
   2346     }
   2347 
   2348     dv_chain->dv_vcnt++;                /* Increment valid count */
   2349 
   2350     /* Concatenate new chain */
   2351 
   2352     dv_chain->dv_chain = src_chain;
   2353 
   2354     return SOC_E_NONE;
   2355 }
   2356 
   2357 /*
   2358  * Function:
   2359  *      soc_dma_dv_reset
   2360  * Purpose:
   2361  *      Reinitialize a dv struct to avoid free/alloc to reuse it.
   2362  * Parameters:
   2363  *      op - operation type requested.
   2364  * Returns:
   2365  *      Nothing.
   2366  */
   2367 
   2368 void
   2369 soc_dma_dv_reset(dvt_t op, dv_t *dv)
   2370 {
   2371     uint32 soc_dma_lock;
   2372 
   2373     SOC_DMA_LOCK(soc_dma_lock);
   2374     dv->dv_op      = op;
   2375     dv->dv_channel = -1;
   2376     dv->dv_vcnt    = 0;
   2377     dv->dv_dcnt    = 0;
   2378 
   2379     /* don't clear all flags */
   2380     dv->dv_flags   &= ~(DV_F_NOTIFY_DSC | DV_F_NOTIFY_CHN);
   2381     dv->dv_chain   = NULL;
   2382     dv->dv_public1.ptr = NULL;
   2383     dv->dv_public2.ptr = NULL;
   2384     dv->dv_public3.ptr = NULL;
   2385     dv->dv_public4.ptr = NULL;
   2386     sal_memset(&dv->tx_param, 0, sizeof(soc_tx_param_t));
   2387     SOC_DMA_UNLOCK(soc_dma_lock);
   2388 }
   2389 
   2390 /*
   2391  * Function:
   2392  *      soc_dma_chan_started_clear
   2393  * Purpose:
   2394  *      Clear the dma_started var for the given channel
   2395  * Parameters:
   2396  *      unit - SOC unit #.
   2397  *      vchan - Virtual channel #
   2398  * Returns:
   2399  *      Nothing
   2400  */
   2401 
   2402 void
   2403 soc_dma_chan_started_clear(int unit, dma_chan_t vchan)
   2404 {
   2405     soc_control_t *soc = SOC_CONTROL(unit);
   2406     sdc_t         *sc = &soc->soc_channels[vchan];
   2407     uint32        soc_dma_lock;
   2408 
   2409     SOC_DMA_LOCK(soc_dma_lock);
   2410     if (sc->sc_dma_started != 0) {
   2411         sc->sc_dma_started = 0;
   2412     }
   2413     SOC_DMA_UNLOCK(soc_dma_lock);
   2414 }
   2415 
   2416 /*
   2417  * Function:
   2418  *      soc_dma_chan_config
   2419  * Purpose:
   2420  *      Configure a particular DMA channel for RX/TX, and configure
   2421  *      appropriate modes.
   2422  * Parameters:
   2423  *      unit - SOC unit #.
   2424  *      c - channel #
   2425  *      type - DV_TX/DV_RX
   2426  *      flags - SOC_DMA_F_XXX
   2427  * Returns:
   2428  *      SOC_E_NONE - success
   2429  *      SOC_E_XXXX - error
   2430  */
   2431 
   2432 int
   2433 soc_dma_chan_config(int unit, dma_chan_t vchan, dvt_t type, uint32 flags)
   2434 {
   2435     uint32        soc_dma_lock;
   2436     soc_control_t *soc = SOC_CONTROL(unit);
   2437     sdc_t         *sc = &soc->soc_channels[vchan];
   2438 
   2439     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2440                 (BSL_META_U(unit,
   2441                             "soc_dma_chan_config: c=%d type=%d\n"), vchan, type));
   2442 
   2443     assert(vchan >= 0 && vchan < soc->soc_dma_channels);
   2444     assert(!(flags & ~(SOC_DMA_F_MBM | SOC_DMA_F_POLL | SOC_DMA_F_INTR_ON_DESC |
   2445                        SOC_DMA_F_TX_DROP | SOC_DMA_F_DEFAULT)));
   2446 
   2447     SOC_DMA_LOCK(soc_dma_lock);
   2448 
   2449     if ((DV_NONE != sc->sc_type) && (sc->sc_q_cnt != 0)) {
   2450         SOC_DMA_UNLOCK(soc_dma_lock);
   2451         return SOC_E_BUSY;    /* Return busy if operations pending */
   2452     }
   2453 
   2454     /*
   2455      * Clear defaults if the channel under configuration is the
   2456      * current default
   2457      */
   2458     if ((sc->sc_type == DV_RX) && (soc->soc_dma_default_rx == sc)) {
   2459         soc->soc_dma_default_rx->sc_flags &= ~SOC_DMA_F_DEFAULT;
   2460         soc->soc_dma_default_rx = NULL;
   2461     } else if ((sc->sc_type == DV_TX) && (soc->soc_dma_default_tx == sc)) {
   2462         soc->soc_dma_default_tx->sc_flags &= ~SOC_DMA_F_DEFAULT;
   2463         soc->soc_dma_default_tx = NULL;
   2464     }
   2465 
   2466     /* Initialize dummy Q entry */
   2467 
   2468     sc->sc_q            = NULL;         /* No queued operations */
   2469     sc->sc_dv_active    = NULL;         /* No active operations */
   2470     sc->sc_q_cnt        = 0;            /* Queue count starts at 0 */
   2471     sc->sc_dma_started  = 0;            /* For continuous mode only */
   2472 
   2473     cmic_drv[unit].chan_config(unit, vchan, type, flags);
   2474 
   2475     sc->sc_flags = flags;
   2476 
   2477 #ifdef  GNATS_2371_WAR
   2478     /*
   2479      * remember if any channels are in drop_tx mode (gnats 2371 workaround)
   2480      */
   2481     soc->dma_droptx = (cr & DC_DROP_TX_ALL) ? 1 : 0;
   2482 #endif  /* GNATS_2371_WAR */
   2483 
   2484     SOC_DMA_UNLOCK(soc_dma_lock);
   2485     return SOC_E_NONE;
   2486 }
   2487 
   2488 /*
   2489  * Function:
   2490  *      soc_dma_chan_counter_get
   2491  * Purpose:
   2492  *      Obtain tx and rx packet counters for a channel
   2493  * Parameters:
   2494  *      unit    - SOC unit #
   2495  *      vchan   - channel #
   2496  *      tx_pkt  - tx packet counter
   2497  *      rx_pkt  - rx packet counter
   2498  * Returns:
   2499  *      SOC_E_NONE - success
   2500  *      SOC_E_XXXX - error
   2501  */
   2502 
   2503 int
   2504 soc_dma_chan_counter_get(int unit, dma_chan_t vchan, uint32 *tx_pkt, uint32 *rx_pkt)
   2505 {
   2506     uint32        soc_dma_lock;
   2507 
   2508     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2509                 (BSL_META_U(unit,
   2510                             "soc_dma_chan_counter_get: c=%d \n"), vchan));
   2511 
   2512     SOC_DMA_LOCK(soc_dma_lock);
   2513 
   2514     cmic_drv[unit].chan_counter_get(unit, vchan, tx_pkt, rx_pkt);
   2515 
   2516     SOC_DMA_UNLOCK(soc_dma_lock);
   2517     return SOC_E_NONE;
   2518 }
   2519 
   2520 /*
   2521  * Function:
   2522  *      soc_dma_chan_counter_clear
   2523  * Purpose:
   2524  *      Clear counters for a channel based on mask.
   2525  *      Can clear any combination of
   2526  *      tx, tx, rx drop counters.
   2527  * Parameters:
   2528  *      unit  - SOC unit #
   2529  *      vchan - channel #
   2530  *      mask  - to decide which counter type
   2531  * Returns:
   2532  *      SOC_E_NONE - success
   2533  *      SOC_E_XXXX - error
   2534  */
   2535 
   2536 int
   2537 soc_dma_chan_counter_clear(int unit, dma_chan_t vchan, uint32 mask)
   2538 {
   2539     uint32        soc_dma_lock;
   2540 
   2541     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2542                 (BSL_META_U(unit,
   2543                             "soc_dma_chan_counter_clear: c=%d \n"), vchan));
   2544 
   2545     SOC_DMA_LOCK(soc_dma_lock);
   2546 
   2547     cmic_drv[unit].chan_counter_clear(unit, vchan, mask);
   2548 
   2549     SOC_DMA_UNLOCK(soc_dma_lock);
   2550     return SOC_E_NONE;
   2551 }
   2552 
   2553 /*
   2554  * Function:
   2555  *      soc_dma_cmc_counter_get
   2556  * Purpose:
   2557  *      Obtain tx and rx packet counters for a cmc
   2558  * Parameters:
   2559  *      unit    - SOC unit #
   2560  *      cmc     - cmc #
   2561  *      tx_pkt  - tx packet counter
   2562  *      rx_pkt  - rx packet counter
   2563  * Returns:
   2564  *      SOC_E_NONE - success
   2565  *      SOC_E_XXXX - error
   2566  */
   2567 
   2568 int
   2569 soc_dma_cmc_counter_get(int unit, int cmc, uint32 *tx_pkt, uint32 *rx_pkt)
   2570 {
   2571     uint32        soc_dma_lock;
   2572 
   2573     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2574                 (BSL_META_U(unit,
   2575                             "soc_dma_cmc_counter_get: cmc=%d \n"), cmc));
   2576 
   2577     SOC_DMA_LOCK(soc_dma_lock);
   2578 
   2579     cmic_drv[unit].cmc_counter_get(unit, cmc, tx_pkt, rx_pkt);
   2580 
   2581     SOC_DMA_UNLOCK(soc_dma_lock);
   2582     return SOC_E_NONE;
   2583 }
   2584 
   2585 /*
   2586  * Function:
   2587  *      soc_dma_cmc_counter_clear
   2588  * Purpose:
   2589  *      Clear counters for a cmc based on mask.
   2590  *      Can clear any combination of
   2591  *      tx, tx, rx drop counters.
   2592  * Parameters:
   2593  *      unit  - SOC unit #
   2594  *      cmc   - cmc #
   2595  *      mask  - to decide which counter type
   2596  * Returns:
   2597  *      SOC_E_NONE - success
   2598  *      SOC_E_XXXX - error
   2599  */
   2600 
   2601 int
   2602 soc_dma_cmc_counter_clear(int unit, int cmc, uint32 mask)
   2603 {
   2604     uint32        soc_dma_lock;
   2605 
   2606     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2607                 (BSL_META_U(unit,
   2608                             "soc_dma_cmc_counter_clear: cmc=%d \n"), cmc));
   2609 
   2610     SOC_DMA_LOCK(soc_dma_lock);
   2611 
   2612     cmic_drv[unit].cmc_counter_clear(unit, cmc, mask);
   2613 
   2614     SOC_DMA_UNLOCK(soc_dma_lock);
   2615     return SOC_E_NONE;
   2616 }
   2617 
   2618 /*
   2619  * Function:
   2620  *      soc_dma_chan_cos_ctrl_get
   2621  * Purpose:
   2622  *      Obtain cos ctrl value for a channel
   2623  * Parameters:
   2624  *      unit     - SOC unit #
   2625  *      vchan    - channel #
   2626  *      cfg      - to decide which cos ctrl register either 0 or 1
   2627  *      cos_ctrl - obtaining cos ctrl value by reference
   2628  * Returns:
   2629  *      SOC_E_NONE - success
   2630  *      SOC_E_XXXX - error
   2631  */
   2632 
   2633 int
   2634 soc_dma_chan_cos_ctrl_get(int unit, dma_chan_t vchan,
   2635                      uint32 cfg, uint32 *cos_ctrl)
   2636 {
   2637     uint32        soc_dma_lock;
   2638 
   2639     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2640                 (BSL_META_U(unit,
   2641                             "soc_dma_cos_ctrl_get: c=%d \n"), vchan));
   2642 
   2643     SOC_DMA_LOCK(soc_dma_lock);
   2644 
   2645     cmic_drv[unit].chan_cos_ctrl_get(unit, vchan, cfg, cos_ctrl);
   2646 
   2647     SOC_DMA_UNLOCK(soc_dma_lock);
   2648     return SOC_E_NONE;
   2649 }
   2650 
   2651 /*
   2652  * Function:
   2653  *      soc_dma_chan_cos_ctrl_set
   2654  * Purpose:
   2655  *      Set cos ctrl value for a channel
   2656  * Parameters:
   2657  *      unit     - SOC unit #
   2658  *      vchan    - channel #
   2659  *      cfg      - to decide which cos ctrl register either 0 or 1
   2660  *      cos_ctrl - cos ctrl value to be set
   2661  * Returns:
   2662  *      SOC_E_NONE - success
   2663  *      SOC_E_XXXX - error
   2664  */
   2665 
   2666 int
   2667 soc_dma_chan_cos_ctrl_set(int unit, dma_chan_t vchan,
   2668                      uint32 cfg, uint32 cos_ctrl)
   2669 {
   2670     uint32        soc_dma_lock;
   2671 
   2672     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2673                 (BSL_META_U(unit,
   2674                             "soc_dma_cos_ctrl_set: c=%d \n"), vchan));
   2675 
   2676     SOC_DMA_LOCK(soc_dma_lock);
   2677 
   2678     cmic_drv[unit].chan_cos_ctrl_set(unit, vchan, cfg, cos_ctrl);
   2679 
   2680     SOC_DMA_UNLOCK(soc_dma_lock);
   2681     return SOC_E_NONE;
   2682 }
   2683 
   2684 /*
   2685  * Function:
   2686  *      soc_dma_cos_ctrl_queue_get
   2687  * Purpose:
   2688  *      Set cos ctrl value for a channel
   2689  * Parameters:
   2690  *      unit     - SOC unit #
   2691  *      vchan    - channel #
   2692  *      cfg      - to decide which cos ctrl register either 0 or 1
   2693  *      cos_ctrl - cos ctrl value to be set
   2694  * Returns:
   2695  *      SOC_E_NONE - success
   2696  *      SOC_E_XXXX - error
   2697  */
   2698 
   2699 int
   2700 soc_dma_cos_ctrl_queue_get(int unit, int cmc, int chan,
   2701                            int queue, uint32 *cos_ctrl)
   2702 {
   2703     uint32        soc_dma_lock;
   2704 
   2705     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2706                 (BSL_META_U(unit,
   2707                             "soc_dma_cos_ctrl_queue_get: c=%d \n"), chan));
   2708 
   2709     SOC_DMA_LOCK(soc_dma_lock);
   2710 
   2711     cmic_drv[unit].chan_cos_ctrl_queue_get(unit, cmc, chan, queue, cos_ctrl);
   2712 
   2713     SOC_DMA_UNLOCK(soc_dma_lock);
   2714     return SOC_E_NONE;
   2715 }
   2716 
   2717 /*
   2718  * Function:
   2719  *      soc_dma_cos_ctrl_queue_get
   2720  * Purpose:
   2721  *      Set cos ctrl value for a channel
   2722  * Parameters:
   2723  *      unit     - SOC unit #
   2724  *      vchan    - channel #
   2725  *      cfg      - to decide which cos ctrl register either 0 or 1
   2726  *      cos_ctrl - cos ctrl value to be set
   2727  * Returns:
   2728  *      SOC_E_NONE - success
   2729  *      SOC_E_XXXX - error
   2730  */
   2731 
   2732 int
   2733 soc_dma_cos_ctrl_reg_addr_get(int unit, int cmc, int chan,
   2734                               int queue, uint32 *reg_addr)
   2735 {
   2736     uint32        soc_dma_lock;
   2737 
   2738     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2739                 (BSL_META_U(unit,
   2740                             "soc_dma_cos_ctrl_reg_addr_get: c=%d \n"), chan));
   2741 
   2742     SOC_DMA_LOCK(soc_dma_lock);
   2743 
   2744     cmic_drv[unit].chan_cos_ctrl_reg_addr_get(unit, cmc, chan, queue, reg_addr);
   2745 
   2746     SOC_DMA_UNLOCK(soc_dma_lock);
   2747     return SOC_E_NONE;
   2748 }
   2749 
   2750 /*
   2751  * Function:
   2752  *      soc_dma_loopback_config
   2753  * Purpose:
   2754  *      setup cmic to operate in loopback mode
   2755  * Parameters:
   2756  *      unit - SOC unit #
   2757  *      cfg  - to decide to put/remove cmic in loopback mode
   2758  * Returns:
   2759  *      SOC_E_NONE - success
   2760  *      SOC_E_XXXX - error
   2761  */
   2762 
   2763 int
   2764 soc_dma_loopback_config(int unit, uint32 cfg)
   2765 {
   2766     uint32        soc_dma_lock;
   2767 
   2768     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2769                 (BSL_META_U(unit,
   2770                             "soc_dma_loopback_config\n")));
   2771 
   2772 
   2773     SOC_DMA_LOCK(soc_dma_lock);
   2774 
   2775     cmic_drv[unit].loopback_config(unit, cfg);
   2776 
   2777     SOC_DMA_UNLOCK(soc_dma_lock);
   2778     return SOC_E_NONE;
   2779 }
   2780 
   2781 /*
   2782  * Function:
   2783  *      soc_dma_header_size_get
   2784  * Purpose:
   2785  *      obtain ep to cpu header size
   2786  * Parameters:
   2787  *      unit - SOC unit #
   2788  *      hdr_size - return value of the ep to cpu header size
   2789  * Returns:
   2790  *      SOC_E_NONE - success
   2791  *      SOC_E_XXXX - error
   2792  */
   2793 
   2794 int
   2795 soc_dma_header_size_get(int unit, uint32 *hdr_size)
   2796 {
   2797     cmic_drv[unit].header_size_get(unit, hdr_size);
   2798 
   2799     return SOC_E_NONE;
   2800 }
   2801 
   2802 /*
   2803  * Function:
   2804  *      soc_dma_max_rx_channels_get
   2805  * Purpose:
   2806  *      obtain maximum number of dma channels that can be used for BCM RX
   2807  * Parameters:
   2808  *      unit - SOC unit #
   2809  *      max_rx_channels - maximum rx channels that can be used
   2810  * Returns:
   2811  *      SOC_E_NONE - success
   2812  *      SOC_E_XXXX - error
   2813  */
   2814 
   2815 int
   2816 soc_dma_max_rx_channels_get(int unit, uint32 *max_rx_channels)
   2817 {
   2818     cmic_drv[unit].max_rx_channels_get(unit, max_rx_channels);
   2819 
   2820     return SOC_E_NONE;
   2821 }
   2822 
   2823 /*
   2824  * Function:
   2825  *      soc_dma_masks_get
   2826  * Purpose:
   2827  *      obtain the individual big endian masks
   2828  * Parameters:
   2829  *      unit - SOC unit #
   2830  *      pkt_endian    - pkt endian mask
   2831  *      desc_endian   - desc endian mask
   2832  *      header_endian - header endian mask
   2833  * Returns:
   2834  *      SOC_E_NONE - success
   2835  *      SOC_E_XXXX - error
   2836  */
   2837 
   2838 int
   2839 soc_dma_masks_get(int unit, uint32 *pkt_endian,
   2840                         uint32 *desc_endian, uint32 *header_endian)
   2841 {
   2842     uint32        soc_dma_lock;
   2843 
   2844     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2845                 (BSL_META_U(unit,
   2846                             "soc_dma_maks_get\n")));
   2847 
   2848 
   2849     SOC_DMA_LOCK(soc_dma_lock);
   2850 
   2851     cmic_drv[unit].masks_get(unit, pkt_endian,
   2852                              desc_endian, header_endian);
   2853 
   2854     SOC_DMA_UNLOCK(soc_dma_lock);
   2855     return SOC_E_NONE;
   2856 }
   2857 
   2858 /*
   2859  * Function:
   2860  *      soc_dma_chan_check_done
   2861  * Purpose:
   2862  *      to check whether the channel done has completed
   2863  * Parameters:
   2864  *      unit     - SOC unit #
   2865  *      vchan    - channel #
   2866  *      type     - either chain done or desc done
   2867  *      detected - return value
   2868  * Returns:
   2869  *      SOC_E_NONE - success
   2870  *      SOC_E_XXXX - error
   2871  */
   2872 
   2873 int
   2874 soc_dma_chan_poll_done(int unit, dma_chan_t vchan,
   2875                         soc_dma_poll_type_t type,
   2876                         int *detected)
   2877 {
   2878     uint32        soc_dma_lock;
   2879 
   2880     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2881                 (BSL_META_U(unit,
   2882                             "soc_dma_chan_poll_done\n")));
   2883 
   2884 
   2885     SOC_DMA_LOCK(soc_dma_lock);
   2886 
   2887     cmic_drv[unit].chan_poll(unit, vchan, type, detected);
   2888 
   2889     SOC_DMA_UNLOCK(soc_dma_lock);
   2890     return SOC_E_NONE;
   2891 }
   2892 
   2893 /*
   2894  * Function:
   2895  *      soc_dma_chan_status_get
   2896  * Purpose:
   2897  *      to obtain channel status
   2898  * Parameters:
   2899  *      unit   - SOC unit #
   2900  *      vchan  - channel #
   2901  *      status - channel status
   2902  * Returns:
   2903  *      SOC_E_NONE - success
   2904  *      SOC_E_XXXX - error
   2905  */
   2906 
   2907 int
   2908 soc_dma_chan_status_get(int unit, dma_chan_t vchan,
   2909                         uint32 mask, int *status)
   2910 {
   2911     uint32        soc_dma_lock;
   2912 
   2913     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2914                 (BSL_META_U(unit,
   2915                             "soc_dma_chan_status_get\n")));
   2916 
   2917     SOC_DMA_LOCK(soc_dma_lock);
   2918 
   2919     cmic_drv[unit].chan_status_get(unit, vchan, mask, status);
   2920 
   2921     SOC_DMA_UNLOCK(soc_dma_lock);
   2922     return SOC_E_NONE;
   2923 }
   2924 
   2925 /*
   2926  * Function:
   2927  *      soc_dma_chan_status_clear
   2928  * Purpose:
   2929  *      to clear channel status
   2930  * Parameters:
   2931  *      unit  - SOC unit #
   2932  *      vchan - channel #
   2933  * Returns:
   2934  *      SOC_E_NONE - success
   2935  *      SOC_E_XXXX - error
   2936  */
   2937 
   2938 int
   2939 soc_dma_chan_status_clear(int unit, dma_chan_t vchan)
   2940 {
   2941     uint32        soc_dma_lock;
   2942 
   2943     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2944                 (BSL_META_U(unit,
   2945                             "soc_dma_chan_status_clear\n")));
   2946 
   2947     SOC_DMA_LOCK(soc_dma_lock);
   2948 
   2949     cmic_drv[unit].chan_status_clear(unit, vchan);
   2950 
   2951     SOC_DMA_UNLOCK(soc_dma_lock);
   2952     return SOC_E_NONE;
   2953 }
   2954 
   2955 /*
   2956  * Function:
   2957  *      soc_dma_chan_halt_get
   2958  * Purpose:
   2959  *      to obtain channel halt status
   2960  * Parameters:
   2961  *      unit   - SOC unit #
   2962  *      vchan  - channel #
   2963  *      halt   - halt status
   2964  * Returns:
   2965  *      SOC_E_NONE - success
   2966  *      SOC_E_XXXX - error
   2967  */
   2968 
   2969 int
   2970 soc_dma_chan_halt_get(int unit, dma_chan_t vchan,
   2971                         uint32 mask, int *halt)
   2972 {
   2973     uint32        soc_dma_lock;
   2974 
   2975     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   2976                 (BSL_META_U(unit,
   2977                             "soc_dma_chan_halt_get\n")));
   2978 
   2979     SOC_DMA_LOCK(soc_dma_lock);
   2980 
   2981     cmic_drv[unit].chan_halt_get(unit, vchan, mask, halt);
   2982 
   2983     SOC_DMA_UNLOCK(soc_dma_lock);
   2984     return SOC_E_NONE;
   2985 }
   2986 
   2987 /*
   2988  * Function:
   2989  *      soc_dma_chan_ctrl_reg_get
   2990  * Purpose:
   2991  *      to obtain channel control reg value
   2992  * Parameters:
   2993  *      unit  - SOC unit #
   2994  *      vchan - channel #
   2995  *      val   - channel control reg value
   2996  * Returns:
   2997  *      SOC_E_NONE - success
   2998  *      SOC_E_XXXX - error
   2999  */
   3000 
   3001 int
   3002 soc_dma_chan_ctrl_reg_get(int unit, dma_chan_t vchan,
   3003                           uint32 *val)
   3004 {
   3005     uint32        soc_dma_lock;
   3006 
   3007     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3008                 (BSL_META_U(unit,
   3009                             "soc_dma_chan_ctrl_reg_get\n")));
   3010 
   3011     SOC_DMA_LOCK(soc_dma_lock);
   3012 
   3013     cmic_drv[unit].chan_ctrl_reg_get(unit, vchan, val);
   3014 
   3015     SOC_DMA_UNLOCK(soc_dma_lock);
   3016     return SOC_E_NONE;
   3017 }
   3018 
   3019 /*
   3020  * Function:
   3021  *      soc_dma_chan_ctrl_reg_set
   3022  * Purpose:
   3023  *      to set channel control reg value
   3024  * Parameters:
   3025  *      unit  - SOC unit #
   3026  *      vchan - channel #
   3027  *      val   - channel control reg value
   3028  * Returns:
   3029  *      SOC_E_NONE - success
   3030  *      SOC_E_XXXX - error
   3031  */
   3032 
   3033 int
   3034 soc_dma_chan_ctrl_reg_set(int unit, dma_chan_t vchan,
   3035                           uint32 val)
   3036 {
   3037     uint32        soc_dma_lock;
   3038 
   3039     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3040                 (BSL_META_U(unit,
   3041                             "soc_dma_chan_ctrl_reg_set\n")));
   3042 
   3043     SOC_DMA_LOCK(soc_dma_lock);
   3044 
   3045     cmic_drv[unit].chan_ctrl_reg_set(unit, vchan, val);
   3046 
   3047     SOC_DMA_UNLOCK(soc_dma_lock);
   3048     return SOC_E_NONE;
   3049 }
   3050 
   3051 /*
   3052  * Function:
   3053  *      soc_dma_chan_rxbuf_threshold_cfg
   3054  * Purpose:
   3055  *      to set channel rxbuf threshold value
   3056  * Parameters:
   3057  *      unit  - SOC unit #
   3058  *      vchan - channel #
   3059  *      val   - mmu backpressure value
   3060  * Returns:
   3061  *      SOC_E_NONE - success
   3062  *      SOC_E_XXXX - error
   3063  */
   3064 
   3065 int
   3066 soc_dma_chan_rxbuf_threshold_cfg(int unit, dma_chan_t vchan,
   3067                                  uint32 val)
   3068 {
   3069     uint32        soc_dma_lock;
   3070 
   3071     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3072                 (BSL_META_U(unit,
   3073                             "soc_dma_chan_rxbuf_threshold_cfg\n")));
   3074 
   3075     SOC_DMA_LOCK(soc_dma_lock);
   3076 
   3077     cmic_drv[unit].chan_rxbuf_threshold_cfg(unit, vchan, val);
   3078 
   3079     SOC_DMA_UNLOCK(soc_dma_lock);
   3080     return SOC_E_NONE;
   3081 }
   3082 
   3083 /*
   3084  * Function:
   3085  *      soc_dma_cmc_rxbuf_threshold_cfg
   3086  * Purpose:
   3087  *      to set cmc rxbuf threshold value
   3088  * Parameters:
   3089  *      unit  - SOC unit #
   3090  *      cmx   - cmc #
   3091  *      val   - mmu backpressure value
   3092  * Returns:
   3093  *      SOC_E_NONE - success
   3094  *      SOC_E_XXXX - error
   3095  */
   3096 
   3097 int
   3098 soc_dma_cmc_rxbuf_threshold_cfg(int unit, int cmc,
   3099                                 uint32 val)
   3100 {
   3101     uint32        soc_dma_lock;
   3102 
   3103     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3104                 (BSL_META_U(unit,
   3105                             "soc_dma_cmc_rxbuf_threshold_cfg\n")));
   3106 
   3107     SOC_DMA_LOCK(soc_dma_lock);
   3108 
   3109     cmic_drv[unit].cmc_rxbuf_threshold_cfg(unit, cmc, val);
   3110 
   3111     SOC_DMA_UNLOCK(soc_dma_lock);
   3112     return SOC_E_NONE;
   3113 }
   3114 
   3115 /*
   3116  * Function:
   3117  *      soc_dma_free_list
   3118  * Purpose:
   3119  *      Free everything on the cached DV list.
   3120  * Parameters:
   3121  *      unit - StrataSwitch unit #.
   3122  * Returns:
   3123  *      Nothing.
   3124  */
   3125 STATIC void
   3126 soc_dma_free_list(int unit)
   3127 {
   3128     uint32        soc_dma_lock;
   3129     soc_control_t *soc = SOC_CONTROL(unit);
   3130     dv_t          *dv;
   3131 
   3132     SOC_DMA_LOCK(soc_dma_lock);
   3133     soc->soc_dv_tx_free_cnt = 0;           /* Mark no TX free DVs on list */
   3134     dv = soc->soc_dv_tx_free;              /* Pick up TX free list */
   3135     soc->soc_dv_tx_free = NULL;            /* NULL list off soc structure */
   3136     SOC_DMA_UNLOCK(soc_dma_lock);
   3137 
   3138     while (NULL != dv) {
   3139         dv_t    *tdv = dv->dv_chain;
   3140         if (tx_dv_free_cb) {
   3141             tx_dv_free_cb(unit, dv);
   3142         }
   3143         soc_cm_sfree(unit, dv->dv_dcb);
   3144         soc_cm_sfree(unit, dv->dv_dmabuf);
   3145         soc_at_free(unit, dv);
   3146         dv = tdv;
   3147     }
   3148 
   3149     SOC_DMA_LOCK(soc_dma_lock);
   3150     soc->soc_dv_rx_free_cnt = 0;           /* Mark no RX free DVs on list */
   3151     dv = soc->soc_dv_rx_free;              /* Pick up RX free list */
   3152     soc->soc_dv_rx_free = NULL;            /* NULL list off soc structure */
   3153     SOC_DMA_UNLOCK(soc_dma_lock);
   3154 
   3155     while (NULL != dv) {
   3156         dv_t    *rdv = dv->dv_chain;
   3157         if (rx_dv_free_cb) {
   3158             rx_dv_free_cb(unit, dv);
   3159         }
   3160         soc_cm_sfree(unit, dv->dv_dcb);
   3161         soc_cm_sfree(unit, dv->dv_dmabuf);
   3162         soc_at_free(unit, dv);
   3163         dv = rdv;
   3164     }
   3165 }
   3166 
   3167 /*
   3168  * Function:
   3169  *      soc_dma_init
   3170  * Purpose:
   3171  *      Initialize the SOC DMA routines for a SOC unit.
   3172  * Parameters:
   3173  *      unit - SOC unit #
   3174  * Returns:
   3175  *      SOC_E_NONE - Success
   3176  *      SOC_E_BUSY - DMA channel busy.
   3177  *      SOC_E_XXX
   3178  * Notes:
   3179  *      This routine frees all DV's on the free list, and configures
   3180  *      a default channel configuration.
   3181  */
   3182 
   3183 int
   3184 soc_dma_init(int unit)
   3185 {
   3186     int channel_bitmap;
   3187     uint32 flags = 0;
   3188 #ifdef INCLUDE_KNET
   3189     uint8 init_knet_hw = TRUE;
   3190 #endif
   3191 
   3192     soc_dma_free_list(unit);           /* Free current DV list */
   3193 
   3194     /* Init the device */
   3195     cmic_drv[unit].init(unit);
   3196 
   3197     channel_bitmap = soc_property_get(unit,
   3198                                       spn_PKTDMA_POLL_MODE_CHANNEL_BITMAP, 0x0);
   3199     flags = channel_bitmap & (1 << 0) ? SOC_DMA_F_MBM | SOC_DMA_F_DEFAULT |
   3200                                         SOC_DMA_F_POLL :
   3201                                         SOC_DMA_F_MBM | SOC_DMA_F_DEFAULT;
   3202 
   3203     SOC_IF_ERROR_RETURN
   3204         (soc_dma_chan_config(unit, 0, DV_TX, flags));
   3205 
   3206     flags = channel_bitmap & (1 << 1) ? SOC_DMA_F_MBM | SOC_DMA_F_DEFAULT |
   3207                                         SOC_DMA_F_POLL :
   3208                                         SOC_DMA_F_MBM | SOC_DMA_F_DEFAULT;
   3209     SOC_IF_ERROR_RETURN
   3210         (soc_dma_chan_config(unit, 1, DV_RX, flags));
   3211 
   3212     if (SOC_IS_DNX(unit))
   3213     {
   3214         /** Init all channels on CMC0 except channel 0 as RX on Dune */
   3215         SOC_IF_ERROR_RETURN
   3216             (soc_dma_chan_config(unit, 2, DV_RX, flags));
   3217         SOC_IF_ERROR_RETURN
   3218             (soc_dma_chan_config(unit, 3, DV_RX, flags));
   3219         if (soc_feature(unit, soc_feature_cmicx)) {
   3220             SOC_IF_ERROR_RETURN
   3221                 (soc_dma_chan_config(unit, 4, DV_RX, flags));
   3222             SOC_IF_ERROR_RETURN
   3223                 (soc_dma_chan_config(unit, 5, DV_RX, flags));
   3224             SOC_IF_ERROR_RETURN
   3225                 (soc_dma_chan_config(unit, 6, DV_RX, flags));
   3226             SOC_IF_ERROR_RETURN
   3227                 (soc_dma_chan_config(unit, 7, DV_RX, flags));
   3228         }
   3229     }
   3230     else
   3231     {
   3232         SOC_IF_ERROR_RETURN
   3233             (soc_dma_chan_config(unit, 2, DV_NONE, SOC_DMA_F_MBM));
   3234         SOC_IF_ERROR_RETURN
   3235             (soc_dma_chan_config(unit, 3, DV_NONE, SOC_DMA_F_MBM));
   3236 
   3237         if (soc_feature(unit, soc_feature_cmicx)) {
   3238             SOC_IF_ERROR_RETURN
   3239                 (soc_dma_chan_config(unit, 4, DV_NONE, SOC_DMA_F_MBM));
   3240             SOC_IF_ERROR_RETURN
   3241                 (soc_dma_chan_config(unit, 5, DV_NONE, SOC_DMA_F_MBM));
   3242             SOC_IF_ERROR_RETURN
   3243                 (soc_dma_chan_config(unit, 6, DV_NONE, SOC_DMA_F_MBM));
   3244             SOC_IF_ERROR_RETURN
   3245                 (soc_dma_chan_config(unit, 7, DV_NONE, SOC_DMA_F_MBM));
   3246         }
   3247     }
   3248 
   3249 #ifdef INCLUDE_KNET
   3250 
   3251     if (SOC_KNET_MODE(unit)) {
   3252         if (SOC_WARM_BOOT(unit) &&
   3253             soc_property_get(unit, spn_WARMBOOT_KNET_SHUTDOWN_MODE, 0)) {
   3254             init_knet_hw = FALSE;
   3255         }
   3256         if (soc_feature(unit, soc_feature_cos_rx_dma)) {
   3257             /* Enable additional Rx DMA channels by default */
   3258             SOC_IF_ERROR_RETURN
   3259                 (soc_dma_chan_config(unit, 2, DV_RX, SOC_DMA_F_MBM));
   3260             SOC_IF_ERROR_RETURN
   3261                 (soc_dma_chan_config(unit, 3, DV_RX, SOC_DMA_F_MBM));
   3262             if (soc_feature(unit, soc_feature_cmicx)) {
   3263                 SOC_IF_ERROR_RETURN
   3264                     (soc_dma_chan_config(unit, 4, DV_RX, SOC_DMA_F_MBM));
   3265                 SOC_IF_ERROR_RETURN
   3266                     (soc_dma_chan_config(unit, 5, DV_RX, SOC_DMA_F_MBM));
   3267                 SOC_IF_ERROR_RETURN
   3268                     (soc_dma_chan_config(unit, 6, DV_RX, SOC_DMA_F_MBM));
   3269                 SOC_IF_ERROR_RETURN
   3270                     (soc_dma_chan_config(unit, 7, DV_RX, SOC_DMA_F_MBM));
   3271             }
   3272 #ifdef BCM_CMICM_SUPPORT
   3273             if (soc_feature(unit, soc_feature_cmicm)) {
   3274                 /* COS-based DMA channel mapping always enabled */
   3275             } else
   3276 #endif
   3277 #ifdef BCM_CMICX_SUPPORT
   3278             if (soc_feature(unit, soc_feature_cmicx)) {
   3279                 /* COS-based DMA channel mapping always enabled */
   3280             } else
   3281 #endif
   3282             {
   3283                 /* Enable COS-based DMA channel mapping */
   3284                 soc_pci_write(unit, CMIC_CONFIG,
   3285                               (soc_pci_read(unit, CMIC_CONFIG) |
   3286                                CC_COS_QUALIFIED_DMA_RX_EN));
   3287             }
   3288         }
   3289         if (init_knet_hw) {
   3290             soc_knet_hw_init(unit);
   3291         }
   3292     }
   3293 #endif
   3294 
   3295     return(SOC_E_NONE);
   3296 }
   3297 
   3298 #ifdef INCLUDE_KNET
   3299 
   3300 STATIC void
   3301 soc_dma_done_knet(int unit, sdc_t *sc)
   3302 {
   3303     dv_t *dv_chain;
   3304     dv_t *dv_active;
   3305 
   3306     assert(SOC_KNET_MODE(unit));
   3307 
   3308     /*
   3309      * Reap done descriptors, and possibly notify callers of descriptor
   3310      * completion.
   3311      */
   3312     if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) {
   3313         dv_chain = sc->sc_q;
   3314         dv_active = sc->sc_dv_active;
   3315         if (dv_chain && dv_active) {
   3316             soc_dma_process_done_desc(unit, dv_chain, dv_active);
   3317         }
   3318         return;
   3319     }
   3320 
   3321     do {
   3322         dv_chain = sc->sc_q;
   3323         dv_active = sc->sc_dv_active;
   3324         if (dv_active && sc->sc_q_cnt) {
   3325             sc->sc_dv_active =
   3326                 soc_dma_process_done_desc(unit, dv_chain, dv_active);
   3327 
   3328             if (dv_chain->dv_dcnt &&
   3329                 dv_chain->dv_dcnt == dv_chain->dv_vcnt) {
   3330 
   3331                 sc->sc_q    = dv_chain->dv_next;    /* Unlink current DV */
   3332                 sc->sc_q_cnt--;                     /* Decrement */
   3333 
   3334                 soc_dma_start_channel(unit, sc);
   3335 
   3336                 if (dv_chain->dv_flags & DV_F_NOTIFY_CHN) {
   3337                     if (dv_chain->dv_done_chain) {
   3338                         dv_chain->dv_done_chain(unit, dv_chain);
   3339                     }
   3340                 }
   3341             }
   3342         }
   3343     } while (sc->sc_dv_active != dv_active);
   3344 }
   3345 
   3346 STATIC int
   3347 soc_dma_handle_knet_event(kcom_msg_t *kmsg, unsigned int len, void *cookie)
   3348 {
   3349     if (kmsg->hdr.type == KCOM_MSG_TYPE_EVT &&
   3350         kmsg->hdr.opcode == KCOM_M_DMA_INFO) {
   3351         kcom_dma_info_t *dma_info = &kmsg->dma_info.dma_info;
   3352         int unit = kmsg->hdr.unit;
   3353         uint32 soc_dma_lock;
   3354         soc_control_t *soc = SOC_CONTROL(unit);
   3355         int chan;
   3356 
   3357         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   3358                     (BSL_META_U(unit,
   3359                                 "soc_knet_handle_event: KCOM_M_DMA_INFO\n")));
   3360 
   3361         SOC_DMA_LOCK(soc_dma_lock);
   3362 
   3363         if (dma_info->flags & KCOM_DMA_INFO_F_TX_DONE) {
   3364             soc_dma_done_knet(unit, &soc->soc_channels[0]);
   3365         }
   3366 
   3367         if (dma_info->flags & KCOM_DMA_INFO_F_RX_DONE) {
   3368             for (chan = 1; chan < soc->soc_max_channels; chan++) {
   3369                 soc_dma_done_knet(unit, &soc->soc_channels[chan]);
   3370             }
   3371         }
   3372 
   3373         SOC_DMA_UNLOCK(soc_dma_lock);
   3374 
   3375         /* Handled */
   3376         return 1;
   3377     }
   3378     /* Not handled */
   3379     return 0;
   3380 }
   3381 
   3382 #endif /* INCLUDE_KNET */
   3383 
   3384 /*
   3385  * Function:
   3386  *      soc_dma_attach
   3387  * Purpose:
   3388  *      Setup DMA structures when a device is attached.
   3389  * Parameters:
   3390  *      unit - StrataSwitch unit #.
   3391  * Returns:
   3392  *      SOC_E_NONE - Attached successful.
   3393  *      SOC_E_xxx  - Attach failed.
   3394  * Notes:
   3395  *      Initializes data structure without regards to the current fields,
   3396  *      calling this routine without detach first may result in memory
   3397  *      leaks.
   3398  */
   3399 
   3400 int
   3401 soc_dma_attach(int unit, int reset)
   3402 {
   3403     uint32        soc_dma_lock;
   3404     soc_control_t *soc = SOC_CONTROL(unit);
   3405     int           i;
   3406 
   3407 #ifdef INCLUDE_KNET
   3408     if (soc_knet_init(unit) == SOC_E_NONE) {
   3409         SOC_KNET_MODE_SET(unit, 1);
   3410         soc_knet_rx_unregister(soc_dma_handle_knet_event);
   3411         soc_knet_rx_register(soc_dma_handle_knet_event, NULL, 0);
   3412     }
   3413 #endif
   3414 
   3415     soc->soc_dv_size   = soc_property_get(unit, spn_PDMA_DV_FREE_SIZE, SOC_DMA_DV_FREE_SIZE);
   3416     soc->soc_dv_cnt    = soc_property_get(unit, spn_PDMA_DV_FREE_COUNT, SOC_DMA_DV_FREE_CNT);
   3417 
   3418     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3419                          (BSL_META_U(unit,
   3420                                      "DMA driver using dv size = %d and dv cnt = %d\n"),
   3421                                      soc->soc_dv_size, soc->soc_dv_cnt));
   3422 
   3423     soc->stat.dv_alloc      = 0;        /* Init Alloc count */
   3424     soc->stat.dv_free       = 0;        /* Init Free count */
   3425     soc->stat.dv_alloc_q    = 0;        /* Init Alloc from Q count */
   3426     soc->soc_dv_tx_free_cnt    = 0;     /* Init Free list Q Count */
   3427     soc->soc_dv_rx_free_cnt    = 0;
   3428     soc->soc_dma_default_tx = NULL;
   3429     soc->soc_dma_default_rx = NULL;
   3430     if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) {
   3431         soc->soc_max_channels = SOC_CMCS_NUM(unit) * N_DMA_CHAN;
   3432         soc->soc_dma_channels = SOC_PCI_CMCS_NUM(unit) * N_DMA_CHAN;
   3433     } else if (soc_feature(unit, soc_feature_cmicx)) {
   3434         soc->soc_max_channels = SOC_CMCS_NUM(unit) * CMICX_N_DMA_CHAN;
   3435         soc->soc_dma_channels = SOC_PCI_CMCS_NUM(unit) * CMICX_N_DMA_CHAN;
   3436     } else {
   3437         soc->soc_max_channels = N_DMA_CHAN;
   3438         soc->soc_dma_channels = N_DMA_CHAN;
   3439     }
   3440 
   3441     soc->next_int0_cmc      = 0;
   3442 
   3443 #ifdef  BCM_XGS3_SWITCH_SUPPORT
   3444     if (soc_feature(unit, soc_feature_txdma_purge)) {
   3445         /*
   3446          * Allocate a 64 byte packet for TX purge packet
   3447          */
   3448         if (soc->tx_purge_pkt == NULL) {
   3449             soc->tx_purge_pkt = soc_cm_salloc(unit, 64, "tx_purge");
   3450         }
   3451     }
   3452 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   3453 
   3454 
   3455     /* Clear and Assign the driver interface */
   3456     sal_memset(&cmic_drv[unit], 0, sizeof(soc_cmic_dma_drv_t));
   3457     soc->stat.pci_cmpl_timeout = 0;
   3458 #ifdef BCM_CMICDV2_SUPPORT
   3459     if (soc_feature(unit, soc_feature_continuous_dma)) {
   3460         if (soc_property_get(unit, spn_PDMA_CONTINUOUS_MODE_ENABLE, 0)) {
   3461             soc_cmicd_dma_drv_init(unit, &cmic_drv[unit]);
   3462         } else {
   3463             soc_cmicm_dma_drv_init(unit, &cmic_drv[unit]);
   3464         }
   3465     }
   3466 #endif
   3467 
   3468 #ifdef BCM_CMICX_SUPPORT
   3469     if (soc_feature(unit, soc_feature_cmicx)) {
   3470         soc_cmicx_dma_drv_init(unit, &cmic_drv[unit]);
   3471     }
   3472 #endif
   3473 
   3474 #ifdef BCM_CMICM_SUPPORT
   3475     if ((cmic_drv[unit].init == 0) &&
   3476         soc_feature(unit, soc_feature_cmicm)) {
   3477         soc_cmicm_dma_drv_init(unit, &cmic_drv[unit]);
   3478     }
   3479 #endif
   3480     if (cmic_drv[unit].init == 0) {
   3481         soc_cmice_dma_drv_init(unit, &cmic_drv[unit]);
   3482     }
   3483 
   3484     if (reset) {
   3485         /* Init specifics */
   3486         cmic_drv[unit].ctrl_init(unit);
   3487     }
   3488 
   3489     for (i = 0; i < soc->soc_dma_channels; i++) {
   3490         sdc_t   *s = &soc->soc_channels[i];
   3491         int rv;
   3492 
   3493         if (! reset) {
   3494             /*
   3495              * soc_dma_abort_channel does not require any data structures be set
   3496              * up, it clears hardware state only.
   3497              */
   3498             SOC_DMA_LOCK(soc_dma_lock);
   3499             rv = soc_dma_abort_channel(unit, i);
   3500             SOC_DMA_UNLOCK(soc_dma_lock);
   3501             SOC_IF_ERROR_RETURN(rv);
   3502         }
   3503 
   3504         sal_memset(s, 0, sizeof(*s));           /* Start off 0 */
   3505         s->sc_type    = DV_NONE;
   3506         s->sc_channel = i;
   3507     }
   3508     SOC_IF_ERROR_RETURN(soc_dma_init(unit));
   3509 
   3510     LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3511              (BSL_META_U(unit,
   3512                          "Enabling %s DMA mode\n"),
   3513                          ((SOC_DMA_MODE(unit) ==
   3514                           SOC_DMA_MODE_CONTINUOUS) ? "Continuous" : "Legacy Chained")));
   3515 
   3516 #ifdef INCLUDE_KNET
   3517     if (SOC_KNET_MODE(unit)) {
   3518         return SOC_E_NONE;
   3519     }
   3520 #endif
   3521 
   3522     if (soc_property_get(unit, spn_DCB_INTR_MITIGATE_ENABLE, 0) &&
   3523         (!soc_dma_intr_mitigation[unit].enabled)) {
   3524         char thread_name[32];
   3525         sal_memset(&soc_dma_intr_mitigation[unit], 0,
   3526                    sizeof(soc_dma_intr_mitigation[unit]));
   3527         soc_dma_intr_mitigation[unit].enabled = 1;
   3528         for (i = 0; i < soc->soc_dma_channels; i++) {
   3529             sdc_t   *s = &soc->soc_channels[i];
   3530             sdc_intr_mitigate_t *sdc_mtg;
   3531             if (s->sc_type == DV_RX) {
   3532                 sdc_mtg =
   3533                     &soc_dma_intr_mitigation[unit].chans_intr_mitigation[i];
   3534                 sal_sprintf(sdc_mtg->sem_name, "semDmaM%d_%d",
   3535                             unit, s->sc_channel);
   3536                 sdc_mtg->thread_sem = sal_sem_create(sdc_mtg->sem_name,
   3537                                                      0, 0);
   3538                 sal_sprintf(thread_name, "bcmDmaIntrM%d_%d",
   3539                             unit, s->sc_channel);
   3540                 sdc_mtg->thread_running = 1;
   3541                 sdc_mtg->thread_id = sal_thread_create(thread_name, 4096,
   3542                        soc_property_get(unit, spn_SOC_DMA_MONITOR_THREAD_PRI, 0),
   3543                        (void (*)(void*))soc_dma_monitor_thread,
   3544                        INT_TO_PTR(unit << 16 | s->sc_channel));
   3545             }
   3546         }
   3547     }
   3548     return SOC_E_NONE;
   3549 }
   3550 
   3551 /*
   3552  * Function:
   3553  *      soc_dma_detach
   3554  * Purpose:
   3555  *      Abort DMA active on the specified channel, and free
   3556  *      internal memory associated with DMA on the specified unit.
   3557  *      It is up to the caller to ensure NO more DMAs are started.
   3558  * Parameters:
   3559  *      unit - StrataSwitch Unit number
   3560  * Returns:
   3561  *      SOC_E_TIMEOUT - indicates attempts to abort active
   3562  *              operations failed. Device is detached, but operation
   3563  *              is undefined at this point.
   3564  *      SOC_E_NONE - Operation sucessful.
   3565  */
   3566 
   3567 int
   3568 soc_dma_detach(int unit)
   3569 {
   3570     soc_control_t       *soc = SOC_CONTROL(unit);
   3571     (void)soc_dma_abort(unit);
   3572 #ifdef  BCM_XGS3_SWITCH_SUPPORT
   3573     if (soc_feature(unit, soc_feature_txdma_purge)) {
   3574         if (SOC_CONTROL(unit)->tx_purge_pkt != NULL) {
   3575             soc_cm_sfree(unit, SOC_CONTROL(unit)->tx_purge_pkt);
   3576             SOC_CONTROL(unit)->tx_purge_pkt = NULL;
   3577         }
   3578     }
   3579 #endif  /* BCM_XGS3_SWITCH_SUPPORT */
   3580     soc_dma_free_list(unit);
   3581 
   3582     if (soc_dma_intr_mitigation[unit].enabled) {
   3583         int i;
   3584         for (i = 0; i < soc->soc_dma_channels ; i++) {
   3585             sdc_intr_mitigate_t *sdc_mtg =
   3586                 &soc_dma_intr_mitigation[unit].chans_intr_mitigation[i];
   3587             if (sdc_mtg->thread_running) {
   3588                 sdc_mtg->mitigation_started = 0;
   3589                 sdc_mtg->thread_running = 0;
   3590                 sdc_mtg->rx_chain_intr = sdc_mtg->rx_chain_intr_prev = 0;
   3591                 sal_sem_give(sdc_mtg->thread_sem);
   3592             }
   3593         }
   3594         soc_dma_intr_mitigation[unit].enabled = 0;
   3595     }
   3596     return SOC_E_NONE;
   3597 }
   3598 
   3599 /*
   3600  * Function:
   3601  *      soc_dma_poll_channel
   3602  * Purpose:
   3603  *      Poll one, or ALL of the channels.
   3604  * Parameters:
   3605  *      unit - StrataSwitch unit number.
   3606  *      c - DMA channel to poll
   3607  * Returns:
   3608  *      Nothing
   3609  */
   3610 
   3611 STATIC void
   3612 soc_dma_poll_channel(int unit, dma_chan_t vchan)
   3613 {
   3614     uint32        soc_dma_lock;
   3615     soc_control_t *soc = SOC_CONTROL(unit);
   3616     sdc_t         *sc = &soc->soc_channels[vchan];
   3617     int done_detected;
   3618 
   3619     if (((sc->sc_flags & SOC_DMA_F_POLL)) && (sc->sc_dv_active)) {
   3620         LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3621                     (BSL_META_U(unit,
   3622                                 "soc_dma_poll_channel: c=%d"), vchan));
   3623         /*
   3624          * The _soc_dma_done_[desc|chain] routines expect to be called
   3625          * ONLY from an interrupt handler since they may not always
   3626          * grab the lock.
   3627          */
   3628         SOC_DMA_LOCK(soc_dma_lock);
   3629 
   3630         done_detected = 0;
   3631         cmic_drv[unit].chan_poll(unit, vchan,
   3632                                  SOC_DMA_POLL_DESC_DONE,
   3633                                  &done_detected);
   3634 
   3635         if (done_detected) {
   3636             if (soc_feature(unit, soc_feature_cmicx)) {
   3637                 soc_dma_cmicx_done_desc(unit, (uint32)vchan);
   3638             } else {
   3639                 soc_dma_done_desc(unit, (uint32)vchan);
   3640             }
   3641             soc->stat.intr_desc--;      /* undo increment in done_desc */
   3642         }
   3643 
   3644         done_detected = 0;
   3645         cmic_drv[unit].chan_poll(unit, vchan,
   3646                                  SOC_DMA_POLL_CHAIN_DONE,
   3647                                  &done_detected);
   3648 
   3649         if (done_detected) {
   3650             soc_dma_done_chain(unit, (uint32)vchan);
   3651             soc->stat.intr_chain--;      /* undo increment in done_chain */
   3652         }
   3653 
   3654         SOC_DMA_UNLOCK(soc_dma_lock);
   3655     }
   3656 }
   3657 
   3658 /*
   3659  * Function:
   3660  *      soc_dma_poll
   3661  * Purpose:
   3662  *      Poll one, or all DMA channels.
   3663  * Parameters:
   3664  *      unit - StrataSwitch unit #.
   3665  *      c    - DMA channel to poll, or -1
   3666  * Returns:
   3667  *      Nothing
   3668  */
   3669 
   3670 void
   3671 soc_dma_poll(int unit, dma_chan_t vchan)
   3672 {
   3673     soc_control_t       *soc = SOC_CONTROL(unit);
   3674 
   3675     assert(vchan < soc->soc_dma_channels);
   3676 
   3677     if (vchan < 0) {
   3678         for (vchan = 0; vchan < soc->soc_dma_channels; vchan++) {
   3679             soc_dma_poll_channel(unit, vchan);
   3680         }
   3681     } else {
   3682         soc_dma_poll_channel(unit, vchan);
   3683     }
   3684 }
   3685 
   3686 /*
   3687  * Reuse DV field.
   3688  */
   3689 #define dv_sem          dv_public4.ptr
   3690 #define dv_poll         dv_public4.ptr
   3691 
   3692 /*
   3693  * Function:
   3694  *      soc_dma_wait_done (Internal only)
   3695  * Purpose:
   3696  *      Callout for DMA chain done.
   3697  * Parameters:
   3698  *      unit - StrataSwitch Unit #.
   3699  *      dv_chain - Chain completed.
   3700  * Returns:
   3701  *      Nothing
   3702  */
   3703 
   3704 STATIC void
   3705 soc_dma_wait_done(int unit, dv_t *dv_chain)
   3706 {
   3707     COMPILER_REFERENCE(unit);
   3708     sal_sem_give((sal_sem_t)dv_chain->dv_sem);
   3709 }
   3710 
   3711 STATIC void
   3712 soc_dma_wait_desc_done(int unit, dv_t *dv_chain, dcb_t *dcb)
   3713 {
   3714     COMPILER_REFERENCE(unit);
   3715 
   3716     if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) {
   3717         if (dv_chain->dv_done_desc_subs != NULL) {
   3718             dv_chain->dv_done_desc_subs(unit, dv_chain, NULL);
   3719         }
   3720     }
   3721     sal_sem_give((sal_sem_t)dv_chain->dv_sem);
   3722 }
   3723 
   3724 /*
   3725  * Function:
   3726  *      soc_dma_poll_done (internal)
   3727  * Purpose:
   3728  *      Callout for DMA chain done.
   3729  * Parameters:
   3730  *      unit - StrataSwitch Unit #.
   3731  *      dv_chain - Chain completed.
   3732  * Returns:
   3733  *      Nothing
   3734  */
   3735 
   3736 STATIC void
   3737 soc_dma_poll_done(int unit, dv_t *dv_chain)
   3738 {
   3739     COMPILER_REFERENCE(unit);
   3740     *(volatile int *)dv_chain->dv_poll = TRUE;
   3741 }
   3742 
   3743 STATIC void
   3744 soc_dma_poll_desc_done(int unit, dv_t *dv_chain, dcb_t *dcb)
   3745 {
   3746     COMPILER_REFERENCE(unit);
   3747     *(volatile int *)dv_chain->dv_poll = TRUE;
   3748 }
   3749 
   3750 /*
   3751  * Function:
   3752  *      soc_dma_wait
   3753  * Purpose:
   3754  *      Start a DMA operation and wait for it's completion.
   3755  * Parameters:
   3756  *      unit - StrataSwitch unit #.
   3757  *      dv_chain - pointer to dv chain to execute.
   3758  *      usec - Time out in microseconds.  Same meanings as sal_sem_take
   3759  * Returns:
   3760  *      SOC_E_XXXX
   3761  */
   3762 
   3763 STATIC sal_tls_key_t *dma_sem_key = NULL;
   3764 
   3765 STATIC void
   3766 soc_dma_sem_free(void *param)
   3767 {
   3768     sal_sem_t sem = (sal_sem_t)param;
   3769 
   3770     if (sem) {
   3771         sal_sem_destroy(sem);
   3772     }
   3773 }
   3774 
   3775 int
   3776 soc_dma_wait_timeout(int unit, dv_t *dv_chain, int usec)
   3777 {
   3778     int         rv = SOC_E_NONE;
   3779     sdc_t       *sc;
   3780     volatile int done;
   3781     sal_usecs_t start_time;
   3782     int diff_time;
   3783 
   3784     if ((sc = soc_dma_channel(unit, -1, dv_chain)) == NULL) {
   3785         return(SOC_E_RESOURCE);
   3786     }
   3787 
   3788     /* If a polling channel, use POLLED mode */
   3789 
   3790     if ((sc->sc_flags & SOC_DMA_F_POLL) )     {
   3791         dv_chain->dv_sem = NULL;
   3792         dv_chain->dv_done_chain = soc_dma_poll_done;
   3793         dv_chain->dv_done_desc = soc_dma_poll_desc_done;
   3794         dv_chain->dv_poll = (void *) &done;
   3795         done = FALSE;
   3796         LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3797                     (BSL_META_U(unit,
   3798                                 "soc_dma_wait_timeout- Polled\n")));
   3799     } else {
   3800         if (dma_sem_key == NULL) {
   3801 	        dma_sem_key = sal_tls_key_create(soc_dma_sem_free);
   3802         }
   3803         dv_chain->dv_sem = sal_tls_key_get(dma_sem_key);
   3804         if (dv_chain->dv_sem == NULL) {
   3805         	dv_chain->dv_sem = sal_sem_create("dv_sem", sal_sem_BINARY, 0);
   3806 	        if (!dv_chain->dv_sem) {
   3807 	            return(SOC_E_MEMORY);
   3808 	        }
   3809         	sal_tls_key_set(dma_sem_key, (void *)dv_chain->dv_sem);
   3810         }
   3811         dv_chain->dv_done_chain = soc_dma_wait_done;
   3812         dv_chain->dv_done_desc = soc_dma_wait_desc_done;
   3813         LOG_VERBOSE(BSL_LS_SOC_PACKETDMA,
   3814                     (BSL_META_U(unit,
   3815                                 "soc_dma_wait_timeout- Not polled\n")));
   3816     }
   3817 
   3818     if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) {
   3819         SET_NOTIFY_DSC_ONLY(dv_chain->dv_flags);
   3820     } else {
   3821         SET_NOTIFY_CHN_ONLY(dv_chain->dv_flags);
   3822     }
   3823 
   3824     rv = soc_dma_start_dv(unit, sc, dv_chain);
   3825     if (SOC_FAILURE(rv)) {
   3826         if (dma_sem_key == NULL) {
   3827             if (dv_chain->dv_sem != NULL) {
   3828                 sal_sem_destroy((sal_sem_t)dv_chain->dv_sem);
   3829             }
   3830         }
   3831         return rv;
   3832     }
   3833 
   3834     start_time = sal_time_usecs();
   3835     diff_time = 0;
   3836 
   3837     if ((sc->sc_flags & SOC_DMA_F_POLL) )     {
   3838         while (!done) {
   3839             soc_dma_poll(unit, sc->sc_channel);
   3840             if ((usec != sal_sem_FOREVER) && !done) {
   3841                 diff_time = SAL_USECS_SUB(sal_time_usecs(), start_time);
   3842                 if (diff_time > usec) {
   3843                     rv = SOC_E_TIMEOUT;
   3844                     break;
   3845                 } else if (diff_time < 0) {
   3846                     /* Restart in case system time changed */
   3847                     start_time = sal_time_usecs();
   3848                 }
   3849             }
   3850         }
   3851     } else {
   3852         if (sal_sem_take((sal_sem_t)dv_chain->dv_sem, sal_sem_FOREVER)) {
   3853             (void)soc_dma_abort_dv(unit, dv_chain); /* Clean up */
   3854             rv = SOC_E_TIMEOUT;
   3855         }
   3856         if (dma_sem_key == NULL) {
   3857         	if (dv_chain->dv_sem != NULL) {
   3858 	            sal_sem_destroy((sal_sem_t)dv_chain->dv_sem);
   3859 	        }
   3860         }
   3861     }
   3862 
   3863     return(rv);
   3864 }
   3865 
   3866 /*
   3867  * Function:
   3868  *      soc_dma_wait
   3869  * Purpose:
   3870  *      Start a DMA operation and wait for it's completion.
   3871  * Parameters:
   3872  *      unit - StrataSwitch unit #.
   3873  *      dv_chain - pointer to dv chain to execute.
   3874  * Returns:
   3875  *      SOC_E_XXXX
   3876  */
   3877 
   3878 int
   3879 soc_dma_wait(int unit, dv_t *dv_chain)
   3880 {
   3881     return soc_dma_wait_timeout(unit, dv_chain, sal_sem_FOREVER);
   3882 }
   3883 
   3884 /*
   3885  * Function:
   3886  *      soc_dma_chan_dvt_get
   3887  * Purpose:
   3888  *      Get the DV type for the given channel
   3889  * Parameters:
   3890  *      unit
   3891  *      chan
   3892  * Returns:
   3893  *      BCM_E_XXX
   3894  * Notes:
   3895  *      Does not check if channel is valid
   3896  */
   3897 
   3898 dvt_t
   3899 soc_dma_chan_dvt_get(int unit, dma_chan_t vchan)
   3900 {
   3901     return SOC_CONTROL(unit)->soc_channels[vchan].sc_type;
   3902 }
   3903 
   3904 /***********************************************************************
   3905  *
   3906  * Simple ROM TX/RX Mode
   3907  *
   3908  * The following API calls may be used in lieue of the regular calls in
   3909  * order to provide a simplified, polling-driven transmit/receive API.
   3910  * These routines are very inefficient, but they are easy to use and
   3911  * don't require interrupt processing.
   3912  *
   3913  * soc_dma_rom_init() - configure chip for this mode
   3914  * soc_dma_rom_detach() - deconfigure
   3915  * soc_dma_rom_tx_start() - start a packet transmit; returns immediately
   3916  * soc_dma_rom_tx_poll() - check if transmit is done yet
   3917  * soc_dma_rom_tx_abort() - abort a transmit in progress
   3918  * soc_dma_rom_rx_poll() - get receive packet, if any; returns immediately
   3919  *
   3920  * soc_dma_rom_dcb_alloc() - utility routine for creating packet descriptor
   3921  * soc_dma_rom_dcb_free() - utility routine for freeing packet descriptor
   3922  */
   3923 
   3924 /*
   3925  * Variable:
   3926  *      soc_dma_rom_control
   3927  * Purpose:
   3928  *      Global control variables for the soc_dma_rom API.
   3929  */
   3930 
   3931 static struct {
   3932     struct {
   3933         dv_t            *dv;
   3934         volatile int    done;
   3935     } tx, rx;
   3936     int psize;
   3937 } soc_dma_rom_control[SOC_MAX_NUM_DEVICES];
   3938 
   3939 /*
   3940  * Function:
   3941  *      soc_dma_rom_dcb_alloc
   3942  * Purpose:
   3943  *      Allocate a DCB packet structure for use with RX and TX functions.
   3944  * Parameters:
   3945  *      unit    -       unit number
   3946  *      psize   -       packet buffer size
   3947  * Returns:
   3948  *      DCB pointer on success, NULL on failure.
   3949  * Notes:
   3950  *      Use this function to allocate a DCB structure and associated
   3951  *      packet memory.  A packet buffer of size 'psize' will be
   3952  *      allocated and associated with this DCB.
   3953  */
   3954 
   3955 dcb_t *
   3956 soc_dma_rom_dcb_alloc(int unit, int psize)
   3957 {
   3958     void                *pkt;
   3959     dcb_t               *dcb;
   3960 
   3961     if ((dcb = soc_cm_salloc(unit,
   3962                              SOC_DCB_SIZE(unit),
   3963                              "soc_dma_rom_dcb_alloc")) == NULL) {
   3964         return NULL;
   3965     }
   3966 
   3967     if ((pkt = soc_cm_salloc(unit,
   3968                              psize,
   3969                              "soc_dma_rom_dcb_alloc_packet")) == NULL) {
   3970         soc_cm_sfree(unit, dcb);
   3971         return NULL;
   3972     }
   3973 
   3974     /* Setup DCB defaults */
   3975     sal_memset(dcb, 0, SOC_DCB_SIZE(unit));
   3976     SOC_DCB_INIT(unit, dcb);
   3977     SOC_DCB_ADDR_SET(unit, dcb, (sal_vaddr_t)pkt);
   3978     SOC_DCB_REQCOUNT_SET(unit, dcb, psize);
   3979     SOC_DCB_SG_SET(unit, dcb, 0);
   3980     SOC_DCB_CHAIN_SET(unit, dcb, 0);
   3981 
   3982     /* Everything else should be specified by the caller */
   3983     return dcb;
   3984 }
   3985 
   3986 /*
   3987  * Function:
   3988  *      soc_dma_rom_dcb_free
   3989  * Purpose:
   3990  *      Free a DCB packet structure allocated with soc_dma_rom_dcb_free()
   3991  * Parameters:
   3992  *      unit    -       unit number
   3993  *      dcb     -       dcb pointer
   3994  * Returns:
   3995  *      SOC_E_XXX
   3996  */
   3997 
   3998 int
   3999 soc_dma_rom_dcb_free(int unit, dcb_t *dcb)
   4000 {
   4001     if (dcb) {
   4002         void            *pkt;
   4003 
   4004         pkt = (void *)SOC_DCB_ADDR_GET(unit, dcb);
   4005 
   4006         if (pkt != NULL) {
   4007             soc_cm_sfree(unit, pkt);
   4008         }
   4009 
   4010         soc_cm_sfree(unit, dcb);
   4011     }
   4012 
   4013     return SOC_E_NONE;
   4014 }
   4015 
   4016 /*
   4017  * Function:
   4018  *      soc_dma_rom_dv_start_polled
   4019  * Purpose:
   4020  *      Start an asyncronous, polled DV DMA op
   4021  * Parameters:
   4022  *      unit    -       unit
   4023  *      channel -       channel to start on
   4024  *      dv      -       dv
   4025  *      poll    -       pointer to poll-done variable
   4026  * Returns:
   4027  *      SOC_E_XXX
   4028  * Notes:
   4029  *      Helper function for soc_dma_rom() rx and tx.
   4030  */
   4031 
   4032 static int
   4033 soc_dma_rom_dv_start_polled(int unit, int vchan,
   4034                              dv_t *dv, volatile void *poll)
   4035 {
   4036     assert(dv);
   4037 
   4038     /* Setup chain-done notification */
   4039 
   4040     dv->dv_flags |= DV_F_NOTIFY_CHN;
   4041     dv->dv_sem = NULL;
   4042     dv->dv_done_chain = soc_dma_poll_done;
   4043     dv->dv_poll = (void *)poll;
   4044 
   4045     /* Start up this chain */
   4046 
   4047     return soc_dma_start(unit, vchan, dv);
   4048 }
   4049 
   4050 /*
   4051  * Function:
   4052  *      soc_dma_rom_rx_start
   4053  * Purpose:
   4054  *      Start one packet DMA rx
   4055  * Parameters:
   4056  *      unit    -       unit
   4057  * Returns:
   4058  *      SOC_E_XXX
   4059  */
   4060 
   4061 static int
   4062 soc_dma_rom_rx_start(int unit)
   4063 {
   4064     dv_t                *dv;
   4065     int                 rv;
   4066 
   4067     /* Get our RX DV  */
   4068 
   4069     if ((dv = soc_dma_rom_control[unit].rx.dv) == NULL) {
   4070         return SOC_E_INIT;
   4071     }
   4072 
   4073     /* Reset our DV */
   4074 
   4075     soc_dma_dv_reset(DV_RX, dv);
   4076 
   4077     /* Allocate a DCB/packet structure */
   4078 
   4079     dv->dv_dcb = soc_dma_rom_dcb_alloc(unit,
   4080                                        soc_dma_rom_control[unit].psize);
   4081 
   4082     /* Bring it on */
   4083 
   4084     if ((rv = soc_dma_rom_dv_start_polled(unit, SOC_DMA_ROM_RX_CHANNEL, dv,
   4085                            &soc_dma_rom_control[unit].rx.done)) < 0) {
   4086         /* D'oh */
   4087         soc_dma_rom_dcb_free(unit, dv->dv_dcb);
   4088 
   4089         dv->dv_dcb = NULL;
   4090 
   4091         return rv;
   4092     }
   4093 
   4094     return rv;
   4095 }
   4096 
   4097 
   4098 
   4099 /*
   4100  * Function:
   4101  *      soc_dma_rom_init
   4102  * Purpose:
   4103  *      Initialize simple polled tx/rx (ROM mode).
   4104  * Parameters:
   4105  *      unit            - StrataSwitch unit #
   4106  *      max_packet_rx   - Maximum RX packet size
   4107  * Returns:
   4108  *      SOC_E_XXX
   4109  */
   4110 
   4111 int
   4112 soc_dma_rom_init(int unit, int max_packet_rx, int tx, int rx)
   4113 {
   4114     dv_t                *dv_rx, *dv_tx;
   4115 
   4116     sal_memset(&soc_dma_rom_control[unit], 0,
   4117                sizeof(soc_dma_rom_control[unit]));
   4118 
   4119     /* Reconfigure TX/RX channels for polling */
   4120 
   4121     if (tx) {
   4122         SOC_IF_ERROR_RETURN(
   4123             soc_dma_chan_config(unit, SOC_DMA_ROM_TX_CHANNEL, DV_TX,
   4124                                 SOC_DMA_F_MBM | SOC_DMA_F_POLL | SOC_DMA_F_DEFAULT));
   4125     }
   4126 
   4127     if (rx) {
   4128         SOC_IF_ERROR_RETURN(
   4129             soc_dma_chan_config(unit, SOC_DMA_ROM_RX_CHANNEL, DV_RX,
   4130                                 SOC_DMA_F_MBM | SOC_DMA_F_POLL | SOC_DMA_F_DEFAULT));
   4131     }
   4132 
   4133     soc_dma_rom_control[unit].psize = max_packet_rx;
   4134 
   4135     /* Allocate our TX/RX DVs */
   4136 
   4137     if ((dv_rx = soc_dma_dv_alloc(unit, DV_RX, 1)) == NULL) {
   4138         return SOC_E_MEMORY;
   4139     }
   4140 
   4141     if ((dv_tx = soc_dma_dv_alloc(unit, DV_TX, 1)) == NULL) {
   4142         soc_dma_dv_free(unit, dv_rx);
   4143         return SOC_E_MEMORY;
   4144     }
   4145 
   4146     /*
   4147      * We play around with the DCB in these DVs quite a bit. Free the
   4148      * originals so we can muck with it later.
   4149      */
   4150 
   4151     soc_cm_sfree(unit, dv_rx->dv_dcb);
   4152     soc_cm_sfree(unit, dv_tx->dv_dcb);
   4153 
   4154     /* Store our new DVs */
   4155 
   4156     soc_dma_rom_control[unit].rx.dv = dv_rx;
   4157     soc_dma_rom_control[unit].tx.dv = dv_tx;
   4158 
   4159     /* Startup an RX */
   4160 
   4161     if (rx) {
   4162         soc_dma_rom_rx_start(unit);
   4163     }
   4164 
   4165     /* No TX's outstanding */
   4166 
   4167     soc_dma_rom_control[unit].tx.done = 1;
   4168 
   4169     return SOC_E_NONE;
   4170 }
   4171 
   4172 /*
   4173  * Function:
   4174  *      soc_dma_rom_detach
   4175  * Purpose:
   4176  *      Finalize the polled TX/RX module
   4177  * Parameters:
   4178  *      unit - StrataSwitch unit #
   4179  * Returns:
   4180  *      SOC_E_XXX
   4181  */
   4182 
   4183 int
   4184 soc_dma_rom_detach(int unit)
   4185 {
   4186     int                 rv;
   4187     dv_t                *dv;
   4188 
   4189     /* Kill DMA */
   4190 
   4191     rv = soc_dma_detach(unit);
   4192 
   4193     /*
   4194      * Free our buffers We need to free our custom packet DCBs, then
   4195      * replace the DV's dcb pointer which we freed at init time with a
   4196      * new pointer before we hand it back.
   4197      */
   4198 
   4199     dv = soc_dma_rom_control[unit].rx.dv;
   4200 
   4201     /* Free our RX DCB */
   4202 
   4203     if (dv->dv_dcb) {
   4204         soc_dma_rom_dcb_free(unit, dv->dv_dcb);
   4205     }
   4206 
   4207     dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit), "sdma_dv_alloc");
   4208 
   4209     dv = soc_dma_rom_control[unit].tx.dv;
   4210 
   4211     /*
   4212      * Do not deallocate the DCB associated with TX.
   4213      * This was allocated by the caller.
   4214      */
   4215 
   4216     dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit), "sdma_dv_alloc");
   4217 
   4218     sal_memset(&soc_dma_rom_control[unit], 0,
   4219                sizeof(soc_dma_rom_control[unit]));
   4220 
   4221     return rv;
   4222 }
   4223 
   4224 /*
   4225  * Function:
   4226  *      soc_dma_rom_tx_start
   4227  * Purpose:
   4228  *      Kick off a packet transmit (ROM mode)
   4229  * Parameters:
   4230  *      unit - StrataSwitch unit #
   4231  *      dcb  - Device specific DMA descriptor block structure
   4232  * Notes:
   4233  *      This function will transmit one packet as described by the dcb
   4234  *      parameter.
   4235  *
   4236  *      The DCB packet structure should be allocated using
   4237  *      soc_dma_rom_dcb_alloc().
   4238  *
   4239  *      The caller must setup the DCB structure correctly for the chip
   4240  *      on which the packet will be transmitted.  On the BCM5670 the
   4241  *      packet data must contain the Higig header.
   4242  *
   4243  *      This routine does not wait for transmit complete.  Use
   4244  *      soc_dma_rom_tx_poll() to determine transmit completion.
   4245  *
   4246  *      The application may not re-use the dcb or packet buffer memory
   4247  *      or transmit any other packets until the transmit is complete.
   4248  */
   4249 
   4250 int
   4251 soc_dma_rom_tx_start(int unit, dcb_t *dcb)
   4252 {
   4253     dv_t                *dv;
   4254 
   4255     /* Get our TX DV */
   4256 
   4257     if ((dv = soc_dma_rom_control[unit].tx.dv) == NULL) {
   4258         return SOC_E_INIT;
   4259     }
   4260 
   4261     /* Reset our DV */
   4262     soc_dma_dv_reset(DV_TX, dv);
   4263 
   4264     /* Our DCB has already been allocated. Drop it in our DV. */
   4265 
   4266     dv->dv_dcb = dcb;
   4267     dv->dv_vcnt = 1;
   4268 
   4269     /* Send it */
   4270 
   4271     soc_dma_rom_control[unit].tx.done = 0;
   4272 
   4273     return soc_dma_rom_dv_start_polled(unit, SOC_DMA_ROM_TX_CHANNEL,
   4274                                         dv,
   4275                                         &soc_dma_rom_control[unit].tx.done);
   4276 }
   4277 
   4278 /*
   4279  * Function:
   4280  *      soc_dma_rom_tx_poll
   4281  * Purpose:
   4282  *      Indicate whether previous transmit with soc_dma_rom_tx_start()
   4283  *      has completed.
   4284  * Parameters:
   4285  *      unit - StrataSwitch unit #
   4286  *      done - (OUT) TRUE or FALSE, indicating whether transmit was done
   4287  * Returns:
   4288  *      SOC_E_XXX
   4289  * Notes:
   4290  *      After completion, the original DCB and packet memory may be reused.
   4291  */
   4292 
   4293 int
   4294 soc_dma_rom_tx_poll(int unit, int *done)
   4295 {
   4296     soc_dma_poll(unit, SOC_DMA_ROM_TX_CHANNEL);
   4297 
   4298     *done = soc_dma_rom_control[unit].tx.done;
   4299 
   4300     return SOC_E_NONE;
   4301 }
   4302 
   4303 /*
   4304  * Function:
   4305  *      soc_dma_rom_tx_abort
   4306  * Purpose:
   4307  *      Abort a transmit in progress.
   4308  * Parameters:
   4309  *      unit - StrataSwitch unit #
   4310  * Returns:
   4311  *      SOC_E_XXX
   4312  */
   4313 
   4314 int
   4315 soc_dma_rom_tx_abort(int unit)
   4316 {
   4317     if (soc_dma_rom_control[unit].tx.done == 0) {
   4318         soc_dma_rom_control[unit].tx.done = 1;
   4319         return soc_dma_abort_channel(unit, SOC_DMA_ROM_TX_CHANNEL);
   4320     }
   4321 
   4322     return SOC_E_NONE;
   4323 }
   4324 
   4325 
   4326 /*
   4327  * Function:
   4328  *      soc_dma_rom_rx_poll
   4329  * Purpose:
   4330  *      See if a packet is waiting, and it so, return it
   4331  * Parameters:
   4332  *      unit - StrataSwitch unit #
   4333  *      dcb - (OUT) The packet's associated dcb, NULL if no packet ready.
   4334  * Returns:
   4335  *      SOC_E_XXX
   4336  * Notes:
   4337  *      The caller must parse the DCB structure to retrieve the
   4338  *      the packet information.
   4339  *
   4340  *      The caller must call soc_dma_rom_dcb_free() when done with
   4341  *      this packet.
   4342  */
   4343 
   4344 int
   4345 soc_dma_rom_rx_poll(int unit, dcb_t **dcb)
   4346 {
   4347     /* Has our last RX DMA completed? */
   4348 
   4349     soc_dma_poll(unit, SOC_DMA_ROM_RX_CHANNEL);
   4350 
   4351     if (soc_dma_rom_control[unit].rx.done) {
   4352         /* Packet received.  Pull out the DCB */
   4353 
   4354         *dcb = soc_dma_rom_control[unit].rx.dv->dv_dcb;
   4355         soc_dma_rom_control[unit].rx.dv->dv_dcb = NULL;
   4356         soc_dma_rom_control[unit].rx.done = 0;
   4357 
   4358         /* Start another DMA */
   4359 
   4360         soc_dma_rom_rx_start(unit);
   4361     } else {
   4362         *dcb = NULL;
   4363     }
   4364 
   4365     return SOC_E_NONE;
   4366 }
   4367 
   4368 #endif /* BCM_CMIC_SUPPORT */