openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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