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

cmicm_sbusdma_desc.c (14196B)


      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: CMICM SBUS Descriptor based DMA Driver.
      8  */
      9 
     10 #include <shared/bsl.h>
     11 #include <soc/drv.h>
     12 #include <soc/debug.h>
     13 #include <soc/cm.h>
     14 #include <soc/sbusdma_internal.h>
     15 
     16 #if defined(BCM_CMICM_SUPPORT) && defined(BCM_SBUSDMA_SUPPORT)
     17 
     18 #include <soc/cmicm.h>
     19 
     20 #define SOC_SBUSDMA_FP_RETRIES 200
     21 
     22 typedef struct { /* h/w desc structure */
     23     uint32 cntrl;    /* DMA control info */
     24     uint32 req;      /* DMA request info (refer h/w spec for details) */
     25     uint32 count;    /* DMA count */
     26     uint32 opcode;   /* Schan opcode (refer h/w spec for details) */
     27     uint32 addr;     /* Schan address */
     28     uint32 hostaddr; /* h/w mapped host address */
     29 } soc_sbusdma_desc_t;
     30 
     31 
     32 STATIC uint32 _cmicm_irq_sbusdma_ch[] = {
     33     IRQ_SBUSDMA_CH0_DONE,
     34     IRQ_SBUSDMA_CH1_DONE,
     35     IRQ_SBUSDMA_CH2_DONE
     36 };
     37 
     38 STATIC int _soc_desc_multi_cmc = 0;
     39 
     40 
     41 /*******************************************
     42 * @function _cmicm_sbusdma_desc_endian_config (private)
     43 * purpose Configure endianess of sbus dma descriptor
     44 *
     45 * @param unit [in] unit
     46 * @param desc [in] soc_sbusdma_desc_t pointer
     47 *
     48 * @returns None
     49 * @end
     50  */
     51 STATIC void
     52 _cmicm_sbusdma_desc_endian_config(int unit, soc_sbusdma_desc_t *desc)
     53 {
     54     int  big_pio, big_packet, big_other;
     55 
     56     soc_endian_get(unit, &big_pio, &big_packet, &big_other);
     57 
     58     if (big_other) {
     59        soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
     60                                &(desc->req), HOSTMEMWR_ENDIANESSf, 1);
     61        soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
     62                                &(desc->req), HOSTMEMRD_ENDIANESSf, 1);
     63     }
     64 }
     65 
     66 /*******************************************
     67 * @function _cmicm_sbusdma_desc_prepare
     68 * purpose API to prepare h/w descriptor
     69 *
     70 * @param unit [in] unit
     71 * @param desc [in] soc_sbusdma_desc_t pointer
     72 * @param cfg [in] soc_sbusdma_desc_cfg_t pointer
     73 * @param count [in] descriptor count
     74 * @param cfg_count [in] configuration count
     75 * @param append [in] last of appended
     76 *
     77 * @returns SOC_E_NONE
     78 * @returns SOC_E_XXX
     79 *
     80 * @end
     81  */
     82 STATIC
     83 void _cmicm_sbusdma_desc_prepare(int unit, soc_sbusdma_desc_t *desc,
     84                                 soc_sbusdma_desc_cfg_t *cfg, int count,
     85                                 soc_sbusdma_desc_ctrl_t *ctrl, int append)
     86 {
     87     sal_vaddr_t hptr = (sal_vaddr_t)(ctrl->buff);
     88     uint32 flags;
     89     schan_msg_t msg;
     90     int opcode, dst_blk, acc_type;
     91     int           data_byte_len = 0;
     92 
     93     sal_memset(desc, 0, sizeof(soc_sbusdma_desc_t));
     94     schan_msg_clear(&msg);
     95     flags = (ctrl->flags & SOC_SBUSDMA_CFG_USE_FLAGS) ? cfg->flags : ctrl->flags;
     96 
     97 
     98     if (flags & SOC_SBUSDMA_WRITE_CMD_MSG) {
     99         opcode = (flags & SOC_SBUSDMA_MEMORY_CMD_MSG) ?
    100             WRITE_MEMORY_CMD_MSG : WRITE_REGISTER_CMD_MSG;
    101         data_byte_len = cfg->width * sizeof(uint32);
    102     } else {
    103         opcode = (flags & SOC_SBUSDMA_MEMORY_CMD_MSG) ?
    104             READ_MEMORY_CMD_MSG : READ_REGISTER_CMD_MSG;
    105     }
    106     acc_type = cfg->acc_type;
    107     dst_blk = cfg->blk;
    108 
    109     soc_schan_header_cmd_set(unit, &msg.header, opcode, dst_blk, 0,
    110                              acc_type, data_byte_len, 0, 0);
    111 
    112 
    113     desc->count = cfg->count;
    114     desc->opcode = msg.dwords[0];
    115     desc->addr = cfg->addr;
    116 
    117     /* Prepare h/w desc */
    118     if ((ctrl->cfg_count == 1) || (count == ctrl->cfg_count - 1)) {
    119         desc->cntrl |= SOC_SBUSDMA_CTRL_LAST;
    120     }
    121     if (append && count) {
    122         desc->cntrl |= SOC_SBUSDMA_CTRL_APND;
    123     }
    124 
    125     if (ctrl->cfg_count == 1) {
    126         desc->hostaddr = soc_cm_l2p(unit, cfg->buff);
    127     } else {
    128        if (append) {
    129            desc->hostaddr = soc_cm_l2p(unit, ctrl->buff);
    130            ctrl->buff =  (void *)(hptr + (cfg->count * cfg->width));
    131        } else {
    132            desc->hostaddr = soc_cm_l2p(unit, cfg->buff);
    133        }
    134     }
    135     if ((opcode ==  WRITE_MEMORY_CMD_MSG) ||
    136         (opcode ==  WRITE_REGISTER_CMD_MSG)){
    137         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
    138                           &(desc->req), REQ_WORDSf, cfg->width);
    139         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
    140                           &(desc->req), REP_WORDSf, 0);
    141     } else {
    142         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
    143                           &(desc->req), REP_WORDSf, cfg->width);
    144         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
    145                           &(desc->req), REQ_WORDSf, 0);
    146         if (flags & SOC_SBUSDMA_CFG_MOR) {
    147             soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
    148                               &(desc->req), IGNORE_SBUS_EARLYACKf, 1);
    149             soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
    150                               &(desc->req), PEND_CLOCKSf, 30);
    151         }
    152     }
    153 
    154     soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr,
    155                       &(desc->req), INCR_SHIFTf, cfg->addr_shift);
    156 
    157     _cmicm_sbusdma_desc_endian_config(unit, desc);
    158 
    159     return;
    160 }
    161 
    162 /*******************************************
    163 * @function _cmicm_sbusdma_desc_create
    164 * purpose API to prepare h/w descriptor
    165 *
    166 * @param unit [in] unit
    167 * @param desc [in] soc_sbusdma_desc_ctrl_t pointer
    168 * @param cfg [in] soc_sbusdma_desc_cfg_t pointer
    169 * @param desc [out] descriptor pointer
    170 *
    171 * @returns SOC_E_NONE
    172 * @returns SOC_E_XXX
    173 *
    174 * @end
    175  */
    176 STATIC
    177 int _cmicm_sbusdma_desc_create(int unit, soc_sbusdma_desc_ctrl_t *ctrl,
    178                         soc_sbusdma_desc_cfg_t *cfg, void **desc)
    179 {
    180     soc_sbusdma_desc_t *dma_desc;
    181     uint8 append = 0;
    182     sal_vaddr_t hptr = (sal_vaddr_t)(ctrl->buff);
    183     uint32 count;
    184 
    185     if (ctrl->cfg_count == 1) { /* single mode */
    186          dma_desc = soc_cm_salloc(unit, sizeof(soc_sbusdma_desc_t),
    187                                       "soc_sbusdma_desc_t");
    188         if (dma_desc == NULL) {
    189             return SOC_E_MEMORY;
    190         }
    191         _cmicm_sbusdma_desc_prepare(unit, dma_desc, cfg, 0, ctrl, 0);
    192     } else {
    193         if (ctrl->buff) {
    194             append = 1;
    195         }
    196         dma_desc = soc_cm_salloc(unit, sizeof(soc_sbusdma_desc_t) *
    197                                       ctrl->cfg_count, "soc_sbusdma_desc_t");
    198         if (dma_desc == NULL) {
    199             return SOC_E_MEMORY;
    200         }
    201         for (count = 0; count < ctrl->cfg_count; count++) {
    202             _cmicm_sbusdma_desc_prepare(unit, &dma_desc[count], &cfg[count],
    203                                                          count, ctrl, append);
    204         }
    205         ctrl->buff = (void *)hptr;
    206     }
    207     *desc = dma_desc;
    208 
    209     return SOC_E_NONE;
    210 }
    211 
    212 
    213 /*******************************************
    214 * @function _cmicm_sbusdma_intr_wait
    215 * purpose API to wait Descriptor DMA complete
    216 *
    217 * @param unit [in] unit
    218 * @param cmc [in] cmc
    219 * @param ch [in] channel
    220 * @param interval [in] timeout
    221 *
    222 * @returns SOC_E_NONE
    223 * @returns SOC_E_XXX
    224 *
    225 * @end
    226  */
    227 STATIC int
    228 _cmicm_sbusdma_intr_wait(int unit, int cmc, int ch, int timeout)
    229 {
    230     int rv = SOC_E_TIMEOUT;
    231     int rval;
    232 
    233     soc_cmicm_cmcx_intr0_enable(unit, cmc, _cmicm_irq_sbusdma_ch[ch]);
    234     if (sal_sem_take(SOC_CONTROL(unit)->sbusDmaIntrs[cmc][ch], timeout) < 0) {
    235         rv = SOC_E_TIMEOUT;
    236     }
    237     soc_cmicm_cmcx_intr0_disable(unit, cmc, _cmicm_irq_sbusdma_ch[ch]);
    238 
    239     rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch));
    240     if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr,
    241                           rval, DONEf)) {
    242         rv = SOC_E_NONE;
    243         if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr,
    244                               rval, ERRORf)) {
    245             rv = SOC_E_FAIL;
    246             cmicm_sbusdma_curr_op_details(unit, cmc, ch);
    247         }
    248     }
    249 
    250     return rv;
    251 }
    252 
    253 /*******************************************
    254 * @function _cmicm_sbusdma_poll_wait
    255 * purpose API to wait Descriptor using Polling mode
    256 *
    257 * @param unit [in] unit
    258 * @param cmc [in] cmc
    259 * @param ch [in] channel
    260 * @param interval [in] timeout
    261 *
    262 * @returns SOC_E_NONE
    263 * @returns SOC_E_XXX
    264 *
    265 * @end
    266  */
    267 STATIC int
    268 _cmicm_sbusdma_poll_wait(int unit, int cmc, int ch, int timeout)
    269 {
    270    soc_timeout_t to;
    271    int rv = SOC_E_TIMEOUT;
    272    int rval;
    273 
    274    soc_timeout_init(&to, timeout, 0);
    275 
    276    do {
    277        rval = soc_pci_read(unit,
    278                            CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch));
    279        
    280        if (SAL_BOOT_PLISIM && !SAL_BOOT_BCMSIM) {
    281            rv = SOC_E_NONE;
    282            break;
    283        }
    284        if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr,
    285                              rval, DONEf)) {
    286            rv = SOC_E_NONE;
    287            if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr,
    288                                  rval, ERRORf)) {
    289                rv = SOC_E_FAIL;
    290                cmicm_sbusdma_curr_op_details(unit, cmc, ch);
    291            }
    292            break;
    293        }
    294    } while(!(soc_timeout_check(&to)));
    295 
    296    return rv;
    297 
    298 }
    299 
    300 /*******************************************
    301 * @function _cmicm_sbusdma_wait
    302 * purpose API to wait Descriptor DMA complete
    303 *
    304 * @param unit [in] unit
    305 * @param cmc [in] cmc
    306 * @param ch [in] channel
    307 * @param interval [in] time interval
    308 * @param intrEnb [in] interrupt enable
    309 *
    310 * @returns SOC_E_NONE
    311 * @returns SOC_E_XXX
    312 *
    313 * @end
    314  */
    315 STATIC int
    316 _cmicm_sbusdma_wait(int unit, int cmc, int ch, int interval, uint8 intrEnb)
    317 {
    318     int rv = SOC_E_TIMEOUT;
    319     int rval;
    320     uint32 ctrl;
    321 
    322     if (intrEnb) {
    323         rv = _cmicm_sbusdma_intr_wait(unit, cmc, ch, interval);
    324     } else {
    325         rv = _cmicm_sbusdma_poll_wait(unit, cmc, ch, interval);
    326     }
    327 
    328     if (rv != SOC_E_NONE) {
    329         if (rv != SOC_E_TIMEOUT) {
    330             LOG_ERROR(BSL_LS_SOC_COMMON,
    331                       (BSL_META_U(unit,
    332                                   "failed(ERR)\n")));
    333             cmicm_sbusdma_error_details(unit,
    334                 soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)));
    335         } else { /* Timeout cleanup */
    336             soc_timeout_t to;
    337 
    338             LOG_ERROR(BSL_LS_SOC_COMMON,
    339                       (BSL_META_U(unit,
    340                                   "%s timeout\n"),
    341                        intrEnb ?
    342                        "interrupt" : "polling"));
    343 
    344             /* Abort DMA */
    345             ctrl = soc_pci_read(unit,
    346                                 CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch));
    347             soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr,
    348                                 &ctrl, ABORTf, 1);
    349             soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch),
    350                                 ctrl);
    351 
    352             /* Check the done bit to confirm */
    353             soc_timeout_init(&to, interval, 0);
    354             while (1) {
    355                 rval = soc_pci_read(unit,
    356                                     CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch));
    357                 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr,
    358                     rval, DONEf)) {
    359                     break;
    360                 }
    361                 if (soc_timeout_check(&to)) {
    362                     LOG_ERROR(BSL_LS_SOC_COMMON,
    363                               (BSL_META_U(unit,
    364                                           "_cmicm_sbusdma_desc: Abort Failed\n")));
    365                     break;
    366                 }
    367             }
    368         }
    369     } /* rv != SOC_E_NONE */
    370 
    371     if (_soc_desc_multi_cmc) {
    372         cmicm_sbusdma_ch_put(unit, cmc, ch);
    373     }
    374 
    375     return rv;
    376 }
    377 
    378 /*******************************************
    379 * @function _cmicm_sbusdma_program
    380 * purpose API to program Descriptor DMA
    381 *
    382 * @param unit [in] unit
    383 * @param cmc [out] cmc
    384 * @param swd [out] _soc_sbusdma_state_t pointer
    385 * @param ch [out] channel
    386 *
    387 * @returns SOC_E_NONE
    388 * @returns SOC_E_XXX
    389 *
    390 * @end
    391  */
    392 STATIC int
    393 _cmicm_sbusdma_program(int unit, int *cmc, _soc_sbusdma_state_t *swd, int *ch)
    394 {
    395     uint32 ctrl;
    396     int i;
    397     soc_sbusdma_desc_t *desc = swd->desc;
    398 
    399     /*   multicmc */
    400     if (_soc_desc_multi_cmc) {
    401              SOC_IF_ERROR_RETURN(cmicm_sbusdma_ch_get(unit, cmc, ch));
    402              assert((*ch >= 0) && (*ch < CMIC_CMCx_SBUSDMA_CHAN_MAX));
    403     }
    404 
    405     ctrl = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(*cmc, *ch));
    406 
    407     soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl,
    408                       MODEf, 1);
    409     soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl,
    410                       ABORTf, 0);
    411     soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl,
    412                       STARTf, 0);
    413     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(*cmc, *ch), ctrl);
    414 
    415     /* write desc address */
    416     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_DESCADDR(*cmc, *ch),
    417                   soc_cm_l2p(unit, desc));
    418 
    419     /* Debug stuff */
    420     LOG_VERBOSE(BSL_LS_SOC_DMA,
    421                 (BSL_META_U(unit,
    422                             "Count: %d, cmc = %d, ch = %d\n"),
    423                             swd->ctrl.cfg_count, *cmc, *ch));
    424     for (i = 0; i < swd->ctrl.cfg_count; i++) {
    425         LOG_VERBOSE(BSL_LS_SOC_DMA,
    426                     (BSL_META_U(unit,
    427                                 "cntrl: %08x, req: %08x, count: %08x, "
    428                                 "opcode: %08x, saddr: %08x, haddr: %08x\n"),
    429                                 desc[i].cntrl, desc[i].req,
    430                                 desc[i].count, desc[i].opcode,
    431                                 desc[i].addr, desc[i].hostaddr));
    432     }
    433 
    434     soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl,
    435                       STARTf, 1);
    436     /* Start DMA */
    437     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(*cmc, *ch), ctrl);
    438 
    439     return SOC_E_NONE;
    440 }
    441 
    442 
    443 /*******************************************
    444 * @function cmicm_sbusdma_desc_init
    445 * purpose API to Initialize cmicm Descriptor DMA
    446 *
    447 * @param unit [in] unit
    448 * @param drv [out] soc_sbusdma_desc_drv_t pointer
    449 *
    450 * @returns SOC_E_NONE
    451 * @returns SOC_E_XXX
    452 *
    453 * @end
    454  */
    455 int cmicm_sbusdma_desc_init(int unit,
    456                             soc_sbusdma_desc_drv_t *drv)
    457 {
    458     /* Cache multi CMC flag */
    459     if (SOC_CHECK_MULTI_CMC(unit)) {
    460         _soc_desc_multi_cmc = 1;
    461     }
    462     drv->soc_sbusdma_desc_detach = NULL;
    463     drv->soc_sbusdma_program = _cmicm_sbusdma_program;
    464     drv->soc_sbusdma_desc_create = _cmicm_sbusdma_desc_create;
    465     drv->soc_sbusdma_wait = _cmicm_sbusdma_wait;
    466 
    467     return SOC_E_NONE;
    468 }
    469 
    470 
    471 #endif