l2.c (14823B)
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: l2.c 8 * Purpose: Katana L2 functions 9 */ 10 11 #include <soc/mem.h> 12 #include <soc/drv.h> 13 #include <bcm/error.h> 14 #include <shared/bsl.h> 15 #ifdef BCM_CMICM_SUPPORT 16 #include <soc/cmicm.h> 17 #endif 18 #ifdef BCM_KATANA_SUPPORT 19 #include <soc/katana.h> 20 #endif 21 22 23 #if defined(BCM_ESW_SUPPORT) 24 #if defined(BCM_KATANA_SUPPORT) && defined(BCM_CMICM_SUPPORT) 25 26 #define RD_DMA_CFG_REG 0 27 #define RD_DMA_HOTMEM_THRESHOLD_REG 1 28 #define RD_DMA_STAT 2 29 #define RD_DMA_STAT_CLR 3 30 31 int 32 _soc_mem_kt_fifo_dma_start(int unit, int chan, soc_mem_t mem, int copyno, 33 int host_entries, void *host_buf) 34 { 35 soc_control_t *soc = SOC_CONTROL(unit); 36 soc_reg_t cfg_reg, thresh_reg; 37 uint32 addr, rval, data_beats, sel, spacing; 38 uint8 at; 39 int cmc = SOC_PCI_CMC(unit); 40 41 if (chan < 0 || chan > 3 || host_buf == NULL) { 42 return SOC_E_PARAM; 43 } 44 45 if(!soc_feature(unit, soc_feature_cmicm)) { 46 return BCM_E_UNAVAIL; 47 } 48 49 switch (host_entries) { 50 case 64: sel = 0; break; 51 case 128: sel = 1; break; 52 case 256: sel = 2; break; 53 case 512: sel = 3; break; 54 case 1024: sel = 4; break; 55 case 2048: sel = 5; break; 56 case 4096: sel = 6; break; 57 case 8192: sel = 7; break; 58 case 16384: sel = 8; break; 59 case 32768: sel = 9; break; 60 case 65536: sel = 10; break; 61 default: 62 return SOC_E_PARAM; 63 } 64 65 if (mem != ING_IPFIX_EXPORT_FIFOm && mem != EGR_IPFIX_EXPORT_FIFOm && 66 mem != EXT_L2_MOD_FIFOm && mem != L2_MOD_FIFOm) { 67 return SOC_E_BADID; 68 } 69 70 if (copyno == MEM_BLOCK_ANY) { 71 copyno = SOC_MEM_BLOCK_ANY(unit, mem); 72 } 73 74 data_beats = soc_mem_entry_words(unit, mem); 75 76 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_SBUS_START_ADDRESS_OFFSET(cmc, chan); 77 rval = soc_mem_addr_get(unit, mem, 0, copyno, 0, &at); 78 soc_pci_write(unit, addr, rval); 79 80 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, chan); 81 rval = soc_cm_l2p(unit, host_buf); 82 soc_pci_write(unit, addr, rval); 83 84 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_READ_PTR_OFFSET(cmc, chan); 85 soc_pci_write(unit, addr, rval); 86 87 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD_OFFSET(cmc, chan); 88 rval = 0; 89 thresh_reg = _soc_kt_fifo_reg_get (unit, 90 cmc, chan, RD_DMA_HOTMEM_THRESHOLD_REG); 91 soc_reg_field_set(unit, thresh_reg, &rval, ADDRESSf, 92 host_entries / 16 * data_beats * sizeof(uint32)); 93 soc_pci_write(unit, addr, rval); 94 95 cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_CFG_REG); 96 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, chan); 97 rval = 0; 98 rval = soc_pci_read(unit, addr); 99 soc_reg_field_set(unit, cfg_reg, &rval, BEAT_COUNTf, data_beats); 100 soc_reg_field_set(unit, cfg_reg, &rval, HOST_NUM_ENTRIES_SELf, sel); 101 soc_reg_field_set(unit, cfg_reg, &rval, TIMEOUT_COUNTf, 200); 102 103 if (soc_feature(unit, soc_feature_multi_sbus_cmds)) { 104 105 if (soc->sbusCmdSpacing < 0) { 106 spacing = data_beats > 7 ? data_beats + 1 : 8; 107 } else { 108 spacing = soc->sbusCmdSpacing; 109 } 110 if ((SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_ESM) || 111 (SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_XQPORT) || 112 (SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_GXPORT) || 113 (SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_SPORT) || 114 (SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_GPORT)) { 115 spacing = 0; 116 } 117 if (spacing) { 118 soc_reg_field_set(unit, cfg_reg, &rval, 119 MULTIPLE_SBUS_CMD_SPACINGf, spacing); 120 soc_reg_field_set(unit, cfg_reg, &rval, 121 ENABLE_MULTIPLE_SBUS_CMDSf, 1); 122 } 123 } 124 soc_pci_write(unit, addr, rval); 125 126 soc_reg_field_set(unit, cfg_reg, &rval, ENABLEf, 1); 127 /* soc_reg_field_set(unit, cfg_reg, &rval, ENABLE_VALf, 1);*/ 128 soc_pci_write(unit, addr, rval); 129 130 return SOC_E_NONE; 131 } 132 133 int 134 _soc_mem_kt_fifo_dma_stop(int unit, int chan) 135 { 136 soc_reg_t cfg_reg; 137 uint32 addr, rval; 138 int cmc = SOC_PCI_CMC(unit); 139 140 if (chan < 0 || chan > 3) { 141 return SOC_E_PARAM; 142 } 143 144 if(!soc_feature(unit, soc_feature_cmicm)) { 145 return BCM_E_UNAVAIL; 146 } 147 148 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, chan); 149 cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_CFG_REG); 150 rval = soc_pci_read(unit, addr); 151 152 /* Resetting ENABLE field disables the channel on which the DMA thread 153 is running. This is done to ensure that no operation is performed in that 154 channel when corresponding DMA thread is not active. As the operations 155 happening in the L2 layer in Mod_Fifo mode are communicated to upper layer 156 via callbacks processed from DMA copy, it is important to disable channel 157 when dma thread is stopped and is enabled again when DMA thread is started*/ 158 159 soc_reg_field_set(unit, cfg_reg, &rval, ENABLEf, 0); 160 soc_pci_write(unit, addr, rval); 161 162 return SOC_E_NONE; 163 } 164 165 int 166 _soc_mem_kt_fifo_dma_get_read_ptr(int unit, int chan, void **host_ptr, int *count) 167 { 168 soc_reg_t cfg_reg, stat_reg; 169 int host_entries, data_beats; 170 soc_field_t overflow_field; 171 uint32 addr, rval, stat, hostmem_addr, read_ptr, write_ptr; 172 int cmc = SOC_PCI_CMC(unit); 173 174 if (chan < 0 || chan > 3 || host_ptr == NULL) { 175 return SOC_E_PARAM; 176 } 177 178 if(!soc_feature(unit, soc_feature_cmicm)) { 179 return BCM_E_UNAVAIL; 180 } 181 182 read_ptr = 0; 183 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_READ_PTR_OFFSET(cmc, chan); 184 soc_pci_getreg(unit, addr, &read_ptr); 185 186 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_WRITE_PTR_OFFSET(cmc, chan); 187 write_ptr = 0; 188 soc_pci_getreg(unit, addr, &write_ptr); 189 190 if (write_ptr == 0) { 191 return SOC_E_EMPTY; 192 } 193 194 switch(chan) { 195 case 1: overflow_field = FIFO_CH1_DMA_HOSTMEM_OVERFLOWf; break; 196 case 2: overflow_field = FIFO_CH2_DMA_HOSTMEM_OVERFLOWf; break; 197 case 3: overflow_field = FIFO_CH3_DMA_HOSTMEM_OVERFLOWf; break; 198 default: overflow_field = FIFO_CH0_DMA_HOSTMEM_OVERFLOWf; break; 199 } 200 201 if (read_ptr == write_ptr) { 202 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, chan); 203 stat = 0; 204 soc_pci_getreg(unit, addr, &stat); 205 stat_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_STAT); 206 if (!soc_reg_field_get(unit, stat_reg, stat, overflow_field)) { 207 return SOC_E_EMPTY; 208 } 209 210 /* Re-read write pointer */ 211 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_WRITE_PTR_OFFSET(cmc, chan); 212 write_ptr = 0; 213 soc_pci_getreg(unit, addr, &write_ptr); 214 } 215 216 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, chan); 217 hostmem_addr = 0; 218 soc_pci_getreg(unit, addr, &hostmem_addr); 219 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, chan); 220 rval = 0; 221 soc_pci_getreg(unit, addr, &rval); 222 223 cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_CFG_REG); 224 data_beats = soc_reg_field_get(unit, cfg_reg, rval, BEAT_COUNTf); 225 if (data_beats <= 0) { 226 LOG_ERROR(BSL_LS_BCM_L2, 227 (BSL_META_U(unit, 228 "Invalid BEAT_COUNT (%d) in " 229 "CMIC_CMC%d_FIFO_CH%d_RD_DMA_CFG \n"), data_beats, cmc, chan)); 230 return SOC_E_CONFIG; 231 } 232 233 switch (soc_reg_field_get(unit, cfg_reg, rval, HOST_NUM_ENTRIES_SELf)) { 234 case 0: host_entries = 64; break; 235 case 1: host_entries = 128; break; 236 case 2: host_entries = 256; break; 237 case 3: host_entries = 512; break; 238 case 4: host_entries = 1024; break; 239 case 5: host_entries = 2048; break; 240 case 6: host_entries = 4096; break; 241 case 7: host_entries = 8192; break; 242 case 8: host_entries = 16384; break; 243 case 9: host_entries = 32768; break; 244 case 10: host_entries = 65536; break; 245 default: return SOC_E_CONFIG; 246 } 247 248 *host_ptr = soc_cm_p2l(unit, read_ptr); 249 if (read_ptr >= write_ptr) { 250 *count = host_entries - 251 (read_ptr - hostmem_addr) / data_beats / sizeof(uint32); 252 } else { 253 *count = (write_ptr - read_ptr) / data_beats / sizeof(uint32); 254 } 255 256 return (*count) ? SOC_E_NONE : SOC_E_EMPTY; 257 } 258 259 int 260 _soc_mem_kt_fifo_dma_advance_read_ptr(int unit, int chan, int count) 261 { 262 soc_reg_t cfg_reg, statclr_reg; 263 soc_field_t overflow_field; 264 int host_entries, data_beats; 265 uint32 addr, rval, statclr; 266 uint32 *host_buf, *read_ptr; 267 int cmc = SOC_PCI_CMC(unit); 268 269 if (chan < 0 || chan > 3) { 270 return SOC_E_PARAM; 271 } 272 273 if(!soc_feature(unit, soc_feature_cmicm)) { 274 return BCM_E_UNAVAIL; 275 } 276 277 cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_CFG_REG); 278 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, chan); 279 rval = 0; 280 soc_pci_getreg(unit, addr, &rval); 281 data_beats = soc_reg_field_get(unit, cfg_reg, rval, BEAT_COUNTf); 282 283 switch (soc_reg_field_get(unit, cfg_reg, rval, HOST_NUM_ENTRIES_SELf)) { 284 case 0: host_entries = 64; break; 285 case 1: host_entries = 128; break; 286 case 2: host_entries = 256; break; 287 case 3: host_entries = 512; break; 288 case 4: host_entries = 1024; break; 289 case 5: host_entries = 2048; break; 290 case 6: host_entries = 4096; break; 291 case 7: host_entries = 8192; break; 292 case 8: host_entries = 16384; break; 293 case 9: host_entries = 32768; break; 294 case 10: host_entries = 65536; break; 295 default: return SOC_E_CONFIG; 296 } 297 298 if (count < 0 || count >= host_entries) { 299 return SOC_E_PARAM; 300 } 301 302 /* Clear threshold overflow_field bit */ 303 switch(chan) { 304 case 1: overflow_field = FIFO_CH1_DMA_HOSTMEM_OVERFLOWf; break; 305 case 2: overflow_field = FIFO_CH2_DMA_HOSTMEM_OVERFLOWf; break; 306 case 3: overflow_field = FIFO_CH3_DMA_HOSTMEM_OVERFLOWf; break; 307 default: overflow_field = FIFO_CH0_DMA_HOSTMEM_OVERFLOWf; break; 308 } 309 310 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_CLR_OFFSET(cmc, chan); 311 statclr_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_STAT_CLR); 312 statclr = 0; 313 soc_reg_field_set(unit, statclr_reg, &statclr, overflow_field, 1); 314 soc_pci_write(unit, addr, statclr); 315 316 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, chan); 317 rval = 0; 318 soc_pci_getreg(unit, addr, &rval); 319 host_buf = soc_cm_p2l(unit, rval); 320 321 addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_READ_PTR_OFFSET(cmc, chan); 322 rval = 0; 323 soc_pci_getreg(unit, addr, &rval); 324 read_ptr = soc_cm_p2l(unit, rval); 325 326 read_ptr += count * data_beats; 327 if (read_ptr >= &host_buf[host_entries * data_beats]) { 328 read_ptr -= host_entries * data_beats; 329 } 330 rval = soc_cm_l2p(unit, read_ptr); 331 soc_pci_write(unit, addr, rval); 332 333 return SOC_E_NONE; 334 } 335 336 soc_reg_t 337 _soc_kt_fifo_reg_get(int unit, int cmc, int chan, int type) 338 { 339 switch(type) { 340 case RD_DMA_HOTMEM_THRESHOLD_REG: 341 switch((cmc << 4) + chan) { 342 case 0x00: return CMIC_CMC0_FIFO_CH0_RD_DMA_HOSTMEM_THRESHOLDr; 343 case 0x01: return CMIC_CMC0_FIFO_CH1_RD_DMA_HOSTMEM_THRESHOLDr; 344 case 0x02: return CMIC_CMC0_FIFO_CH2_RD_DMA_HOSTMEM_THRESHOLDr; 345 case 0x03: return CMIC_CMC0_FIFO_CH3_RD_DMA_HOSTMEM_THRESHOLDr; 346 case 0x10: return CMIC_CMC1_FIFO_CH0_RD_DMA_HOSTMEM_THRESHOLDr; 347 case 0x11: return CMIC_CMC1_FIFO_CH1_RD_DMA_HOSTMEM_THRESHOLDr; 348 case 0x12: return CMIC_CMC1_FIFO_CH2_RD_DMA_HOSTMEM_THRESHOLDr; 349 case 0x13: return CMIC_CMC1_FIFO_CH3_RD_DMA_HOSTMEM_THRESHOLDr; 350 case 0x20: return CMIC_CMC2_FIFO_CH0_RD_DMA_HOSTMEM_THRESHOLDr; 351 case 0x21: return CMIC_CMC2_FIFO_CH1_RD_DMA_HOSTMEM_THRESHOLDr; 352 case 0x22: return CMIC_CMC2_FIFO_CH2_RD_DMA_HOSTMEM_THRESHOLDr; 353 case 0x23: return CMIC_CMC2_FIFO_CH3_RD_DMA_HOSTMEM_THRESHOLDr; 354 default: return CMIC_CMC0_FIFO_CH0_RD_DMA_HOSTMEM_THRESHOLDr; 355 } 356 break; 357 case RD_DMA_CFG_REG: 358 switch((cmc << 4) + chan) { 359 case 0x00: return CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr; 360 case 0x01: return CMIC_CMC0_FIFO_CH1_RD_DMA_CFGr; 361 case 0x02: return CMIC_CMC0_FIFO_CH2_RD_DMA_CFGr; 362 case 0x03: return CMIC_CMC0_FIFO_CH3_RD_DMA_CFGr; 363 case 0x10: return CMIC_CMC1_FIFO_CH0_RD_DMA_CFGr; 364 case 0x11: return CMIC_CMC1_FIFO_CH1_RD_DMA_CFGr; 365 case 0x12: return CMIC_CMC1_FIFO_CH2_RD_DMA_CFGr; 366 case 0x13: return CMIC_CMC1_FIFO_CH3_RD_DMA_CFGr; 367 case 0x20: return CMIC_CMC2_FIFO_CH0_RD_DMA_CFGr; 368 case 0x21: return CMIC_CMC2_FIFO_CH1_RD_DMA_CFGr; 369 case 0x22: return CMIC_CMC2_FIFO_CH2_RD_DMA_CFGr; 370 case 0x23: return CMIC_CMC2_FIFO_CH3_RD_DMA_CFGr; 371 default: return CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr; 372 } 373 case RD_DMA_STAT: 374 switch((cmc << 4) + chan) { 375 case 0x00: return CMIC_CMC0_FIFO_CH0_RD_DMA_STATr; 376 case 0x01: return CMIC_CMC0_FIFO_CH1_RD_DMA_STATr; 377 case 0x02: return CMIC_CMC0_FIFO_CH2_RD_DMA_STATr; 378 case 0x03: return CMIC_CMC0_FIFO_CH3_RD_DMA_STATr; 379 case 0x10: return CMIC_CMC1_FIFO_CH0_RD_DMA_STATr; 380 case 0x11: return CMIC_CMC1_FIFO_CH1_RD_DMA_STATr; 381 case 0x12: return CMIC_CMC1_FIFO_CH2_RD_DMA_STATr; 382 case 0x13: return CMIC_CMC1_FIFO_CH3_RD_DMA_STATr; 383 case 0x20: return CMIC_CMC2_FIFO_CH0_RD_DMA_STATr; 384 case 0x21: return CMIC_CMC2_FIFO_CH1_RD_DMA_STATr; 385 case 0x22: return CMIC_CMC2_FIFO_CH2_RD_DMA_STATr; 386 case 0x23: return CMIC_CMC2_FIFO_CH3_RD_DMA_STATr; 387 default: return CMIC_CMC0_FIFO_CH0_RD_DMA_STATr; 388 } 389 case RD_DMA_STAT_CLR: 390 switch((cmc << 4) + chan) { 391 case 0x00: return CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr; 392 case 0x01: return CMIC_CMC0_FIFO_CH1_RD_DMA_STAT_CLRr; 393 case 0x02: return CMIC_CMC0_FIFO_CH2_RD_DMA_STAT_CLRr; 394 case 0x03: return CMIC_CMC0_FIFO_CH3_RD_DMA_STAT_CLRr; 395 case 0x10: return CMIC_CMC1_FIFO_CH0_RD_DMA_STAT_CLRr; 396 case 0x11: return CMIC_CMC1_FIFO_CH1_RD_DMA_STAT_CLRr; 397 case 0x12: return CMIC_CMC1_FIFO_CH2_RD_DMA_STAT_CLRr; 398 case 0x13: return CMIC_CMC1_FIFO_CH3_RD_DMA_STAT_CLRr; 399 case 0x20: return CMIC_CMC2_FIFO_CH0_RD_DMA_STAT_CLRr; 400 case 0x21: return CMIC_CMC2_FIFO_CH1_RD_DMA_STAT_CLRr; 401 case 0x22: return CMIC_CMC2_FIFO_CH2_RD_DMA_STAT_CLRr; 402 case 0x23: return CMIC_CMC2_FIFO_CH3_RD_DMA_STAT_CLRr; 403 default: return CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr; 404 } 405 default: return INVALIDr; break; 406 } 407 } 408 409 #endif /*BCM_CMICM_SUPPORT && BCM_KATANA_SUPPORT*/ 410 #endif /*BCM_ESW_SUPPORT*/