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_misc.c (25635B)


      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  * CMICx miscllaneous functions
      8  */
      9 
     10 #include <shared/bsl.h>
     11 #include <sal/core/libc.h>
     12 #include <sal/core/boot.h>
     13 #include <soc/debug.h>
     14 #include <soc/cm.h>
     15 #include <soc/drv.h>
     16 #include <soc/error.h>
     17 #include <sal/core/sync.h>
     18 #include <soc/util.h>
     19 #include <soc/cmic.h>
     20 
     21 #ifdef BCM_CMICX_SUPPORT
     22 #include <soc/cmicx.h>
     23 #include <soc/iproc.h>
     24 #endif
     25 
     26 /* PCIe capabilities */
     27 #ifndef PCI_CAPABILITY_LIST
     28 #define PCI_CAPABILITY_LIST     0x34
     29 #endif
     30 #ifndef PCI_CAP_ID_EXP
     31 #define PCI_CAP_ID_EXP          0x10
     32 #endif
     33 #ifndef PCI_EXP_DEVCAP
     34 #define PCI_EXP_DEVCAP          4
     35 #endif
     36 #ifndef PCI_EXP_DEVCTL
     37 #define PCI_EXP_DEVCTL          8
     38 #endif
     39 #ifndef PCI_EXT_CAP_START
     40 #define PCI_EXT_CAP_START       0x100
     41 #endif
     42 #ifndef PCI_EXT_CAP_ID
     43 #define PCI_EXT_CAP_ID(_hdr)    (_hdr & 0x0000ffff)
     44 #endif
     45 #ifndef PCI_EXT_CAP_VER
     46 #define PCI_EXT_CAP_VER(_hdr)   ((_hdr >> 16) & 0xf)
     47 #endif
     48 #ifndef PCI_EXT_CAP_NEXT
     49 #define PCI_EXT_CAP_NEXT(_hdr)  ((_hdr >> 20) & 0xffc)
     50 #endif
     51 #ifndef PCI_EXT_CAP_ID_VNDR
     52 #define PCI_EXT_CAP_ID_VNDR     0x0b
     53 #endif
     54 
     55 
     56 #ifdef BCM_CMICX_SUPPORT
     57 /**************************************************
     58 * @function soc_is_cmicx(unit)
     59 * purpose API to test if soc has cmicx
     60 *
     61 * @param unit [in] unit
     62 *
     63 * @returns SOC_E_NONE
     64 * @returns SOC_E_XXX
     65 *
     66 * @end
     67  */
     68 int soc_is_cmicx(int unit)
     69 {
     70     unsigned int cap_base, rval;
     71     if (SOC_IS_MONTEREY(unit))
     72         return FALSE;  
     73     /* Look for PCIe vendor-specific extended capability (VSEC) */
     74     cap_base = PCI_EXT_CAP_START;
     75     while (cap_base) {
     76         rval = soc_pci_conf_read(unit, cap_base);
     77         if (rval == 0xffffffff) {
     78            /* Assume PCI HW read error */
     79            return 0;
     80         }
     81 
     82         if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) {
     83             break;
     84         }
     85         cap_base = PCI_EXT_CAP_NEXT(rval);
     86     }
     87     if (cap_base) {
     88         /*
     89          * VSEC layout:
     90          *
     91          * 0x00: PCI Express Extended Capability Header
     92          * 0x04: Vendor-Specific Header
     93          * 0x08: Vendor-Specific Register 1
     94          * 0x0c: Vendor-Specific Register 2
     95          *     ...
     96          * 0x24: Vendor-Specific Register 8
     97          */
     98          /* Read PCIe Vendor Specific Register 1 */
     99          /* VENODR REG FORMAT
    100           * [7:0] iProc Rev = 8'h0E (for P14)
    101           * [11:8] CMIC BAR = 4'h1 (BAR64-1)
    102           * [15:12] CMIC Version = 4'h4
    103           * [19:16] CMIC Rev = 4'h1
    104           * [22:20] SBUS Version = 4'h4
    105           */
    106 
    107         rval = soc_pci_conf_read(unit, cap_base + 8);
    108 
    109         if (((rval >> 12) & 0xf) == 0x4) {
    110             return 1;
    111         }
    112     }
    113 
    114     return 0;
    115 
    116 }
    117 /**************************************************
    118 * @function soc_cmicx_iproc_version_get
    119 * purpose API to test if soc has cmicx
    120 *
    121 * @param unit [in] unit
    122 * @param iproc_ver [out] iproc version
    123 * @param cmic_ver  [out] cmic version
    124 * @param cmic_rev  [out] cmic revision
    125 *
    126 * @returns SOC_E_NONE
    127 * @returns SOC_E_XXX
    128 *
    129 * @end
    130  */
    131 int soc_cmicx_iproc_version_get(int unit, unsigned int *iproc_ver,
    132                                       unsigned int *cmic_ver,
    133                                       unsigned int *cmic_rev)
    134 {
    135     unsigned int cap_base, rval;
    136     if (SOC_IS_MONTEREY(unit))
    137         return FALSE;
    138     /* Look for PCIe vendor-specific extended capability (VSEC) */
    139     cap_base = PCI_EXT_CAP_START;
    140     while (cap_base) {
    141         rval = soc_pci_conf_read(unit, cap_base);
    142         if (rval == 0xffffffff) {
    143            /* Assume PCI HW read error */
    144            return 0;
    145         }
    146 
    147         if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) {
    148             break;
    149         }
    150         cap_base = PCI_EXT_CAP_NEXT(rval);
    151     }
    152     if (cap_base) {
    153         /*
    154          * VSEC layout:
    155          *
    156          * 0x00: PCI Express Extended Capability Header
    157          * 0x04: Vendor-Specific Header
    158          * 0x08: Vendor-Specific Register 1
    159          * 0x0c: Vendor-Specific Register 2
    160          *     ...
    161          * 0x24: Vendor-Specific Register 8
    162          */
    163          /* Read PCIe Vendor Specific Register 1 */
    164          /* VENODR REG FORMAT
    165           * [7:0] iProc Rev = 8'h0E (for P14)
    166           * [11:8] CMIC BAR = 4'h1 (BAR64-1)
    167           * [15:12] CMIC Version = 4'h4
    168           * [19:16] CMIC Rev = 4'h1
    169           * [22:20] SBUS Version = 4'h4
    170           */
    171 
    172         rval = soc_pci_conf_read(unit, cap_base + 8);
    173 
    174         *iproc_ver = rval & 0xff;
    175         *cmic_ver = (rval >> 12) & 0xf;
    176         *cmic_rev = (rval >> 16) & 0xf;
    177         return 1;
    178     }
    179 
    180     return 0;
    181 
    182 }
    183 
    184 /**************************************************
    185 * @function soc_cmicx_pci_test
    186 * purpose API to test PCI access to cmicx registers
    187 *
    188 * @param unit [in] unit
    189 *
    190 * @returns SOC_E_NONE
    191 * @returns SOC_E_XXX
    192 *
    193 * @end
    194  */
    195 int soc_cmicx_pci_test(int unit)
    196 {
    197     int i;
    198     uint32 tmp, reread;
    199     uint32 pat;
    200 
    201     SCHAN_LOCK(unit);
    202 
    203     /* Check for address uniqueness */
    204 
    205         for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) {
    206             pat = 0x55555555 ^ (i << 24 | i << 16 | i << 8 | i);
    207             soc_pci_write(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i), pat);
    208         }
    209 
    210         for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) {
    211             pat = 0x55555555 ^ (i << 24 | i << 16 | i << 8 | i);
    212             tmp = soc_pci_read(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i));
    213             if (tmp != pat) {
    214                 goto error;
    215             }
    216         }
    217 
    218     if (!SAL_BOOT_QUICKTURN) {  /* Takes too long */
    219         /* Rotate walking zero/one pattern through each register */
    220 
    221         pat = 0xff7f0080;       /* Simultaneous walking 0 and 1 */
    222 
    223         for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) {
    224             int j;
    225 
    226             for (j = 0; j < 32; j++) {
    227                     soc_pci_write(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i), pat);
    228                     tmp = soc_pci_read(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i));
    229                 if (tmp != pat) {
    230                     goto error;
    231                 }
    232                 pat = (pat << 1) | ((pat >> 31) & 1);	/* Rotate left */
    233             }
    234         }
    235     }
    236 
    237     /* Clear to zeroes when done */
    238 
    239     for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) {
    240             soc_pci_write(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i), 0);
    241     }
    242     SCHAN_UNLOCK(unit);
    243     return SOC_E_NONE;
    244 
    245  error:
    246     reread = soc_pci_read(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i));
    247 
    248     LOG_ERROR(BSL_LS_SOC_COMMON,
    249               (BSL_META_U(unit,
    250                           "FATAL PCI error testing PCIM[0x%x]:\n"
    251                           "Wrote 0x%x, read 0x%x, re-read 0x%x\n"),
    252                i, pat, tmp, reread));
    253 
    254     SCHAN_UNLOCK(unit);
    255     return SOC_E_INTERNAL;
    256 }
    257 
    258 /**************************************************
    259 * @function soc_cmicx_paxb_tx_arbiter_set
    260 * purpose: API to set tx arbiter
    261 *
    262 * @param unit [in] unit
    263 * @param unit [in] enable
    264 * @param unit [in] priority
    265 *
    266 * @returns SOC_E_NONE
    267 * @returns SOC_E_XXX
    268 *
    269 * @end
    270  */
    271 int soc_cmicx_paxb_tx_arbiter_set(int unit, uint8 enable, uint8 priority)
    272 {
    273     uint32 cmic_reg_val = 0;
    274 
    275     if (SOC_IS_TRIDENT3X(unit)) {
    276         soc_reg_field_set(unit, PAXB_0_PAXB_TX_ARBITER_PRIORITYr, &cmic_reg_val,
    277                           TX_REQ_SEQ_ENf, enable);
    278         soc_reg_field_set(unit, PAXB_0_PAXB_TX_ARBITER_PRIORITYr, &cmic_reg_val,
    279                           TX_ARB_PRIORITYf, priority);
    280         SOC_IF_ERROR_RETURN(WRITE_PAXB_0_PAXB_TX_ARBITER_PRIORITYr(unit, cmic_reg_val));
    281     }
    282 
    283     return SOC_E_NONE;
    284 }
    285 
    286 /**************************************************
    287 * @function soc_cmicx_reg_offset_get
    288 * purpose: API to get min and max offsets for cmicx reg
    289 *
    290 * @param unit [out] min
    291 * @param unit [out] max
    292 *
    293 * @returns none
    294 *
    295 * @end
    296  */
    297 
    298 void soc_cmicx_reg_offset_get(uint32 *min, uint32 *max)
    299 {
    300     *min = CMICX_OFFSET_MIN;
    301     *max = CMICX_OFFSET_MAX;
    302 
    303     return;
    304 }
    305 
    306 /* store the cmc and IF of a DMA channel */
    307 typedef struct {
    308     uint8 channel_cmc;
    309     uint8 channel_id;
    310 } channel_ids_t;
    311 
    312 /*
    313  * structure/object storing channel_ids_ts that can be added, and then iterated,
    314  * while the current channel_ids_t can be removed during iteration.
    315  * All functions have O(1) runtime.
    316  * Does not preserve the order of the channels.
    317  */
    318 #define CHANS_GROUP_MAX_SIZE (CMIC_CMC_NUM_MAX * CMICX_N_DMA_CHAN)
    319 typedef struct {
    320     unsigned nof_chans;
    321     channel_ids_t channels[CHANS_GROUP_MAX_SIZE];
    322 } chans_group_t;
    323 typedef channel_ids_t *chans_group_iter_t;
    324 /* init object to be empty */
    325 STATIC INLINE void chans_group_init(chans_group_t *group) {
    326     group->nof_chans = 0;
    327 }
    328 /* init the itertor to the start of the group */
    329 STATIC INLINE void chans_group_iter_start(chans_group_t *group, chans_group_iter_t *iter) {
    330     *iter = group->channels;
    331 }
    332 /* is iterator pointing to beyond the end of the group */
    333 STATIC INLINE int chans_group_is_end(chans_group_t *group, chans_group_iter_t iter) {
    334     return iter >= group->channels + group->nof_chans;
    335 }
    336 /* return the size (number of channels) of the group */
    337 STATIC INLINE unsigned chans_group_get_nof_chans(chans_group_t *group) {
    338     return group->nof_chans;
    339 }
    340 /* Insert a channel to the group */
    341 STATIC INLINE void chans_group_insert(chans_group_t *group, int cmc, int chan) {
    342     chans_group_iter_t i = group->channels + group->nof_chans;
    343     assert(group->nof_chans < CHANS_GROUP_MAX_SIZE);
    344     i->channel_cmc = cmc;
    345     i->channel_id = chan;
    346     ++group->nof_chans;
    347 }
    348 /*
    349  * Remove the channel pointed to by the iterator from the group,
    350  * the iterator will point to a channel not yet traversed,
    351  * or point past the end of the group if all channels were traversed
    352  */
    353 STATIC INLINE void chans_group_delete(chans_group_t *group, chans_group_iter_t iter) {
    354     assert(group->nof_chans > 0);
    355     *iter = group->channels[--group->nof_chans];
    356 }
    357 /* get the cahnnel pointed to by the iterator */
    358 STATIC INLINE void chans_group_iter_t_get(chans_group_iter_t channel_iter, int *cmc, int *chan) {
    359     *cmc = channel_iter->channel_cmc;
    360     *chan = channel_iter->channel_id;
    361 }
    362 
    363 typedef enum { /* possible states of the timeout used by cmicx_dma_abort() */
    364     abort_timeout_not_initialized,
    365     abort_timeout_not_passed,
    366     abort_timeout_passed
    367 } abort_timeout_state_t;
    368 
    369 /* The timeout needs to be at least 50ms which is the PCIe completion timeout value  */
    370 #define MIN_CMICX_DMA_ABORT_TIMEOUT 50000
    371 #define DEFAULT_CMICX_DMA_ABORT_TIMEOUT (MIN_CMICX_DMA_ABORT_TIMEOUT * 6 / 5)
    372 #define CMICX_INITIAL_SLEEP 10000
    373 
    374 /*
    375  * Function:
    376  *      cmicx_dma_abort
    377  * Purpose:
    378  *      Deconfigure previously defined DMA operations and abort pending operation.
    379  *      Useful in case SDK was not de-initialized / not brought down properly,
    380  *      and when not resetting on startup; like in an unscheduled warm boot.
    381  *      Most important for DMA operations initiated by the device operating on
    382  *      external CPU memory, like FIFO and packet DMA.
    383  *      Also handles operations that did not complete.
    384  * Parameters:
    385  *      unit - SOC unit #
    386  *      flags - flags specifying not to handle some DMA types
    387  * Returns:
    388  *      SOC_E_NONE - success
    389  *      SOC_E_XXXX - error code
    390  * Notes:
    391  */
    392 int
    393 soc_cmicx_dma_abort(int unit, uint32 flags)
    394 {
    395     int cmc, chan, nof_channels, nof_failures = 0;
    396     int cmc_num_max = CMIC_CMC_NUM_MAX;
    397     uint32 val, cmic_address, done;
    398     
    399     sal_usecs_t start_time = 0, iter_time, timeout, timeout_sleep = CMICX_INITIAL_SLEEP;
    400     abort_timeout_state_t timeout_state = abort_timeout_not_initialized;
    401     chans_group_iter_t channel_iter;
    402     chans_group_t packet_channels, sbus_channels, fifo_channels, ccm_channels, schan_fifo_channels;
    403 
    404     LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "aborting and disabling DMA\n")));
    405 
    406     /* Abort all DMA types */
    407     /* Use flag SOC_DMA_ABORT_CMC0 in case other CMC's are used by the internal Arm CPUs */
    408 
    409     if (flags & SOC_DMA_ABORT_CMC0) {
    410         cmc_num_max = 1;
    411     }
    412 
    413     timeout = soc_property_get(unit, spn_DMA_ABORT_TIMEOUT_USEC, DEFAULT_CMICX_DMA_ABORT_TIMEOUT);
    414     if (timeout < MIN_CMICX_DMA_ABORT_TIMEOUT) {
    415         timeout = MIN_CMICX_DMA_ABORT_TIMEOUT;
    416     }
    417 
    418     /* abort packet DMA in all channels */
    419     chans_group_init(&packet_channels);
    420     if ((flags & SOC_DMA_ABORT_SKIP_PACKET) == 0) {
    421         for (cmc = 0; cmc < cmc_num_max; ++cmc) {
    422             for (chan = 0; chan < CMIC_CMCx_PKTDMA_NOF_CHANS; ++chan) {
    423                 cmic_address = CMIC_CMCx_PKTDMA_CHy_CTRL_OFFSET(cmc, chan);
    424                 /* if CMIC_CMCx_PKTDMA_CHy_CTRL.DMA_EN == 1 */
    425                 val = soc_pci_read(unit, cmic_address);
    426                 if (val & PKTDMA_ENABLE) {
    427                     /* set CMIC_CMCx_PKTDMA_CHy_CTRL.ABORT_DMA=1 to abort, and later wait for CMIC_CMCx_SHARED_IRQ_STAT0.CHy_CHAIN_DONE==1 */
    428                     soc_pci_write(unit, cmic_address, val | PKTDMA_ABORT);
    429                     chans_group_insert(&packet_channels, cmc, chan); /* mark the channel to be waited on */
    430                     LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting packet DMA CMC %d channel %d\n"), cmc, chan));
    431                 }
    432             }
    433         }
    434     }
    435 
    436     /* abort s-bus DMA in all channels */
    437     chans_group_init(&sbus_channels);
    438     if ((flags & SOC_DMA_ABORT_SKIP_SBUS) == 0) {
    439         /* For  CMCs x=0-1  and channels y=0-3 and [channel used by this CPU] */
    440         for (cmc = 0; cmc < cmc_num_max; ++cmc) {
    441             for (chan = 0; chan < CMIC_CMCx_SBUSDMA_CHAN_MAX; ++chan) {
    442                 cmic_address = CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, chan);
    443                 /* if CMIC_CMCx_SBUSDMA_CHy_CONTROL.START == 1 */
    444                 val = soc_pci_read(unit, cmic_address);
    445                 if (val & CMIC_CMCx_SBUSDMA_CHy_CONTROL_START) {
    446                     /* set CMIC_CMCx_SBUSDMA_CHy_CONTROL.ABORT=1 to abort */
    447                     soc_pci_write(unit, cmic_address, val | CMIC_CMCx_SBUSDMA_CHy_CONTROL_ABORT);
    448                     chans_group_insert(&sbus_channels, cmc, chan); /* mark the channel to be waited on */
    449                     LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting s-bus DMA CMC %d channel %d\n"), cmc, chan));
    450                 }
    451             }
    452         }
    453     }
    454 
    455     /* abort FIFO DMA in all channels, FIFO DMA is not per CMC */
    456     chans_group_init(&fifo_channels);
    457     if ((flags & SOC_DMA_ABORT_SKIP_FIFO) == 0) {
    458         for (chan = 0; chan < CMICX_N_FIFODMA_CHAN; ++chan) {
    459             cmic_address = CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_OFFSET(chan);
    460             /* if CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG.ENABLE == 1 */
    461             val = soc_pci_read(unit, cmic_address);
    462             if (val & CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_ENABLE) {
    463                 /* set CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG.ABORT=1 to abort */
    464                 soc_pci_write(unit, cmic_address, val | CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_ABORT);
    465                 chans_group_insert(&fifo_channels, 0, chan); /* mark the channel to be waited on */
    466                 LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting FIFO DMA channel %d\n"), chan));
    467             }
    468         }
    469     }
    470 
    471     /* abort CCM DMA in all channels */
    472     chans_group_init(&ccm_channels);
    473     if ((flags & SOC_DMA_ABORT_SKIP_CCM) == 0) {
    474         /* For  CMCs x=0-1  and channels y=0-1 and [channel used by this CPU] */
    475         for (cmc = 0; cmc < cmc_num_max; ++cmc) {
    476             for (chan = 0; chan < CMICX_N_CCMDMA_CHAN; ++chan) {
    477                 cmic_address = CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, chan);
    478                 /* if CMIC_CMCx_CCMDMA_CHy_CFG.EN == 1 */
    479                 val = soc_pci_read(unit, cmic_address);
    480                 if (val & CMIC_CMCx_CCMDMA_CHy_CFG_EN) {
    481                     /* set CMIC_CMCx_CCMDMA_CHy_CFG.ABORT=1 to abort */
    482                     soc_pci_write(unit, cmic_address, val | CMIC_CMCx_CCMDMA_CHy_CFG_ABORT);
    483                     chans_group_insert(&ccm_channels, cmc, chan); /* mark the channel to be waited on */
    484                     LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting CCM DMA CMC %d channel %d\n"), cmc, chan));
    485                 }
    486             }
    487         }
    488     }
    489 
    490     /* abort s-chan FIFO in all channels, s-chan FIFO is not per CMC */
    491     chans_group_init(&schan_fifo_channels);
    492     if ((flags & SOC_DMA_ABORT_SKIP_SCHAN_FIFO) == 0) {
    493         /* For channels y=0-1 and [channels used by this CPU] */
    494         for (chan = 0; chan < CMIC_SCHAN_FIFO_NUM_MAX; ++chan) {
    495             cmic_address = CMIC_SCHAN_FIFO_CHx_CTRL(chan);
    496             /* if CMIC_COMMON_POOL_SCHAN_FIFO_0_CHy_CTRL.START == 1 */
    497             val = soc_pci_read(unit, cmic_address);
    498             if (val & SCHAN_FIFO_CTRL_START) {
    499                 /* set CMIC_COMMON_POOL_SCHAN_FIFO_0_CHy_CTRL.ABORT=1 to abort */
    500                 soc_pci_write(unit, cmic_address, val | SCHAN_FIFO_CTRL_ABORT);
    501                 chans_group_insert(&schan_fifo_channels, 0, chan); /* mark the channel to be waited on */
    502                 LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting s-chan FIFO channel %d\n"), chan));
    503             }
    504         }
    505     }
    506 
    507     nof_channels = chans_group_get_nof_chans(&packet_channels) + chans_group_get_nof_chans(&sbus_channels) +
    508       chans_group_get_nof_chans(&fifo_channels) + chans_group_get_nof_chans(&ccm_channels) + chans_group_get_nof_chans(&schan_fifo_channels);
    509 
    510     /* loop and check that each abort finished. When it finished or after time out, clear the operation and disable the DMA */
    511     do {
    512         /* measure time at the start of the iteration */
    513         iter_time = sal_time_usecs();
    514         if (timeout_state == abort_timeout_not_initialized) {
    515             timeout_state = abort_timeout_not_passed;
    516             start_time = iter_time;
    517         }
    518         if (iter_time - start_time >= timeout ) { /* was the timeout value reached? */
    519             timeout_state = abort_timeout_passed;
    520         }
    521 
    522 
    523         /* for all packet DMA channels still not done */
    524         for (chans_group_iter_start(&packet_channels, &channel_iter); !chans_group_is_end(&packet_channels, channel_iter); ++channel_iter) {
    525             chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */
    526             /* If the abort is done (CMIC_CMCx_SHARED_IRQ_STAT0.CHy_CHAIN_DONE==1), disable packet DMA */
    527             done = soc_pci_read(unit, CMIC_CMCx_SHARED_IRQ_STAT0_OFFSET(cmc)) & DS_CMCx_CHy_DMA_CHAIN_DONE(chan);
    528             if (done || timeout_state == abort_timeout_passed) {
    529                 /* clear CMIC_CMCx_PKTDMA_CHy_CTRL.ABORT_DMA|DMA_EN in the same write to disable; it also clears statuses */
    530                 cmic_address = CMIC_CMCx_PKTDMA_CHy_CTRL_OFFSET(cmc, chan);
    531                 val = soc_pci_read(unit, cmic_address);
    532                 soc_pci_write(unit, cmic_address, val & ~(PKTDMA_ENABLE | PKTDMA_ABORT));
    533                 if (done) { /* remove the channel from the channels waited on */
    534                     chans_group_delete(&packet_channels, channel_iter--);
    535                 } else {
    536                     LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort packet DMA in CMC %d channel %d, check with the design team\n"), cmc, chan));
    537                     ++nof_failures;
    538                 }
    539             }
    540         }
    541 
    542         /* for all s-bus DMA channels still not done */
    543         for (chans_group_iter_start(&sbus_channels, &channel_iter); !chans_group_is_end(&sbus_channels, channel_iter); ++channel_iter) {
    544             chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */
    545             /* If the abort is done (CMIC_CMCx_SBUSDMA_CHy_STAT.DONE==1), then clear the operation */
    546             done = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, chan)) & CMIC_CMCx_SBUSDMA_CHy_STATUS_DONE;
    547             if (done || timeout_state == abort_timeout_passed) {
    548                 /* clear CMIC_CMCx_SBUSDMA_CHy_CONTROL.ABORT|START in the same write disables the original operation and abort, and clears statuses */
    549                 cmic_address = CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, chan);
    550                 val = soc_pci_read(unit, cmic_address);
    551                 soc_pci_write(unit, cmic_address, val & ~(CMIC_CMCx_SBUSDMA_CHy_CONTROL_ABORT |CMIC_CMCx_SBUSDMA_CHy_CONTROL_START ));
    552                 if (done) { /* remove the channel from the channels waited on */
    553                     chans_group_delete(&sbus_channels, channel_iter--);
    554                 } else {
    555                     LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort s-bus DMA in CMC %d channel %d, check with the design team\n"), cmc, chan));
    556                     ++nof_failures;
    557                 }
    558             }
    559         }
    560 
    561         /* for all FIFO DMA channels still not done */
    562         for (chans_group_iter_start(&fifo_channels, &channel_iter); !chans_group_is_end(&fifo_channels, channel_iter); ++channel_iter) {
    563             chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */
    564             /* If the abort is done (CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_STAT.ABORTED==1), then clear the operation and disable */
    565             done = soc_pci_read(unit, CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_STAT_OFFSET(chan)) & CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_STAT_ABORTED;
    566             if (done || timeout_state == abort_timeout_passed) {
    567                 /* clear CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG.ABORT|ENABLE in the same write: disables and clears statuses */
    568                 cmic_address = CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_OFFSET(chan);
    569                 val = soc_pci_read(unit, cmic_address);
    570                 soc_pci_write(unit, cmic_address, val & ~(CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_ABORT | CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_ENABLE));
    571                 if (done) { /* remove the channel from the channels waited on */
    572                     chans_group_delete(&fifo_channels, channel_iter--);
    573                 } else {
    574                     LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort FIFO DMA in channel %d, check with the design team\n"), chan));
    575                     ++nof_failures;
    576                 }
    577             }
    578         }
    579 
    580         /* for all CCM DMA channels still not done */
    581         for (chans_group_iter_start(&ccm_channels, &channel_iter); !chans_group_is_end(&ccm_channels, channel_iter); ++channel_iter) {
    582             chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */
    583             /* If the abort is done (CMIC_CMCx_CCMDMA_CHy_STAT.DONE==1), then clear the operation */
    584             done = soc_pci_read(unit, CMIC_CMCx_CCMDMA_CHy_STAT_OFFSET(cmc, chan)) & CMIC_CMCx_CCMDMA_CHy_STAT_DONE;
    585             if (done || timeout_state == abort_timeout_passed) {
    586                 /* clear CMIC_CMCx_CCMDMA_CHy_CFG.ABORT|EN in the same write: disables and clears statuses */
    587                 cmic_address = CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, chan);
    588                 val = soc_pci_read(unit, cmic_address);
    589                 soc_pci_write(unit, cmic_address, val & ~(CMIC_CMCx_CCMDMA_CHy_CFG_ABORT | CMIC_CMCx_CCMDMA_CHy_CFG_EN));
    590                 if (done) { /* remove the channel from the channels waited on */
    591                     chans_group_delete(&ccm_channels, channel_iter--);
    592                 } else {
    593                     LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort CCM DMA in CMC %d channel %d, check with the design team\n"), cmc, chan));
    594                     ++nof_failures;
    595                 }
    596             }
    597         }
    598 
    599         /* for all s-chan FIFO channels still not done */
    600         for (chans_group_iter_start(&schan_fifo_channels, &channel_iter); !chans_group_is_end(&schan_fifo_channels, channel_iter); ++channel_iter) {
    601             chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */
    602             /* If the abort is done (CMIC_COMMON_POOL_SCHAN_FIFO_0_CHy_STATUS.DONE==1), then clear the operation */
    603             done = soc_pci_read(unit, CMIC_SCHAN_FIFO_CHx_STATUS(chan)) & SCHAN_FIFO_STATUS_DONE;
    604             if (done || timeout_state == abort_timeout_passed) {
    605                 /* clear CMIC_COMMON_POOL_SCHAN_FIFO_0_CHy_CTRL.ABORT|START in the same write: disables and clears statuses*/
    606                 cmic_address = CMIC_SCHAN_FIFO_CHx_CTRL(chan);
    607                 val = soc_pci_read(unit, cmic_address);
    608                 soc_pci_write(unit, cmic_address, val & ~(SCHAN_FIFO_CTRL_ABORT | SCHAN_FIFO_CTRL_START));
    609                 if (done) { /* remove the channel from the channels waited on */
    610                     chans_group_delete(&schan_fifo_channels, channel_iter--);
    611                 } else {
    612                     LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort s-chan FIFO in channel %d, check with the design team\n"), chan));
    613                     ++nof_failures;
    614                 }
    615             }
    616         }
    617 
    618 
    619         if (timeout_state != abort_timeout_not_passed || (!chans_group_get_nof_chans(&packet_channels) &&
    620             !chans_group_get_nof_chans(&sbus_channels) && !chans_group_get_nof_chans(&fifo_channels) &&
    621             !chans_group_get_nof_chans(&ccm_channels) && !chans_group_get_nof_chans(&schan_fifo_channels))) {
    622             break; /* exist if the timeout passed at the start of the iteration, or if there is no channel left to wait for */
    623         }
    624         sal_usleep(timeout_sleep); /* wait before the next iteration */
    625         timeout_sleep += CMICX_INITIAL_SLEEP; /* next time sleep more, will use less than sqrt(2 * timeout / CMICX_INITIAL_SLEEP) iterations */
    626     } while (1);
    627 
    628 
    629     LOG_INFO(BSL_LS_SOC_DMA, (BSL_META_U(unit,
    630       "Aborted and disabled %d DMA channels with %d abort failures\n"), nof_channels, nof_failures));
    631 
    632     return nof_failures ? SOC_E_TIMEOUT : SOC_E_NONE;
    633 }
    634 
    635 #endif /* BCM_CMICX_SUPPORT  */