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_l2mod.c (12296B)


      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 L2MOD Driver
      8  */
      9 
     10 #include <shared/bsl.h>
     11 #include <shared/alloc.h>
     12 #include <sal/core/boot.h>
     13 #include <sal/core/libc.h>
     14 #include <soc/drv.h>
     15 #include <soc/debug.h>
     16 #include <soc/cm.h>
     17 #include <soc/l2x.h>
     18 #include <soc/fifodma_internal.h>
     19 
     20 #if defined(BCM_CMICX_SUPPORT) && defined(BCM_FIFODMA_SUPPORT)
     21 #include <soc/cmicx.h>
     22 #include <soc/intr_cmicx.h>
     23 #endif
     24 
     25 #if defined(BCM_ESW_SUPPORT) && defined(BCM_CMICX_SUPPORT)
     26 
     27 STATIC int
     28 _soc_td3_l2mod_sbus_fifo_enable(int unit, int enable)
     29 {
     30     uint32 rval = 0;
     31 
     32     soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_DELETEf, enable);
     33     soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_LEARNf, enable);
     34     soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_INSERTf, enable);
     35 
     36     SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval));
     37     return SOC_E_NONE;
     38 }
     39 
     40 extern uint32 soc_mem_fifo_delay_value;
     41 
     42 STATIC void
     43 _soc_cmicx_l2mod_sbus_fifo_dma_thread(void *unit_vp)
     44 {
     45     uint8 overflow, timeout;
     46     int i, count, handled_count, adv_threshold;
     47     int unit = PTR_TO_INT(unit_vp);
     48     int cmc = SOC_PCI_CMC(unit);
     49     soc_control_t *soc = SOC_CONTROL(unit);
     50     uint32 entries_per_buf, rval;
     51     int rv, interval, non_empty;
     52     uint8 ch;
     53     uint32 *buff_max;
     54     void *host_entry, *host_buff;
     55     int entry_words;
     56     uint32 hostmem_timeout, hostmem_overflow, done, error;
     57 
     58     if (SOC_IS_TRIDENT3X(unit)) {
     59         /*
     60          * Channel 0 is for X pipe
     61          * Channel 1 is for Y pipe but nothing will go into Y pipe L2_MOD_FIFO.
     62          */
     63         ch = SOC_MEM_FIFO_DMA_CHANNEL_0;
     64     } else {
     65         ch = SOC_MEM_FIFO_DMA_CHANNEL_1;
     66     }
     67 
     68     entries_per_buf = soc_property_get(unit, spn_L2XMSG_HOSTBUF_SIZE, 1024);
     69     adv_threshold = entries_per_buf / 2;
     70 
     71     entry_words = soc_mem_entry_words(unit, L2_MOD_FIFOm);
     72     host_buff = soc_cm_salloc(unit, entries_per_buf * entry_words * sizeof(uint32),
     73                              "L2_MOD DMA Buffer");
     74     if (host_buff == NULL) {
     75         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
     76                            SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__,
     77                            SOC_E_MEMORY);
     78         goto cleanup_exit;
     79     }
     80 
     81     soc_fifodma_stop(unit, ch);
     82 
     83     rv = soc_fifodma_masks_get(unit, &hostmem_timeout, &hostmem_overflow, &error, &done);
     84 
     85     rv = soc_fifodma_start(unit, ch, TRUE, L2_MOD_FIFOm, 0, MEM_BLOCK_ANY, 0,
     86                                       entries_per_buf, host_buff);
     87     if (SOC_FAILURE(rv)) {
     88         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
     89                            SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv);
     90         goto cleanup_exit;
     91     }
     92 
     93     host_entry = host_buff;
     94     buff_max = (uint32 *)host_entry + (entries_per_buf * entry_words);
     95 
     96     if (!soc_feature(unit, soc_feature_fifo_dma)) {
     97         soc_fifodma_intr_enable(unit, ch);
     98     }
     99 
    100     if (SOC_IS_TRIDENT3X(unit)) {
    101         _soc_td3_l2mod_sbus_fifo_enable(unit, 1);
    102     }
    103 
    104     while ((interval = soc->l2x_interval)) {
    105         overflow = 0; timeout = 0;
    106         if (soc->l2modDmaIntrEnb) {
    107             soc_fifodma_intr_enable(unit, ch);
    108             if (sal_sem_take(soc->arl_notify, interval) < 0) {
    109                 LOG_VERBOSE(BSL_LS_SOC_INTR,
    110                             (BSL_META_U(unit,
    111                                         "%s polling timeout soc_mem_fifo_delay_value=%d\n"),
    112                              soc->l2x_name, soc_mem_fifo_delay_value));
    113             } else {
    114                 LOG_VERBOSE(BSL_LS_SOC_INTR,
    115                             (BSL_META_U(unit,
    116                                         "%s woken up soc_mem_fifo_delay_value=%d\n"),
    117                              soc->l2x_name, soc_mem_fifo_delay_value));
    118                 /* check for timeout or overflow and either process or continue */
    119                 soc_fifodma_status_get(unit, ch, &rval);
    120                 timeout = rval & hostmem_timeout;
    121                 if (!timeout) {
    122                     /* overflow = soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr,
    123                                                  rval, HOSTMEM_OVERFLOWf); */
    124                     overflow = rval & hostmem_overflow;
    125                     timeout |= overflow;
    126                 }
    127             }
    128 
    129         } else {
    130             sal_usleep(interval);
    131         }
    132 
    133         handled_count = 0;
    134 
    135         do {
    136             non_empty = FALSE;
    137 
    138             /* get entry count, process if nonzero else continue */
    139             rv = soc_fifodma_num_entries_get(unit, ch, &count);
    140             if (SOC_SUCCESS(rv)) {
    141                 non_empty = TRUE;
    142                 if (count > adv_threshold) {
    143                     count = adv_threshold;
    144                 }
    145                 /* Invalidate DMA memory to read */
    146                 if (((uint32 *)host_entry + count * entry_words) > buff_max) {
    147                     /* roll-over cases */
    148                     soc_cm_sinval(unit, host_entry,
    149                         (buff_max - (uint32 *)host_entry) * sizeof(uint32));
    150                     soc_cm_sinval(unit, host_buff,
    151                         ((count * entry_words) - (buff_max - (uint32 *)host_entry)) * sizeof(uint32));
    152                 }
    153                 else {
    154                     soc_cm_sinval(unit, host_entry, (count * entry_words) * sizeof(uint32));
    155                 }
    156                 for (i = 0; i < count; i++) {
    157                     if(!soc->l2x_interval) {
    158                         goto cleanup_exit;
    159                     }
    160 #if defined(BCM_TRIDENT2_SUPPORT)
    161                     _soc_td2_l2mod_fifo_process(unit, soc->l2x_flags, host_entry);
    162 #endif
    163                     host_entry = (uint32 *)host_entry + entry_words;
    164                     /* handle roll over */
    165                     if ((uint32 *)host_entry >= buff_max) {
    166                         host_entry = host_buff;
    167                     }
    168 
    169                     handled_count++;
    170                     /*
    171                      * PPA may wait for available space in mod_fifo, lower the
    172                      * threshold when ppa is running, therefore read point can
    173                      * be updated sooner.
    174                      */
    175                     if (SOC_CONTROL(unit)->l2x_ppa_in_progress && i >= 63) {
    176                         i++;
    177                         break;
    178                     }
    179                 }
    180                 soc_fifodma_set_entries_read(unit, ch, i);
    181             }
    182 
    183             /* check and clear error */
    184             soc_fifodma_status_get(unit, ch, &rval);
    185             if (rval & done) {
    186                 LOG_ERROR(BSL_LS_SOC_COMMON,
    187                           (BSL_META_U(unit,
    188                                       "FIFO DMA engine terminated for cmc[%d]:ch[%d]\n"),
    189                            cmc, ch));
    190                 if (rval & error) {
    191                     LOG_ERROR(BSL_LS_SOC_COMMON,
    192                               (BSL_META_U(unit,
    193                                           "FIFO DMA engine encountered error: [0x%x]\n"),
    194                                rval));
    195                 }
    196                 goto cleanup_exit;
    197             }
    198 
    199             if (!SOC_CONTROL(unit)->l2x_ppa_in_progress) {
    200                 /* For some operating systems, sal_thread_yield is
    201                  * not sufficient to yield CPU resource to other lower
    202                  * priority thread
    203                  */
    204                 if ((handled_count * 2) >= adv_threshold) {
    205                     sal_usleep(1000);
    206                     handled_count = 0;
    207                 }
    208             }
    209         } while (non_empty);
    210         /* Clearing of the FIFO_CH_DMA_INT interrupt by resetting
    211            overflow & timeout status in FIFO_CHy_RD_DMA_STAT_CLR reg */
    212         if (timeout) {
    213             soc_fifodma_status_clear(unit, ch);
    214         }
    215     }
    216 
    217 cleanup_exit:
    218     soc_fifodma_stop(unit, ch);
    219 
    220     if (SOC_IS_TRIDENT3X(unit)) {
    221         _soc_td3_l2mod_sbus_fifo_enable(unit, 0);
    222     }
    223 
    224     if (host_buff != NULL) {
    225         soc_cm_sfree(unit, host_buff);
    226     }
    227 
    228     soc->l2x_pid = SAL_THREAD_ERROR;
    229     sal_thread_exit(0);
    230 }
    231 
    232 /*
    233  * Function:
    234  *     soc_l2mod_running
    235  * Purpose:
    236  *     Determine the L2MOD sync thread running parameters
    237  * Parameters:
    238  *     unit - unit number.
    239  *     flags (OUT) - if non-NULL, receives the current flag settings
    240  *     interval (OUT) - if non-NULL, receives the current pass interval
    241  * Returns:
    242  *     Boolean; TRUE if L2MOD sync thread is running
    243  */
    244 
    245 int
    246 _soc_cmicx_l2mod_running(int unit, uint32 *flags, sal_usecs_t *interval)
    247 {
    248 #ifdef BCM_XGS3_SWITCH_SUPPORT
    249     soc_control_t *soc = SOC_CONTROL(unit);
    250 
    251     if (SOC_IS_XGS3_SWITCH(unit)) {
    252         if (soc->l2x_pid != SAL_THREAD_ERROR) {
    253             if (flags != NULL) {
    254                 *flags = soc->l2x_flags;
    255             }
    256             if (interval != NULL) {
    257                 *interval = soc->l2x_interval;
    258             }
    259         }
    260 
    261         return (soc->l2x_pid != SAL_THREAD_ERROR);
    262     }
    263 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    264     return SOC_E_UNAVAIL;
    265 }
    266 
    267 /*
    268  * Function:
    269  *     _soc_cmicx_l2mod_stop
    270  * Purpose:
    271  *     Stop cmicx L2MOD-related thread
    272  * Parameters:
    273  *     unit - unit number.
    274  * Returns:
    275  *     SOC_E_XXX
    276  */
    277 int
    278 _soc_cmicx_l2mod_stop(int unit)
    279 {
    280     soc_control_t * soc = SOC_CONTROL(unit);
    281     int rv = SOC_E_NONE;
    282     uint8 ch = SOC_MEM_FIFO_DMA_CHANNEL_0;
    283 
    284     if (SOC_IS_XGS3_SWITCH(unit)) {
    285         LOG_INFO(BSL_LS_SOC_ARL,
    286                  (BSL_META_U(unit,
    287                              "soc_cmicx_l2mod_stop: unit=%d\n"), unit));
    288 
    289         _soc_td3_l2mod_sbus_fifo_enable(unit, 0);
    290 
    291         if (!soc_feature(unit, soc_feature_fifo_dma) || SOC_IS_HELIX5(unit)) {
    292             soc_fifodma_intr_disable(unit, ch);
    293             soc->l2x_interval = 0;  /* Request exit */
    294         }
    295 
    296         if (soc->l2modDmaIntrEnb) {
    297             /* Wake up thread so it will check the exit flag */
    298             if(soc->arl_notify) {
    299                 sal_sem_give(soc->arl_notify);
    300             }
    301         }
    302 
    303         return rv;
    304     }
    305     return SOC_E_UNAVAIL;
    306 }
    307 
    308 int
    309 _soc_cmicx_l2mod_start(int unit, uint32 flags, sal_usecs_t interval)
    310 {
    311     soc_control_t * soc = SOC_CONTROL(unit);
    312     int             pri;
    313 
    314     if (!soc_feature(unit, soc_feature_arl_hashed)) {
    315         return SOC_E_UNAVAIL;
    316     }
    317 
    318     if (soc->l2x_interval != 0) {
    319         SOC_IF_ERROR_RETURN(_soc_cmicx_l2mod_stop(unit));
    320     }
    321 
    322     sal_snprintf(soc->l2x_name, sizeof(soc->l2x_name), "bcmL2MOD.%d", unit);
    323 
    324     soc->l2x_flags = flags;
    325     soc->l2x_interval = interval;
    326 
    327     if (interval == 0) {
    328         return SOC_E_NONE;
    329     }
    330 
    331     if (soc->l2x_pid == SAL_THREAD_ERROR) {
    332         pri = soc_property_get(unit, spn_L2XMSG_THREAD_PRI, 50);
    333 
    334         soc->l2x_pid =
    335                 sal_thread_create(soc->l2x_name, SAL_THREAD_STKSZ, pri,
    336                                   _soc_cmicx_l2mod_sbus_fifo_dma_thread, INT_TO_PTR(unit));
    337         if (soc->l2x_pid == SAL_THREAD_ERROR) {
    338             LOG_ERROR(BSL_LS_SOC_COMMON,
    339                       (BSL_META_U(unit,
    340                                   "soc_cmicx_l2mod_start: Could not start L2MOD thread\n")));
    341             return SOC_E_MEMORY;
    342         }
    343     }
    344 
    345     return SOC_E_NONE;
    346 }
    347 
    348 int
    349 _soc_cmicx_l2mod_sbus_fifo_field_set(int unit, soc_field_t field, int enable)
    350 {
    351     uint32 rval = 0;
    352     uint32 fval = enable?1:0;
    353 
    354     if (SOC_IS_TRIDENT3X(unit)) {
    355         if(soc_reg_field_valid(unit, L2_MOD_FIFO_ENABLEr, field)) {
    356             SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &rval));
    357 
    358             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, field, fval);
    359 
    360             SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval));
    361         }
    362         return SOC_E_NONE;
    363     }
    364 
    365     return SOC_E_UNAVAIL;
    366 }
    367 
    368 int
    369 _soc_cmicx_l2mod_sbus_fifo_field_get(int unit, soc_field_t field, int *enable)
    370 {
    371     uint32 reg = 0;
    372     uint32 fval = 0;
    373 
    374     if (SOC_IS_TRIDENT3X(unit)) {
    375         if(soc_reg_field_valid(unit, L2_MOD_FIFO_ENABLEr, field)) {
    376             SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &reg));
    377 
    378             fval = soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, reg, field);
    379         }
    380         *enable = fval?1:0;
    381         return SOC_E_NONE;
    382     }
    383 
    384     return SOC_E_UNAVAIL;
    385 }
    386 
    387 #endif /* BCM_ESW_SUPPORT && BCM_CMICX_SUPPORT */
    388