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

cmicx_sbusdma_desc.c (14837B)


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