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

cmice_dma.c (15648B)


      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:     CMICE interface drvier for SOC DMA
      8  */
      9 
     10 #include <sal/core/boot.h>
     11 #include <sal/core/libc.h>
     12 #include <shared/alloc.h>
     13 #include <shared/bsl.h>
     14 
     15 #include <soc/debug.h>
     16 #include <soc/cm.h>
     17 #include <soc/dma.h>
     18 #include <soc/drv.h>
     19 #include <soc/dcb.h>
     20 
     21 #ifdef INCLUDE_KNET
     22 #include <soc/knet.h>
     23 #endif
     24 
     25 #ifdef BCM_CMIC_SUPPORT
     26 
     27 /* Static Driver Functions */
     28 
     29 /*
     30  * Function:
     31  *      cmice_dma_ctrl_init
     32  * Purpose:
     33  *      Reset the CMICE DMA Control to a known good state for
     34  *      the specified SOC unit.
     35  * Parameters:
     36  *      unit - SOC unit #
     37  * Returns:
     38  *      SOC_E_NONE - success
     39  *      SOC_E_XXXX - error code
     40  * Notes:
     41  */
     42 static int
     43 cmice_dma_ctrl_init(int unit)
     44 {
     45     int rv = SOC_E_NONE;
     46 
     47     soc_pci_write(unit, CMIC_DMA_CTRL, 0); /* Known good state */
     48 
     49     return rv;
     50 }
     51 
     52 /*
     53  * Function:
     54  *      cmice_dma_init
     55  * Purpose:
     56  *      Initialize the CMICE DMA for the specified SOC unit.
     57  * Parameters:
     58  *      unit - SOC unit #
     59  * Returns:
     60  *      SOC_E_NONE - success
     61  *      SOC_E_XXXX - error code
     62  * Notes:
     63  */
     64 static int
     65 cmice_dma_init(int unit)
     66 {
     67     int rv = SOC_E_NONE;
     68 
     69     cmice_dma_ctrl_init(unit);
     70 
     71     return rv;
     72 }
     73 
     74 /*
     75  * Function:
     76  *      cmice_dma_chan_config
     77  * Purpose:
     78  *      Configure the CMICE DMA channel for the specified SOC unit.
     79  * Parameters:
     80  *      unit - SOC unit #
     81  *      chan - channel #
     82  *      type - tx or rx
     83  *      f_intr - interrupt flags
     84  * Returns:
     85  *      SOC_E_NONE - success
     86  *      SOC_E_XXXX - error code
     87  * Notes:
     88  */
     89 static int
     90 cmice_dma_chan_config(int unit, int chan, dvt_t type, uint32 flags)
     91 {
     92     int           rv = SOC_E_NONE;
     93     soc_control_t *soc = SOC_CONTROL(unit);
     94     sdc_t         *sc = &soc->soc_channels[chan];
     95     uint32        bits, cr;
     96 
     97     /* Define locals and turn flags into easy to use things */
     98     int f_mbm = (flags & SOC_DMA_F_MBM) != 0;
     99     int f_interrupt = (flags & SOC_DMA_F_POLL) == 0;
    100     int f_drop = (flags & SOC_DMA_F_TX_DROP) != 0;
    101     int f_default = (flags & SOC_DMA_F_DEFAULT) != 0;
    102     int f_desc_intr = (flags & SOC_DMA_F_INTR_ON_DESC) != 0;
    103     int init_hw = TRUE;
    104 
    105 #ifdef INCLUDE_KNET
    106     if (SOC_KNET_MODE(unit) && SOC_WARM_BOOT(unit) &&
    107         soc_property_get(unit, spn_WARMBOOT_KNET_SHUTDOWN_MODE, 0)) {
    108         init_hw = FALSE;
    109     }
    110 #endif
    111 
    112     /* Initial state of channel */
    113     sc->sc_flags = 0;                   /* Clear flags to start */
    114     if (init_hw) {
    115         (void)soc_intr_disable(unit, IRQ_DESC_DONE(chan) | IRQ_CHAIN_DONE(chan));
    116         soc_pci_write(unit, CMIC_DMA_STAT, DS_DMA_EN_CLR(chan));
    117         soc_pci_write(unit, CMIC_DMA_STAT, DS_DESC_DONE_CLR(chan));
    118         soc_pci_write(unit, CMIC_DMA_STAT, DS_CHAIN_DONE_CLR(chan));
    119     }
    120 
    121     /* Setup new mode */
    122     bits  = f_mbm ? DC_MOD_BITMAP(chan) : DC_NO_MOD_BITMAP(chan);
    123     bits |= f_drop ? DC_DROP_TX(chan) : DC_NO_DROP_TX(chan);
    124     bits |= f_desc_intr ? DC_INTR_ON_DESC(chan) : DC_INTR_ON_PKT(chan);
    125 
    126     if (type == DV_TX) {
    127         bits |= DC_MEM_TO_SOC(chan);
    128         if (f_default) {
    129             soc->soc_dma_default_tx = sc;
    130         }
    131     } else if (type == DV_RX) {
    132         bits |= DC_SOC_TO_MEM(chan);
    133         if (f_default) {
    134             soc->soc_dma_default_rx = sc;
    135         }
    136     } else if (type == DV_NONE) {
    137         f_interrupt = FALSE;            /* Force off */
    138     } else {
    139         assert(0);
    140     }
    141 #ifdef INCLUDE_KNET
    142     if (SOC_KNET_MODE(unit)) {
    143         /* Interrupt are handled by kernel */
    144         f_interrupt = FALSE;
    145     }
    146 #endif
    147     if (f_interrupt) {
    148         (void)soc_intr_enable(unit,
    149                               IRQ_DESC_DONE(chan) | IRQ_CHAIN_DONE(chan));
    150     }
    151     sc->sc_type = type;
    152 
    153     if (init_hw) {
    154         cr = soc_pci_read(unit, CMIC_DMA_CTRL);
    155         cr &= ~DC_CHAN_MASK(chan);             /* Clear this channels bits */
    156         cr |= bits;                         /* Set new values */
    157         soc_pci_write(unit, CMIC_DMA_CTRL, cr);
    158     }
    159 
    160     return rv;
    161 }
    162 
    163 /*
    164  * Function:
    165  *      cmice_dma_chan_start
    166  * Purpose:
    167  *      Start the CMICE DMA channel for the specified SOC unit.
    168  * Parameters:
    169  *      unit - SOC unit #
    170  *      sc   - SOC channel data structure pointer
    171  * Returns:
    172  *      SOC_E_NONE - success
    173  *      SOC_E_XXXX - error code
    174  * Notes:
    175  */
    176 static int
    177 cmice_dma_chan_start(int unit, sdc_t *sc)
    178 {
    179     int rv = SOC_E_NONE;
    180     dv_t *dv;
    181 
    182     if ((dv = sc->sc_dv_active = sc->sc_q) == NULL) {
    183         sc->sc_q_tail = NULL;
    184         return rv;
    185     }
    186 
    187 #ifdef INCLUDE_KNET
    188     if (SOC_KNET_MODE(unit)) {
    189         return rv;
    190     }
    191 #endif
    192 
    193     /* Set up DMA descriptor address */
    194     soc_pci_write(unit, CMIC_DMA_DESC(sc->sc_channel),
    195                   soc_cm_l2p(unit, sc->sc_q->dv_dcb));
    196     /* Start DMA (Actually starts when the done bit is cleared below) */
    197     soc_pci_write(unit, CMIC_DMA_STAT,
    198                   DS_DMA_EN_SET(sc->sc_channel));
    199 
    200     SDK_CONFIG_MEMORY_BARRIER;
    201 
    202     /*
    203      * Clear CHAIN_DONE if required, and re-enable the
    204      * interrupt. This is required to support multiple DMA
    205      */
    206     if (sc->sc_flags & SOC_DMA_F_CLR_CHN_DONE) {
    207         soc_pci_write(unit, CMIC_DMA_STAT,
    208                       DS_CHAIN_DONE_CLR(sc->sc_channel));
    209     } else {
    210         sc->sc_flags |= SOC_DMA_F_CLR_CHN_DONE;
    211     }
    212     if (!(sc->sc_flags & SOC_DMA_F_POLL)) {
    213         (void)soc_intr_enable(unit, IRQ_CHAIN_DONE(sc->sc_channel));
    214     }
    215 
    216     return rv;
    217 }
    218 
    219 /*
    220  * Function:
    221  *      cmice_dma_chan_dv_start
    222  * Purpose:
    223  *      Adds DV to the ready queue for CMICE DMA for the specified SOC unit.
    224  * Parameters:
    225  *      unit - SOC unit #
    226  *      chan - channel #
    227  * Returns:
    228  *      SOC_E_NONE - success
    229  *      SOC_E_XXXX - error code
    230  * Notes:
    231  *      Assumes SOC_DMA_LOCK is held for CMIC_DMA_CTRL manipulation.
    232  */
    233 static int
    234 cmice_dma_chan_dv_start(int unit, sdc_t *sc, dv_t *dv_chain)
    235 {
    236     int rv = SOC_E_NONE;
    237 
    238     dv_chain->dv_next = NULL;
    239     if (sc->sc_q_cnt != 0) {
    240         sc->sc_q_tail->dv_next = dv_chain;
    241     } else {
    242         sc->sc_q = dv_chain;
    243     }
    244     sc->sc_q_tail = dv_chain;
    245     sc->sc_q_cnt++;
    246     if (sc->sc_dv_active == NULL) {     /* Start DMA if channel not active */
    247         rv = cmice_dma_chan_start(unit, sc);
    248     }
    249 
    250     return rv;
    251 }
    252 
    253 /*
    254  * Function:
    255  *      cmice_dma_chan_poll
    256  * Purpose:
    257  *      Poll the CMICE DMA channel for the specified SOC unit.
    258  * Parameters:
    259  *      unit - SOC unit #
    260  *      chan - channel #
    261  *      type - poll type (chain done or desc done)
    262  *      detected - poll result pointer to be updated
    263  * Returns:
    264  *      SOC_E_NONE - success
    265  *      SOC_E_XXXX - error code
    266  * Notes:
    267  *      Assumes that SOC_DMA_LOCK is held when called.
    268  */
    269 static int
    270 cmice_dma_chan_poll(int unit,
    271                     int chan,
    272                     soc_dma_poll_type_t type,
    273                     int *detected)
    274 {
    275     int rv = SOC_E_NONE;
    276 
    277     switch (type) {
    278     case SOC_DMA_POLL_DESC_DONE:
    279         *detected = ( soc_pci_read(unit, CMIC_DMA_STAT)
    280                       & DS_DESC_DONE_TST(chan) );
    281         break;
    282     case SOC_DMA_POLL_CHAIN_DONE:
    283         *detected = ( soc_pci_read(unit, CMIC_DMA_STAT)
    284                       & DS_CHAIN_DONE_TST(chan) );
    285         break;
    286     default:
    287         break;
    288     }
    289 
    290     return rv;
    291 }
    292 
    293 /*
    294  * Function:
    295  *      cmice_dma_chan_abort
    296  * Purpose:
    297  *      Aborts active DMA on the CMICE DMA channel for the specified SOC unit.
    298  * Parameters:
    299  *      unit - SOC unit #
    300  *      chan - channel #
    301  * Returns:
    302  *      SOC_E_NONE   - Success
    303  *      SOC_E_TIMEOUT - failed (Timeout)
    304  * Notes:
    305  *      Assumes SOC_DMA_LOCK is held for CMIC_DMA_CTRL manipulation.
    306  */
    307 static int
    308 cmice_dma_chan_abort(int unit, int chan)
    309 {
    310     int		        to;
    311     uint32          ctrl;
    312     int             rv = SOC_E_NONE;
    313 
    314     soc_pci_write(unit, CMIC_DMA_STAT, DS_DMA_EN_CLR(chan));
    315 
    316     SDK_CONFIG_MEMORY_BARRIER;
    317 
    318     ctrl = soc_pci_read(unit, CMIC_DMA_CTRL);
    319     assert((ctrl & DC_ABORT_DMA(chan)) == 0);
    320     soc_pci_write(unit, CMIC_DMA_CTRL, ctrl | DC_ABORT_DMA(chan));
    321 
    322     SDK_CONFIG_MEMORY_BARRIER;
    323 
    324     to = soc_property_get(unit, spn_PDMA_TIMEOUT_USEC, 500000);
    325 
    326     while ((to >= 0) &&
    327            ((soc_pci_read(unit, CMIC_DMA_STAT) & DS_DMA_ACTIVE(chan)) != 0)) {
    328         sal_udelay(1000);
    329         to -= 1000;
    330     }
    331 
    332     if ((soc_pci_read(unit, CMIC_DMA_STAT) & DS_DMA_ACTIVE(chan)) != 0) {
    333         LOG_ERROR(BSL_LS_SOC_PACKETDMA,
    334                   (BSL_META_U(unit,
    335                               "soc_dma_abort_channel unit %d: "
    336                               "channel %d abort timeout\n"),
    337                    unit, chan));
    338         rv = SOC_E_TIMEOUT;
    339         if (SOC_WARM_BOOT(unit)) {
    340             return rv;
    341         }
    342     }
    343 
    344     soc_pci_write(unit, CMIC_DMA_CTRL, ctrl);
    345     soc_pci_write(unit, CMIC_DMA_STAT, DS_DESC_DONE_CLR(chan));
    346     soc_pci_write(unit, CMIC_DMA_STAT, DS_CHAIN_DONE_CLR(chan));
    347 
    348     SDK_CONFIG_MEMORY_BARRIER;
    349 
    350     return rv;
    351 }
    352 
    353 /*
    354  * Function:
    355  *      cmice_dma_chan_tx_purge
    356  * Purpose:
    357  *      Aborts active DMA on the CMICE DMA channel for the specified SOC unit.
    358  * Parameters:
    359  *      unit - SOC unit #
    360  *      chan - channel #
    361  * Returns:
    362  *      SOC_E_NONE   - Success
    363  *      SOC_E_TIMEOUT - failed (Timeout)
    364  * Notes:
    365  *      Assumes SOC_DMA_LOCK is held for CMIC_DMA_CTRL manipulation.
    366  */
    367 static int
    368 cmice_dma_chan_tx_purge(int unit, int chan, dv_t *dv)
    369 {
    370     sal_usecs_t start_time;
    371     int         diff_time;
    372     uint32      dma_stat;
    373     uint32      dma_state;
    374     uint32      ctrl;
    375     int         rv = SOC_E_NONE;
    376 
    377     ctrl = soc_pci_read(unit, CMIC_DMA_CTRL);
    378     soc_pci_write(unit, CMIC_DMA_CTRL, ctrl | DC_MEM_TO_SOC(chan));
    379     soc_pci_write(unit, CMIC_DMA_DESC(chan),
    380                   soc_cm_l2p(unit, dv->dv_dcb));
    381     /* Start DMA */
    382     soc_pci_write(unit, CMIC_DMA_STAT, DS_DMA_EN_SET(chan));
    383 
    384     start_time = sal_time_usecs();
    385     diff_time = 0;
    386     dma_state = (DS_DESC_DONE_TST(chan) | DS_CHAIN_DONE_TST(chan));
    387     do {
    388         sal_udelay(SAL_BOOT_SIMULATION ? 1000 : 10);
    389         dma_stat = soc_pci_read(unit, CMIC_DMA_STAT) &
    390             (DS_DESC_DONE_TST(chan) | DS_CHAIN_DONE_TST(chan));
    391         diff_time = SAL_USECS_SUB(sal_time_usecs(), start_time);
    392         if (diff_time > DMA_ABORT_TIMEOUT) { /* 10 Sec(QT)/10 msec */
    393             rv = SOC_E_TIMEOUT;
    394             break;
    395         } else if (diff_time < 0) {
    396             /* Restart in case system time changed */
    397             start_time = sal_time_usecs();
    398         }
    399     } while (dma_stat != dma_state);
    400     /* Clear CHAIN_DONE and DESC_DONE */
    401     soc_pci_write(unit, CMIC_DMA_STAT, DS_DMA_EN_CLR(chan));
    402     soc_pci_write(unit, CMIC_DMA_STAT, DS_DESC_DONE_CLR(chan));
    403     soc_pci_write(unit, CMIC_DMA_STAT, DS_CHAIN_DONE_CLR(chan));
    404     soc_pci_write(unit, CMIC_DMA_CTRL, ctrl);
    405 
    406     return rv;
    407 }
    408 
    409 /*
    410  * Function:
    411  *      cmice_dma_chan_desc_done_intr_enable
    412  * Purpose:
    413  *      Clears desc done on the CMICE DMA channel for the specified SOC unit.
    414  * Parameters:
    415  *      unit - SOC unit #
    416  *      chan - channel #
    417  * Returns:
    418  *      SOC_E_NONE - success
    419  *      SOC_E_XXXX - error code
    420  * Notes:
    421  *      INTERRUPT LEVEL ROUTINE.
    422  */
    423 static int
    424 cmice_dma_chan_desc_done_intr_enable(int unit, int chan)
    425 {
    426     int rv = SOC_E_NONE;
    427 
    428     (void)soc_intr_enable(unit, IRQ_DESC_DONE(chan));
    429 
    430     return rv;
    431 }
    432 
    433 /*
    434  * Function:
    435  *      cmice_dma_chan_desc_done
    436  * Purpose:
    437  *      Clears desc done on the CMICE DMA channel for the specified SOC unit.
    438  * Parameters:
    439  *      unit - SOC unit #
    440  *      chan - channel #
    441  * Returns:
    442  *      SOC_E_NONE - success
    443  *      SOC_E_XXXX - error code
    444  * Notes:
    445  *      INTERRUPT LEVEL ROUTINE.
    446  */
    447 static int
    448 cmice_dma_chan_desc_done(int unit, int chan)
    449 {
    450     int rv = SOC_E_NONE;
    451 
    452     soc_pci_write(unit, CMIC_DMA_STAT, DS_DESC_DONE_CLR(chan));
    453 
    454     /* Flush posted writes from PCI bridge */
    455     (void)soc_pci_read(unit, CMIC_DMA_STAT);
    456 
    457     return rv;
    458 }
    459 
    460 /*
    461  * Function:
    462  *      cmice_dma_chan_chain_done
    463  * Purpose:
    464  *      on the CMICE DMA channel for the specified SOC unit.
    465  * Parameters:
    466  *      unit - SOC unit #
    467  *      chan - channel #
    468  *      mitigation - >0 = interrupt mitigation on
    469  * Returns:
    470  *      SOC_E_NONE - success
    471  *      SOC_E_XXXX - error code
    472  * Notes:
    473  *      INTERRUPT LEVEL ROUTINE.
    474  */
    475 static int
    476 cmice_dma_chan_chain_done(int unit, int chan, int mitigation)
    477 {
    478     int rv = SOC_E_NONE;
    479 
    480     if (mitigation) {
    481         (void)soc_intr_disable(unit,
    482                                IRQ_DESC_DONE(chan)
    483                                | IRQ_CHAIN_DONE(chan));
    484     } else {
    485         (void)soc_intr_disable(unit, IRQ_CHAIN_DONE(chan));
    486     }
    487     /* Enable DMA */
    488     soc_pci_write(unit, CMIC_DMA_STAT, DS_DMA_EN_CLR(chan));
    489 
    490     /* Clear the descriptor done stat bit */
    491     soc_pci_write(unit, CMIC_DMA_STAT, DS_DESC_DONE_CLR(chan));
    492 
    493     /* Flush posted writes from PCI bridge */
    494     (void)soc_pci_read(unit, CMIC_DMA_STAT);
    495 
    496     return rv;
    497 }
    498 
    499 /*
    500  * Function:
    501  *      cmice_dma_max_rx_channels_get
    502  * Purpose:
    503  *      obtain maximum number of dma channels that can be used for BCM RX
    504  * Parameters:
    505  *      unit - SOC unit #
    506  *      max_rx_channels - maximum rx channels that can be used
    507  * Returns:
    508  *      SOC_E_NONE - success
    509  *      SOC_E_XXXX - error
    510  */
    511 
    512 static int
    513 cmice_dma_max_rx_channels_get(int unit, uint32 *max_rx_channels)
    514 {
    515     int rv = SOC_E_NONE;
    516 
    517     /*
    518      * Only CMC0 is used for BCM RX hence we can have
    519      * N_DMA_CHAN number of maximum rx channels
    520      */
    521 
    522     *max_rx_channels = N_DMA_CHAN;
    523 
    524     return rv;
    525 }
    526 
    527 /* Public Functions */
    528 
    529 /*
    530  * Function:
    531  *      soc_cmice_dma_drv_init
    532  * Purpose:
    533  *      Initialize the CMICE DMA driver for the specified SOC unit.
    534  *      Assign function pointers for SOC DMA driver interface.
    535  * Parameters:
    536  *      unit - SOC unit #
    537  * Returns:
    538  *      SOC_E_NONE - success
    539  *      SOC_E_XXXX - error code
    540  * Notes:
    541  */
    542 int
    543 soc_cmice_dma_drv_init(int unit, soc_cmic_dma_drv_t *drv)
    544 {
    545     int rv = SOC_E_NONE;
    546 
    547     drv->init                       = cmice_dma_init;
    548     drv->ctrl_init                  = cmice_dma_ctrl_init;
    549     drv->chan_config                = cmice_dma_chan_config;
    550     drv->chan_dv_start              = cmice_dma_chan_dv_start;
    551     drv->chan_start                 = cmice_dma_chan_start;
    552     drv->chan_poll                  = cmice_dma_chan_poll;
    553     drv->chan_abort                 = cmice_dma_chan_abort;
    554     drv->chan_tx_purge              = cmice_dma_chan_tx_purge;
    555     drv->chan_desc_done_intr_enable = cmice_dma_chan_desc_done_intr_enable;
    556     drv->chan_desc_done             = cmice_dma_chan_desc_done;
    557     drv->chan_chain_done            = cmice_dma_chan_chain_done;
    558     drv->chan_reload_done           = NULL;
    559     drv->chan_counter_get           = NULL;
    560     drv->chan_counter_clear         = NULL;
    561     drv->chan_cos_ctrl_get          = NULL;
    562     drv->chan_cos_ctrl_set          = NULL;
    563     drv->chan_cos_ctrl_queue_get    = NULL;
    564     drv->chan_cos_ctrl_reg_addr_get = NULL;
    565     drv->chan_status_get            = NULL;
    566     drv->chan_status_clear          = NULL;
    567     drv->chan_halt_get              = NULL;
    568     drv->chan_ctrl_reg_get          = NULL;
    569     drv->chan_ctrl_reg_set          = NULL;
    570     drv->chan_rxbuf_threshold_cfg   = NULL;
    571     drv->cmc_rxbuf_threshold_cfg    = NULL;
    572     drv->cmc_counter_get            = NULL;
    573     drv->cmc_counter_clear          = NULL;
    574     drv->loopback_config            = NULL;
    575     drv->masks_get                  = NULL;
    576     drv->header_size_get            = NULL;
    577     drv->max_rx_channels_get        = cmice_dma_max_rx_channels_get;
    578     drv->pci_timeout_handle         = NULL;
    579 
    580     return rv;
    581 }
    582 
    583 #endif /* BCM_CMIC_SUPPORT */