cmicm_dma_fifo.c (46739B)
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: CMICM FIFO DMA driver. 8 */ 9 10 #include <shared/bsl.h> 11 #include <shared/bitop.h> 12 13 14 #include <sal/core/boot.h> 15 #include <sal/core/libc.h> 16 #include <shared/alloc.h> 17 18 #include <soc/drv.h> 19 #include <soc/debug.h> 20 #include <soc/cm.h> 21 #include <soc/l2x.h> 22 23 #ifdef BCM_CMICM_SUPPORT 24 #include <soc/cmicm.h> 25 #endif 26 27 #ifdef BCM_TRIUMPH3_SUPPORT 28 #include <soc/er_tcam.h> 29 #include <soc/triumph3.h> 30 #endif 31 32 #ifdef BCM_KATANA2_SUPPORT 33 #include <soc/katana2.h> 34 #include <soc/katana.h> 35 #endif 36 37 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 38 39 #if (!defined(_LIMITS_H)) && !defined(_LIBC_LIMITS_H_) 40 41 #if (!defined(INT_MIN)) && !defined(INT_MAX) 42 #define INT_MIN (((int)1)<<(sizeof(int)*8-1)) 43 #define INT_MAX (~INT_MIN) 44 #endif 45 46 #ifndef UINT_MAX 47 #define UINT_MAX ((unsigned)-1) 48 #endif 49 50 #endif 51 52 #ifdef BCM_KATANA2_SUPPORT 53 #define RD_DMA_CFG_REG 0 54 #define RD_DMA_HOTMEM_THRESHOLD_REG 1 55 #define RD_DMA_STAT 2 56 #define RD_DMA_STAT_CLR 3 57 #endif 58 59 #if defined(BCM_CMICM_SUPPORT) && defined(BCM_XGS3_SWITCH_SUPPORT) 60 61 #define API_DISABLE 0 62 #define API_ENABLE 1 63 64 #define API_USE 1 65 #define API_NOT_USE 2 66 67 typedef struct _l2_mod_fifo_enable { 68 uint32 api_val; 69 uint32 api_is_set; 70 } _l2_mod_fifo_enable_t; 71 72 typedef struct _aux_arb_cntl { 73 uint32 api_val; 74 uint32 api_is_set; 75 } _aux_arb_cntl_t; 76 77 static _aux_arb_cntl_t aux_arb_cntl_reg[SOC_MAX_NUM_DEVICES]; 78 static _l2_mod_fifo_enable_t l2_mod_fifo_reg[SOC_MAX_NUM_DEVICES]; 79 80 #define API_SET_AUX_ARB_CNTL(unit, field, fvalue) do { \ 81 soc_reg_field_set(unit, AUX_ARB_CONTROLr, \ 82 &aux_arb_cntl_reg[unit].api_val, field, \ 83 ((fvalue) ? API_ENABLE: API_DISABLE)); \ 84 soc_reg_field_set(unit, AUX_ARB_CONTROLr, \ 85 &aux_arb_cntl_reg[unit].api_is_set, field, API_USE); \ 86 } while(0) 87 88 #define API_GET_AUX_ARB_CNTL(unit, field) \ 89 ((soc_reg_field_get(unit, AUX_ARB_CONTROLr, \ 90 aux_arb_cntl_reg[unit].api_is_set, field)) ? \ 91 ((soc_reg_field_get(unit, AUX_ARB_CONTROLr, \ 92 aux_arb_cntl_reg[unit].api_val, field)) ? \ 93 API_ENABLE : API_DISABLE) : \ 94 API_NOT_USE) 95 96 97 #define API_SET_L2_MOD_FIFO_ENABLE(unit, field, fvalue) do { \ 98 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, \ 99 &l2_mod_fifo_reg[unit].api_val, field, \ 100 ((fvalue) ? API_ENABLE: API_DISABLE)); \ 101 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, \ 102 &l2_mod_fifo_reg[unit].api_is_set, field, API_USE); \ 103 } while(0) 104 105 #define API_GET_L2_MOD_FIFO_ENABLE(unit, field) \ 106 ((soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, \ 107 l2_mod_fifo_reg[unit].api_is_set, field)) ? \ 108 ((soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, \ 109 l2_mod_fifo_reg[unit].api_val, field)) ? \ 110 API_ENABLE : API_DISABLE) : \ 111 API_NOT_USE) 112 #endif 113 114 #ifdef BCM_CMICM_SUPPORT 115 116 typedef struct _hostmem_address_remap_allocation{ 117 int in_use; 118 int cmc; 119 int ch; 120 } _hostmem_address_remap_allocation_t; 121 122 #define NOF_HOSTMEM_ADDR_REMAP_ENTRIES (16) 123 #define HOSTMEM_ADDR_REMAP_POSITION (28) 124 #define HOSTMEM_ADDR_REMAP_MASK (0xF) 125 126 127 _hostmem_address_remap_allocation_t hostmem_address_remap_allocation[SOC_MAX_NUM_DEVICES][NOF_HOSTMEM_ADDR_REMAP_ENTRIES]; 128 129 static void 130 _soc_mem_fifo_dma_address_remap_set( 131 int unit, 132 int cmc, 133 int entry_idx, 134 uint32 value) 135 { 136 uint32 remap_address[NOF_HOSTMEM_ADDR_REMAP_ENTRIES]; 137 soc_field_t remap_f[NOF_HOSTMEM_ADDR_REMAP_ENTRIES] = { 138 ADDR_0f, ADDR_1f, ADDR_2f, ADDR_3f, ADDR_4f, 139 ADDR_0f, ADDR_1f, ADDR_2f, ADDR_3f, ADDR_4f, 140 ADDR_0f, ADDR_1f, ADDR_2f, ADDR_3f, ADDR_4f, 141 ADDR_0f}; 142 uint32 rval; 143 144 remap_address[0] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc); 145 remap_address[1] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc); 146 remap_address[2] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc); 147 remap_address[3] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc); 148 remap_address[4] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc); 149 remap_address[5] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc); 150 remap_address[6] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc); 151 remap_address[7] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc); 152 remap_address[8] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc); 153 remap_address[9] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc); 154 remap_address[10] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc); 155 remap_address[11] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc); 156 remap_address[12] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc); 157 remap_address[13] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc); 158 remap_address[14] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc); 159 remap_address[15] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_3_OFFSET(cmc); 160 161 rval = soc_pci_read(unit, remap_address[entry_idx]); 162 soc_reg_field_set(unit, CMIC_CMC0_HOSTMEM_ADDR_REMAP_0r, &rval, remap_f[entry_idx], value); 163 soc_pci_write(unit, remap_address[entry_idx], rval); 164 } 165 166 int 167 _soc_mem_address_remap_allocation_init( 168 int unit) 169 { 170 int base_cmc = SOC_PCI_CMC(unit); 171 int num_of_cmc = SOC_PCI_CMCS_NUM(unit); 172 int cmc, entry_idx; 173 char *propkey; 174 uint32 remap_entries_reserved; 175 176 propkey = spn_HOST_MEMORY_ADDRESS_REMAP_ENTRIES_RESERVED_CMC; 177 sal_memset(hostmem_address_remap_allocation[unit], 0x0, 178 sizeof(_hostmem_address_remap_allocation_t)*NOF_HOSTMEM_ADDR_REMAP_ENTRIES); 179 180 /* consider remap_entries_reserved!=0 only for cmc=1 and pci_cmc=0 */ 181 /* this is the only constelation that the remap management is allowed */ 182 for(cmc=base_cmc; cmc<(num_of_cmc+base_cmc); cmc++) 183 { 184 remap_entries_reserved = soc_property_port_get(unit, cmc, propkey, 0); 185 if(remap_entries_reserved != 0) 186 { 187 if ((cmc != 1) || (base_cmc != 0)) 188 { 189 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U 190 (unit, "Soc host_memory_address_remap_entries_cmc_%d!=0 is allowed only for cmc=1 and pci_cmc=0\n"), cmc)); 191 return SOC_E_PARAM; 192 } 193 else 194 { 195 /* mark the reserved entries in database */ 196 for(entry_idx = 0; entry_idx < NOF_HOSTMEM_ADDR_REMAP_ENTRIES; entry_idx++) 197 { 198 if(SHR_BITGET(&remap_entries_reserved, entry_idx)) 199 { 200 hostmem_address_remap_allocation[unit][entry_idx].in_use = TRUE; 201 hostmem_address_remap_allocation[unit][entry_idx].cmc = -1; 202 hostmem_address_remap_allocation[unit][entry_idx].ch = -1; 203 } 204 else 205 { 206 /* clear the HW table for none ukernel (Arm-firmware) entries */ 207 _soc_mem_fifo_dma_address_remap_set(unit, cmc, entry_idx, 0); 208 } 209 } 210 } 211 } 212 } 213 return SOC_E_NONE; 214 } 215 216 int 217 _soc_mem_address_remap_dealloc( 218 int unit, 219 int cmc, 220 int ch) 221 { 222 int entry_idx; 223 224 for(entry_idx = 0; entry_idx < NOF_HOSTMEM_ADDR_REMAP_ENTRIES; entry_idx++) 225 { 226 if(hostmem_address_remap_allocation[unit][entry_idx].cmc == cmc && 227 hostmem_address_remap_allocation[unit][entry_idx].ch == ch && 228 hostmem_address_remap_allocation[unit][entry_idx].in_use == TRUE) 229 { 230 hostmem_address_remap_allocation[unit][entry_idx].in_use = FALSE; 231 /* clear HW */ 232 _soc_mem_fifo_dma_address_remap_set(unit, cmc, entry_idx, 0); 233 } 234 } 235 236 return SOC_E_NONE; 237 } 238 239 int 240 _soc_mem_address_remap_alloc( 241 int unit, 242 int cmc, 243 int ch, 244 int nof_entries, 245 uint32 remap_val, 246 uint32 *remap_entry_base) 247 { 248 int entry_idx; 249 int base_entry = 0, available_entries = 0; 250 251 if((nof_entries == 0) || (nof_entries > NOF_HOSTMEM_ADDR_REMAP_ENTRIES)) 252 { 253 return SOC_E_INTERNAL; 254 } 255 /* find free entry. If need to allocate more than one entry, all the entries must be consecutive */ 256 for(entry_idx = 0; (entry_idx < NOF_HOSTMEM_ADDR_REMAP_ENTRIES); entry_idx++) 257 { 258 if(hostmem_address_remap_allocation[unit][entry_idx].in_use == FALSE) 259 { 260 if(available_entries == 0) 261 { 262 base_entry = entry_idx; 263 } 264 available_entries++; 265 } 266 else 267 { 268 available_entries = 0; 269 } 270 if(available_entries == nof_entries) 271 { 272 break; 273 } 274 } 275 if(entry_idx == NOF_HOSTMEM_ADDR_REMAP_ENTRIES) 276 { 277 return SOC_E_RESOURCE; 278 } 279 /* update database and write to HW */ 280 for (entry_idx = base_entry; entry_idx < (base_entry + nof_entries); entry_idx++) 281 { 282 hostmem_address_remap_allocation[unit][entry_idx].in_use = TRUE; 283 hostmem_address_remap_allocation[unit][entry_idx].cmc = cmc; 284 hostmem_address_remap_allocation[unit][entry_idx].ch = ch; 285 /* write to HW: update the remap value into the relevant register */ 286 _soc_mem_fifo_dma_address_remap_set(unit, cmc, entry_idx, remap_val); 287 remap_val++; 288 } 289 290 * remap_entry_base = base_entry; 291 292 return SOC_E_NONE; 293 } 294 295 /** 296 * Function used to update HOSTMEM_ADDR_REMAP in case that it wasn't made during init stage. 297 * This function is called for manage a scenario when both SDK and Ukernel (ARM) use the same CMC 298 * SDK use the DMA channels and ARM use other CMC capbilities. 299 * Still, the remap table is common per cmc and need to verify that both application 300 * do not run each other entries in the table. 301 * Here we just write the value into the given entry. 302 * 303 * @param unit 304 * @param cmc - cmc to update 305 * @param ch - Channel used. should be between 0 and 3. 306 * @param phy_address - the phiscal address wich need to remap. 307 * @param remap_entry_base - indicates what is the base remap entry that need to update. 308 * relevant only for cmc1. if remap_entry_base=-1, no remap is required. 309 * @param base_entry - output value which indicate which is the base entry that allocated, 310 * and will be used in the hostmem start address offset register 311 * 312 * 313 * @return int - success or failure. 314 */ 315 static int 316 _soc_mem_fifo_dma_address_remap_handle( 317 int unit, 318 int cmc, 319 int ch, 320 uint32 phy_address, 321 uint32 *base_entry) 322 { 323 int nof_entries = 1; 324 uint32 remap_entry_base; 325 uint32 remamp_base_val, remap_val; 326 uint32 rval; 327 328 /** calculate the remap value: { 1'b0, 1'b1, physical_address_bits_31..28(4) } */ 329 remamp_base_val = ((phy_address >> HOSTMEM_ADDR_REMAP_POSITION) & HOSTMEM_ADDR_REMAP_MASK); 330 remap_val = (0x10 | remamp_base_val); 331 332 /* if the phy_address-bits31..28 is not the max value, we will allocate another entry consecutive to the base entry */ 333 /* for case that the size of the host_buffer crossing "sections" */ 334 if(remamp_base_val != HOSTMEM_ADDR_REMAP_MASK) 335 { 336 nof_entries++; 337 } 338 339 rval = _soc_mem_address_remap_alloc(unit, cmc, ch, nof_entries, remap_val, &remap_entry_base); 340 if (rval != SOC_E_NONE) 341 { 342 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "can't alloc hostmem address remap entry\n"))); 343 return rval; 344 } 345 346 *base_entry = remap_entry_base; 347 return SOC_E_NONE; 348 } 349 350 351 /* DMA FIFO init for registers or memories */ 352 353 /** 354 * Function used to (partially) configure the DMA to 355 * write to a redirect writes from a register/memory 356 * to a host memory. 357 * 358 * 359 * @param unit 360 * @param ch - Channel used. should be between 0 and 3. 361 * @param is_mem 362 * @param mem -name of memory, if memory is used (0 otherwise). 363 * @param reg - name of register, if register used (0 otherwise). 364 * @param copyno 365 * @param force_entry_size - in a case that entry size does not match 366 * the register\memory size - ignore when equals to 0. 367 * @param host_entries - number of host entries used by the DMA. 368 * Must be a power of 2 between 64 and 16384. 369 * Note that only after host_entries writes does the DMA wrap around the host_buff. 370 * @param host_buff - local memory on which the DMA writes. should be big enough to 371 * allow host_entries writes, 372 * in other words whould be the size of host_entries * ( size of memory or 373 * register used, in bytes). 374 * Other register the caller may need to configure seperatly: 375 * CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD - The amount of writes by the DMA until a 376 * threshold based interrupt occurs. 377 * 378 * TIMEOUT_COUNT field in CMIC_CMCx_FIFO_CHy_RD_DMA - Time between a DMA write and a 379 * timeout based interrupt. 380 * (May be set to 0 to disable timeout based interrupts). 381 * 382 * Endianess field in CMIC_CMCx_FIFO_CHy_RD_DMA. 383 * 384 * @return int - success or failure. 385 */ 386 int 387 _soc_mem_sbus_fifo_dma_start_memreg(int unit, int ch, 388 int is_mem, soc_mem_t mem, soc_reg_t reg, 389 int copyno, int force_entry_size, 390 int host_entries, void *host_buff) 391 { 392 uint8 at; 393 uint32 rval, data_beats, sel, phy_address; 394 int cmc; 395 int blk; 396 schan_msg_t msg; 397 int acc_type; 398 uint32 base_remap_entry; 399 char *propkey; 400 uint32 remap_entries_reserved; 401 402 if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) { 403 if (ch < 0 || ch > 12 || host_buff == NULL) { 404 return SOC_E_PARAM; 405 } 406 cmc = ch / 4; 407 ch = ch % 4; 408 } else { 409 cmc = SOC_PCI_CMC(unit); 410 if (ch < 0 || ch > 3 || host_buff == NULL) { 411 return SOC_E_PARAM; 412 } 413 } 414 415 switch (host_entries) { 416 case 64: sel = 0; break; 417 case 128: sel = 1; break; 418 case 256: sel = 2; break; 419 case 512: sel = 3; break; 420 case 1024: sel = 4; break; 421 case 2048: sel = 5; break; 422 case 4096: sel = 6; break; 423 case 8192: sel = 7; break; 424 case 16384: sel = 8; break; 425 default: 426 return SOC_E_PARAM; 427 } 428 429 #ifdef BCM_IPFIX_SUPPORT 430 #ifdef BCM_PETRA_SUPPORT 431 if (!SOC_IS_SAND(unit)) 432 #endif 433 { 434 if (mem != ING_IPFIX_EXPORT_FIFOm && mem != EGR_IPFIX_EXPORT_FIFOm && 435 mem != L2_MOD_FIFOm && mem != FT_EXPORT_FIFOm && 436 mem != FT_EXPORT_DATA_ONLYm && 437 mem != EGR_SER_FIFOm && mem != ING_SER_FIFOm && 438 mem != CENTRAL_CTR_EVICTION_FIFOm) { 439 return SOC_E_BADID; 440 } 441 } 442 #endif 443 444 /* Differentiate between reg and mem to get address, size and block */ 445 if ((!is_mem) && SOC_REG_IS_VALID(unit, reg)) { 446 data_beats = BYTES2WORDS(soc_reg_bytes(unit, reg)); 447 rval = soc_reg_addr_get(unit, reg, REG_PORT_ANY, 0, 448 SOC_REG_ADDR_OPTION_NONE, &blk, &at); 449 } else { 450 data_beats = soc_mem_entry_words(unit, mem); 451 if (copyno == MEM_BLOCK_ANY) { 452 copyno = SOC_MEM_BLOCK_ANY(unit, mem); 453 } 454 rval = soc_mem_addr_get(unit, mem, 0, copyno, 0, &at); 455 blk = SOC_BLOCK2SCH(unit, copyno); 456 } 457 /*Force entry size*/ 458 if (force_entry_size > 0) 459 { 460 data_beats = BYTES2WORDS(force_entry_size); 461 } 462 463 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_SBUS_START_ADDRESS_OFFSET(cmc, ch), rval); 464 465 schan_msg_clear(&msg); 466 if (is_mem) { 467 acc_type = SOC_MEM_ACC_TYPE(unit, mem); 468 } else { 469 acc_type = 0; 470 } 471 soc_schan_header_cmd_set(unit, &msg.header, FIFO_POP_CMD_MSG, blk, 0, 472 acc_type, 4, 0, 0); 473 474 /* Set 1st schan ctrl word as opcode */ 475 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_OPCODE_OFFSET(cmc, ch), msg.dwords[0]); 476 477 phy_address = soc_cm_l2p(unit, host_buff); 478 479 /** workarroud for issue when both ukernel (ARM) and SDK (Pci-e) use cmc-1 and need to share the remap entries*/ 480 /** in this case, the remap table is not 1x1 and need to update the relevant entries */ 481 propkey = spn_HOST_MEMORY_ADDRESS_REMAP_ENTRIES_RESERVED_CMC; 482 remap_entries_reserved = soc_property_port_get(unit, cmc, propkey, 0); 483 if ((SOC_IS_JERICHO(unit)) && 484 (SOC_PCI_CMCS_NUM(unit) > 1) && (remap_entries_reserved != 0)) 485 { 486 rval = _soc_mem_fifo_dma_address_remap_handle(unit, cmc, ch, phy_address, &base_remap_entry); 487 if (rval != SOC_E_NONE) 488 { 489 return rval; 490 } 491 492 phy_address = ((phy_address & ((1<<HOSTMEM_ADDR_REMAP_POSITION) - 1)) | (base_remap_entry << HOSTMEM_ADDR_REMAP_POSITION)); 493 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, ch), 494 phy_address); 495 } 496 else 497 { 498 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, ch), 499 phy_address); 500 } 501 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch)); 502 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, BEAT_COUNTf, 503 data_beats); 504 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, 505 HOST_NUM_ENTRIES_SELf, sel); 506 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, ABORTf, 0); 507 508 /* Note: Following might need to be tuned */ 509 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, 510 TIMEOUT_COUNTf, 1000); 511 /* Note: Following could be removed ?? */ 512 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, 513 NACK_FATALf, 1); 514 515 if (soc_feature(unit, soc_feature_multi_sbus_cmds)) { 516 517 } 518 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval); 519 520 if (SOC_IS_SAND(unit)) { 521 /* Always 1 in Arad when interrupt mechanism is not enabled */ 522 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD_OFFSET(cmc, ch), 523 1); 524 } else { 525 /* Note: Following might need to be tuned */ 526 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD_OFFSET(cmc, ch), 527 host_entries/10); 528 } 529 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, ENABLEf, 1); 530 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval); 531 return SOC_E_NONE; 532 } 533 534 #ifdef BCM_KATANA2_SUPPORT 535 int 536 _soc_kt2_mem_sbus_fifo_dma_start_memreg(int unit, int ch, 537 int is_mem, soc_mem_t mem, soc_reg_t reg, 538 int copyno, int host_entries, void *host_buff) 539 { 540 uint8 at; 541 uint32 rval, data_beats, sel; 542 int cmc; 543 int blk; 544 schan_msg_t msg; 545 soc_reg_t cfg_reg; 546 int acc_type; 547 if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) { 548 if (ch < 0 || ch > 12 || host_buff == NULL) { 549 return SOC_E_PARAM; 550 } 551 cmc = ch / 4; 552 ch = ch % 4; 553 } else { 554 cmc = SOC_PCI_CMC(unit); 555 if (ch < 0 || ch > 3 || host_buff == NULL) { 556 return SOC_E_PARAM; 557 } 558 } 559 560 switch (host_entries) { 561 case 64: sel = 0; break; 562 case 128: sel = 1; break; 563 case 256: sel = 2; break; 564 case 512: sel = 3; break; 565 case 1024: sel = 4; break; 566 case 2048: sel = 5; break; 567 case 4096: sel = 6; break; 568 case 8192: sel = 7; break; 569 case 16384: sel = 8; break; 570 default: 571 return SOC_E_PARAM; 572 } 573 574 if (mem != L2_MOD_FIFOm) { 575 return SOC_E_BADID; 576 } 577 578 /* Differentiate between reg and mem to get address, size and block */ 579 if ((!is_mem) && SOC_REG_IS_VALID(unit, reg)) { 580 data_beats = BYTES2WORDS(soc_reg_bytes(unit, reg)); 581 rval = soc_reg_addr_get(unit, reg, REG_PORT_ANY, 0, 582 SOC_REG_ADDR_OPTION_NONE, &blk, &at); 583 } else { 584 data_beats = soc_mem_entry_words(unit, mem); 585 if (copyno == MEM_BLOCK_ANY) { 586 copyno = SOC_MEM_BLOCK_ANY(unit, mem); 587 } 588 rval = soc_mem_addr_get(unit, mem, 0, copyno, 0, &at); 589 blk = SOC_BLOCK2SCH(unit, copyno); 590 } 591 592 soc_pci_write(unit, 593 CMIC_CMCx_FIFO_CHy_RD_DMA_SBUS_START_ADDRESS_OFFSET(cmc, ch), rval); 594 595 schan_msg_clear(&msg); 596 if (is_mem) { 597 acc_type = SOC_MEM_ACC_TYPE(unit, mem); 598 } else { 599 acc_type = 0; 600 } 601 soc_schan_header_cmd_set(unit, &msg.header, FIFO_POP_CMD_MSG, 602 blk, 0, acc_type, 4, 0, 0); 603 604 605 /* Set 1st schan ctrl word as opcode */ 606 soc_pci_write(unit, 607 CMIC_CMCx_FIFO_CHy_RD_DMA_OPCODE_OFFSET(cmc, ch), msg.dwords[0]); 608 609 rval = soc_cm_l2p(unit, host_buff); 610 soc_pci_write(unit, 611 CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, ch), 612 rval); 613 614 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch)); 615 cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, ch, RD_DMA_CFG_REG); 616 617 soc_reg_field_set(unit, cfg_reg, &rval, BEAT_COUNTf, 618 data_beats); 619 soc_reg_field_set(unit, cfg_reg, &rval, 620 HOST_NUM_ENTRIES_SELf, sel); 621 soc_reg_field_set(unit, cfg_reg, &rval, ABORTf, 0); 622 623 /* Note: Following might need to be tuned */ 624 soc_reg_field_set(unit, cfg_reg, &rval, 625 TIMEOUT_COUNTf, 1000); 626 /* Note: Following could be removed ?? */ 627 soc_reg_field_set(unit, cfg_reg, &rval, 628 NACK_FATALf, 1); 629 630 if (soc_feature(unit, soc_feature_multi_sbus_cmds)) { 631 632 } 633 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval); 634 635 /* Note: Following might need to be tuned */ 636 soc_pci_write(unit, 637 CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD_OFFSET(cmc, ch), 638 host_entries/10); 639 soc_reg_field_set(unit, cfg_reg, &rval, ENABLEf, 1); 640 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval); 641 return SOC_E_NONE; 642 } 643 644 #endif 645 646 int 647 _soc_mem_sbus_fifo_dma_start(int unit, int ch, soc_mem_t mem, int copyno, 648 int host_entries, void *host_buff) 649 { 650 651 #ifdef BCM_KATANA2_SUPPORT 652 if (SOC_IS_KATANA2(unit)) { 653 return _soc_kt2_mem_sbus_fifo_dma_start_memreg(unit, ch, 654 TRUE /* is_mem */, mem, 0, 655 copyno, host_entries, host_buff); 656 } 657 #endif 658 return _soc_mem_sbus_fifo_dma_start_memreg(unit, ch, 659 TRUE /* is_mem */, mem, 0, 660 copyno, 0, host_entries, host_buff); 661 662 } 663 664 #ifdef BCM_KATANA2_SUPPORT 665 int 666 _soc_kt2_mem_sbus_fifo_dma_stop(int unit, int ch) 667 { 668 int cmc, iter = 0; 669 uint32 rval; 670 int to = SAL_BOOT_QUICKTURN ? 30000000 : 10000000; 671 soc_reg_t cfg_reg , cfg_stat; 672 673 if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) { 674 if (ch < 0 || ch > 12) { 675 return SOC_E_PARAM; 676 } 677 cmc = ch / 4; 678 ch = ch % 4; 679 } else { 680 cmc = SOC_PCI_CMC(unit); 681 if (ch < 0 || ch > 3) { 682 return SOC_E_PARAM; 683 } 684 } 685 cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, ch, RD_DMA_CFG_REG); 686 cfg_stat= _soc_kt_fifo_reg_get (unit, cmc, ch,RD_DMA_STAT); 687 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch)); 688 if (!soc_reg_field_get(unit, cfg_reg, rval, ENABLEf)) { 689 return SOC_E_NONE; 690 } 691 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch)); 692 soc_reg_field_set(unit, cfg_reg, &rval, ABORTf, 1); 693 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval); 694 695 sal_udelay(1000); 696 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch)); 697 698 while (soc_reg_field_get(unit, cfg_stat, rval, DONEf) == 0 && 699 iter++ <to) { 700 sal_udelay(1000); 701 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch)); 702 } 703 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch)); 704 soc_reg_field_set(unit, cfg_reg, &rval, ENABLEf, 0); 705 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval); 706 707 if (iter >= to) { 708 LOG_ERROR(BSL_LS_SOC_COMMON, 709 (BSL_META_U(unit, 710 "FIFO DMA abort failed !!\n"))); 711 return SOC_E_INTERNAL; 712 } 713 return SOC_E_NONE; 714 } 715 #endif 716 717 718 int 719 _soc_mem_sbus_fifo_dma_stop(int unit, int ch) 720 { 721 int cmc, iter = 0; 722 uint32 rval; 723 int to = SAL_BOOT_QUICKTURN ? 30000000 : 10000000; 724 725 #ifdef BCM_KATANA2_SUPPORT 726 if (SOC_IS_KATANA2(unit) ) { 727 return _soc_kt2_mem_sbus_fifo_dma_stop(unit,ch); 728 } 729 #endif 730 731 if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) { 732 if (ch < 0 || ch > 12) { 733 return SOC_E_PARAM; 734 } 735 cmc = ch / 4; 736 ch = ch % 4; 737 } else { 738 cmc = SOC_PCI_CMC(unit); 739 if (ch < 0 || ch > 3) { 740 return SOC_E_PARAM; 741 } 742 } 743 744 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch)); 745 if (!soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, rval, ENABLEf)) { 746 return SOC_E_NONE; 747 } 748 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch)); 749 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, ABORTf, 1); 750 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval); 751 752 sal_udelay(1000); 753 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch)); 754 755 while (soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, rval, DONEf) == 0 && 756 iter++ <to) { 757 sal_udelay(1000); 758 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch)); 759 } 760 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch)); 761 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, ENABLEf, 0); 762 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval); 763 764 if (iter >= to) { 765 LOG_ERROR(BSL_LS_SOC_COMMON, 766 (BSL_META_U(unit, 767 "FIFO DMA abort failed !!\n"))); 768 return SOC_E_INTERNAL; 769 } 770 return SOC_E_NONE; 771 } 772 773 int 774 _soc_mem_sbus_fifo_dma_get_num_entries(int unit, int ch, int *count) 775 { 776 uint32 val = 0; 777 int cmc; 778 779 if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) { 780 if (ch < 0 || ch > 12) { 781 return SOC_E_PARAM; 782 } 783 cmc = ch / 4; 784 ch = ch % 4; 785 } else { 786 cmc = SOC_PCI_CMC(unit); 787 if (ch < 0 || ch > 3) { 788 return SOC_E_PARAM; 789 } 790 } 791 792 val = soc_pci_read(unit, 793 CMIC_CMCx_FIFO_CHy_RD_DMA_NUM_OF_ENTRIES_VALID_IN_HOSTMEM_OFFSET(cmc, ch)); 794 *count = val; 795 if (val) { 796 return SOC_E_NONE; 797 } 798 return SOC_E_EMPTY; 799 } 800 801 int 802 _soc_mem_sbus_fifo_dma_set_entries_read(int unit, int ch, uint32 num) 803 { 804 int cmc; 805 806 if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) { 807 if (ch < 0 || ch > 12) { 808 return SOC_E_PARAM; 809 } 810 cmc = ch / 4; 811 ch = ch % 4; 812 } else { 813 cmc = SOC_PCI_CMC(unit); 814 if (ch < 0 || ch > 3) { 815 return SOC_E_PARAM; 816 } 817 } 818 819 820 821 soc_pci_write(unit, 822 CMIC_CMCx_FIFO_CHy_RD_DMA_NUM_OF_ENTRIES_READ_FRM_HOSTMEM_OFFSET(cmc, ch), num); 823 return SOC_E_NONE; 824 } 825 826 #ifdef BCM_XGS3_SWITCH_SUPPORT /* DPPCOMPILEENABLE */ 827 828 STATIC int 829 _soc_l2mod_sbus_fifo_enable(int unit, uint8 val) 830 { 831 uint32 rval = 0; 832 833 if (val == 0) { 834 SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval)); 835 return SOC_E_NONE; 836 } else { 837 SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &rval)); 838 839 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, 840 INTERNAL_L2_ENTRYf, val); 841 if (soc_feature(unit, soc_feature_esm_support)) { 842 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, 843 EXTERNAL_L2_ENTRYf, val); 844 } 845 /* enable by default unless API disable explicitly */ 846 if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_DELETEf)) { 847 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_DELETEf, val); 848 } 849 if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_INSERTf)) { 850 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_INSERTf, val); 851 } 852 if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_LEARNf)) { 853 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_LEARNf, val); 854 } 855 if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_MEMWRf)) { 856 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_MEMWRf, val); 857 } 858 SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval)); 859 } 860 return SOC_E_NONE; 861 } 862 863 STATIC int 864 _soc_td2_l2mod_sbus_fifo_enable(int unit, int enable) 865 { 866 uint32 rval = 0; 867 868 if (enable == 0) { 869 SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, rval)); 870 return SOC_E_NONE; 871 } else { 872 SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, &rval)); 873 /* enable by default unless API disable explicitly */ 874 if (API_DISABLE != API_GET_AUX_ARB_CNTL(unit, L2_MOD_FIFO_ENABLE_L2_DELETEf)) { 875 soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, 876 L2_MOD_FIFO_ENABLE_L2_DELETEf, enable); 877 } 878 if (API_DISABLE != API_GET_AUX_ARB_CNTL(unit, L2_MOD_FIFO_ENABLE_AGEf)) { 879 soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, L2_MOD_FIFO_ENABLE_AGEf, 880 enable); 881 } 882 if (API_DISABLE != API_GET_AUX_ARB_CNTL(unit, L2_MOD_FIFO_ENABLE_LEARNf)) { 883 soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, L2_MOD_FIFO_ENABLE_LEARNf, 884 enable); 885 } 886 /* disable by default unless API enable explicitly */ 887 if (API_ENABLE == API_GET_AUX_ARB_CNTL(unit, L2_MOD_FIFO_ENABLE_L2_INSERTf)) { 888 soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, L2_MOD_FIFO_ENABLE_L2_INSERTf, 889 enable); 890 } 891 SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, rval)); 892 } 893 return SOC_E_NONE; 894 } 895 896 #ifdef BCM_TOMAHAWK_SUPPORT 897 STATIC int 898 _soc_th_l2mod_sbus_fifo_enable(int unit, int enable) 899 { 900 uint32 rval = 0; 901 902 if (enable == 0) { 903 SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, enable)); 904 return SOC_E_NONE; 905 } else { 906 SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &rval)); 907 908 /* enable by default unless API disable explicitly */ 909 if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_DELETEf)) { 910 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_DELETEf, enable); 911 } 912 if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_LEARNf)) { 913 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_LEARNf, enable); 914 } 915 SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval)); 916 } 917 918 return SOC_E_NONE; 919 } 920 #endif /* BCM_TOMAHAWK_SUPPORT */ 921 922 extern uint32 soc_mem_fifo_delay_value; 923 924 STATIC void 925 _soc_l2mod_sbus_fifo_dma_thread(void *unit_vp) 926 { 927 uint8 overflow, timeout; 928 int i, count, handled_count, adv_threshold; 929 int unit = PTR_TO_INT(unit_vp); 930 int cmc = SOC_PCI_CMC(unit); 931 soc_control_t *soc = SOC_CONTROL(unit); 932 uint32 entries_per_buf, rval; 933 int rv, interval, non_empty; 934 uint8 ch; 935 uint32 *buff_max, intr_mask; 936 void *host_entry, *host_buff; 937 int entry_words; 938 939 if (SOC_IS_TD2_TT2(unit)) { 940 /* 941 * Channel 0 is for X pipe 942 * Channel 1 is for Y pipe but nothing will go into Y pipe L2_MOD_FIFO. 943 */ 944 ch = SOC_MEM_FIFO_DMA_CHANNEL_0; 945 } else { 946 ch = SOC_MEM_FIFO_DMA_CHANNEL_1; 947 } 948 intr_mask = IRQ_CMCx_FIFO_CH_DMA(ch); 949 950 entries_per_buf = soc_property_get(unit, spn_L2XMSG_HOSTBUF_SIZE, 1024); 951 adv_threshold = entries_per_buf / 2; 952 953 entry_words = soc_mem_entry_words(unit, L2_MOD_FIFOm); 954 host_buff = soc_cm_salloc(unit, entries_per_buf * entry_words * sizeof(uint32), 955 "L2_MOD DMA Buffer"); 956 if (host_buff == NULL) { 957 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 958 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, 959 SOC_E_MEMORY); 960 goto cleanup_exit; 961 } 962 (void)_soc_mem_sbus_fifo_dma_stop(unit, ch); 963 964 rv = _soc_mem_sbus_fifo_dma_start(unit, ch, L2_MOD_FIFOm, MEM_BLOCK_ANY, 965 entries_per_buf, host_buff); 966 if (SOC_FAILURE(rv)) { 967 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 968 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv); 969 goto cleanup_exit; 970 } 971 972 host_entry = host_buff; 973 buff_max = (uint32 *)host_entry + (entries_per_buf * entry_words); 974 975 if (!soc_feature(unit, soc_feature_fifo_dma)) { 976 soc_cmicm_intr0_enable(unit, 977 IRQ_CMCx_FIFO_CH_DMA(SOC_MEM_FIFO_DMA_CHANNEL_1)); 978 } 979 if (SOC_IS_TRIUMPH3(unit)) { 980 _soc_l2mod_sbus_fifo_enable(unit, 1); 981 #ifdef BCM_TOMAHAWK_SUPPORT 982 } else if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 983 _soc_th_l2mod_sbus_fifo_enable(unit, 1); 984 #endif /* BCM_TOMAHAWK_SUPPORT */ 985 } else { 986 _soc_td2_l2mod_sbus_fifo_enable(unit, 1); 987 } 988 989 while ((interval = soc->l2x_interval)) { 990 overflow = 0; timeout = 0; 991 if (soc->l2modDmaIntrEnb) { 992 soc_cmicm_intr0_enable(unit, intr_mask); 993 if (sal_sem_take(soc->arl_notify, interval) < 0) { 994 LOG_VERBOSE(BSL_LS_SOC_INTR, 995 (BSL_META_U(unit, 996 "%s polling timeout soc_mem_fifo_delay_value=%d\n"), 997 soc->l2x_name, soc_mem_fifo_delay_value)); 998 } else { 999 LOG_VERBOSE(BSL_LS_SOC_INTR, 1000 (BSL_META_U(unit, 1001 "%s woken up soc_mem_fifo_delay_value=%d\n"), 1002 soc->l2x_name, soc_mem_fifo_delay_value)); 1003 /* check for timeout or overflow and either process or continue */ 1004 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch)); 1005 timeout = soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, 1006 rval, HOSTMEM_TIMEOUTf); 1007 if (!timeout) { 1008 overflow = soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, 1009 rval, HOSTMEM_OVERFLOWf); 1010 timeout |= overflow; 1011 } 1012 } 1013 1014 } else { 1015 sal_usleep(interval); 1016 } 1017 1018 handled_count = 0; 1019 do { 1020 non_empty = FALSE; 1021 /* get entry count, process if nonzero else continue */ 1022 rv = _soc_mem_sbus_fifo_dma_get_num_entries(unit, ch, &count); 1023 if (SOC_SUCCESS(rv)) { 1024 non_empty = TRUE; 1025 if (count > adv_threshold) { 1026 count = adv_threshold; 1027 } 1028 /* Invalidate DMA memory to read */ 1029 if (((uint32 *)host_entry + count * entry_words) > buff_max) { 1030 /* roll-over cases */ 1031 soc_cm_sinval(unit, host_entry, 1032 (buff_max - (uint32 *)host_entry) * sizeof(uint32)); 1033 soc_cm_sinval(unit, host_buff, 1034 ((count * entry_words) - (buff_max - (uint32 *)host_entry)) * sizeof(uint32)); 1035 } 1036 else { 1037 soc_cm_sinval(unit, host_entry, (count * entry_words) * sizeof(uint32)); 1038 } 1039 for (i = 0; i < count; i++) { 1040 if(!soc->l2x_interval) { 1041 goto cleanup_exit; 1042 } 1043 #ifdef BCM_TRIUMPH3_SUPPORT 1044 if (SOC_IS_TRIUMPH3(unit)) { 1045 soc_tr3_l2mod_fifo_process(unit, soc->l2x_flags, 1046 host_entry); 1047 } else 1048 #endif 1049 { 1050 #ifdef BCM_KATANA2_SUPPORT 1051 if (SOC_IS_KATANA2(unit)) { 1052 _soc_kt_l2mod_fifo_process(unit, soc->l2x_flags, 1053 host_entry); 1054 1055 } else 1056 #endif 1057 #ifdef BCM_HURRICANE2_SUPPORT 1058 if (soc_feature(unit, soc_feature_fifo_dma_hu2)) { 1059 _soc_hu2_l2mod_fifo_process(unit, soc->l2x_flags, 1060 host_entry); 1061 1062 } else 1063 #endif 1064 { 1065 #ifdef BCM_TRIDENT2_SUPPORT 1066 _soc_td2_l2mod_fifo_process(unit, soc->l2x_flags, 1067 host_entry); 1068 #endif /* BCM_TRIDENT2_SUPPORT*/ 1069 } 1070 } 1071 host_entry = (uint32 *)host_entry + entry_words; 1072 /* handle roll over */ 1073 if ((uint32 *)host_entry >= buff_max) { 1074 host_entry = host_buff; 1075 } 1076 1077 handled_count ++; 1078 /* 1079 * PPA may wait for available space in mod_fifo, lower the 1080 * threshold when ppa is running, therefore read point can 1081 * be updated sooner. 1082 */ 1083 if (SOC_CONTROL(unit)->l2x_ppa_in_progress && i >= 63) { 1084 i++; 1085 break; 1086 } 1087 } 1088 (void)_soc_mem_sbus_fifo_dma_set_entries_read(unit, ch, i); 1089 } 1090 1091 /* check and clear error */ 1092 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch)); 1093 if (soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, rval, 1094 DONEf)) { 1095 LOG_ERROR(BSL_LS_SOC_COMMON, 1096 (BSL_META_U(unit, 1097 "FIFO DMA engine terminated for cmc[%d]:ch[%d]\n"), 1098 cmc, ch)); 1099 if (soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, rval, 1100 ERRORf)) { 1101 LOG_ERROR(BSL_LS_SOC_COMMON, 1102 (BSL_META_U(unit, 1103 "FIFO DMA engine encountered error: [0x%x]\n"), 1104 rval)); 1105 } 1106 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1107 SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, SOC_E_INTERNAL); 1108 goto cleanup_exit; 1109 } 1110 1111 if (!SOC_CONTROL(unit)->l2x_ppa_in_progress) { 1112 /* For some operating systems, sal_thread_yield is 1113 * not sufficient to yield CPU resource to other lower 1114 * priority thread 1115 */ 1116 if ((handled_count * 2) >= adv_threshold) { 1117 sal_usleep(1000); 1118 handled_count = 0; 1119 } 1120 } 1121 } while (non_empty); 1122 /* Clearing of the FIFO_CH_DMA_INT interrupt by resetting 1123 overflow & timeout status in FIFO_CHy_RD_DMA_STAT_CLR reg */ 1124 if (timeout) { 1125 rval = 0; 1126 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr, &rval, 1127 HOSTMEM_OVERFLOWf, 1); 1128 soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr, &rval, 1129 HOSTMEM_TIMEOUTf, 1); 1130 soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_CLR_OFFSET(cmc, ch), 1131 rval); 1132 } 1133 } 1134 1135 cleanup_exit: 1136 (void)_soc_mem_sbus_fifo_dma_stop(unit, ch); 1137 1138 if (host_buff != NULL) { 1139 soc_cm_sfree(unit, host_buff); 1140 } 1141 if (SOC_IS_TRIUMPH3(unit)) { 1142 _soc_l2mod_sbus_fifo_enable(unit, 0); 1143 #ifdef BCM_TOMAHAWK_SUPPORT 1144 } else if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 1145 _soc_th_l2mod_sbus_fifo_enable(unit, 0); 1146 #endif /* BCM_TOMAHAWK_SUPPORT */ 1147 } else { 1148 _soc_td2_l2mod_sbus_fifo_enable(unit, 0); 1149 } 1150 1151 soc->l2x_pid = SAL_THREAD_ERROR; 1152 sal_thread_exit(0); 1153 } 1154 1155 /* 1156 * Function: 1157 * soc_l2mod_running 1158 * Purpose: 1159 * Determine the L2MOD sync thread running parameters 1160 * Parameters: 1161 * unit - unit number. 1162 * flags (OUT) - if non-NULL, receives the current flag settings 1163 * interval (OUT) - if non-NULL, receives the current pass interval 1164 * Returns: 1165 * Boolean; TRUE if L2MOD sync thread is running 1166 */ 1167 1168 int 1169 _soc_l2mod_running(int unit, uint32 *flags, sal_usecs_t *interval) 1170 { 1171 #ifdef BCM_XGS3_SWITCH_SUPPORT 1172 soc_control_t *soc = SOC_CONTROL(unit); 1173 1174 if (SOC_IS_XGS3_SWITCH(unit)) { 1175 if (soc->l2x_pid != SAL_THREAD_ERROR) { 1176 if (flags != NULL) { 1177 *flags = soc->l2x_flags; 1178 } 1179 if (interval != NULL) { 1180 *interval = soc->l2x_interval; 1181 } 1182 } 1183 1184 return (soc->l2x_pid != SAL_THREAD_ERROR); 1185 } 1186 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 1187 return SOC_E_UNAVAIL; 1188 } 1189 1190 /* 1191 * Function: 1192 * _soc_l2mod_stop 1193 * Purpose: 1194 * Stop L2MOD-related thread 1195 * Parameters: 1196 * unit - unit number. 1197 * Returns: 1198 * SOC_E_XXX 1199 */ 1200 int 1201 _soc_l2mod_stop(int unit) 1202 { 1203 soc_control_t * soc = SOC_CONTROL(unit); 1204 int rv = SOC_E_NONE; 1205 uint8 ch = SOC_MEM_FIFO_DMA_CHANNEL_1; 1206 1207 if (SOC_IS_XGS3_SWITCH(unit)) { 1208 LOG_INFO(BSL_LS_SOC_ARL, 1209 (BSL_META_U(unit, 1210 "soc_l2mod_stop: unit=%d\n"), unit)); 1211 1212 if (SOC_IS_TRIUMPH3(unit)) { 1213 _soc_l2mod_sbus_fifo_enable(unit, 0); 1214 #ifdef BCM_TOMAHAWK_SUPPORT 1215 } else if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 1216 _soc_th_l2mod_sbus_fifo_enable(unit, 0); 1217 #endif /* BCM_TOMAHAWK_SUPPORT */ 1218 } else { 1219 _soc_td2_l2mod_sbus_fifo_enable(unit, 0); 1220 } 1221 if (!soc_feature(unit, soc_feature_fifo_dma)) { 1222 soc_cmicm_intr0_disable(unit, IRQ_CMCx_FIFO_CH_DMA(ch)); 1223 soc->l2x_interval = 0; /* Request exit */ 1224 } 1225 1226 if (soc->l2modDmaIntrEnb) { 1227 /* Wake up thread so it will check the exit flag */ 1228 sal_sem_give(soc->arl_notify); 1229 } 1230 1231 return rv; 1232 } 1233 return SOC_E_UNAVAIL; 1234 } 1235 1236 int 1237 _soc_l2mod_start(int unit, uint32 flags, sal_usecs_t interval) 1238 { 1239 soc_control_t * soc = SOC_CONTROL(unit); 1240 int pri; 1241 1242 if (!soc_feature(unit, soc_feature_arl_hashed)) { 1243 return SOC_E_UNAVAIL; 1244 } 1245 1246 if (soc->l2x_interval != 0) { 1247 SOC_IF_ERROR_RETURN(_soc_l2mod_stop(unit)); 1248 } 1249 1250 sal_snprintf(soc->l2x_name, sizeof(soc->l2x_name), "bcmL2MOD.%d", unit); 1251 1252 soc->l2x_flags = flags; 1253 soc->l2x_interval = interval; 1254 1255 if (interval == 0) { 1256 return SOC_E_NONE; 1257 } 1258 1259 if (soc->l2x_pid == SAL_THREAD_ERROR) { 1260 pri = soc_property_get(unit, spn_L2XMSG_THREAD_PRI, 50); 1261 1262 soc->l2x_pid = 1263 sal_thread_create(soc->l2x_name, SAL_THREAD_STKSZ, pri, 1264 _soc_l2mod_sbus_fifo_dma_thread, INT_TO_PTR(unit)); 1265 if (soc->l2x_pid == SAL_THREAD_ERROR) { 1266 LOG_ERROR(BSL_LS_SOC_COMMON, 1267 (BSL_META_U(unit, 1268 "soc_l2mod_start: Could not start L2MOD thread\n"))); 1269 return SOC_E_MEMORY; 1270 } 1271 } 1272 1273 return SOC_E_NONE; 1274 } 1275 1276 int 1277 _soc_l2mod_sbus_fifo_field_set(int unit, soc_field_t field, int enable) 1278 { 1279 uint32 rval = 0; 1280 uint32 fval = enable?1:0; 1281 1282 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT(unit) || 1283 SOC_IS_TITAN2(unit) || SOC_IS_TITAN(unit)|| 1284 SOC_IS_HURRICANE2(unit)|| SOC_IS_HURRICANE3(unit)|| 1285 SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit) || 1286 SOC_IS_KATANA2(unit)) { 1287 if(soc_reg_field_valid(unit, AUX_ARB_CONTROLr, field)) { 1288 SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, &rval)); 1289 1290 soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, field, fval); 1291 1292 SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, rval)); 1293 1294 API_SET_AUX_ARB_CNTL(unit, field, fval); 1295 } 1296 return SOC_E_NONE; 1297 } 1298 if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TOMAHAWKX(unit)) { 1299 if(soc_reg_field_valid(unit, L2_MOD_FIFO_ENABLEr, field)) { 1300 SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &rval)); 1301 1302 soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, field, fval); 1303 1304 SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval)); 1305 1306 API_SET_L2_MOD_FIFO_ENABLE(unit, field, fval); 1307 } 1308 return SOC_E_NONE; 1309 } 1310 return SOC_E_UNAVAIL; 1311 } 1312 1313 int 1314 _soc_l2mod_sbus_fifo_field_get(int unit, soc_field_t field, int *enable) 1315 { 1316 uint32 reg = 0; 1317 uint32 fval = 0; 1318 1319 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT(unit) || 1320 SOC_IS_TITAN2(unit) || SOC_IS_TITAN(unit) || 1321 SOC_IS_HURRICANE2(unit) || SOC_IS_HURRICANE3(unit) || 1322 SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit) || 1323 SOC_IS_KATANA2(unit)) { 1324 if(soc_reg_field_valid(unit, AUX_ARB_CONTROLr, field)) { 1325 SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, ®)); 1326 1327 fval = soc_reg_field_get(unit, AUX_ARB_CONTROLr, reg, field); 1328 } 1329 *enable = fval?1:0; 1330 return SOC_E_NONE; 1331 } 1332 if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TOMAHAWKX(unit)) { 1333 if(soc_reg_field_valid(unit, L2_MOD_FIFO_ENABLEr, field)) { 1334 SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, ®)); 1335 1336 fval = soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, reg, field); 1337 1338 } 1339 *enable = fval?1:0; 1340 return SOC_E_NONE; 1341 } 1342 1343 return SOC_E_UNAVAIL; 1344 } 1345 1346 #endif /* BCM_XGS3_SWITCH_SUPPORT */ /* DPPCOMPILEENABLE */ 1347 #endif /* BCM_CMICM_SUPPORT */ 1348 #endif /* defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) */ 1349 1350