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, ®val)); 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