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

re_report.c (27917B)


      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  * File:       bregex.c
      8  * Purpose:    Regex Eevent notification API
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <sal/core/libc.h>
     14 #include <soc/drv.h>
     15 #ifdef BCM_CMICM_SUPPORT
     16 #include <soc/cmicm.h>
     17 #endif
     18 
     19 #include <soc/mem.h>
     20 
     21 #include <bcm/error.h>
     22 #include <bcm/cosq.h>
     23 
     24 #include <bcm_int/esw/mbcm.h>
     25 #include <bcm_int/esw/firebolt.h>
     26 #include <bcm_int/esw/scorpion.h>
     27 #include <bcm_int/esw/triumph.h>
     28 #include <bcm_int/esw/triumph2.h>
     29 #include <bcm_int/esw/trident.h>
     30 #include <bcm_int/esw/hurricane.h>
     31 #include <bcm_int/esw/fb4regex.h>
     32 
     33 #include <bcm_int/esw_dispatch.h>
     34 
     35 #if defined(INCLUDE_REGEX)
     36 
     37 #if defined(BCM_TRIUMPH3_SUPPORT)
     38 
     39 #define _BCM_FT_REPORT_MAX_CB   4
     40 
     41 typedef enum _bcm_ft_report_cb_state_e {
     42     _BCM_FT_REPORT_CALLBACK_STATE_INVALID = 0,
     43     _BCM_FT_REPORT_CALLBACK_STATE_ACTIVE,
     44     _BCM_FT_REPORT_CALLBACK_STATE_REGISTERED,
     45     _BCM_FT_REPORT_CALLBACK_STATE_UNREGISTERED
     46 } _bcm_ft_report_cb_state_t;
     47 
     48 typedef struct _bcm_ft_report_cb_entry_s {
     49     _bcm_ft_report_cb_state_t state;
     50     uint32  reports;
     51     bcm_regex_report_cb callback;
     52     void *userdata;
     53 } _bcm_ft_report_cb_entry_t;
     54 
     55 typedef struct _bcm_ft_report_ctrl_s {
     56     _bcm_ft_report_cb_entry_t callback_entry[_BCM_FT_REPORT_MAX_CB];
     57     sal_thread_t pid;          /* export fifo processing thread process id */
     58     VOL sal_usecs_t interval;  /* export fifo processing polling interval */
     59 } _bcm_ft_report_ctrl_t;
     60 
     61 static _bcm_ft_report_ctrl_t *_bcm_ft_report_ctrl[BCM_MAX_NUM_UNITS];
     62 
     63 extern int
     64 _bcm_tr3_get_match_id(int unit, int signature_id, int *match_id);
     65 
     66 int
     67 _bcm_ft_key_field_get(uint32 *fld, int bp, int len, uint32 *kfld)
     68 {
     69     int ii, bval;
     70 
     71     for (ii = 0; ii < (31 + len)/32; ii++) {
     72         kfld[ii] = 0;
     73     }
     74 
     75     for (ii = 0; ii < len; ii++) {
     76         bval = fld[(bp+ii)/32] & (1 << ((bp + ii) % 32));
     77         if (bval) {
     78             kfld[ii/32] |= 1 << (ii % 32);
     79         }
     80     }
     81     return 0;
     82 }
     83 
     84 int
     85 _bcm_ft_key_field_set(uint32 *fld, int bp, int len, uint32 *kfld)
     86 {
     87     int ii, bval;
     88 
     89     for (ii = 0; ii < len; ii++) {
     90         bval = kfld[ii/32] & (1 << (ii % 32));
     91         if (bval) {
     92             fld[(bp+ii)/32] |= 1 << ((bp + ii) % 32);
     93         }
     94     }
     95     return 0;
     96 }
     97 
     98 int
     99 _bcm_ft_key_field_get_char(uint32 *fld, int bp, int len, uint8 *kfld)
    100 {
    101     int ii, bval;
    102 
    103     for (ii = 0; ii < (7 + len)/8; ii++) {
    104         kfld[ii] = 0;
    105     }
    106 
    107     for (ii = 0; ii < len; ii++) {
    108         bval = fld[(bp+ii)/32] & (1 << ((bp + ii) % 32));
    109         if (bval) {
    110             kfld[ii/8] |= 1 << (ii % 8);
    111         }
    112     }
    113     return 0;
    114 }
    115 
    116 int
    117 _bcm_ft_key_field_set_char(uint32 *fld, int bp, int len, uint8 *kfld)
    118 {
    119     int ii, bval;
    120 
    121     for (ii = 0; ii < len; ii++) {
    122         bval = kfld[ii/8] & (1 << (ii % 8));
    123         if (bval) {
    124             fld[(bp+ii)/32] |= 1 << ((bp + ii) % 32);
    125         }
    126     }
    127     return 0;
    128 }
    129 
    130 int
    131 _bcm_ft_ctr_enabled(int unit)
    132 {
    133     uint32 regval, fval;
    134 
    135     SOC_IF_ERROR_RETURN(READ_FT_CONFIGr(unit, &regval));
    136     fval = soc_reg_field_get(unit, FT_CONFIGr, regval, CNT_MODEf);
    137 
    138     if ((fval == 1) || (fval == 2)) {
    139         return fval;
    140     }
    141     return 0;
    142 }
    143 
    144 STATIC int
    145 _bcm_ft_report_process_export_entry(int unit,
    146                          void *entry, bcm_regex_report_t *data,
    147                          int *pending, uint32 *pdir)
    148 {
    149     soc_mem_t mem;
    150     uint32 val, pk[4], pkl[6];
    151     bcm_ip6_t sip6, dip6;
    152     uint8  *p8;
    153     uint32 type, ip1, ip2, p1, p2, pt;
    154     int rv = 0, i;
    155     uint32 dir;
    156     uint64 tmp_packet_count;          /* Packet count. */
    157     uint64 tmp_byte_count;            /* Packet count. */
    158 
    159     mem = FT_EXPORT_FIFOm;
    160 
    161     type = soc_mem_field32_get(unit, mem, entry, KEY_TYPEf);
    162     *pending = 0;
    163 
    164     if ((type == _REGEX_SESSION_KEY_TYPE_IPV4) ||
    165         (type == _REGEX_SESSION_KEY_TYPE_IPV6_UPPER)) {
    166         val = soc_mem_field32_get(unit, mem, entry, SIGNATURE_IDf);
    167         rv = _bcm_tr3_get_match_id(unit, val, &data->match_id);
    168         if (rv) {
    169             return BCM_E_NOT_FOUND;
    170         }
    171 
    172         dir = soc_mem_field32_get(unit, mem, entry, KEY_DIRECTIONf);
    173         *pdir = dir;
    174         LOG_INFO(BSL_LS_BCM_REGEX,
    175                  (BSL_META_U(unit,
    176                              " KEY_DIRECTION = 0x%x\n"),
    177                   dir));
    178         LOG_INFO(BSL_LS_BCM_REGEX,
    179                  (BSL_META_U(unit,
    180                              " KEY_TYPE = 0x%x\n"),
    181                   type));
    182         val = soc_mem_field32_get(unit, mem, entry, EVENT_IDf);
    183         data->flags = 0;
    184         if (val & BCM_REGEX_REPORT_NEW) {
    185             data->flags |= BCM_REGEX_REPORT_NEW;
    186         }
    187         if ((val & BCM_REGEX_REPORT_MATCHED) &&
    188             (soc_mem_field32_get(unit, mem, entry, SME_MATCHf))) {
    189             data->flags |= BCM_REGEX_REPORT_MATCHED;
    190         }
    191         if (val & BCM_REGEX_REPORT_END) {
    192             data->flags |= BCM_REGEX_REPORT_END;
    193             data->flow_end_reason =  soc_mem_field32_get(unit, mem, entry, TCP_FIN_Rf);
    194             if(!(data->flow_end_reason)) {
    195                 data->flow_end_reason = soc_mem_field32_get(unit, mem, entry, TCP_FIN_Ff);
    196             }
    197             if(!(data->flow_end_reason)) {
    198                 data->flow_end_reason = soc_mem_field32_get(unit, mem, entry, TCP_RESETf);
    199             }
    200         }
    201         val = soc_mem_field32_get(unit, mem, entry, FLOW_STATEf);
    202         LOG_INFO(BSL_LS_BCM_REGEX,
    203                  (BSL_META_U(unit,
    204                              " FLOW_STATE = 0x%03x\n"),
    205                   val));
    206 
    207         soc_mem_field_get(unit, mem, entry, KEYf, pk);
    208         p8 = (uint8*) pk;
    209         LOG_INFO(BSL_LS_BCM_REGEX,
    210                  (BSL_META_U(unit,
    211                              "pk = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"),
    212                   *p8, *(p8+1), *(p8+2), *(p8+3), *(p8+4), *(p8+5), *(p8+6), *(p8+7), *(p8+8), *(p8+9), *(p8+10), *(p8+11), *(p8+12)));
    213 
    214         if (type == _REGEX_SESSION_KEY_TYPE_IPV4) {
    215             for (i = 0; i < 16; i++) {
    216                 data->sip6[i] = 0;
    217                 data->dip6[i] = 0;
    218             }
    219 
    220             _bcm_ft_key_field_get(pk, _REGEX_KEY_FIELD_V4_OFFSET_PORT_1,
    221                                   _REGEX_KEY_FIELD_V4_LENGTH_PORT_1, &p1);
    222             _bcm_ft_key_field_get(pk, _REGEX_KEY_FIELD_V4_OFFSET_PORT_2,
    223                                   _REGEX_KEY_FIELD_V4_LENGTH_PORT_2, &p2);
    224             _bcm_ft_key_field_get(pk, _REGEX_KEY_FIELD_V4_OFFSET_PROTOCOL,
    225                                   _REGEX_KEY_FIELD_V4_LENGTH_PROTOCOL, &pt);
    226             _bcm_ft_key_field_get(pk, _REGEX_KEY_FIELD_V4_OFFSET_IP_1,
    227                                   _REGEX_KEY_FIELD_V4_LENGTH_IP_1, &ip1);
    228             _bcm_ft_key_field_get(pk, _REGEX_KEY_FIELD_V4_OFFSET_IP_2,
    229                                   _REGEX_KEY_FIELD_V4_LENGTH_IP_2, &ip2);
    230 
    231             if (dir == _REGEX_SESSION_DIRECTION_REVERSE) {
    232               data->sip = ip1;
    233               data->dip = ip2;
    234               data->src_port = p1;
    235               data->dst_port = p2;
    236             } else {
    237               data->dip = ip1;
    238               data->sip = ip2;
    239               data->dst_port = p1;
    240               data->src_port = p2;
    241             }
    242             data->protocol = pt;
    243         } else if (type == _REGEX_SESSION_KEY_TYPE_IPV6_UPPER) {
    244             LOG_INFO(BSL_LS_BCM_REGEX,
    245                      (BSL_META_U(unit,
    246                                  " Get upper address, direction = %d...\n"),
    247                       dir));
    248             *pending = 1;
    249             data->dip = 0;
    250             data->sip = 0;
    251             data->src_port = 0;
    252             data->dst_port = 0;
    253             data->protocol = 0;
    254             p1 = 0;
    255             p2 = 0;
    256             pt = 0;
    257             ip1 = 0;
    258             ip2 = 0;
    259 
    260             if (dir == _REGEX_SESSION_DIRECTION_FORWARD) {
    261                 _bcm_ft_key_field_get_char(pk, _REGEX_KEY_UPPER_V6_OFFSET_IP_2,
    262                                            _REGEX_KEY_UPPER_V6_LENGTH_IP_2,
    263                                            &sip6[_REGEX_KEY_LOWER_V6_LENGTH_IP_2/8]);
    264                 } else {
    265                 _bcm_ft_key_field_get_char(pk, _REGEX_KEY_UPPER_V6_OFFSET_IP_2,
    266                                            _REGEX_KEY_UPPER_V6_LENGTH_IP_2,
    267                                            &dip6[_REGEX_KEY_LOWER_V6_LENGTH_IP_2/8]);
    268             }
    269         }
    270 
    271         LOG_INFO(BSL_LS_BCM_REGEX,
    272                  (BSL_META_U(unit,
    273                              " FT_EXPORT_FIFOm = 0x%x, mem = 0x%x\n"), FT_EXPORT_FIFOm,
    274                   mem));
    275 
    276         if (data->flags & BCM_REGEX_REPORT_NEW) {
    277              data->packet_count_to_server = 0;
    278              data->byte_count_to_server   = 0;
    279              data->packet_count_to_client = 0;
    280              data->byte_count_to_client = 0;
    281              data->packet_count = 0;
    282          }
    283 
    284         soc_mem_field64_get(unit, mem, entry, L2_PKT_CNT_Ff,
    285                             &tmp_packet_count);
    286         COMPILER_64_ADD_64(data->packet_count_to_server,tmp_packet_count);
    287 
    288         soc_mem_field64_get(unit, mem, entry, L2_BYTE_CNT_Ff,
    289                             &tmp_byte_count);
    290         COMPILER_64_ADD_64(data->byte_count_to_server,tmp_byte_count);
    291 
    292         soc_mem_field64_get(unit, mem, entry, L2_PKT_CNT_Rf,
    293                             &tmp_packet_count);
    294         COMPILER_64_ADD_64(data->packet_count_to_client,tmp_packet_count);
    295 
    296         soc_mem_field64_get(unit, mem, entry, L2_BYTE_CNT_Rf,
    297                             &tmp_byte_count);
    298         COMPILER_64_ADD_64(data->byte_count_to_client,tmp_byte_count);
    299 
    300         data->byte_count = data->byte_count_to_client +
    301             data->byte_count_to_server;
    302         data->packet_count = data->packet_count_to_client +
    303             data->packet_count_to_server;
    304 
    305         if (_bcm_ft_ctr_enabled(unit) != 2)
    306         {
    307             data->packet_count_to_server = 0;
    308             data->byte_count_to_server   = 0;
    309             data->packet_count_to_client = 0;
    310             data->byte_count_to_client   = 0;
    311             if (_bcm_ft_ctr_enabled(unit) == 0) {
    312                data->packet_count = 0;
    313                data->byte_count = 0;
    314             }          
    315         }
    316 
    317         /*
    318         These values can look confusing, but ID_TIMESTAMP represents the
    319         time at which the flow was created, and stays the same while the
    320         flow exists.
    321 
    322         LAST_TIMESTAMP represents the last time a packet was received on
    323         the flow.
    324 
    325         START_TIMESTAMP is somewhat confusing, since it seems it should
    326         represent the time at which the flow started, but actually its
    327         value can change while the flow exists, and will actually show
    328         the last time the flow was refreshed.
    329         */
    330 
    331         data->start_timestamp = soc_mem_field32_get(unit, mem, entry, ID_TIMESTAMPf);
    332         data->last_timestamp = soc_mem_field32_get(unit, mem, entry, LAST_TIMESTAMPf);
    333         data->refresh_timestamp = soc_mem_field32_get(unit, mem, entry, START_TIMESTAMPf);
    334     } else {
    335         data->dip = 0;
    336         data->sip = 0;
    337 
    338         dir = *pdir;
    339 
    340         type = soc_mem_field32_get(unit, mem, entry, KEY_TYPEf);
    341         LOG_INFO(BSL_LS_BCM_REGEX,
    342                  (BSL_META_U(unit,
    343                              " KEY_TYPE = 0x%x\n"),
    344                   type));
    345         LOG_INFO(BSL_LS_BCM_REGEX,
    346                  (BSL_META_U(unit,
    347                              " Get lower address, direction = %d, ports, proto...\n"),
    348                   dir));
    349 
    350         soc_mem_field_get(unit, mem, entry, IPV6_LOWER_KEYf, pkl);
    351         p8 = (uint8*) pkl;
    352         LOG_INFO(BSL_LS_BCM_REGEX,
    353                  (BSL_META_U(unit,
    354                              "pkl = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"),
    355                   *p8, *(p8+1), *(p8+2), *(p8+3), *(p8+4), *(p8+5), *(p8+6), *(p8+7), *(p8+8), *(p8+9), *(p8+10), *(p8+11), *(p8+12),
    356                   *(p8+13), *(p8+14), *(p8+15), *(p8+16), *(p8+17), *(p8+18), *(p8+19), *(p8+20), *(p8+21), *(p8+22), *(p8+23)));
    357 
    358         _bcm_ft_key_field_get(pkl, _REGEX_KEY_LOWER_V6_OFFSET_PORT_1,
    359                               _REGEX_KEY_LOWER_V6_LENGTH_PORT_1, &p1);
    360         _bcm_ft_key_field_get(pkl, _REGEX_KEY_LOWER_V6_OFFSET_PORT_2,
    361                               _REGEX_KEY_LOWER_V6_LENGTH_PORT_2, &p2);
    362         _bcm_ft_key_field_get(pkl, _REGEX_KEY_LOWER_V6_OFFSET_PROTOCOL,
    363                               _REGEX_KEY_LOWER_V6_LENGTH_PROTOCOL, &pt);
    364 
    365         if (dir == _REGEX_SESSION_DIRECTION_REVERSE) {
    366           data->src_port = p1;
    367           data->dst_port = p2;
    368             } else {
    369           data->dst_port = p1;
    370           data->src_port = p2;
    371             }
    372         data->protocol = pt;
    373 
    374         LOG_INFO(BSL_LS_BCM_REGEX,
    375                  (BSL_META_U(unit,
    376                              "p8 = %p, p8+port/proto = %p\n"),
    377                   p8, p8+_REGEX_PROTOCOL_PORT_LENGTH_V6/8));
    378         p8 += _REGEX_PROTOCOL_PORT_LENGTH_V6/8; /* skip past ports/proto */
    379 
    380         LOG_INFO(BSL_LS_BCM_REGEX,
    381                  (BSL_META_U(unit,
    382                              "pkl+port/proto = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"),
    383                   *p8, *(p8+1), *(p8+2), *(p8+3), *(p8+4), *(p8+5), *(p8+6), *(p8+7), *(p8+8), *(p8+9), *(p8+10), *(p8+11), *(p8+12),
    384                   *(p8+13), *(p8+14), *(p8+15), *(p8+16), *(p8+17), *(p8+18)));
    385 
    386         if (dir == _REGEX_SESSION_DIRECTION_FORWARD) {
    387             _bcm_ft_key_field_get_char(pkl, _REGEX_KEY_LOWER_V6_OFFSET_IP_1,
    388                                   _REGEX_KEY_LOWER_V6_LENGTH_IP_1, dip6);
    389         } else {
    390             _bcm_ft_key_field_get_char(pkl, _REGEX_KEY_LOWER_V6_OFFSET_IP_1,
    391                                   _REGEX_KEY_LOWER_V6_LENGTH_IP_1, sip6);
    392         }
    393         if (dir == _REGEX_SESSION_DIRECTION_FORWARD) {
    394             _bcm_ft_key_field_get_char(pkl, _REGEX_KEY_LOWER_V6_OFFSET_IP_2,
    395                                   _REGEX_KEY_LOWER_V6_LENGTH_IP_2, sip6);
    396             } else {
    397             _bcm_ft_key_field_get_char(pkl, _REGEX_KEY_LOWER_V6_OFFSET_IP_2,
    398                                   _REGEX_KEY_LOWER_V6_LENGTH_IP_2, dip6);
    399             }
    400 
    401         /*
    402         IPv6 addresses will go into hardware in reverse order, so reverse
    403         the addresses here before returning them
    404         */
    405 
    406         for (i = 0; i < _SHR_L3_IP6_ADDRLEN; i++) {
    407             data->sip6[i] = sip6[_SHR_L3_IP6_ADDRLEN - i - 1];
    408             data->dip6[i] = dip6[_SHR_L3_IP6_ADDRLEN - i - 1];
    409         }
    410 
    411         *pdir = dir;
    412     }
    413 
    414     data->match_flags = 0;
    415     data->match_flags |= (*pdir == 1) ? BCM_REGEX_MATCH_TO_SERVER :
    416                                  BCM_REGEX_MATCH_TO_CLIENT;
    417 
    418     LOG_INFO(BSL_LS_BCM_REGEX,
    419              (BSL_META_U(unit,
    420                          "Flags :0x%x\n"),
    421               data->flags));
    422     LOG_INFO(BSL_LS_BCM_REGEX,
    423              (BSL_META_U(unit,
    424                          "Match Flags :0x%x\n"),
    425               data->match_flags));
    426 
    427     return BCM_E_NONE;
    428 }
    429 
    430 STATIC void
    431 _bcm_report_fifo_dma_thread(void *unit_vp)
    432 {
    433     int unit = PTR_TO_INT(unit_vp);
    434     _bcm_ft_report_ctrl_t *rctrl = _bcm_ft_report_ctrl[unit];
    435     _bcm_ft_report_cb_entry_t *cb_entry;
    436     bcm_regex_report_t data;
    437     int rv, entries_per_buf, interval, count, i, j, non_empty;
    438     int chan, entry_words, pending=0;
    439     void *host_buf = NULL;
    440     void *host_entry;
    441     uint32 dir = 0, *buff_max, rval;
    442     uint8  overflow, timeout;
    443     soc_mem_t   ftmem;
    444     soc_control_t *soc = SOC_CONTROL(unit);
    445     int cmc = SOC_PCI_CMC(unit);
    446     bcm_regex_config_t config;
    447 
    448     chan = SOC_MEM_FIFO_DMA_CHANNEL_0;
    449     rv = bcm_esw_regex_config_get(unit, &config);
    450     if (BCM_FAILURE(rv)) {
    451         LOG_VERBOSE(BSL_LS_BCM_INTR,
    452                     (BSL_META_U(unit,
    453                                 " failed to retrieve configuration, rv = %d\n"), rv));
    454         goto cleanup_exit;
    455     }
    456     entries_per_buf = config.report_buffer_size;
    457 
    458     LOG_VERBOSE(BSL_LS_BCM_INTR,
    459                 (BSL_META_U(unit,
    460                             " starting _bcm_report_fifo_dma_thread\n")));
    461 
    462     ftmem = FT_EXPORT_FIFOm;
    463     entry_words = soc_mem_entry_words(unit, ftmem);
    464     host_buf = soc_cm_salloc(unit, entries_per_buf * entry_words * WORDS2BYTES(1),
    465                              "FT export fifo DMA Buffer");
    466     if (host_buf == NULL) {
    467         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
    468                            SOC_SWITCH_EVENT_THREAD_REGEX_REPORT, __LINE__,
    469                            BCM_E_MEMORY);
    470         goto cleanup_exit;
    471     }
    472 
    473     rv = soc_mem_fifo_dma_start(unit, chan,
    474                                 ftmem, MEM_BLOCK_ANY,
    475                                 entries_per_buf, host_buf);
    476     if (BCM_FAILURE(rv)) {
    477         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
    478                            SOC_SWITCH_EVENT_THREAD_REGEX_REPORT,
    479                            __LINE__, rv);
    480         LOG_VERBOSE(BSL_LS_BCM_INTR,
    481                     (BSL_META_U(unit,
    482                                 " soc_mem_fifo_dma_start failed, rv = %d\n"), rv));
    483         goto cleanup_exit;
    484     }
    485 
    486     host_entry = host_buf;
    487     buff_max = (uint32 *)host_entry + (entries_per_buf * entry_words);
    488 
    489     while ((interval = rctrl->interval) > 0) {
    490         overflow = 0; timeout = 0;
    491         if (soc->ftreportIntrEnb) {
    492             soc_cmicm_intr0_enable(unit, IRQ_CMCx_FIFO_CH_DMA(chan));
    493             if (sal_sem_take(SOC_CONTROL(unit)->ftreportIntr, interval) < 0) {
    494                 LOG_VERBOSE(BSL_LS_BCM_INTR,
    495                             (BSL_META_U(unit,
    496                                         " polling timeout ft_export_fifo=%d\n"), interval));
    497             } else {
    498                 /* Disabling the interrupt (CHAN0) as the read process is underway */
    499                 soc_cmicm_intr0_disable(unit, IRQ_CMCx_FIFO_CH_DMA(chan));
    500                 LOG_VERBOSE(BSL_LS_BCM_INTR,
    501                             (BSL_META_U(unit,
    502                                         "woken up interval=%d\n"), interval));
    503                 /* check for timeout or overflow and either process or continue */
    504                 rval = soc_pci_read(unit,
    505                                     CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, chan));
    506                 overflow = soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr,
    507                                              rval, HOSTMEM_TIMEOUTf);
    508                 timeout = soc_reg_field_get(unit,
    509                                             CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, rval, HOSTMEM_OVERFLOWf);
    510                 overflow |= timeout ? 1 : 0;
    511             }
    512         } else {
    513             sal_usleep(interval);
    514         }
    515 
    516         if (rctrl->interval <= 0) {
    517             break;
    518         }
    519 
    520         /* reconcile the user registered callbacks. */
    521         for (i = 0; i < _BCM_FT_REPORT_MAX_CB; i++) {
    522             cb_entry = &rctrl->callback_entry[i];
    523             switch (cb_entry->state) {
    524                 case _BCM_FT_REPORT_CALLBACK_STATE_REGISTERED:
    525                     cb_entry->state = _BCM_FT_REPORT_CALLBACK_STATE_ACTIVE;
    526                     break;
    527                 case _BCM_FT_REPORT_CALLBACK_STATE_UNREGISTERED:
    528                     cb_entry->state = _BCM_FT_REPORT_CALLBACK_STATE_INVALID;
    529                     break;
    530                 default:
    531                     break;
    532             }
    533         }
    534 
    535         non_empty = FALSE;
    536         do {
    537             rv = soc_mem_fifo_dma_get_num_entries(unit, chan, &count);
    538             if (SOC_SUCCESS(rv)) {
    539                 non_empty = TRUE;
    540                 for (i = 0; i < count; i++) {
    541                     rv = _bcm_ft_report_process_export_entry(unit, host_entry,
    542                                                              &data, &pending, &dir);
    543                     host_entry = (uint32 *)host_entry + entry_words;
    544                     /* handle roll over */
    545                     if ((uint32 *)host_entry >= buff_max) {
    546                         host_entry = host_buf;
    547                     }
    548                     for (j = 0; (j < _BCM_FT_REPORT_MAX_CB) && !pending && !rv; j++) {
    549                         cb_entry = &rctrl->callback_entry[j];
    550                         if ((cb_entry->state == _BCM_FT_REPORT_CALLBACK_STATE_ACTIVE) &&
    551                             ((cb_entry->reports & BCM_REGEX_REPORT_ALL) |
    552                              (data.flags & cb_entry->reports))) {
    553                             cb_entry->callback(unit, &data, cb_entry->userdata);
    554                         }
    555                     }
    556                 }
    557                 if (overflow) {
    558                     rval = 0;
    559                     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr,
    560                                       &rval, HOSTMEM_OVERFLOWf, 1);
    561                     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr,
    562                                       &rval, HOSTMEM_TIMEOUTf, 1);
    563                     soc_pci_write(unit,
    564                                   CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_CLR_OFFSET(cmc, chan), rval);
    565                 }
    566                 (void)_soc_mem_sbus_fifo_dma_set_entries_read(unit, chan, i);
    567             } else {
    568                 if (overflow) {
    569                     rval = 0;
    570                     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr,
    571                                       &rval, HOSTMEM_OVERFLOWf, 1);
    572                     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr,
    573                                       &rval, HOSTMEM_TIMEOUTf, 1);
    574                     soc_pci_write(unit,
    575                                   CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_CLR_OFFSET(cmc, chan), rval);
    576                 }
    577                 LOG_VERBOSE(BSL_LS_BCM_INTR,
    578                             (BSL_META_U(unit,
    579                                         " soc_mem_fifo_dma_get_num_entries failed, rv=%d\n"), rv));
    580                 non_empty = FALSE;
    581             }
    582         } while (non_empty);
    583     }
    584 
    585 cleanup_exit:
    586     LOG_VERBOSE(BSL_LS_BCM_INTR,
    587                 (BSL_META_U(unit,
    588                             " stopping _bcm_report_fifo_dma_thread\n")));
    589     (void)soc_mem_fifo_dma_stop(unit, chan);
    590 
    591     if (host_buf != NULL) {
    592         soc_cm_sfree(unit, host_buf);
    593     }
    594     rctrl->pid = SAL_THREAD_ERROR;
    595     sal_thread_exit(0);
    596 }
    597 
    598 STATIC int
    599 _bcm_regex_report_init(int unit)
    600 {
    601     _bcm_ft_report_ctrl_t *rctrl = _bcm_ft_report_ctrl[unit];
    602 
    603     LOG_VERBOSE(BSL_LS_BCM_INTR,
    604                 (BSL_META_U(unit,
    605                             " _bcm_regex_report_init\n")));
    606     if (rctrl == NULL) {
    607         rctrl = sal_alloc(sizeof(_bcm_ft_report_ctrl_t), "Re_Report_ctrl Data");
    608         if (rctrl == NULL) {
    609             return BCM_E_MEMORY;
    610         }
    611         sal_memset(rctrl, 0, sizeof(_bcm_ft_report_ctrl_t));
    612 
    613         _bcm_ft_report_ctrl[unit] = rctrl;
    614 
    615         rctrl->pid = SAL_THREAD_ERROR;
    616     }
    617 
    618     return BCM_E_NONE;
    619 }
    620 
    621 static int
    622 bcm_regex_report_control(int unit, sal_usecs_t interval)
    623 {
    624     _bcm_ft_report_ctrl_t *rctrl = _bcm_ft_report_ctrl[unit];
    625     char name[32];
    626 
    627     rctrl = _bcm_ft_report_ctrl[unit];
    628 
    629     sal_snprintf(name, sizeof(name), "bcmFtExportDma.%d", unit);
    630 
    631     rctrl->interval = interval;
    632     if (interval) {
    633         if (rctrl->pid == SAL_THREAD_ERROR) {
    634             rctrl->pid = sal_thread_create(name, SAL_THREAD_STKSZ,
    635                                                 soc_property_get(unit, spn_BCM_FT_REPORT_THREAD_PRI, 50),
    636                                                 _bcm_report_fifo_dma_thread,
    637                                                 INT_TO_PTR(unit));
    638             if (rctrl->pid == SAL_THREAD_ERROR) {
    639                 LOG_ERROR(BSL_LS_BCM_COMMON,
    640                           (BSL_META_U(unit,
    641                                       "Could not start thread %s\n"), name));
    642                 return BCM_E_MEMORY;
    643             }
    644         }
    645     } else {
    646         /* Wake up thread so it will check the changed interval value */
    647         sal_sem_give(SOC_CONTROL(unit)->ftreportIntr);
    648     }
    649 
    650     return BCM_E_NONE;
    651 }
    652 
    653 int
    654 _bcm_esw_regex_report_register(int unit, uint32 reports,
    655                        bcm_regex_report_cb callback, void *userdata)
    656 {
    657     _bcm_ft_report_ctrl_t *rctrl;
    658     _bcm_ft_report_cb_entry_t *entry;
    659     int free_index, i;
    660 
    661     if (!soc_feature(unit, soc_feature_regex)) {
    662         return BCM_E_UNAVAIL;
    663     }
    664 
    665     if (_bcm_ft_report_ctrl[unit] == NULL) {
    666         BCM_IF_ERROR_RETURN(_bcm_regex_report_init(unit));
    667     }
    668     rctrl = _bcm_ft_report_ctrl[unit];
    669 
    670     if (callback == NULL) {
    671         return BCM_E_PARAM;
    672     }
    673 
    674     free_index = -1;
    675     for (i = 0; i < _BCM_FT_REPORT_MAX_CB; i++) {
    676         entry = &rctrl->callback_entry[i];
    677         if (entry->state == _BCM_FT_REPORT_CALLBACK_STATE_INVALID ||
    678             (rctrl->pid == SAL_THREAD_ERROR &&
    679              entry->state == _BCM_FT_REPORT_CALLBACK_STATE_UNREGISTERED)) {
    680             if (free_index < 0) {
    681                 free_index = i;
    682             }
    683         } else if (entry->state == _BCM_FT_REPORT_CALLBACK_STATE_ACTIVE ||
    684                    entry->state == _BCM_FT_REPORT_CALLBACK_STATE_REGISTERED) {
    685             if (entry->callback == callback && entry->userdata == userdata) {
    686                 return BCM_E_NONE;
    687             }
    688         }
    689     }
    690 
    691     if (free_index < 0) {
    692         return BCM_E_RESOURCE;
    693     }
    694     entry = &rctrl->callback_entry[free_index];
    695     entry->callback = callback;
    696     entry->userdata = userdata;
    697     entry->reports = reports;
    698     entry->state = _BCM_FT_REPORT_CALLBACK_STATE_REGISTERED;
    699 
    700     return bcm_regex_report_control(unit, 100000);
    701 }
    702 
    703 int
    704 _bcm_esw_regex_report_unregister(int unit, uint32 reports,
    705                          bcm_regex_report_cb callback,
    706                          void *userdata)
    707 {
    708     _bcm_ft_report_ctrl_t *rctrl;
    709     _bcm_ft_report_cb_entry_t *entry;
    710     int i, num_active = 0;
    711 
    712     if (!soc_feature(unit, soc_feature_regex)) {
    713         return BCM_E_UNAVAIL;
    714     }
    715 
    716     if (_bcm_ft_report_ctrl[unit] == NULL) {
    717         return BCM_E_INIT;
    718     }
    719     rctrl = _bcm_ft_report_ctrl[unit];
    720 
    721     for (i = 0; i < _BCM_FT_REPORT_MAX_CB; i++) {
    722         entry = &rctrl->callback_entry[i];
    723         if (entry->callback == callback && entry->userdata == userdata) {
    724             entry->reports &= ~reports;
    725             if (!entry->reports) {
    726                 entry->state = _BCM_FT_REPORT_CALLBACK_STATE_UNREGISTERED;
    727                 continue;
    728             }
    729         }
    730         if ((entry->state == _BCM_FT_REPORT_CALLBACK_STATE_ACTIVE) ||
    731             (entry->state == _BCM_FT_REPORT_CALLBACK_STATE_REGISTERED)) {
    732             num_active++;
    733         }
    734     }
    735     if (num_active == 0) {
    736         bcm_regex_report_control(unit, 0);
    737     }
    738     return BCM_E_NONE;
    739 }
    740 
    741 int _bcm_esw_regex_report_reset(int unit)
    742 {
    743     _bcm_ft_report_ctrl_t *rctrl;
    744     _bcm_ft_report_cb_entry_t *entry;
    745     int i;
    746 
    747     if (!soc_feature(unit, soc_feature_regex)) {
    748         return BCM_E_UNAVAIL;
    749     }
    750 
    751     if (_bcm_ft_report_ctrl[unit] == NULL) {
    752         return BCM_E_NONE;
    753     }
    754 
    755     rctrl = _bcm_ft_report_ctrl[unit];
    756 
    757     for (i = 0; i < _BCM_FT_REPORT_MAX_CB; i++) {
    758         entry = &rctrl->callback_entry[i];
    759         if ((entry->state == _BCM_FT_REPORT_CALLBACK_STATE_ACTIVE) ||
    760             (entry->state == _BCM_FT_REPORT_CALLBACK_STATE_REGISTERED)) {
    761             _bcm_esw_regex_report_unregister(unit, entry->reports,
    762                                              entry->callback, entry->userdata);
    763         }
    764     }
    765     return BCM_E_NONE;
    766 }
    767 
    768 #else
    769 int
    770 _bcm_esw_regex_report_register(int unit, uint32 reports,
    771                        bcm_regex_report_cb callback, void *userdata)
    772 {
    773     return BCM_E_UNAVAIL;
    774 }
    775 
    776 int
    777 _bcm_esw_regex_report_unregister(int unit, uint32 reports,
    778                          bcm_regex_report_cb callback,
    779                          void *userdata)
    780 {
    781     return BCM_E_UNAVAIL;
    782 }
    783 
    784 int _bcm_esw_regex_report_reset(int unit)
    785 {
    786     return BCM_E_UNAVAIL;
    787 }
    788 
    789 
    790 #endif /* BCM_TRIUMPH3_SUPPORT */
    791 
    792 #endif /* INCLUDE_REGEX */
    793