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_reg.c (28237B)


      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-DMA Register Driver
      8  */
      9 
     10 #include <shared/bsl.h>
     11 #include <shared/alloc.h>
     12 #include <soc/drv.h>
     13 #include <soc/debug.h>
     14 #include <soc/cm.h>
     15 #include <soc/sbusdma_internal.h>
     16 
     17 #if defined(BCM_CMICX_SUPPORT) && defined(BCM_SBUSDMA_SUPPORT)
     18 #include <soc/cmicx.h>
     19 #include <soc/intr_cmicx.h>
     20 
     21 #ifdef BCM_SAND_SUPPORT
     22 #include <soc/sand/sand_aux_access.h>
     23 #endif
     24 
     25 #define SBUSDMA_REG_WAIT(wparam) \
     26                   (&((cmic_sbusdma_wparam_t  *)wparam)->wait)
     27 
     28 typedef struct cmicx_sbusdma_prog_s {
     29     uint8     rev_slam;
     30     uint8     mem_clear;
     31     int       opcode;
     32     int       cmc;
     33     int       ch;
     34     uint32    data_beats;
     35     uint32    start_addr;
     36     uint32    count;
     37     uint32    ser_flags;
     38 }cmicx_sbusdma_prog_t;
     39 
     40 
     41 /*******************************************
     42 * @function _cmicx_sbusdma_reg_program
     43 * purpose Programing the registers and start DMA
     44 *
     45 * @param unit [in] unit
     46 * @param param [in] soc_sbusdma_reg_param_t pointer
     47 * @param prog [in] cmicx_sbusdma_prog_t pointer
     48 *
     49 * @returns SOC_E_NONE
     50 * @returns SOC_E_XXX
     51 *
     52 * @end
     53  */
     54 STATIC void
     55 _cmicx_sbusdma_reg_program(int unit, schan_msg_t *msg,
     56                            soc_sbusdma_reg_param_t  *param,
     57                            cmicx_sbusdma_prog_t  *prog)
     58 {
     59     uint32        ctrl, rval;
     60     uint32        spacing;
     61     int big_pio, big_packet, big_other;
     62     soc_control_t *soc = SOC_CONTROL(unit);
     63 
     64      LOG_VERBOSE(BSL_LS_SOC_DMA,
     65                (BSL_META_U(unit,
     66                 "CMIC_CMCx_SBUSDMA_CHy_REQUEST=0x%x, "
     67                 "CMIC_CMCx_SBUSDMA_CHy_CONTROL= 0x%x\n"),
     68                 CMIC_CMCx_SBUSDMA_CHy_REQUEST(prog->cmc, prog->ch),
     69                 CMIC_CMCx_SBUSDMA_CHy_CONTROL(prog->cmc, prog->ch)));
     70     soc_endian_get(unit, &big_pio, &big_packet, &big_other);
     71     ctrl = soc_pci_read(unit,
     72                         CMIC_CMCx_SBUSDMA_CHy_CONTROL(prog->cmc, prog->ch));
     73     /* Set mode */
     74     soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl,
     75                       MODEf, 0);
     76     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(prog->cmc,
     77                   prog->ch), ctrl);
     78     /* Set 1st schan ctrl word as opcode */
     79     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_OPCODE(prog->cmc, prog->ch),
     80                   msg->dwords[0]);
     81     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_HOSTADDR_LO(prog->cmc, prog->ch),
     82                   PTR_TO_INT(soc_cm_l2p(unit, param->buffer)));
     83     /* Add HI ADDRESS */
     84     if (soc_cm_get_bus_type(unit) & SOC_PCI_DEV_TYPE) {
     85         soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_HOSTADDR_HI(prog->cmc, prog->ch),
     86                   (PTR_HI_TO_INT(soc_cm_l2p(unit, param->buffer)) |
     87                                 CMIC_PCIE_SO_OFFSET));
     88     } else {
     89         soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_HOSTADDR_HI(prog->cmc, prog->ch),
     90                   PTR_HI_TO_INT(soc_cm_l2p(unit, param->buffer)));
     91     }
     92     /* Start Address */
     93     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_ADDRESS(prog->cmc, prog->ch),
     94                   prog->start_addr);
     95     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_COUNT(prog->cmc, prog->ch),
     96                   prog->count);
     97 
     98     /* Program beats, increment/decrement, single */
     99 
    100     rval = 0;
    101     if (big_other) {
    102        soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    103              HOSTMEMWR_ENDIANESSf, 1);
    104        soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    105              HOSTMEMRD_ENDIANESSf, 1);
    106     }
    107     soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    108       INCR_SHIFTf, 0);
    109 
    110     if(prog->opcode == READ_MEMORY_CMD_MSG) {
    111         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    112                           REP_WORDSf, prog->data_beats);
    113         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    114                           REQ_WORDSf, 0);
    115     }
    116 
    117     if(prog->opcode == WRITE_MEMORY_CMD_MSG) {
    118         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    119                           REQ_WORDSf, prog->data_beats);
    120         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    121                           REP_WORDSf, 0);
    122         if (prog->mem_clear) {
    123             soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    124                               REQ_SINGLEf, 1);
    125         } else {
    126             soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    127                               REQ_SINGLEf, 0);
    128         }
    129         if (prog->rev_slam) {
    130             soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    131                               DECRf, 1);
    132         } else {
    133             soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    134                               DECRf, 0);
    135         }
    136 #ifdef BCM_HELIX5_SUPPORT
    137         if (SOC_IS_HELIX5(unit)) {
    138             if(param->mem == PMQPORT_WC_UCMEM_DATAm) {
    139                 /* H/W will increment the PRAM address automatically per write transaction in PM4X10Q Q mode.
    140                    Disable CMIC SBUS increase address.
    141                  */
    142                 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    143                                   INCR_NOADDf, 1);
    144             }
    145         }
    146 #endif
    147     }
    148 
    149     if (soc_feature(unit, soc_feature_multi_sbus_cmds)) {
    150         /*
    151          * rules for spacing:
    152          * 1. word_count + 1
    153          * 2. special requirements (i.e. higher value)
    154          *    before collect all special requirement, set to 8 or above
    155          */
    156         if (soc->sbusCmdSpacing < 0) {
    157             spacing = prog->data_beats > 7 ? prog->data_beats + 1 : 8;
    158         } else {
    159             spacing = soc->sbusCmdSpacing;
    160         }
    161         if (!((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_IPIPE) ||
    162                (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_EPIPE))) {
    163             spacing = 0;
    164         }
    165         soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval,
    166                           PEND_CLOCKSf, spacing);
    167     }
    168     soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_REQUEST(prog->cmc,
    169                   prog->ch), rval);
    170     return;
    171 }
    172 
    173 /*******************************************
    174 * @function _cmicx_sbusdma_reg_complete
    175 * purpose Wait and complete the DMA
    176 *
    177 * @param unit [in] unit
    178 * @param param [in] soc_sbusdma_reg_param_t pointer
    179 * @param wparam [in] void pointer
    180 *
    181 * @returns SOC_E_NONE
    182 * @returns SOC_E_XXX
    183 *
    184 * @end
    185  */
    186 STATIC int
    187 _cmicx_sbusdma_reg_complete(int unit, void *data,
    188                                       void *wparam)
    189 {
    190     int rv;
    191     uint32 do_not_perform_start_operation = 0;
    192     uint32 ctrl, rval;
    193     cmic_sbusdma_wait_t  *wait;
    194     soc_sbusdma_reg_param_t  *param;
    195 #ifdef PRINT_DMA_TIME
    196     int diff_time;
    197     uint32 count;
    198     uint32 data_beats;
    199 #endif
    200 
    201     if ((data == NULL) || (wparam == NULL)) {
    202         return SOC_E_PARAM;
    203     }
    204 
    205     param = (soc_sbusdma_reg_param_t  *)data;
    206     wait = SBUSDMA_REG_WAIT(wparam);
    207 #ifdef PRINT_DMA_TIME
    208     count = param->index_end - param->index_begin + 1;
    209     data_beats = soc_mem_entry_words(unit, param->mem);
    210     wait->start_time = sal_time_usecs();
    211 #endif
    212     if((param->flags & SOC_MEM_WRITE_STATUS_ONLY) != 0)
    213     {
    214         do_not_perform_start_operation = 1;
    215     }
    216     if (wait->intr_enb) {
    217         rv = cmicx_sbusdma_intr_wait(unit, wait->cmc, wait->ch,
    218                                      wait->timeout, do_not_perform_start_operation);
    219         if (rv != SOC_E_TIMEOUT) {
    220             SOC_CONTROL(unit)->stat.intr_tslam++;
    221         }
    222     } else {
    223         rv = cmicx_sbusdma_poll_wait(unit, wait->cmc, wait->ch,
    224                                      wait->timeout, do_not_perform_start_operation);
    225     }
    226 
    227 #ifdef PRINT_DMA_TIME
    228     diff_time = SAL_USECS_SUB(sal_time_usecs(), wait->start_time);
    229     LOG_VERBOSE(BSL_LS_SOC_DMA,
    230                 (BSL_META_U(unit,
    231                  "(%s)HW dma time[count=%u beats=%u]: %d usecs, [%d nsecs per op]\n"),
    232                  SOC_MEM_UFNAME(unit, param->mem),count,data_beats,
    233                  diff_time, diff_time*1000/count));
    234 #endif
    235 
    236     if (rv != SOC_E_NONE) {
    237         if (rv != SOC_E_TIMEOUT) {
    238             LOG_ERROR(BSL_LS_SOC_DMA,
    239                       (BSL_META_U(unit,
    240                                   "%s.%s failed(ERR %d)\n"),
    241                        SOC_MEM_UFNAME(unit, param->mem),
    242                        SOC_BLOCK_NAME(unit, param->copyno), rv));
    243             cmicx_sbusdma_error_details(unit,
    244                 soc_pci_read(unit,
    245                        CMIC_CMCx_SBUSDMA_CHy_STATUS(wait->cmc, wait->ch)));
    246         } else { /* Timeout cleanup */
    247             soc_timeout_t to;
    248 
    249             LOG_ERROR(BSL_LS_SOC_DMA,
    250                       (BSL_META_U(unit,
    251                                   "%s.%s %s timeout\n"),
    252                        SOC_MEM_UFNAME(unit, param->mem),
    253                        SOC_BLOCK_NAME(unit, param->copyno),
    254                        wait->intr_enb ? "interrupt" : "polling"));
    255 
    256             /* Abort DMA */
    257             ctrl = soc_pci_read(unit,
    258                                 CMIC_CMCx_SBUSDMA_CHy_CONTROL(wait->cmc, wait->ch));
    259             soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl,
    260                               ABORTf, 1);
    261             LOG_ERROR(BSL_LS_SOC_DMA,
    262                       (BSL_META_U(unit,
    263                                   "CMIC_CMC0_SBUSDMA_CH0_CONTROLr = 0x%x\n"), ctrl));
    264             soc_pci_write(unit,
    265                           CMIC_CMCx_SBUSDMA_CHy_CONTROL(wait->cmc, wait->ch), ctrl);
    266 
    267             /* Check the done bit to confirm */
    268             soc_timeout_init(&to, wait->timeout, 0);
    269             while (1) {
    270                 rval = soc_pci_read(unit,
    271                                     CMIC_CMCx_SBUSDMA_CHy_STATUS(wait->cmc, wait->ch));
    272                 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr,
    273                     rval, DONEf)) {
    274                     break;
    275                 }
    276                 if (soc_timeout_check(&to)) {
    277                     LOG_ERROR(BSL_LS_SOC_DMA,
    278                               (BSL_META_U(unit,
    279                                           "_cmicx_sbusdma_reg_read: Abort Failed\n")));
    280                     break;
    281                 }
    282             }
    283         }
    284     } else {
    285         if (wait->opcode == READ_MEMORY_CMD_MSG) {
    286             soc_cm_sinval(unit, (void *)param->buffer,
    287                   WORDS2BYTES(param->data_beats) * wait->count);
    288         }
    289     }
    290     /* Stop and free the channel if not reserved */
    291     cmicx_sbusdma_stop(unit, wait->cmc, wait->ch);
    292 
    293     if (param->vchan == -1) {
    294         cmicx_sbusdma_ch_put(unit, wait->cmc, wait->ch);
    295     }
    296 
    297     return rv;
    298 }
    299 
    300 /*******************************************
    301 * @function _cmicx_sbusdma_reg_prog_init
    302 * purpose Helper function to initialize data for DMA program
    303 *
    304 * @param unit [in] unit
    305 * @param param [in] soc_sbusdma_reg_param_t pointer
    306 * @param msg[out] schan_msg_t pointer
    307 * @param prog[out] cmicx_sbusdma_prog_t pointer
    308 * @param opcode [in] opcode.
    309 *
    310 * @returns SOC_E_NONE
    311 * @returns SOC_E_XXX
    312 *
    313 * @end
    314  */
    315 STATIC int
    316 _cmicx_sbusdma_reg_prog_init(int unit, soc_sbusdma_reg_param_t  *param,
    317                            schan_msg_t   *msg,
    318                            cmicx_sbusdma_prog_t  *prog, int opcode)
    319 {
    320     int           dst_blk, acc_type, dma;
    321     int           data_byte_len = 0;
    322 
    323     LOG_VERBOSE(BSL_LS_SOC_DMA,
    324                 (BSL_META_U(unit,
    325                             "unit %d"
    326                             " mem %s[%u-%u].%s index %d-%d buffer %p\n"),
    327                             unit, SOC_MEM_UFNAME(unit, param->mem),
    328                             param->array_id_start, param->array_id_end,
    329                             SOC_BLOCK_NAME(unit, param->copyno),
    330                             param->index_begin, param->index_end, param->buffer));
    331 
    332     prog->data_beats = param->data_beats;
    333 
    334     prog->opcode = opcode;
    335 
    336     if (param->vchan == -1) {
    337         SOC_IF_ERROR_RETURN(cmicx_sbusdma_ch_get(unit, &prog->cmc, &prog->ch));
    338     } else {
    339        SOC_IF_ERROR_RETURN(cmicx_sbusdma_vchan_to_cmc_ch(unit,
    340                             param->vchan, &prog->cmc, &prog->ch));
    341     }
    342 
    343     LOG_VERBOSE(BSL_LS_SOC_DMA,
    344              (BSL_META_U(unit,
    345                          "unit %d"
    346                          "cmc = %d, channel =%d\n"),
    347                          unit, prog->cmc, prog->ch));
    348 
    349     assert((prog->ch >= 0) && (prog->ch < CMIC_CMCx_SBUSDMA_CHAN_MAX));
    350 
    351     if (opcode == WRITE_MEMORY_CMD_MSG) {
    352         if (param->index_begin > param->index_end) {
    353             prog->count = param->index_begin - param->index_end + 1;
    354             prog->rev_slam = 1;
    355         } else {
    356             prog->count = param->index_end - param->index_begin + 1;
    357         }
    358     } else {
    359         prog->count = param->index_end - param->index_begin + 1;
    360     }
    361 
    362     if (prog->count < 1) {
    363         return SOC_E_NONE;
    364     }
    365 
    366     schan_msg_clear(msg);
    367     acc_type = SOC_MEM_ACC_TYPE(unit, param->mem);
    368 #if defined(BCM_XGS3_SWITCH_SUPPORT)
    369     if (0 != (param->flags & _SOC_SER_FLAG_MULTI_PIPE)) {
    370         if ((param->flags & _SOC_SER_FLAG_ACC_TYPE_MASK) ||
    371             (soc_feature(unit, soc_feature_unique_acc_type_access))) {
    372 
    373             /* Override ACC_TYPE in opcode */
    374             acc_type = param->flags & _SOC_SER_FLAG_ACC_TYPE_MASK;
    375         }
    376     }
    377 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    378     dst_blk = SOC_BLOCK2SCH(unit, param->copyno);
    379     if (opcode == WRITE_MEMORY_CMD_MSG) {
    380         data_byte_len = prog->data_beats * sizeof(uint32);
    381     } else {
    382         data_byte_len = 4;
    383     }
    384 
    385     LOG_VERBOSE(BSL_LS_SOC_DMA,
    386                 (BSL_META_U(unit,
    387                  "unit=%d %s.acc_type = %0x, idx[%0d-%0d]\n"),
    388                  unit, SOC_MEM_NAME(unit, param->mem), acc_type,
    389                  param->index_begin, param->index_end));
    390     /* DMA transaction indicator on SBUS */
    391     dma = 1;
    392 
    393     soc_schan_header_cmd_set(unit, &msg->header, opcode,
    394                              dst_blk, 0, acc_type, data_byte_len, dma, 0);
    395 
    396     return SOC_E_NONE;
    397 }
    398 
    399 /*******************************************
    400 * @function _cmicx_sbusdma_reg_array_read_prog
    401 * purpose : Program DMA for read
    402 *
    403 * @param unit [in] unit
    404 * @param param [in] soc_sbusdma_reg_param_t pointer
    405 * @param prog [in] pointer to void
    406 *
    407 * @returns SOC_E_NONE
    408 * @returns SOC_E_XXX
    409 *
    410 * @end
    411  */
    412 STATIC int
    413 _cmicx_sbusdma_reg_array_read_prog(int unit,
    414              void *data, void *wparam)
    415 {
    416     soc_control_t *soc = SOC_CONTROL(unit);
    417     schan_msg_t   msg;
    418     cmicx_sbusdma_prog_t  prog;
    419     cmic_sbusdma_wait_t  *wait;
    420     uint8         at;
    421     soc_sbusdma_reg_param_t  *param;
    422 
    423     if ((data == NULL) || (wparam == NULL)) {
    424         return SOC_E_PARAM;
    425     }
    426     param = (soc_sbusdma_reg_param_t  *)data;
    427 
    428     wait = SBUSDMA_REG_WAIT(wparam);
    429 
    430     if (wait == NULL) {
    431         return SOC_E_PARAM;
    432     }
    433 
    434     if (param->copyno < 0) {
    435         return SOC_E_PARAM;
    436     }
    437 
    438     LOG_VERBOSE(BSL_LS_SOC_DMA,
    439                 (BSL_META_U(unit,
    440                          "_cmicx_sbusdma_reg_read: unit %d"
    441                          " mem %s.%s[%u] index %d-%d"
    442                          "SER flags 0x%08x buffer %p, copyno = %d\n"),
    443                          unit, SOC_MEM_UFNAME(unit, param->mem),
    444                          SOC_BLOCK_NAME(unit, param->copyno),
    445                          param->array_id_start, param->index_begin,
    446                          param->index_end, param->flags,
    447                          param->buffer, param->copyno));
    448 
    449     sal_memset(&prog, 0, sizeof(cmicx_sbusdma_prog_t));
    450 
    451     param->data_beats = soc_mem_entry_words(unit, param->mem);
    452 
    453     SOC_IF_ERROR_RETURN(_cmicx_sbusdma_reg_prog_init(unit, param, &msg,
    454                                       &prog, READ_MEMORY_CMD_MSG));
    455 
    456     prog.ser_flags = param->flags;
    457     prog.start_addr = soc_mem_addr_get(unit, param->mem, param->array_id_start,
    458                                   param->copyno, param->index_begin, &at);
    459 
    460     _cmicx_sbusdma_reg_program(unit, &msg, param, &prog);
    461 
    462     LOG_VERBOSE(BSL_LS_SOC_DMA,
    463                 (BSL_META_U(unit,
    464                          "_cmicx_sbusdma_reg_read: %d entries %d beats "
    465                          "addr 0x%x (index %d-%d) Interrupt-Mode(%d)"
    466                          "Rev Slam %d\n"),
    467                          prog.count, prog.data_beats, prog.start_addr,
    468                          param->index_begin, param->index_end,
    469                          soc->tableDmaIntrEnb, prog.rev_slam));
    470 
    471     wait->count =  prog.count;
    472     wait->ch = prog.ch;
    473     wait->cmc = prog.cmc;
    474     wait->intr = INTR_SBUSDMA(prog.cmc, prog.ch);
    475     wait->opcode = READ_MEMORY_CMD_MSG;
    476 
    477     return SOC_E_NONE;
    478 }
    479 
    480 
    481 /*******************************************
    482 * @function _cmicx_sbusdma_reg_array_read
    483 * purpose DMA acceleration for soc_mem_read_range() on FB/ER
    484 *
    485 * @param unit [in] unit
    486 * @param param [in] soc_sbusdma_reg_param_t pointer
    487 *
    488 * @returns SOC_E_NONE
    489 * @returns SOC_E_XXX
    490 *
    491 * @end
    492  */
    493 STATIC int
    494 _cmicx_sbusdma_reg_array_read(int unit, soc_sbusdma_reg_param_t  *param)
    495 {
    496     soc_control_t *soc = SOC_CONTROL(unit);
    497     int           rv = SOC_E_NONE;
    498     cmic_sbusdma_wparam_t wparam;
    499 
    500     wparam.wait.intr_enb = soc->tableDmaIntrEnb;
    501     wparam.wait.timeout = soc->tableDmaTimeout;
    502 
    503     rv = _cmicx_sbusdma_reg_array_read_prog(unit, param, &wparam);
    504     SOC_IF_ERROR_RETURN(rv);
    505 
    506     rv = _cmicx_sbusdma_reg_complete(unit, param, &wparam);
    507 
    508     return rv;
    509 }
    510 
    511 /*******************************************
    512 * @function _cmicx_sbusdma_reg_array_write_prog
    513 * purpose DMA acceleration for soc_mem_write_range() on FB/ER
    514 *
    515 * @param unit [in] unit
    516 * @param param [in] soc_sbusdma_reg_param_t pointer
    517 * @param prog [in] pointer to void
    518 *
    519 * @returns SOC_E_NONE
    520 * @returns SOC_E_XXX
    521 *
    522 * @end
    523  */
    524 STATIC int
    525 _cmicx_sbusdma_reg_array_write_prog(int unit,
    526                  void  *data, void *wparam)
    527 {
    528     soc_control_t *soc = SOC_CONTROL(unit);
    529     int           rv = SOC_E_NONE;
    530     schan_msg_t   msg;
    531     unsigned      array_index;
    532     cmicx_sbusdma_prog_t  prog;
    533     cmic_sbusdma_wait_t  *wait;
    534     uint8         at;
    535     soc_sbusdma_reg_param_t  *param;
    536 
    537     if ((data == NULL) || (wparam == NULL)) {
    538         return SOC_E_PARAM;
    539     }
    540     param = (soc_sbusdma_reg_param_t  *)data;
    541 
    542     if ((param->flags & (SOC_MEM_WRITE_COMMIT_ONLY | SOC_MEM_WRITE_STATUS_ONLY | SOC_MEM_WRITE_SET_ONLY)) != 0 && param->array_id_start < param->array_id_end) {
    543         LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit,
    544             "cannot perform partial write operations for multiple memory array indices\n")));
    545         return SOC_E_PARAM;
    546     }
    547 
    548     if ((param->flags & SOC_MEM_WRITE_COMMIT_ONLY) != 0 && param->vchan != -1) {
    549         SOC_IF_ERROR_RETURN(cmicx_sbusdma_vchan_to_cmc_ch(unit,
    550                                 param->vchan, &prog.cmc, &prog.ch));
    551         _cmicx_sbusdma_start(unit, prog.cmc, prog.ch);
    552         return 0;
    553     }
    554     wait = SBUSDMA_REG_WAIT(wparam);
    555 
    556     if (wait == NULL) {
    557         return SOC_E_PARAM;
    558     }
    559 
    560     if (param->copyno < 0) {
    561         return SOC_E_PARAM;
    562     }
    563 
    564     LOG_VERBOSE(BSL_LS_SOC_DMA,
    565              (BSL_META_U(unit,
    566                          "_cmicx_sbusdma_reg_write: unit %d"
    567                          " mem %s[%u-%u].%s index %d-%d buffer %p\n"),
    568                          unit, SOC_MEM_UFNAME(unit, param->mem),
    569                          param->array_id_start, param->array_id_end,
    570                          SOC_BLOCK_NAME(unit, param->copyno),
    571                          param->index_begin, param->index_end, param->buffer));
    572 
    573     sal_memset(&prog, 0, sizeof(cmicx_sbusdma_prog_t));
    574 
    575     param->data_beats = soc_mem_entry_words(unit, param->mem);
    576 
    577     if ((param->flags & (SOC_MEM_WRITE_COMMIT_ONLY | SOC_MEM_WRITE_STATUS_ONLY)) == 0) { /* used by SOC_MEM_WRITE_SET_ONLY */
    578         SOC_IF_ERROR_RETURN(_cmicx_sbusdma_reg_prog_init(unit, param, &msg,
    579                                         &prog, WRITE_MEMORY_CMD_MSG));
    580         prog.mem_clear = param->mem_clear;
    581     } else { /* calculate channel instead */
    582         if (param->vchan == -1) {
    583             LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit,
    584                 "SOC_MEM_WRITE_STATUS_ONLY requires a channel to be specified\n")));
    585             return SOC_E_PARAM;
    586         } else {
    587             SOC_IF_ERROR_RETURN(cmicx_sbusdma_vchan_to_cmc_ch(unit,
    588                                 param->vchan, &prog.cmc, &prog.ch));
    589         }
    590     }
    591     /* fill out the interrupt data */
    592     wait->ch = prog.ch;
    593     wait->cmc = prog.cmc;
    594     wait->intr = INTR_SBUSDMA(prog.cmc, prog.ch);
    595     wait->opcode = WRITE_MEMORY_CMD_MSG;
    596 
    597     for (array_index = param->array_id_start;
    598                            array_index <= param->array_id_end; ++array_index) {
    599         if ((param->flags & (SOC_MEM_WRITE_COMMIT_ONLY | SOC_MEM_WRITE_STATUS_ONLY)) == 0) { /* used by SOC_MEM_WRITE_SET_ONLY */
    600             prog.start_addr = soc_mem_addr_get(unit, param->mem, array_index,
    601                                           param->copyno, param->index_begin, &at);
    602 
    603             _cmicx_sbusdma_reg_program(unit, &msg, param, &prog);
    604 
    605             LOG_VERBOSE(BSL_LS_SOC_DMA,
    606                      (BSL_META_U(unit,
    607                                  "_cmicx_sbusdma_reg_write: %d entries %d beats "
    608                                  "addr 0x%x (index %d-%d) Interrupt-Mode(%d)\n"),
    609                                  prog.count, prog.data_beats, prog.start_addr,
    610                                  param->index_begin, param->index_end,
    611                                  soc->tslamDmaIntrEnb));
    612 
    613             if (param->mem_clear) {
    614                 soc_cm_sflush(unit, param->buffer, WORDS2BYTES(prog.data_beats));
    615             } else {
    616                 soc_cm_sflush(unit, param->buffer, WORDS2BYTES(prog.data_beats)
    617                               * prog.count);
    618             }
    619         }
    620         if ((param->flags & SOC_MEM_WRITE_SET_ONLY ) == 0) { /* used by SOC_MEM_WRITE_STATUS_ONLY */
    621             /* Wait for each index to finish, except the last one */
    622             if (array_index != param->array_id_end) {
    623                 rv = _cmicx_sbusdma_reg_complete(unit, param, wparam);
    624             }
    625         }
    626     } /* end of loop over array indices */
    627 
    628     return rv;
    629 
    630 
    631 }
    632 
    633 /*******************************************
    634 * @function _cmicx_sbusdma_reg_array_write
    635 * purpose Program DMA for write
    636 *
    637 * @param unit [in] unit
    638 * @param param [in] soc_sbusdma_reg_param_t pointer
    639 *
    640 * @returns SOC_E_NONE
    641 * @returns SOC_E_XXX
    642 *
    643 * @end
    644  */
    645 STATIC int
    646 _cmicx_sbusdma_reg_array_write(int unit, soc_sbusdma_reg_param_t  *param)
    647 {
    648     soc_control_t *soc = SOC_CONTROL(unit);
    649     int rv = SOC_E_NONE;
    650     cmic_sbusdma_wparam_t wparam;
    651 
    652     wparam.wait.intr_enb = soc->tslamDmaIntrEnb;
    653     wparam.wait.timeout = soc->tslamDmaTimeout;
    654 
    655     rv = _cmicx_sbusdma_reg_array_write_prog(unit, param, &wparam);
    656     SOC_IF_ERROR_RETURN(rv);
    657 
    658     if ((param->flags & (SOC_MEM_WRITE_COMMIT_ONLY | SOC_MEM_WRITE_SET_ONLY)) == 0) { /* used by SOC_MEM_WRITE_STATUS_ONLY */
    659         rv = _cmicx_sbusdma_reg_complete(unit, param, &wparam);
    660     }
    661 
    662     return rv;
    663 }
    664 
    665 /*******************************************
    666 * @function _cmicx_sbusdma_reg_clear_specific
    667 * purpose: Program DMA to clear specific memory/table
    668 *
    669 * @param unit [in] unit
    670 * @param param [in] soc_sbusdma_reg_param_t pointer
    671 *
    672 * @returns SOC_E_NONE
    673 * @returns SOC_E_XXX
    674 *
    675 * @end
    676  */
    677 STATIC int
    678 _cmicx_sbusdma_reg_clear_specific_prog(int unit,
    679              void  *data, void *wparam)
    680 {
    681     int    rv = SOC_E_NONE;
    682     int    chunk_size, chunk_entries, mem_size, entry_words;
    683     int    index, blk, tmp, copyno;
    684     uint32 *buf;
    685     soc_sbusdma_reg_param_t  *param;
    686 
    687     param = (soc_sbusdma_reg_param_t  *)data;
    688 
    689     if (param == NULL) {
    690         return SOC_E_PARAM;
    691     }
    692     if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)) {
    693         return SOC_E_NONE;
    694     }
    695     chunk_size = SOC_MEM_CLEAR_CHUNK_SIZE_GET(unit);
    696     /* get legal values for indices, if too
    697      * small/big use the memory's boundaries
    698      */
    699     tmp = soc_mem_index_min(unit, param->mem);
    700     if (param->index_begin < soc_mem_index_min(unit, param->mem)) {
    701       param->index_begin = tmp;
    702     }
    703     if (param->index_end < param->index_begin) {
    704         param->index_end = param->index_begin;
    705     } else {
    706          tmp = soc_mem_index_max(unit, param->mem);
    707          if (param->index_end > tmp) {
    708              param->index_end = tmp;
    709          }
    710     }
    711 
    712     entry_words = soc_mem_entry_words(unit, param->mem);
    713     mem_size = (param->index_end - param->index_begin + 1) * entry_words * 4;
    714     if (mem_size < chunk_size) {
    715         chunk_size = mem_size;
    716     }
    717 
    718     buf = soc_cm_salloc(unit, chunk_size, "mem_clear_buf");
    719     if (buf == NULL) {
    720         return SOC_E_MEMORY;
    721     }
    722     chunk_entries = chunk_size / (entry_words * 4);
    723     for (index = 0; index < chunk_entries; index++) {
    724         sal_memcpy(buf + (index * entry_words),
    725                    param->buffer, entry_words * 4);
    726     }
    727 
    728     /* get legal values for memory array indices */
    729     if (SOC_MEM_IS_ARRAY(unit, param->mem)) {
    730         soc_mem_array_info_t *maip = SOC_MEM_ARRAY_INFOP(unit, param->mem);
    731         if (maip) {
    732             if (param->array_id_end >= maip->numels + maip->first_array_index) {
    733                 param->array_id_end = (maip->numels - 1) + maip->first_array_index;
    734             } else if (param->array_id_start < maip->first_array_index) {
    735                 param->array_id_start = maip->first_array_index;
    736             }
    737         }
    738     } else {
    739         param->array_id_start = param->array_id_end = 0;
    740     }
    741     copyno = param->copyno;
    742     MEM_LOCK(unit, param->mem);
    743     SOC_MEM_BLOCK_ITER(unit, param->mem, blk) {
    744         if (copyno != COPYNO_ALL && copyno != blk) {
    745             continue;
    746         }
    747         param->buffer = buf;
    748         param->flags = 0;
    749         param->mem_clear = TRUE;
    750         rv = _cmicx_sbusdma_reg_array_write(unit, param);
    751         if (rv < 0) {
    752             LOG_ERROR(BSL_LS_SOC_DMA,
    753                       (BSL_META_U(unit,
    754                                   "soc_mem_sbusdma_clear: %s.%s[%d-%d] failed: %s\n"),
    755                                   SOC_MEM_UFNAME(unit, param->mem),
    756                                   SOC_BLOCK_NAME(unit, blk),
    757                                   param->index_begin, param->index_end,
    758                                   soc_errmsg(rv)));
    759         }
    760     }
    761     MEM_UNLOCK(unit, param->mem);
    762     /* restoring the copy number since it is modified */
    763     param->copyno = copyno;
    764     soc_cm_sfree(unit, buf);
    765     return rv;
    766 
    767 }
    768 
    769 /*******************************************
    770 * @function _cmicx_sbusdma_reg_clear_specific
    771 * purpose clear a specific memory/table region using
    772 *          DMA write (slam) acceleration.
    773 *
    774 * @param unit [in] unit
    775 * @param param [in] soc_sbusdma_reg_param_t pointer
    776 *
    777 * @returns SOC_E_NONE
    778 * @returns SOC_E_XXX
    779 *
    780 * @end
    781  */
    782 STATIC int
    783 _cmicx_sbusdma_reg_clear_specific(int unit, soc_sbusdma_reg_param_t  *param)
    784 {
    785     int rv = SOC_E_NONE;
    786 
    787     rv = _cmicx_sbusdma_reg_clear_specific_prog(unit, param, NULL);
    788 
    789     return rv;
    790 }
    791 
    792 /*******************************************
    793 * @function _cmicx_sbusdma_cmc_max_num_ch_get
    794 * @Returns number of SBUSDMA channels in cmc
    795 *
    796 * @end
    797  */
    798 STATIC uint32
    799 _cmicx_sbusdma_cmc_max_num_ch_get(int unit)
    800 {
    801     return CMIC_CMCx_SBUSDMA_CHAN_MAX;
    802 }
    803 
    804 /*******************************************
    805 * @function cmicx_sbusdma_reg_init
    806 * purpose API to Initialize cmicx Register DMA
    807 *
    808 * @param unit [in] unit
    809 * @param drv [out] soc_sbusdma_desc_drv_t pointer
    810 *
    811 * @returns SOC_E_NONE
    812 * @returns SOC_E_XXX
    813 *
    814 * @end
    815  */
    816 int cmicx_sbusdma_reg_init(int unit, soc_sbusdma_reg_drv_t *drv)
    817 {
    818     /* Set ARB control register */
    819     soc_pci_write(unit, CMIC_TOP_SBUS_RING_ARB_CTRL_SBUSDMA_OFFSET,
    820                   CMIC_TOP_SBUS_RING_ARB_CTRL_SET);
    821 
    822     drv->soc_mem_sbusdma_read  = _cmicx_sbusdma_reg_array_read;
    823     drv->soc_mem_sbusdma_write = _cmicx_sbusdma_reg_array_write;
    824     drv->soc_mem_sbusdma_clear = _cmicx_sbusdma_reg_clear_specific;
    825     drv->soc_sbusdma_read_prog = _cmicx_sbusdma_reg_array_read_prog;
    826     drv->soc_sbusdma_write_prog = _cmicx_sbusdma_reg_array_write_prog;
    827     drv->soc_sbusdma_clear_prog = _cmicx_sbusdma_reg_clear_specific_prog;
    828     drv->soc_sbusdma_reg_complete =  _cmicx_sbusdma_reg_complete;
    829     drv->soc_sbusdma_cmc_max_num_ch_get = _cmicx_sbusdma_cmc_max_num_ch_get;
    830 
    831     return SOC_E_NONE;
    832 }
    833 
    834 #endif /* BCM_SBUSDMA_SUPPORT */
    835