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