pfc_deadlock.c (44858B)
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 * PFC Deadlock Detection & Recovery 8 */ 9 #if defined(BCM_TOMAHAWK3_SUPPORT) 10 11 #include <shared/bsl.h> 12 13 #include <soc/defs.h> 14 #include <sal/core/libc.h> 15 16 #include <soc/drv.h> 17 #include <soc/mem.h> 18 #include <soc/debug.h> 19 #include <soc/pfc.h> 20 #include <soc/tomahawk.h> 21 #include <soc/tomahawk3.h> 22 #include <soc/scache_dictionary.h> 23 24 #include <bcm/debug.h> 25 #include <bcm/error.h> 26 #include <bcm/cosq.h> 27 #include <bcm_int/esw/mbcm.h> 28 #include <bcm_int/esw/stack.h> 29 #include <bcm_int/esw/cosq.h> 30 #include <bcm_int/esw/pfc_deadlock.h> 31 #include <bcm_int/esw/virtual.h> 32 #include <bcm_int/esw/tomahawk.h> 33 #include <bcm_int/tomahawk3_dispatch.h> 34 #include <bcm_int/esw/tomahawk3.h> 35 36 #define _BCM_TH3_PFC_DEADLOCK_TIMER_MAX 15 37 typedef enum _bcm_th3_pfc_deadlock_op_e { 38 _BCM_TH3_PFC_DEADLOCK_OP_GET = 0, 39 _BCM_TH3_PFC_DEADLOCK_OP_SET = 1 40 } _bcm_th3_pfc_deadlock_op_t; 41 42 typedef enum _bcm_th3_pfc_deadlock_op_origin_e { 43 _BCM_TH3_PFC_DEADLOCK_OP_INTERNAL = 0, 44 _BCM_TH3_PFC_DEADLOCK_OP_EXTERNAL = 1 45 46 } _bcm_th3_pfc_deadlock_op_origin_t; 47 48 typedef struct _bcm_th3_pfc_deadlock_port_config_s { 49 uint32 recovery_timers[TH3_PFC_PRIORITY_NUM]; /* Recovery timer for Action */ 50 uint32 recovery_count[TH3_PFC_PRIORITY_NUM]; /* the recovery count for a give priority */ 51 uint32 recovery_count_acc[TH3_PFC_PRIORITY_NUM]; /* accumulated recovery time for a given priority */ 52 uint32 enabled_priority; /* Bitmap of enabled PFC priority */ 53 uint32 deadlock_priority; /* Bitmap of PFC priority currently in Deadlock State */ 54 55 } _bcm_th3_pfc_deadlock_port_config_t; 56 57 typedef struct _bcm_th3_pfc_deadlock_control_s { 58 uint8 cb_enabled; /* indicate if callback is enabled */ 59 uint32 cb_interval; /* Callback interval, unit is in microsecond */ 60 uint32 cb_count; /* Debug ctr to keep track of #times CB function is called */ 61 _bcm_th3_pfc_deadlock_port_config_t port_config[SOC_MAX_NUM_PORTS]; 62 bcm_switch_pfc_deadlock_action_t recovery_action; /* chip behavior during deadlock recovery */ 63 64 } _bcm_th3_pfc_deadlock_control_t; 65 66 static _bcm_th3_pfc_deadlock_control_t *_bcm_th3_pfc_deadlock_control[BCM_MAX_NUM_UNITS]; 67 static _bcm_pfc_deadlock_cb_t *_bcm_th3_pfc_deadlock_cb[BCM_MAX_NUM_UNITS]; 68 69 STATIC sal_mutex_t _bcm_th3_pfc_lock[SOC_MAX_NUM_DEVICES] = {NULL}; 70 #define PFC_LOCK(unit) sal_mutex_take(_bcm_th3_pfc_lock[unit], sal_mutex_FOREVER) 71 #define PFC_UNLOCK(unit) sal_mutex_give(_bcm_th3_pfc_lock[unit]) 72 73 #define _BCM_TH3_PFC_DEADLOCK_CB(u) _bcm_th3_pfc_deadlock_cb[(u)] 74 #define _BCM_TH3_PFC_DEADLOCK_CONTROL(u) _bcm_th3_pfc_deadlock_control[(u)] 75 #define _BCM_TH3_PFC_DEADLOCK_RECOVERY_TIMER(u, pri, port) \ 76 _bcm_th3_pfc_deadlock_control[(u)]->port_config[(port)].recovery_timers[(pri)] 77 #define _BCM_TH3_PFC_DEADLOCK_RECOVERY_ACCUMULATED(u, pri, port) \ 78 _bcm_th3_pfc_deadlock_control[(u)]->port_config[(port)].recovery_count_acc[(pri)] 79 80 81 #define _BCM_TH3_PFC_DEADLOCK_CONFIG(u, port) \ 82 (&(_bcm_th3_pfc_deadlock_control[(u)]->port_config[(port)])) 83 #define _BCM_TH3_PFC_DEADLOCK_CB_ENABLED(u) \ 84 (_bcm_th3_pfc_deadlock_control[(u)]->cb_enabled) 85 #define _BCM_TH3_PFC_DEADLOCK_CB_COUNT(u) \ 86 (_bcm_th3_pfc_deadlock_control[(u)]->cb_count) 87 88 #define _BCM_TH3_PFC_DEADLOCK_CB_INTERVAL(u) \ 89 (_bcm_th3_pfc_deadlock_control[(u)]->cb_interval) 90 static soc_field_t _timer_init_fields[] = { 91 INIT_VALUE_PFC0f, INIT_VALUE_PFC1f, 92 INIT_VALUE_PFC2f, INIT_VALUE_PFC3f, 93 INIT_VALUE_PFC4f, INIT_VALUE_PFC5f, 94 INIT_VALUE_PFC6f, INIT_VALUE_PFC7f}; 95 static soc_field_t _timer_tick_fields[] = { 96 TICK_UNIT_PFC0f, TICK_UNIT_PFC1f, 97 TICK_UNIT_PFC2f, TICK_UNIT_PFC3f, 98 TICK_UNIT_PFC4f, TICK_UNIT_PFC5f, 99 TICK_UNIT_PFC6f, TICK_UNIT_PFC7f, 100 }; 101 102 static const int _timer_tick_encoding[3] = {1, 10, 100}; 103 static sal_sem_t th3_pfc_deinit_notify[BCM_MAX_NUM_UNITS]; 104 static int th3_pfc_init[BCM_MAX_NUM_UNITS] = {FALSE}; 105 106 STATIC int 107 _bcm_th3_pfc_deadlock_enable_config(int unit, bcm_port_t port, 108 int pfc_priority, _bcm_th3_pfc_deadlock_op_t op, 109 _bcm_th3_pfc_deadlock_op_origin_t op_origin, 110 int *arg); 111 112 /* Routine to begin recovery when a (Port, PFC priority) is deaclared to be 113 * in Deadlock by Hardware 114 */ 115 STATIC int 116 _bcm_th3_pfc_deadlock_recovery_begin(int unit, int port, int pfc_priority) 117 { 118 uint32 rval, temp_mask, ignore_pfc_val; 119 int timer_enable; 120 _bcm_pfc_deadlock_cb_t *pfc_deadlock_cb = NULL; 121 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 122 soc_reg_t int_mask_reg = MMU_INTFI_DD_TIMER_INT_MASKr, 123 ignore_pfc_reg = MMU_INTFI_IGNORE_PORT_PFC_XOFFr; 124 soc_field_t mask_field = PFC_PRIORITY_INT_MASKf, 125 ignore_pfc_f = PRI_IGNORE_XOFFf; 126 127 pfc_deadlock_cb = _BCM_TH3_PFC_DEADLOCK_CB(unit); 128 if (!soc_property_get(unit, spn_PFC_DEADLOCK_SEQ_CONTROL, 0) || 129 (soc_property_get(unit, spn_PFC_DEADLOCK_SEQ_CONTROL, 0) && 130 pfc_deadlock_cb->pfc_deadlock_cb == NULL)) { 131 /* Auto or SDK sequence mode */ 132 /* Mask the interrupt, disable hardware detection timer, ignore_pfc_xoff 133 * and call user cllback function*/ 134 LOG_INFO(BSL_LS_BCM_COSQ, 135 (BSL_META_U(unit, 136 "PFC Deadlock Detected: Priority %d port=%d\n"), 137 pfc_priority, port)); 138 /* 1: Mask the Intr by setting 1 */ 139 rval = 0; 140 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, int_mask_reg, 141 port, 0, &rval)); 142 temp_mask = soc_reg_field_get(unit, int_mask_reg, rval, mask_field); 143 temp_mask |= 1U << pfc_priority; 144 soc_reg_field_set(unit, int_mask_reg, &rval, mask_field, temp_mask); 145 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, int_mask_reg, port, 0, rval)); 146 147 /* 2: Turn timer off */ 148 timer_enable = 0; 149 BCM_IF_ERROR_RETURN 150 (_bcm_th3_pfc_deadlock_enable_config(unit, port, pfc_priority, 151 _BCM_TH3_PFC_DEADLOCK_OP_SET, 152 _BCM_TH3_PFC_DEADLOCK_OP_INTERNAL, &timer_enable)); 153 154 /* 3: For that port, set ignore_pfc_xoff = 1 (per port reg) */ 155 rval = 0; 156 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, ignore_pfc_reg, 157 port, 0, &rval)); 158 ignore_pfc_val = soc_reg_field_get(unit, ignore_pfc_reg, rval, ignore_pfc_f); 159 ignore_pfc_val |= 1U << pfc_priority; 160 soc_reg_field_set(unit, ignore_pfc_reg, &rval, ignore_pfc_f, ignore_pfc_val); 161 162 SOC_IF_ERROR_RETURN( 163 soc_reg32_set(unit, ignore_pfc_reg, port, 0, rval)); 164 165 /* run user callbcak function */ 166 if(pfc_deadlock_cb->pfc_deadlock_cb) { 167 pfc_deadlock_cb->pfc_deadlock_cb(unit, port, pfc_priority, 168 bcmCosqPfcDeadlockRecoveryEventBegin, 169 pfc_deadlock_cb->pfc_deadlock_userdata); 170 } 171 172 port_config = _BCM_TH3_PFC_DEADLOCK_CONFIG(unit, port); 173 /* value 1 is added because the _bcm_th3_pfc_deadlock_recovery_update is 174 * called immediately 175 * first time when recovery begins, i.e before _BCM_TH3_PFC_DEADLOCK_CB_INTERVAL ticks. 176 */ 177 port_config->recovery_count[pfc_priority] = 1 + 178 sal_ceil_func((port_config->recovery_timers[pfc_priority] * 1000) , 179 _BCM_TH3_PFC_DEADLOCK_CB_INTERVAL(unit)); 180 181 port_config->deadlock_priority |= (1U << pfc_priority); 182 } else { 183 /* User control recovery mode */ 184 /* Mask the interrupt, disable HW detection timer and run user callback*/ 185 /* Expect user call back to handle recovery_start and recovery_exit*/ 186 /* 1: Mask the Intr by setting 1 */ 187 rval = 0; 188 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, int_mask_reg, 189 port, 0, &rval)); 190 temp_mask = soc_reg_field_get(unit, int_mask_reg, rval, mask_field); 191 temp_mask |= 1U << pfc_priority; 192 soc_reg_field_set(unit, int_mask_reg, &rval, mask_field, temp_mask); 193 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, int_mask_reg, port, 0, rval)); 194 195 /* 2: Turn timer off */ 196 timer_enable = 0; 197 BCM_IF_ERROR_RETURN 198 (_bcm_th3_pfc_deadlock_enable_config(unit, port, pfc_priority, 199 _BCM_TH3_PFC_DEADLOCK_OP_SET, 200 _BCM_TH3_PFC_DEADLOCK_OP_INTERNAL, &timer_enable)); 201 202 /* run user callbcak function */ 203 pfc_deadlock_cb->pfc_deadlock_cb(unit, port, pfc_priority, 204 bcmCosqPfcDeadlockRecoveryEventBegin, 205 pfc_deadlock_cb->pfc_deadlock_userdata); 206 207 } 208 return BCM_E_NONE; 209 } 210 211 int 212 bcm_th3_pfc_deadlock_recovery_start(int unit, int port, int pfc_priority) 213 { 214 uint32 rval, temp_mask, ignore_pfc_val; 215 int timer_enable; 216 soc_reg_t int_mask_reg = MMU_INTFI_DD_TIMER_INT_MASKr, 217 ignore_pfc_reg = MMU_INTFI_IGNORE_PORT_PFC_XOFFr; 218 soc_field_t mask_field = PFC_PRIORITY_INT_MASKf, 219 ignore_pfc_f = PRI_IGNORE_XOFFf; 220 221 LOG_INFO(BSL_LS_BCM_COSQ, 222 (BSL_META_U(unit, 223 "PFC Deadlock Detected: Priority %d port=%d\n"), 224 pfc_priority, port)); 225 /* 1: Mask the Intr by setting 1 */ 226 rval = 0; 227 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, int_mask_reg, 228 port, 0, &rval)); 229 temp_mask = soc_reg_field_get(unit, int_mask_reg, rval, mask_field); 230 temp_mask |= 1U << pfc_priority; 231 soc_reg_field_set(unit, int_mask_reg, &rval, mask_field, temp_mask); 232 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, int_mask_reg, port, 0, rval)); 233 234 /* 2: Turn timer off */ 235 timer_enable = 0; 236 BCM_IF_ERROR_RETURN 237 (_bcm_th3_pfc_deadlock_enable_config(unit, port, pfc_priority, 238 _BCM_TH3_PFC_DEADLOCK_OP_SET, 239 _BCM_TH3_PFC_DEADLOCK_OP_INTERNAL, &timer_enable)); 240 241 /* 3: For that port, set ignore_pfc_xoff = 1 (per port reg) */ 242 rval = 0; 243 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, ignore_pfc_reg, 244 port, 0, &rval)); 245 ignore_pfc_val = soc_reg_field_get(unit, ignore_pfc_reg, rval, ignore_pfc_f); 246 ignore_pfc_val |= 1U << pfc_priority; 247 soc_reg_field_set(unit, ignore_pfc_reg, &rval, ignore_pfc_f, ignore_pfc_val); 248 249 SOC_IF_ERROR_RETURN( 250 soc_reg32_set(unit, ignore_pfc_reg, port, 0, rval)); 251 252 return BCM_E_NONE; 253 } 254 255 STATIC int 256 _bcm_th3_pfc_deadlock_recovery_end(int unit, int port, int pfc_priority) 257 { 258 uint32 rval, temp_mask, ignore_pfc_val; 259 int timer_enable; 260 soc_reg_t reg, int_mask_reg = MMU_INTFI_DD_TIMER_INT_MASKr, 261 ignore_pfc_reg = MMU_INTFI_IGNORE_PORT_PFC_XOFFr; 262 soc_field_t mask_field = PFC_PRIORITY_INT_MASKf, 263 ignore_pfc_f = PRI_IGNORE_XOFFf; 264 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 265 _bcm_pfc_deadlock_cb_t *pfc_deadlock_cb = NULL; 266 LOG_INFO(BSL_LS_BCM_COSQ, 267 (BSL_META_U(unit, 268 "PFC Deadlock Recovery ends: Prio %d port=%d\n"), 269 pfc_priority, port)); 270 271 /* 1: For that port, set ignore_pfc_xoff = 0 (per port reg) */ 272 rval = 0; 273 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, ignore_pfc_reg, 274 port, 0, &rval)); 275 ignore_pfc_val = soc_reg_field_get(unit, ignore_pfc_reg, rval, ignore_pfc_f); 276 ignore_pfc_val &= ~(1U << pfc_priority); 277 soc_reg_field_set(unit, ignore_pfc_reg, &rval, ignore_pfc_f, ignore_pfc_val); 278 279 SOC_IF_ERROR_RETURN( 280 soc_reg32_set(unit, ignore_pfc_reg, port, 0, rval)); 281 282 /* 2: Unmask the by setting 0 */ 283 rval = 0; 284 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, int_mask_reg, 285 port, 0, &rval)); 286 temp_mask = soc_reg_field_get(unit, int_mask_reg, rval, mask_field); 287 temp_mask &= ~(1U << pfc_priority); 288 soc_reg_field_set(unit, int_mask_reg, &rval, mask_field, temp_mask); 289 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, int_mask_reg, port, 0, rval)); 290 291 /* 3: clear interrupt status, set 1 to clear */ 292 rval = 0; 293 reg = MMU_INTFI_DD_TIMER_INT_STATUSr; 294 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, 295 port, 0, &rval)); 296 rval &= (1U << pfc_priority); 297 SOC_IF_ERROR_RETURN( 298 soc_reg32_set(unit, reg, port, 0, rval)); 299 /* 4 Turn timer back on */ 300 timer_enable = 1; 301 BCM_IF_ERROR_RETURN 302 (_bcm_th3_pfc_deadlock_enable_config(unit, port, pfc_priority, 303 _BCM_TH3_PFC_DEADLOCK_OP_SET, 304 _BCM_TH3_PFC_DEADLOCK_OP_INTERNAL, &timer_enable)); 305 306 pfc_deadlock_cb = _BCM_TH3_PFC_DEADLOCK_CB(unit); 307 if(pfc_deadlock_cb->pfc_deadlock_cb) { 308 pfc_deadlock_cb->pfc_deadlock_cb(unit, port, pfc_priority, 309 bcmCosqPfcDeadlockRecoveryEventEnd, 310 pfc_deadlock_cb->pfc_deadlock_userdata); 311 } 312 313 port_config = _BCM_TH3_PFC_DEADLOCK_CONFIG(unit, port); 314 port_config->deadlock_priority &= ~(1U << pfc_priority); 315 316 317 return BCM_E_NONE; 318 } 319 320 int 321 bcm_th3_pfc_deadlock_recovery_exit(int unit, int port, int pfc_priority) 322 { 323 uint32 rval, temp_mask, ignore_pfc_val; 324 int timer_enable; 325 soc_reg_t reg, int_mask_reg = MMU_INTFI_DD_TIMER_INT_MASKr, 326 ignore_pfc_reg = MMU_INTFI_IGNORE_PORT_PFC_XOFFr; 327 soc_field_t mask_field = PFC_PRIORITY_INT_MASKf, 328 ignore_pfc_f = PRI_IGNORE_XOFFf; 329 LOG_INFO(BSL_LS_BCM_COSQ, 330 (BSL_META_U(unit, 331 "PFC Deadlock Recovery ends: Prio %d port=%d\n"), 332 pfc_priority, port)); 333 334 /* 1: For that port, set ignore_pfc_xoff = 0 (per port reg) */ 335 rval = 0; 336 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, ignore_pfc_reg, 337 port, 0, &rval)); 338 ignore_pfc_val = soc_reg_field_get(unit, ignore_pfc_reg, rval, ignore_pfc_f); 339 ignore_pfc_val &= ~(1U << pfc_priority); 340 soc_reg_field_set(unit, ignore_pfc_reg, &rval, ignore_pfc_f, ignore_pfc_val); 341 342 SOC_IF_ERROR_RETURN( 343 soc_reg32_set(unit, ignore_pfc_reg, port, 0, rval)); 344 345 /* 2: Unmask the by setting 0 */ 346 rval = 0; 347 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, int_mask_reg, 348 port, 0, &rval)); 349 temp_mask = soc_reg_field_get(unit, int_mask_reg, rval, mask_field); 350 temp_mask &= ~(1U << pfc_priority); 351 soc_reg_field_set(unit, int_mask_reg, &rval, mask_field, temp_mask); 352 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, int_mask_reg, port, 0, rval)); 353 354 /* 3: clear interrupt status, set 1 to clear */ 355 rval = 0; 356 reg = MMU_INTFI_DD_TIMER_INT_STATUSr; 357 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, 358 port, 0, &rval)); 359 rval &= (1U << pfc_priority); 360 SOC_IF_ERROR_RETURN( 361 soc_reg32_set(unit, reg, port, 0, rval)); 362 /* 4 Turn timer back on */ 363 timer_enable = 1; 364 BCM_IF_ERROR_RETURN 365 (_bcm_th3_pfc_deadlock_enable_config(unit, port, pfc_priority, 366 _BCM_TH3_PFC_DEADLOCK_OP_SET, 367 _BCM_TH3_PFC_DEADLOCK_OP_INTERNAL, &timer_enable)); 368 369 370 return BCM_E_NONE; 371 } 372 373 STATIC int 374 _bcm_th3_pfc_deadlock_recovery_update(int unit, int port, int pfc_priority) 375 { 376 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 377 port_config = _BCM_TH3_PFC_DEADLOCK_CONFIG(unit, port); 378 379 if ((--port_config->recovery_count[pfc_priority]) == 0) { 380 BCM_IF_ERROR_RETURN( 381 _bcm_th3_pfc_deadlock_recovery_end(unit, port, pfc_priority)); 382 } else { 383 /* port_config->recovery_count is set to value + 1, for the reason 384 * first time i.e when recovery is initiated this is called immediately, 385 * and before _BCM_TH3_PFC_DEADLOCK_CB_INTERVAL ticks. 386 */ 387 port_config->recovery_count_acc[pfc_priority]++; 388 } 389 return BCM_E_NONE; 390 } 391 392 STATIC int 393 _bcm_th3_pfc_deadlock_monitor(int unit) 394 { 395 int i, port, rv = 0; 396 uint32 rval_status, rval_mask, fval_status, fval_mask; 397 soc_reg_t int_status_reg = MMU_INTFI_DD_TIMER_INT_STATUSr, 398 int_mask_reg = MMU_INTFI_DD_TIMER_INT_MASKr; 399 soc_field_t status_field = PFC_PRIORITY_ISRf, 400 mask_field = PFC_PRIORITY_INT_MASKf; 401 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 402 _bcm_th3_pfc_deadlock_control_t *dd_control = 403 _BCM_TH3_PFC_DEADLOCK_CONTROL(unit); 404 _bcm_pfc_deadlock_cb_t *pfc_deadlock_cb = NULL; 405 if(dd_control == NULL) { 406 return BCM_E_INIT; 407 } 408 409 PFC_LOCK(unit); 410 pfc_deadlock_cb = _BCM_TH3_PFC_DEADLOCK_CB(unit); 411 /* check interrupt status for each port */ 412 PBMP_PORT_ITER(unit, port) { 413 port_config = &(dd_control->port_config[port]); 414 if (port_config->enabled_priority == 0) { 415 /* port is not enabled for PFC deadlock detection */ 416 417 continue; 418 } 419 rv = soc_reg32_get(unit, int_status_reg, port, 0, &rval_status); 420 if (SOC_FAILURE(rv)) { 421 PFC_UNLOCK(unit); 422 return rv; 423 } 424 425 fval_status = soc_reg_field_get(unit, 426 int_status_reg, rval_status, status_field); 427 rv = soc_reg32_get(unit, int_mask_reg, port, 0, &rval_mask); 428 if (SOC_FAILURE(rv)) { 429 PFC_UNLOCK(unit); 430 return rv; 431 } 432 fval_mask = soc_reg_field_get(unit, int_mask_reg, rval_mask, 433 mask_field); 434 fval_status = fval_status & (~fval_mask); 435 if (fval_status != 0) { 436 for (i = 0; i < TH3_PFC_PRIORITY_NUM; i++) { 437 if (fval_status & (1U << i)) { 438 rv = _bcm_th3_pfc_deadlock_recovery_begin(unit, port, i); 439 if (BCM_FAILURE(rv)) { 440 PFC_UNLOCK(unit); 441 return rv; 442 } 443 } 444 } 445 } 446 if (!soc_property_get(unit, spn_PFC_DEADLOCK_SEQ_CONTROL, 0) || 447 (pfc_deadlock_cb->pfc_deadlock_cb == NULL)) { 448 /* Update the count for priority already in Deadlock state and Reset 449 * those priority where recovery timer has expired. 450 */ 451 for (i = 0; i < TH3_PFC_PRIORITY_NUM; i++) { 452 if ((port_config->deadlock_priority & (1U << i)) != 0) { 453 rv = _bcm_th3_pfc_deadlock_recovery_update(unit, port, i); 454 if (BCM_FAILURE(rv)) { 455 PFC_UNLOCK(unit); 456 return rv; 457 } 458 } 459 } 460 } 461 } 462 PFC_UNLOCK(unit); 463 return BCM_E_NONE; 464 } 465 466 467 /* Callback routine registered with DPC framework for, 468 * 1) Monitoring Deadlock status 469 * 2) Start/Stop Recovery process 470 */ 471 STATIC void 472 _th3_pfc_deadlock_cb(void* owner, void* time_as_ptr, void *unit_as_ptr, 473 void *unused_1, void* unused_2) 474 { 475 int callback_time = (int)(size_t)time_as_ptr; 476 int unit = (int)(size_t)unit_as_ptr; 477 _bcm_th3_pfc_deadlock_control_t *pfc_deadlock_control = NULL; 478 479 sal_dpc_cancel(INT_TO_PTR(&_th3_pfc_deadlock_cb)); 480 481 if (!th3_pfc_init[unit]) { 482 sal_sem_give(th3_pfc_deinit_notify[unit]); 483 return; 484 } 485 486 pfc_deadlock_control = _BCM_TH3_PFC_DEADLOCK_CONTROL(unit); 487 if (pfc_deadlock_control == NULL) { 488 /* Should not happen, defensive check */ 489 return; 490 } 491 492 _bcm_th3_pfc_deadlock_monitor(unit); 493 494 if (_BCM_TH3_PFC_DEADLOCK_CB_ENABLED(unit)) { 495 sal_dpc_time(callback_time, &_th3_pfc_deadlock_cb, 0, 496 time_as_ptr, unit_as_ptr, 0, 0); 497 } 498 _BCM_TH3_PFC_DEADLOCK_CB_COUNT(unit)++; 499 } 500 501 STATIC int 502 _bcm_th3_pfc_deadlock_cb_update(int unit, int arg) 503 { 504 int port, dd_enabled = 0; 505 _bcm_th3_pfc_deadlock_control_t *pfc_deadlock_control = NULL; 506 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 507 508 pfc_deadlock_control = _BCM_TH3_PFC_DEADLOCK_CONTROL(unit); 509 if (arg == 0) { 510 /* check if dpc routine should be stopped */ 511 PFC_LOCK(unit); 512 PBMP_PORT_ITER(unit, port) { 513 port_config = _BCM_TH3_PFC_DEADLOCK_CONFIG(unit, port); 514 if (port_config->enabled_priority) { 515 dd_enabled = 1; 516 break; 517 } 518 } 519 PFC_UNLOCK(unit); 520 if (dd_enabled == 0) { 521 sal_dpc_cancel(INT_TO_PTR(&_th3_pfc_deadlock_cb)); 522 pfc_deadlock_control->cb_enabled = FALSE; 523 } 524 } else { 525 /* enable background thread if not already enabled*/ 526 if (pfc_deadlock_control->cb_enabled == FALSE) { 527 pfc_deadlock_control->cb_enabled = TRUE; 528 _th3_pfc_deadlock_cb(INT_TO_PTR(&_th3_pfc_deadlock_cb), 529 INT_TO_PTR(_BCM_TH3_PFC_DEADLOCK_CB_INTERVAL(unit)), 530 INT_TO_PTR(unit), 0, 0); 531 } 532 } 533 return BCM_E_NONE; 534 } 535 /* 536 * Function: 537 * _bcm_th3_pfc_deadlock_enable_config 538 * Purpose: 539 * Get/Set per- (port, PFC priority) PFC deadlock detection and 540 * recovery enable. 541 * Parameters: 542 * unit - (IN) device id. 543 * port - (IN) logical port number. 544 * pfc_priority - (IN) PFC priority. 545 * op - (IN) Operation type. 546 * arg - (IN/OUT) Config value. 547 * Returns: 548 * SOC_E_XXX 549 */ 550 STATIC int 551 _bcm_th3_pfc_deadlock_enable_config( 552 int unit, 553 bcm_port_t port, 554 int pfc_priority, 555 _bcm_th3_pfc_deadlock_op_t op, 556 _bcm_th3_pfc_deadlock_op_origin_t op_origin, 557 int *arg) 558 { 559 uint32 rval; 560 soc_reg_t reg = MMU_INTFI_DD_TIMER_ENABLEr; 561 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 562 563 if ((op == _BCM_TH3_PFC_DEADLOCK_OP_SET) && *arg != 0 && *arg != 1) { 564 return BCM_E_PARAM; 565 } 566 567 SOC_IF_ERROR_RETURN(soc_reg32_get(unit, reg, port, 0, &rval)); 568 569 if(op == _BCM_TH3_PFC_DEADLOCK_OP_GET) { 570 *arg = (rval & (1U << pfc_priority)) > 0 ? 1 : 0; 571 } else if (op == _BCM_TH3_PFC_DEADLOCK_OP_SET) { 572 if(*arg == 0) { 573 /* disable PFC deadlock detection and recovery */ 574 rval &= ~(1U << pfc_priority); 575 } else { 576 rval |= 1U << pfc_priority; 577 } 578 SOC_IF_ERROR_RETURN( 579 soc_reg32_set(unit, reg, port, 0, rval)); 580 581 if (op_origin == _BCM_TH3_PFC_DEADLOCK_OP_EXTERNAL) { 582 PFC_LOCK(unit); 583 port_config = _BCM_TH3_PFC_DEADLOCK_CONFIG(unit, port); 584 if(*arg == 0) { 585 port_config->enabled_priority &= ~(1U << pfc_priority); 586 } else { 587 port_config->enabled_priority |= 1U << pfc_priority; 588 } 589 PFC_UNLOCK(unit); 590 BCM_IF_ERROR_RETURN( 591 _bcm_th3_pfc_deadlock_cb_update(unit, *arg)); 592 } 593 } 594 return BCM_E_NONE; 595 } 596 597 STATIC int 598 _bcm_th3_pfc_deadlock_timer_config_get( 599 int unit, 600 bcm_port_t port, 601 int pfc_priority, 602 bcm_cosq_pfc_deadlock_control_t type, 603 int *arg) 604 { 605 soc_reg_t reg = MMU_INTFI_DD_TIMER_CFGr; 606 soc_field_t field = INVALIDf; 607 uint64 rval64; 608 int timer_tick, timer_gran; 609 if(arg == NULL) { 610 return BCM_E_PARAM; 611 } 612 switch (type) { 613 case bcmCosqPFCDeadlockDetectionTimer: 614 field = _timer_init_fields[pfc_priority]; 615 break; 616 case bcmCosqPFCDeadlockRecoveryTimer: 617 PFC_LOCK(unit); 618 *arg = _BCM_TH3_PFC_DEADLOCK_RECOVERY_TIMER 619 (unit, pfc_priority, port); 620 PFC_UNLOCK(unit); 621 break; 622 case bcmCosqPFCDeadlockTimerGranularity: 623 field = _timer_tick_fields[pfc_priority]; 624 break; 625 default: 626 return BCM_E_PARAM; 627 } 628 if(bcmCosqPFCDeadlockRecoveryTimer != type) { 629 SOC_IF_ERROR_RETURN( 630 soc_reg64_get(unit, reg, port, 0, &rval64)); 631 *arg = soc_reg64_field32_get(unit, reg, rval64, field); 632 if(bcmCosqPFCDeadlockDetectionTimer == type) { 633 BCM_IF_ERROR_RETURN(_bcm_th3_pfc_deadlock_timer_config_get 634 (unit, port, pfc_priority, bcmCosqPFCDeadlockTimerGranularity, &timer_tick)); 635 if(timer_tick < 0 || timer_tick >= bcmCosqPFCDeadlockTimerIntervalCount) { 636 return BCM_E_INTERNAL; 637 } 638 timer_gran = _timer_tick_encoding[timer_tick]; 639 *arg *= timer_gran; 640 } 641 } 642 643 return BCM_E_NONE; 644 } 645 646 STATIC int 647 _bcm_th3_pfc_deadlock_timer_config_set( 648 int unit, 649 bcm_port_t port, 650 int pfc_priority, 651 bcm_cosq_pfc_deadlock_control_t type, 652 int arg) 653 { 654 soc_reg_t reg = MMU_INTFI_DD_TIMER_CFGr; 655 soc_field_t field; 656 uint64 rval64; 657 int timer_tick = 0, timer_gran = 0; 658 switch (type) { 659 case bcmCosqPFCDeadlockDetectionTimer: 660 BCM_IF_ERROR_RETURN(_bcm_th3_pfc_deadlock_timer_config_get 661 (unit, port, pfc_priority, bcmCosqPFCDeadlockTimerGranularity, &timer_tick)); 662 if(timer_tick < 0 || timer_tick >= bcmCosqPFCDeadlockTimerIntervalCount) { 663 return BCM_E_INTERNAL; 664 } 665 timer_gran = _timer_tick_encoding[timer_tick]; 666 arg = arg / timer_gran; 667 if ( arg < 0 || arg > _BCM_TH3_PFC_DEADLOCK_TIMER_MAX) { 668 return BCM_E_PARAM; 669 } 670 field = _timer_init_fields[pfc_priority]; 671 break; 672 case bcmCosqPFCDeadlockRecoveryTimer: 673 if(arg < 0) { 674 return BCM_E_PARAM; 675 } 676 PFC_LOCK(unit); 677 _BCM_TH3_PFC_DEADLOCK_RECOVERY_TIMER 678 (unit, pfc_priority, port) = arg; 679 PFC_UNLOCK(unit); 680 break; 681 case bcmCosqPFCDeadlockTimerGranularity: 682 if(arg < bcmCosqPFCDeadlockTimerInterval1MiliSecond || 683 arg >= bcmCosqPFCDeadlockTimerIntervalCount) { 684 return BCM_E_PARAM; 685 } 686 field = _timer_tick_fields[pfc_priority]; 687 break; 688 default: 689 return BCM_E_PARAM; 690 } 691 692 if(type != bcmCosqPFCDeadlockRecoveryTimer) { 693 SOC_IF_ERROR_RETURN(soc_reg64_get(unit, reg, port, 0, &rval64)); 694 soc_reg64_field32_set(unit, reg, &rval64, field, arg); 695 SOC_IF_ERROR_RETURN(soc_reg64_set(unit, reg, port, 0, rval64)); 696 } 697 698 return BCM_E_NONE; 699 } 700 701 int 702 bcm_tomahawk3_cosq_pfc_deadlock_control_get( 703 int unit, bcm_port_t port, 704 int pfc_priority, 705 bcm_cosq_pfc_deadlock_control_t type, 706 int *arg) 707 { 708 if (!SOC_PORT_VALID(unit, port) || arg == NULL) { 709 return BCM_E_PARAM; 710 } 711 if (pfc_priority < 0 || pfc_priority >= TH3_PFC_PRIORITY_NUM) { 712 return BCM_E_PARAM; 713 } 714 715 if (type < 0 || type >= bcmCosqPFCDeadlockControlTypeCount) { 716 return BCM_E_PARAM; 717 } 718 switch (type) { 719 case bcmCosqPFCDeadlockDetectionAndRecoveryEnable: 720 BCM_IF_ERROR_RETURN( 721 _bcm_th3_pfc_deadlock_enable_config(unit, port, 722 pfc_priority, _BCM_TH3_PFC_DEADLOCK_OP_GET, 723 _BCM_TH3_PFC_DEADLOCK_OP_EXTERNAL, arg)); 724 break; 725 case bcmCosqPFCDeadlockDetectionTimer: 726 case bcmCosqPFCDeadlockRecoveryTimer: 727 case bcmCosqPFCDeadlockTimerGranularity: 728 BCM_IF_ERROR_RETURN( 729 _bcm_th3_pfc_deadlock_timer_config_get(unit, port, 730 pfc_priority, type, arg)); 731 break; 732 case bcmCosqPFCDeadlockRecoveryOccurrences: 733 PFC_LOCK(unit); 734 *arg = _BCM_TH3_PFC_DEADLOCK_RECOVERY_ACCUMULATED 735 (unit, pfc_priority, port); 736 *arg = *arg * (_BCM_TH3_PFC_DEADLOCK_CB_INTERVAL(unit)); 737 *arg = *arg / 1000; /* milli seconds */ 738 PFC_UNLOCK(unit); 739 break; 740 default: 741 return BCM_E_PARAM; 742 } 743 return BCM_E_NONE; 744 } 745 746 int 747 bcm_tomahawk3_cosq_pfc_deadlock_control_set( 748 int unit, bcm_port_t port, 749 int pfc_priority, 750 bcm_cosq_pfc_deadlock_control_t type, 751 int arg) 752 { 753 if (!SOC_PORT_VALID(unit, port)) { 754 return BCM_E_PARAM; 755 } 756 if (pfc_priority < 0 || pfc_priority >= TH3_PFC_PRIORITY_NUM) { 757 return BCM_E_PARAM; 758 } 759 if (type < 0 || type >= bcmCosqPFCDeadlockControlTypeCount) { 760 return BCM_E_PARAM; 761 } 762 763 switch (type) { 764 case bcmCosqPFCDeadlockDetectionAndRecoveryEnable: 765 BCM_IF_ERROR_RETURN( 766 _bcm_th3_pfc_deadlock_enable_config(unit, port, 767 pfc_priority, _BCM_TH3_PFC_DEADLOCK_OP_SET, 768 _BCM_TH3_PFC_DEADLOCK_OP_EXTERNAL, &arg)); 769 break; 770 case bcmCosqPFCDeadlockDetectionTimer: 771 case bcmCosqPFCDeadlockRecoveryTimer: 772 case bcmCosqPFCDeadlockTimerGranularity: 773 BCM_IF_ERROR_RETURN( 774 _bcm_th3_pfc_deadlock_timer_config_set(unit, port, 775 pfc_priority, type, arg)); 776 break; 777 case bcmCosqPFCDeadlockRecoveryOccurrences: 778 if (arg == 0) { 779 PFC_LOCK(unit); 780 _BCM_TH3_PFC_DEADLOCK_RECOVERY_ACCUMULATED 781 (unit, pfc_priority, port) = arg; 782 PFC_UNLOCK(unit); 783 break; 784 } else { 785 return BCM_E_PARAM; 786 } 787 default: 788 return BCM_E_PARAM; 789 } 790 return BCM_E_NONE; 791 } 792 793 /* 794 * Function: 795 * _bcm_th3_pfc_switch_control_set 796 * Description: 797 * Set PFC Deadlock feature's switch config. 798 * Parameters: 799 * unit - Device unit number 800 * type - The desired configuration parameter to retrieve. 801 * arg - Set value 802 * Returns: 803 * BCM_E_xxx 804 * Notes: 805 * bcmSwitchPFCDeadlockCosMax - Set operation is not permitted 806 */ 807 int _bcm_th3_pfc_switch_control_set(int unit, bcm_switch_control_t type, int arg) 808 { 809 soc_reg_t reg = INVALIDr; 810 soc_field_t field = INVALIDf; 811 uint32 rval; 812 if (bcmSwitchPFCDeadlockDetectionTimeInterval == type) { 813 return BCM_E_UNAVAIL; 814 } 815 if (bcmSwitchPFCDeadlockRecoveryAction == type) { 816 if(arg < 0 || arg > 1) { 817 return BCM_E_PARAM; 818 } 819 reg = MMU_INTFI_IGNORE_PFC_XOFF_PKT_DISCARDr; 820 field = PURGEf; 821 rval = 0; 822 SOC_IF_ERROR_RETURN( 823 soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval)); 824 soc_reg_field_set(unit, reg, &rval, field, arg); 825 SOC_IF_ERROR_RETURN( 826 soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 827 } 828 return BCM_E_NONE; 829 } 830 831 /* 832 * Function: 833 * _bcm_th3_pfc_switch_control_get 834 * Description: 835 * Get PFC Deadlock feature's switch config. 836 * Parameters: 837 * unit - Device unit number 838 * type - The desired configuration parameter to retrieve. 839 * arg - Pointer to retrieved value 840 * Returns: 841 * BCM_E_xxx 842 * Notes: 843 * bcmSwitchPFCDeadlockCosMax - Set operation is not permitted 844 */ 845 int _bcm_th3_pfc_switch_control_get(int unit, bcm_switch_control_t type, int *arg) 846 { 847 soc_reg_t reg = INVALIDr; 848 soc_field_t field = INVALIDf; 849 uint32 rval; 850 851 if(arg == NULL) { 852 return BCM_E_PARAM; 853 } 854 if (bcmSwitchPFCDeadlockDetectionTimeInterval == type) { 855 return BCM_E_UNAVAIL; 856 } 857 if (bcmSwitchPFCDeadlockRecoveryAction == type) { 858 859 reg = MMU_INTFI_IGNORE_PFC_XOFF_PKT_DISCARDr; 860 field = PURGEf; 861 rval = 0; 862 SOC_IF_ERROR_RETURN( 863 soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval)); 864 *arg = soc_reg_field_get(unit, reg, rval, field); 865 866 } 867 return BCM_E_NONE; 868 } 869 870 /* 871 * Function: 872 * _bcm_th3_pfc_deadlock_info_get 873 * Purpose: 874 * Get bitmap of Enabled(Admin) and Current Deadlock ports status for a 875 * given priority in PFC deadlock feature. 876 * Parameters: 877 * unit - (IN) unit number 878 * priority - (IN) PFC priority 879 * info - (OUT) Info for a given priority 880 * Returns: 881 * BCM_E_XXX 882 */ 883 int _bcm_th3_pfc_deadlock_info_get(int unit, int priority, 884 bcm_cosq_pfc_deadlock_info_t *pfc_deadlock_info) 885 { 886 int port; 887 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 888 if(priority < 0 || priority >= TH3_PFC_PRIORITY_NUM) { 889 return BCM_E_PARAM; 890 } 891 PBMP_ALL_ITER(unit, port) { 892 port_config = _BCM_TH3_PFC_DEADLOCK_CONFIG(unit, port); 893 if((port_config->enabled_priority & (1U << priority)) != 0) { 894 BCM_PBMP_PORT_ADD(pfc_deadlock_info->enabled_pbmp, port); 895 } 896 if((port_config->deadlock_priority & (1U << priority)) != 0) { 897 BCM_PBMP_PORT_ADD(pfc_deadlock_info->deadlock_pbmp, port); 898 } 899 } 900 return BCM_E_NONE; 901 } 902 903 /* 904 * Function: 905 * _bcm_pfc_deadlock_queue_status_get 906 * Purpose: 907 * Get the current Deadlock status for the given Port. 908 * Parameters: 909 * unit - (IN) unit number 910 * gport - (IN) gport 911 * deadlock_status - (OUT) Deatlock status for the given port 912 * bit[0]->PFC priority 0 ... 913 * bit[7] -> PFC priority 7 914 * Returns: 915 * BCM_E_XXX 916 */ 917 int _bcm_th3_pfc_deadlock_port_status_get 918 (int unit, bcm_gport_t gport, uint8 *deadlock_status) 919 { 920 int i, local_port; 921 uint8 deadlock_bmp = 0; 922 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 923 924 if (deadlock_status == NULL) { 925 return BCM_E_PARAM; 926 } 927 928 if (BCM_GPORT_IS_SET(gport)) { 929 if (!BCM_GPORT_IS_LOCAL(gport)) { 930 return BCM_E_PARAM; 931 } 932 BCM_IF_ERROR_RETURN 933 (_bcm_th3_cosq_localport_resolve(unit, gport, (bcm_port_t *) &local_port)); 934 } else { 935 local_port = gport; 936 } 937 938 if (!SOC_PORT_VALID(unit, local_port)) { 939 return BCM_E_PARAM; 940 } 941 PFC_LOCK(unit); 942 port_config = _BCM_TH3_PFC_DEADLOCK_CONFIG(unit, local_port); 943 for(i = 0; i< TH3_PFC_PRIORITY_NUM; i++) { 944 if((port_config->deadlock_priority & (1U << i)) != 0) { 945 deadlock_bmp |= (1U << i); 946 } 947 } 948 *deadlock_status = deadlock_bmp; 949 PFC_UNLOCK(unit); 950 return BCM_E_NONE; 951 } 952 /* 953 * Function: 954 * _bcm_th3_pfc_deadlock_callback_register 955 * Purpose: 956 * Register pfc deadlock recovery callback in PFC deadlock feature. 957 * Parameters: 958 * unit - (IN) unit number 959 * callback - (IN) callback function 960 * userdata - (IN) user data 961 * Returns: 962 * BCM_E_XXX 963 */ 964 965 int _bcm_th3_pfc_deadlock_recovery_event_register( 966 int unit, 967 bcm_cosq_pfc_deadlock_recovery_event_cb_t callback, 968 void *userdata) 969 { 970 _bcm_pfc_deadlock_cb_t *pfc_deadlock_cb = NULL; 971 972 pfc_deadlock_cb = _BCM_TH3_PFC_DEADLOCK_CB(unit); 973 974 pfc_deadlock_cb->pfc_deadlock_cb = callback; 975 pfc_deadlock_cb->pfc_deadlock_userdata = userdata; 976 977 return BCM_E_NONE; 978 979 } 980 981 /* 982 * Function: 983 * _bcm_th3_pfc_deadlock_callback_unregister 984 * Purpose: 985 * Unregister pfc deadlock recovery callback in PFC deadlock feature. 986 * Parameters: 987 * unit - (IN) unit number 988 * callback - (IN) callback function 989 * userdata - (IN) user data 990 * Returns: 991 * BCM_E_XXX 992 */ 993 994 int _bcm_th3_pfc_deadlock_recovery_event_unregister( 995 int unit, 996 bcm_cosq_pfc_deadlock_recovery_event_cb_t callback, 997 void *userdata) 998 { 999 _bcm_pfc_deadlock_cb_t *pfc_deadlock_cb = NULL; 1000 1001 pfc_deadlock_cb = _BCM_TH3_PFC_DEADLOCK_CB(unit); 1002 1003 pfc_deadlock_cb->pfc_deadlock_cb = NULL; 1004 pfc_deadlock_cb->pfc_deadlock_userdata = NULL; 1005 1006 return BCM_E_NONE; 1007 } 1008 1009 /* 1010 * Function: 1011 * _bcm_th3_pfc_deadlock_init 1012 * Purpose: 1013 * Initialize (clear) all states/data-structures 1014 * Parameters: 1015 * unit - unit number 1016 * Returns: 1017 * BCM_E_XXX 1018 */ 1019 int 1020 _bcm_th3_pfc_deadlock_init(int unit) 1021 { 1022 _bcm_th3_pfc_deadlock_control_t *pfc_deadlock_control = NULL; 1023 _bcm_pfc_deadlock_cb_t *pfc_deadlock_cb = NULL; 1024 1025 pfc_deadlock_control = _BCM_TH3_PFC_DEADLOCK_CONTROL(unit); 1026 if (NULL == pfc_deadlock_control) { 1027 pfc_deadlock_control = 1028 sal_alloc(sizeof(_bcm_th3_pfc_deadlock_control_t), "pfc_deadlock_ctrl"); 1029 if (!pfc_deadlock_control) { 1030 return BCM_E_MEMORY; 1031 } 1032 } 1033 1034 sal_memset(pfc_deadlock_control, 0, sizeof(_bcm_th3_pfc_deadlock_control_t)); 1035 _BCM_TH3_PFC_DEADLOCK_CONTROL(unit) = pfc_deadlock_control; 1036 1037 pfc_deadlock_cb = _BCM_TH3_PFC_DEADLOCK_CB(unit); 1038 1039 if (NULL == pfc_deadlock_cb) { 1040 pfc_deadlock_cb = 1041 sal_alloc(sizeof(_bcm_pfc_deadlock_cb_t), "pfc_deadlock_cb"); 1042 if (!pfc_deadlock_cb) { 1043 if (_BCM_TH3_PFC_DEADLOCK_CONTROL(unit) != NULL) { 1044 sal_free(_BCM_TH3_PFC_DEADLOCK_CONTROL(unit)); 1045 _BCM_TH3_PFC_DEADLOCK_CONTROL(unit) = NULL; 1046 } 1047 return BCM_E_MEMORY; 1048 } 1049 } 1050 sal_memset(pfc_deadlock_cb, 0, sizeof(_bcm_pfc_deadlock_cb_t)); 1051 pfc_deadlock_cb->pfc_deadlock_cb = NULL; 1052 pfc_deadlock_cb->pfc_deadlock_userdata = NULL; 1053 _BCM_TH3_PFC_DEADLOCK_CB(unit) = pfc_deadlock_cb; 1054 1055 pfc_deadlock_control->cb_enabled = FALSE; 1056 pfc_deadlock_control->cb_interval = 100 * 1000; /* 100 ms */ 1057 1058 _bcm_th3_pfc_lock[unit] = sal_mutex_create("pfc lock"); 1059 if (_bcm_th3_pfc_lock[unit] == NULL) { 1060 return BCM_E_MEMORY; 1061 } 1062 1063 if (th3_pfc_deinit_notify[unit] == NULL) { 1064 th3_pfc_deinit_notify[unit] = sal_sem_create("pfc deinit notify", sal_sem_BINARY, 0); 1065 if (th3_pfc_deinit_notify[unit] == NULL) { 1066 return BCM_E_MEMORY; 1067 } 1068 } 1069 th3_pfc_init[unit] = TRUE; 1070 1071 return BCM_E_NONE; 1072 } 1073 1074 int _bcm_th3_pfc_deadlock_deinit(int unit) 1075 { 1076 _bcm_th3_pfc_deadlock_control_t *pfc_deadlock_control = NULL; 1077 _bcm_pfc_deadlock_cb_t *pfc_deadlock_cb = NULL; 1078 uint8 cb_enable = FALSE; 1079 1080 pfc_deadlock_control = _BCM_TH3_PFC_DEADLOCK_CONTROL(unit); 1081 if (pfc_deadlock_control != NULL) { 1082 cb_enable = pfc_deadlock_control->cb_enabled; 1083 } 1084 if (th3_pfc_init[unit]) { 1085 th3_pfc_init[unit] = FALSE; 1086 if (cb_enable == TRUE) { 1087 sal_sem_take(th3_pfc_deinit_notify[unit], sal_sem_FOREVER); 1088 } 1089 } 1090 sal_dpc_cancel(INT_TO_PTR(&_th3_pfc_deadlock_cb)); 1091 1092 if (pfc_deadlock_control != NULL) { 1093 sal_free(pfc_deadlock_control); 1094 _BCM_TH3_PFC_DEADLOCK_CONTROL(unit) = NULL; 1095 } 1096 pfc_deadlock_cb = _BCM_TH3_PFC_DEADLOCK_CB(unit); 1097 if (pfc_deadlock_cb != NULL) { 1098 sal_free(pfc_deadlock_cb); 1099 _BCM_TH3_PFC_DEADLOCK_CB(unit) = NULL; 1100 } 1101 if (_bcm_th3_pfc_lock[unit]) { 1102 sal_mutex_destroy(_bcm_th3_pfc_lock[unit]); 1103 _bcm_th3_pfc_lock[unit] = NULL; 1104 } 1105 1106 if (th3_pfc_deinit_notify[unit] != NULL) { 1107 sal_sem_destroy(th3_pfc_deinit_notify[unit]); 1108 th3_pfc_deinit_notify[unit] = NULL; 1109 } 1110 1111 return BCM_E_NONE; 1112 } 1113 1114 int _bcm_th3_pfc_deadlock_port_detach(int unit, bcm_port_t port) 1115 { 1116 _bcm_th3_pfc_deadlock_control_t *pfc_deadlock_control = NULL; 1117 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 1118 1119 pfc_deadlock_control = _BCM_TH3_PFC_DEADLOCK_CONTROL(unit); 1120 1121 if (pfc_deadlock_control == NULL) { 1122 return BCM_E_INIT; 1123 } 1124 port_config = &pfc_deadlock_control->port_config[port]; 1125 sal_memset(port_config->recovery_timers, 0, 1126 sizeof(uint32) * TH3_PFC_PRIORITY_NUM); 1127 sal_memset(port_config->recovery_count, 0, 1128 sizeof(uint32) * TH3_PFC_PRIORITY_NUM); 1129 sal_memset(port_config->recovery_count_acc, 0, 1130 sizeof(uint32) * TH3_PFC_PRIORITY_NUM); 1131 port_config->deadlock_priority = 0; 1132 port_config->enabled_priority = 0; 1133 return BCM_E_NONE; 1134 } 1135 1136 #ifdef BCM_WARM_BOOT_SUPPORT 1137 /* 1138 * Function: 1139 * _bcm_th3_pfc_deadlock_reinit 1140 * Purpose: 1141 * Reinitialize all states/data-structures from HW(Level 1 warmboot) 1142 * and scache. 1143 * Parameters: 1144 * unit - unit number 1145 * Returns: 1146 * BCM_E_XXX 1147 */ 1148 int 1149 _bcm_th3_pfc_deadlock_reinit(int unit, uint8 **scache_ptr) 1150 { 1151 _bcm_th3_pfc_deadlock_control_t *dd_control = 1152 _BCM_TH3_PFC_DEADLOCK_CONTROL(unit); 1153 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 1154 int pri = 0,dd_enable; 1155 uint32 rval_mask, fval_mask; 1156 soc_reg_t int_mask_reg = MMU_INTFI_DD_TIMER_INT_MASKr; 1157 soc_field_t mask_field = PFC_PRIORITY_INT_MASKf; 1158 int port, max_num_ports = 0; 1159 uint16 *u16_scache_p; 1160 uint32 *u32_scache_p; 1161 1162 u16_scache_p = (uint16 *)(*scache_ptr); 1163 1164 max_num_ports = soc_scache_dictionary_entry_get(unit, 1165 ssden_SOC_MAX_NUM_PORTS, 1166 SOC_MAX_NUM_PORTS); 1167 1168 *scache_ptr += (max_num_ports * 8 * sizeof(uint16)); 1169 u32_scache_p = (uint32 *)(*scache_ptr); 1170 1171 *scache_ptr += (max_num_ports * 8 * sizeof(uint32)); 1172 1173 if (dd_control == NULL) { 1174 return BCM_E_INIT; 1175 } 1176 1177 for (port = 0; port < max_num_ports; port++) { 1178 for (pri = 0; pri < TH3_PFC_PRIORITY_NUM; pri++) { 1179 dd_control->port_config[port].recovery_timers[pri] = *u16_scache_p++; 1180 dd_control->port_config[port].recovery_count_acc[pri] = *u32_scache_p++; 1181 } 1182 } 1183 1184 /* check if any ports under dead lock recovery. */ 1185 PBMP_PORT_ITER(unit, port) { 1186 port_config = &(dd_control->port_config[port]); 1187 SOC_IF_ERROR_RETURN( 1188 soc_reg32_get(unit, int_mask_reg, port, 0, &rval_mask)); 1189 fval_mask = soc_reg_field_get(unit, int_mask_reg, rval_mask, 1190 mask_field); 1191 if (fval_mask != 0) { 1192 for (pri = 0; pri < TH3_PFC_PRIORITY_NUM; pri++) { 1193 if (fval_mask & (1U << pri)) { 1194 port_config->deadlock_priority |= (1U << pri); 1195 } 1196 } 1197 } 1198 1199 for (pri = 0; pri < TH3_PFC_PRIORITY_NUM; pri++) { 1200 if (bcm_tomahawk3_cosq_pfc_deadlock_control_get(unit, port, pri, 1201 bcmCosqPFCDeadlockDetectionAndRecoveryEnable, 1202 &dd_enable) == BCM_E_NONE) { 1203 port_config->enabled_priority |= (dd_enable << pri) ; 1204 } 1205 } 1206 } 1207 1208 BCM_IF_ERROR_RETURN 1209 (_bcm_th3_pfc_switch_control_get(unit, 1210 bcmSwitchPFCDeadlockRecoveryAction, &dd_enable)); 1211 dd_control->recovery_action = dd_enable; 1212 1213 return BCM_E_NONE; 1214 } 1215 1216 /* 1217 * Function: 1218 * _bcm_th3_pfc_deadlock_recovery_reset 1219 * Purpose: 1220 * Recover the system back to default state. 1221 * Restore all ports from Deadlock/Recovery state, if Warm boot when 1222 * recovery was in progress 1223 * Parameters: 1224 * unit - unit number 1225 * Returns: 1226 * BCM_E_XXX 1227 */ 1228 int 1229 _bcm_th3_pfc_deadlock_recovery_reset(int unit) 1230 { 1231 int pri = 0, dd_enabled = 0; 1232 bcm_port_t port; 1233 1234 _bcm_th3_pfc_deadlock_port_config_t *port_config = NULL; 1235 _bcm_th3_pfc_deadlock_control_t *dd_control = 1236 _BCM_TH3_PFC_DEADLOCK_CONTROL(unit); 1237 if (dd_control == NULL) { 1238 return BCM_E_INIT; 1239 } 1240 1241 PBMP_PORT_ITER(unit, port) { 1242 port_config = &(dd_control->port_config[port]); 1243 for (pri = 0; pri < TH3_PFC_PRIORITY_NUM; pri++) { 1244 if ((port_config->deadlock_priority & (1U << pri)) != 0) { 1245 port_config->recovery_count[pri] = 0; 1246 BCM_IF_ERROR_RETURN( 1247 _bcm_th3_pfc_deadlock_recovery_end(unit, port, pri)); 1248 } 1249 } 1250 } 1251 PBMP_PORT_ITER(unit, port) { 1252 port_config = &(dd_control->port_config[port]); 1253 if ( port_config->enabled_priority != 0 ) { 1254 dd_enabled = 1; 1255 break; 1256 } 1257 } 1258 if (dd_enabled == 1) { 1259 /* enable background thread if not already enabled. */ 1260 if (dd_control->cb_enabled == FALSE) { 1261 dd_control->cb_enabled = TRUE; 1262 _th3_pfc_deadlock_cb(INT_TO_PTR(&_th3_pfc_deadlock_cb), 1263 INT_TO_PTR(_BCM_TH3_PFC_DEADLOCK_CB_INTERVAL(unit)), 1264 INT_TO_PTR(unit), 0, 0); 1265 } 1266 } 1267 return BCM_E_NONE; 1268 } 1269 #endif /* BCM_WARM_BOOT_SUPPORT */ 1270 #endif 1271