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

tas.c (96275B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        tas.c
      8  * Purpose:     TAS driver
      9  */
     10 
     11 #include <shared/bsl.h>
     12 #include <soc/drv.h>
     13 #include <bcm/cosq.h>
     14 #include <bcm_int/esw/cosq.h>
     15 #include <bcm_int/esw/tas.h>
     16 #include <bcm_int/esw/port.h>
     17 #include <bcm_int/esw_dispatch.h>
     18 #if defined(INCLUDE_PTP)
     19 #include <bcm_int/common/ptp.h>
     20 #endif
     21 #ifdef BCM_GREYHOUND2_SUPPORT
     22 #include <bcm_int/esw/greyhound2.h>
     23 #endif
     24 #ifdef BCM_WARM_BOOT_SUPPORT
     25 #include <soc/scache.h>
     26 #include <bcm_int/esw/switch.h>
     27 #endif /* BCM_WARM_BOOT_SUPPORT */
     28 
     29 #ifdef BCM_TAS_SUPPORT
     30 /*
     31  * Internal TAS profile control structure.
     32  * To keep the software database from bcm api calls and corresponding
     33  * remapped hardware data which should be programed to HW.
     34  */
     35 typedef struct tas_profile_ctrl_s {
     36     sal_mutex_t                     profile_mutex;
     37     bcm_cosq_tas_profile_id_t       pid;
     38     bcm_cosq_tas_profile_state_t    pstate;
     39     bcm_port_t                      port; /* logical port */
     40     int                             hw_index; /* hw profile id */
     41     int                             num_user_entries; /* entries form API */
     42     bcm_cosq_tas_entry_t            *user_entries;
     43     int                             num_hw_entries; /* remapped HW entries */
     44     bcm_cosq_tas_entry_t            *hw_entries;
     45     bcm_ptp_timestamp_t             base_time;
     46     bcm_ptp_timestamp_t             config_change_time;
     47     uint32                          cycle_time;
     48     uint32                          cycle_extension;
     49 
     50     struct tas_profile_ctrl_s       *next;   /* For storing in a linked-list  */
     51 } tas_profile_ctrl_t;
     52 
     53 /* Mutex macro to protect tas_profile */
     54 #define TAS_PROFILE_LOCK(tp) \
     55         do {\
     56             if ((tp)->profile_mutex) { \
     57                 sal_mutex_take((tp)->profile_mutex, sal_mutex_FOREVER); \
     58             }\
     59         } while (0)
     60 #define TAS_PROFILE_UNLOCK(tp) \
     61         do {\
     62             if ((tp)->profile_mutex) { \
     63                 sal_mutex_give((tp)->profile_mutex); \
     64             }\
     65         } while (0)
     66 
     67 /* Define the maximum profile_cnt per profile list */
     68 #define MAX_TAS_PROFILE_CNT     (10)
     69 
     70 /* The soc properties which will be referenced for TAS profile entry remap */
     71 typedef struct tas_prop_info_s {
     72     uint8 txoverrun; /* tas_calendar_auto_adjust_for_txoverrun */
     73     uint8 holdadvance; /* tas_calendar_auto_adjust_for_holdadvance */
     74     int maxsdu[BCM_COS_COUNT]; /* tas_calendar_auto_adjust_ref_maxsdu */
     75 } tas_prop_info_t;
     76 
     77 /*
     78  * Internal TAS control structure.
     79  */
     80 typedef struct bcmi_esw_tas_control_s {
     81     sal_mutex_t                 tas_mutex;
     82     int                         profile_list_count; /* Max profile list count. */
     83     tas_profile_ctrl_t          **profile_list; /* Profiles list.
     84                                                  * Two-dimension list, the first
     85                                                  * point to port, the second
     86                                                  * point to profile associated
     87                                                  * with the port.
     88                                                  */
     89     bcm_cosq_tas_profile_id_t   *active_pid;    /* Active profile id */
     90     bcm_cosq_tas_profile_id_t   *process_pid;   /* Process(commit or pending)
     91                                                  * profile id
     92                                                  */
     93     tas_prop_info_t             *tas_properties; /* Port basis software cache
     94                                                   * of soc properties.
     95                                                   */
     96     /* device specific drivers */
     97     const tas_drv_t             *tas_drvs;
     98 } bcmi_esw_tas_control_t;
     99 
    100 /* TAS control to keep unit-base tas information */
    101 STATIC bcmi_esw_tas_control_t *tas_control[SOC_MAX_NUM_DEVICES] = {NULL};
    102 
    103 /* Check if tas_control has been initialized. */
    104 #define TAS_IS_INIT(unit)                                      \
    105     do {                                                            \
    106         if (tas_control[unit] == NULL) {                        \
    107             LOG_ERROR(BSL_LS_BCM_TAS,                               \
    108                       (BSL_META_U(unit,                             \
    109                                   "TAS Error: Module not initialized\n"))); \
    110             return (BCM_E_INIT);                                    \
    111         }                                                           \
    112     } while (0)
    113 
    114 /* Mutex macro to protect tas_control[] */
    115 #define TAS_LOCK(tc) \
    116         sal_mutex_take((tc)->tas_mutex, sal_mutex_FOREVER)
    117 #define TAS_UNLOCK(tc) \
    118         sal_mutex_give((tc)->tas_mutex)
    119 
    120 /*
    121  * Helper macro to insert the new profile (_inserted_ptr_) to
    122  * tas_control[]->profile_list[_index_]
    123  */
    124 #define TAS_PROFILE_INSERT(_profile_ptr_, _inserted_ptr_, _index_)    \
    125     do {                                                     \
    126         (_inserted_ptr_)->next = (_profile_ptr_)[(_index_)];  \
    127         (_profile_ptr_)[(_index_)] = (_inserted_ptr_);        \
    128     } while (0)
    129 
    130 /*
    131  * Helper macro to remove the profile (_removed_ptr_) from
    132  * tas_control[]->profile_list[_index_]
    133  */
    134 #define TAS_PROFILE_REMOVE(_profile_ptr_, _entry_type_, _removed_ptr_, _index_)\
    135    do {                                                    \
    136        _entry_type_ *_prev_ent_ = NULL;                    \
    137        _entry_type_ *_lkup_ent_ = (_profile_ptr_)[(_index_)]; \
    138        while (NULL != _lkup_ent_) {                        \
    139            if (_lkup_ent_ != (_removed_ptr_))  {           \
    140                _prev_ent_ = _lkup_ent_;                    \
    141                _lkup_ent_ = _lkup_ent_->next;              \
    142                continue;                                   \
    143            }                                               \
    144            if (_prev_ent_ != NULL) {                        \
    145                _prev_ent_->next = (_removed_ptr_)->next;   \
    146            } else {                                        \
    147                (_profile_ptr_)[(_index_)] = (_removed_ptr_)->next; \
    148            }                                               \
    149            break;                                          \
    150        }                                                   \
    151    } while (0)
    152 
    153 /*
    154  * Helper macro to remove all the profiles from
    155  * tas_control[]->profile_list[_index_]
    156  */
    157 #define TAS_PROFILE_REMOVE_ALL(_profile_ptr_, _entry_type_, _index_)       \
    158     do {                                                    \
    159         _entry_type_ *_node_ = NULL;                        \
    160         _entry_type_ *_head_ = (_profile_ptr_)[(_index_)];  \
    161         while (NULL != _head_) {                            \
    162             _node_ = _head_;                                \
    163             _head_ = _head_->next;                          \
    164             sal_free(_node_);                               \
    165             _node_ = NULL;                                  \
    166         }                                                   \
    167    } while (0)
    168 
    169 /*
    170  * Helper macro to iterate the profile entry from
    171  * tas_control[]->profile_list[_index_]
    172  */
    173 #define TAS_PROFILE_ITER(_profile_ptr_, _entry_ptr_, _index_) \
    174     for ((_entry_ptr_) = (_profile_ptr_)[(_index_)]; (_entry_ptr_) != NULL; \
    175          (_entry_ptr_) = (_entry_ptr_)->next)
    176 
    177 /* String corresponding to the enum in bcm_cosq_tas_profile_state_t */
    178 static const char *pstate_string[] =
    179 {
    180     "Init",
    181     "Committed",
    182     "Pending",
    183     "Active",
    184     "Expired",
    185     "Error"
    186 };
    187 
    188 /* Composition of tas profile id */
    189 /*
    190  *  port : max 8 bits (support 256 ports)
    191  *  idx : max  16 bits (0~65535)
    192  */
    193 #define TAS_PID_PORT_START_BIT  24
    194 #define TAS_PID_PORT_END_BIT    31
    195 #define TAS_PID_IDX_START_BIT 0
    196 #define TAS_PID_IDX_END_BIT   15
    197 
    198 #define TAS_PID_PORT_MASK \
    199     ((1 << (TAS_PID_PORT_END_BIT - TAS_PID_PORT_START_BIT + 1)) - 1)
    200 #define TAS_PID_IDX_MASK \
    201     ((1 << (TAS_PID_IDX_END_BIT - TAS_PID_IDX_START_BIT + 1)) - 1)
    202 
    203 /*
    204  * Function:
    205  *     tas_control_get
    206  * Purpose:
    207  *     Get the tas_control[unit] pointer
    208  * Parameters:
    209  *     unit             - (IN) unit number
    210  *     tc               - (OUT) pointer to tas_control[unit]
    211  * Returns:
    212  *     BCM_E_XXX
    213  */
    214 STATIC int
    215 tas_control_get(int unit, bcmi_esw_tas_control_t **tc)
    216 {
    217     /* Input parameters check. */
    218     if (NULL == tc) {
    219         return (BCM_E_PARAM);
    220     }
    221     /* Make sure system was initialized. */
    222     TAS_IS_INIT(unit);
    223 
    224     /* Fill tas control structure. */
    225     *tc = tas_control[unit];
    226 
    227     return (BCM_E_NONE);
    228 }
    229 
    230 /*
    231  * Function:
    232  *    tas_profile_ctrl_get
    233  * Purpose:
    234  *    Get the internal profile information by specifying profile id
    235  * Parameters:
    236  *     unit             - (IN) unit number
    237  *     pid              - (IN) unit number
    238  *     profile_p        - (IN) pointer to internal profile
    239  * Returns:
    240  *     BCM_E_XXX
    241  */
    242 STATIC int
    243 tas_profile_ctrl_get(
    244     int unit,
    245     bcm_cosq_tas_profile_id_t pid,
    246     tas_profile_ctrl_t **profile_p)
    247 {
    248     bcmi_esw_tas_control_t *tc;
    249     tas_profile_ctrl_t *tp;
    250     bcm_port_t  lport;
    251 
    252     if (NULL == profile_p) {
    253         return (BCM_E_PARAM);
    254     }
    255     /* Get unit TAS control structure. */
    256     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
    257 
    258     lport = (pid >> TAS_PID_PORT_START_BIT) & TAS_PID_PORT_MASK;
    259     TAS_LOCK(tc);
    260     /* Iterate over the profiles linked-list looking for a matching id */
    261     tp = tc->profile_list[lport];
    262     while (tp != NULL) {
    263         if (tp->pid == pid) {
    264             *profile_p = tp;
    265             TAS_UNLOCK(tc);
    266             return (BCM_E_NONE);
    267         }
    268         tp = tp->next;
    269     }
    270     TAS_UNLOCK(tc);
    271     return (BCM_E_NOT_FOUND);
    272 }
    273 
    274 /*
    275  * Function:
    276  *     tas_gport_validate
    277  * Purpose:
    278  *     gport parameter check and get the corresponding lport
    279  * Parameters:
    280  *     unit             - (IN) unit number
    281  *     gport            - (IN) gport
    282  *     local_port       - (OUT) logical port
    283  * Returns:
    284  *     BCM_E_XXX
    285  */
    286 STATIC int
    287 tas_gport_validate(int unit, bcm_gport_t gport, bcm_port_t *local_port)
    288 {
    289     BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport, local_port));
    290     if (!BCM_PBMP_MEMBER(PBMP_PORT_ALL(unit), *local_port)) {
    291         return BCM_E_PORT;
    292     }
    293     return BCM_E_NONE;
    294 }
    295 
    296 /* Software cache to keep the soc propery for TAS profile entry remap */
    297 STATIC int
    298 bcmi_esw_tas_property_cache_init(int unit)
    299 {
    300     bcmi_esw_tas_control_t  *tc = NULL;
    301     int rv = BCM_E_NONE;
    302     int p, c;
    303 #ifndef NDEBUG
    304     int len;
    305 #endif /* !NDEBUG */
    306     char *str, *p_str;
    307     tas_prop_info_t  *tas_prop;
    308     char prop[SOC_PROPERTY_NAME_MAX];
    309     int default_sdu = 0;
    310 
    311     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
    312 
    313     TAS_LOCK(tc);
    314     /* Use the max index to keep w/o suffix value */
    315     tas_prop = &tc->tas_properties[tc->profile_list_count];
    316     tas_prop->txoverrun =
    317         soc_property_get(unit, spn_TAS_CALENDAR_AUTO_ADJUST_FOR_TXOVERRUN, 0);
    318     tas_prop->holdadvance =
    319         soc_property_get(unit, spn_TAS_CALENDAR_AUTO_ADJUST_FOR_HOLDADVANCE, 0);
    320     /* Get the default maxsdu size */
    321     default_sdu =
    322         soc_property_get(unit, spn_TAS_CALENDAR_AUTO_ADJUST_REF_MAXSDU, 1522);
    323     for (p = 0; p < tc->profile_list_count; p++) {
    324         tas_prop = &tc->tas_properties[p];
    325         /* tas_calendar_auto_adjust_for_txoverrun<_port#> */
    326         tas_prop->txoverrun =
    327             (uint8)soc_property_port_get(
    328                 unit, (p + 1), spn_TAS_CALENDAR_AUTO_ADJUST_FOR_TXOVERRUN, 0);
    329         /* tas_calendar_auto_adjust_for_holdadvance<_port#> */
    330         tas_prop->holdadvance =
    331             (uint8)soc_property_port_get(
    332                 unit, (p + 1), spn_TAS_CALENDAR_AUTO_ADJUST_FOR_HOLDADVANCE, 0);
    333         /* tas_calendar_auto_adjust_ref_maxsdu<_port#_cos#> */
    334         /* try "name_port%d_cos%d" for explicit match first */
    335         for (c = 0; c < BCM_COS_COUNT; c++) {
    336 #ifndef NDEBUG
    337             len =
    338 #endif /* !NDEBUG */
    339             sal_snprintf(prop, SOC_PROPERTY_NAME_MAX, "%s_port%d_cos%d",
    340                          spn_TAS_CALENDAR_AUTO_ADJUST_REF_MAXSDU, p, c);
    341             assert(len < SOC_PROPERTY_NAME_MAX);
    342             str = soc_property_get_str(unit, prop);
    343             if (str != NULL) {
    344                 tas_prop->maxsdu[c] = _shr_ctoi(str);
    345             } else {
    346                 /* try "name_port%d" for explicit match */
    347                 sal_snprintf(prop, SOC_PROPERTY_NAME_MAX, "%s_port%d",
    348                              spn_TAS_CALENDAR_AUTO_ADJUST_REF_MAXSDU, p);
    349                 p_str = soc_property_get_str(unit, prop);
    350                 if (p_str != NULL) {
    351                     tas_prop->maxsdu[c] = _shr_ctoi(p_str);
    352                 } else {
    353                     /* giving default value */
    354                     tas_prop->maxsdu[c] = default_sdu;
    355                 }
    356             }
    357         }
    358     }
    359     TAS_UNLOCK(tc);
    360     return rv;
    361 }
    362 
    363 /*
    364  * Function:
    365  *     bcmi_esw_tas_property_get
    366  * Purpose:
    367  *     Get the soc property value by specifying soc property
    368  *     with optional suffix (port and cos)
    369  *     If the property is system wise setting or without optional suffix
    370  *     specified, the value will be returned by ignoring the lport and cos
    371  *     parameters.
    372  * Parameters:
    373  *     unit             - (IN) unit number
    374  *     tas_prop         - (IN) soc property type (TAS_PROP_XXX)
    375  *     port             - (IN) lport
    376  *     cos              - (IN) cosq
    377  *     value            - (OUT) value
    378  * Returns:
    379  *     BCM_E_XXX
    380  */
    381 int
    382 bcmi_esw_tas_property_get(
    383     int unit,
    384     int tas_prop,
    385     int port,
    386     int cos,
    387     int *value)
    388 {
    389     bcmi_esw_tas_control_t  *tc = NULL;
    390     int p = port;
    391     int c = cos;
    392     tas_prop_info_t  *prop_info;
    393 
    394     if (value == NULL) {
    395         return BCM_E_PARAM;
    396     }
    397     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
    398 
    399     if (port == -1) {
    400         p = 0;
    401     }
    402     if ((p < 0) || (p >= tc->profile_list_count)) {
    403         return BCM_E_PARAM;
    404     }
    405     if (cos == -1) {
    406         c = 0;
    407     }
    408     if ((c < 0) || (c >= BCM_COS_COUNT)) {
    409         return BCM_E_PARAM;
    410     }
    411     prop_info = &tc->tas_properties[p];
    412     switch (tas_prop) {
    413     case TAS_PROP_TXOVERRUN:
    414         /* won't reference cos */
    415         *value = (int)prop_info->txoverrun;
    416         break;
    417     case TAS_PROP_HOLDADVANCE:
    418         /* won't reference cos */
    419         *value = (int)prop_info->holdadvance;
    420         break;
    421     case TAS_PROP_MAXSDU:
    422         /* Valid when txoverrun is considered */
    423         if (prop_info->txoverrun) {
    424             if ((port == -1) || (cos == -1)) {
    425                 /* if port or cos is not specified,
    426                  * always return default value.
    427                  */
    428                 *value = 1522;
    429             } else {
    430                 *value = prop_info->maxsdu[c];
    431             }
    432         } else {
    433             return BCM_E_UNAVAIL;
    434         }
    435         break;
    436     default:
    437         return BCM_E_UNAVAIL;
    438     }
    439     return BCM_E_NONE;
    440 }
    441 
    442 /*
    443  * Function:
    444  *     bcmi_esw_tas_control_set
    445  * Purpose:
    446  *     Set various configurations for TAS.
    447  *     Internal function to dispatch to device specific function.
    448  * Parameters:
    449  *     unit             - (IN) unit number
    450  *     port             - (IN) gport id
    451  *     type             - (IN) tas control type defined in bcm_cos_tas_control_t
    452  *     arg              - (IN) tas control value
    453  * Returns:
    454  *     BCM_E_XXX
    455  * Notes:
    456  *     Most of the TAS configurations are on port basis. For some configuration
    457  *     which is on system basis, the gport should assign to -1.
    458  */
    459 int
    460 bcmi_esw_tas_control_set(
    461     int unit,
    462     bcm_gport_t port,
    463     bcm_cosq_tas_control_t type,
    464     int arg)
    465 {
    466     bcm_port_t lport = -1;
    467     bcmi_esw_tas_control_t  *tc = NULL;
    468     const tas_drv_t *td;
    469 
    470     if (type == bcmCosqTASControlTASPTPLock) {
    471         /* bcmCosqTASControlTASPTPLock only take gport=-1 */
    472         if (port != BCM_GPORT_INVALID) {
    473             return BCM_E_PARAM;
    474         }
    475     } else {
    476         BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport));
    477     }
    478 
    479     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
    480 
    481     td = tc->tas_drvs;
    482     if (td->tas_control_set != NULL) {
    483         return td->tas_control_set(unit, lport, type, arg);
    484     }
    485 
    486     return BCM_E_UNAVAIL;
    487 }
    488 
    489 /*
    490  * Function:
    491  *     bcmi_esw_tas_control_get
    492  * Purpose:
    493  *     Get various configurations for TAS.
    494  *     Internal function to dispatch to device specific function.
    495  * Parameters:
    496  *     unit             - (IN) unit number
    497  *     port             - (IN) gport id
    498  *     type             - (IN) tas control type defined in bcm_cos_tas_control_t
    499  *     arg              - (OUT) tas control value
    500  * Returns:
    501  *     BCM_E_XXX
    502  * Notes:
    503  *     Most of the TAS configurations are on port basis. For some configuration
    504  *     which is on system basis, the gport should assign to -1.
    505  */
    506 int
    507 bcmi_esw_tas_control_get(
    508     int unit,
    509     bcm_gport_t port,
    510     bcm_cosq_tas_control_t type,
    511     int *arg)
    512 {
    513     bcm_port_t lport = -1;
    514     bcmi_esw_tas_control_t  *tc = NULL;
    515     const tas_drv_t *td;
    516 
    517     if (type == bcmCosqTASControlTASPTPLock) {
    518         /* bcmCosqTASControlTASPTPLock only take gport=-1 */
    519         if (port != BCM_GPORT_INVALID) {
    520             return BCM_E_PARAM;
    521         }
    522     } else {
    523         BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport));
    524     }
    525     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
    526 
    527     td = tc->tas_drvs;
    528     if (td->tas_control_get != NULL) {
    529         return td->tas_control_get(unit, lport, type, arg);
    530     }
    531 
    532     return BCM_E_UNAVAIL;
    533 }
    534 
    535 /*
    536  * Function:
    537  *     bcm_esw_tas_status_get
    538  * Purpose:
    539  *     Get TAS status by specifying the type.
    540  *     Internal function to dispatch to device specific function.
    541  * Parameters:
    542  *     unit             - (IN) unit number
    543  *     port             - (IN) gport id
    544  *     type             - (IN) tas status type defined in bcm_cos_tas_status_t
    545  *     arg              - (OUT) tas status value
    546  * Returns:
    547  *     BCM_E_XXX
    548  */
    549 int
    550 bcmi_esw_tas_status_get(
    551     int unit,
    552     bcm_gport_t port,
    553     bcm_cosq_tas_status_t type,
    554     int *arg)
    555 {
    556     bcmi_esw_tas_control_t  *tc = NULL;
    557     bcm_port_t lport;
    558     const tas_drv_t *td;
    559 
    560     BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport));
    561     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
    562 
    563     td = tc->tas_drvs;
    564     if (td->tas_status_get != NULL) {
    565         return td->tas_status_get(unit, lport, type, arg);
    566     }
    567     return BCM_E_UNAVAIL;
    568 }
    569 
    570 /* Time helper function */
    571 #define TAS_PTP_STACK_ID    (0)
    572 #define TAS_PTP_CLOCK_NUM   (0)
    573 /*
    574  * Function:
    575  *     bcmi_tas_current_time
    576  * Purpose:
    577  *     Get the current PTP time
    578  * Parameters:
    579  *     unit             - (IN) unit number
    580  *     current_time     - (OUT) current time
    581  * Returns:
    582  *     BCM_E_XXX
    583  */
    584 int
    585 bcmi_tas_current_time(int unit, bcm_ptp_timestamp_t *current_time)
    586 {
    587     int     rv = BCM_E_UNAVAIL;
    588     char    s[32];
    589 
    590     if (current_time == NULL) {
    591         return BCM_E_PARAM;
    592     }
    593 #if defined(INCLUDE_PTP)
    594     if (soc_feature(unit, soc_feature_ptp) ||
    595         soc_feature(unit, soc_feature_use_local_1588)) {
    596         rv = bcm_esw_ptp_clock_time_get(unit, TAS_PTP_STACK_ID,
    597                                         TAS_PTP_CLOCK_NUM, current_time);
    598     } else
    599 #endif
    600     {
    601         return BCM_E_UNAVAIL;
    602     }
    603     if (bsl_check(bslLayerBcm, bslSourceTas, bslSeverityDebug, unit)) {
    604         _shr_format_uint64_hexa_string(current_time->seconds, s);
    605         LOG_DEBUG(BSL_LS_BCM_TAS,
    606                   (BSL_META_U(unit, "Time stamp: sec: %s ns %09u\n"),
    607                    s, (unsigned)current_time->nanoseconds));
    608     }
    609     return rv;
    610 }
    611 
    612 /*
    613  * Function:
    614  *     bcmi_tas_ptp_to_ns
    615  * Purpose:
    616  *     Helper function to covert ptp to nanoseconds.
    617  * Parameters:
    618  *     ptp_time         - (IN) ptp time in bcm_ptp_timestamp_t format
    619  * Returns:
    620  *     time in nanoseconds
    621  */
    622 uint64
    623 bcmi_tas_ptp_to_ns(bcm_ptp_timestamp_t ptp_time)
    624 {
    625     uint64 time;
    626     uint32 one_sec = TAS_PTP_TIME_NANOSEC_MAX;
    627 
    628     COMPILER_64_COPY(time, ptp_time.seconds);
    629     COMPILER_64_UMUL_32(time, one_sec);
    630     COMPILER_64_ADD_32(time, ptp_time.nanoseconds);
    631 
    632     return time;
    633 }
    634 
    635 /*
    636  * Function:
    637  *     bcmi_tas_ns_to_ptp
    638  * Purpose:
    639  *     Helper function to covert nanoseconds to PTP
    640  * Parameters:
    641  *     ns               - (IN) time in nanoseconds
    642  *     ptp_time         - (OUT) ptp time in bcm_ptp_timestamp_t format
    643  */
    644 void
    645 bcmi_tas_ns_to_ptp(uint64 ns, bcm_ptp_timestamp_t *ptp_time)
    646 {
    647     uint64 one_sec, sec;
    648     uint32 nsec;
    649 
    650     if (ptp_time == NULL) {
    651         LOG_ERROR(BSL_LS_BCM_TAS,
    652                   (BSL_META("ptp_time ptr is NULL !\n")));
    653         return;
    654     }
    655     /* temp parameter to do 64bit operation */
    656     COMPILER_64_SET(one_sec, 0, TAS_PTP_TIME_NANOSEC_MAX);
    657     COMPILER_64_COPY(sec, ns);
    658 
    659     /* sec = ns/TAS_PTP_TIME_NANOSEC_MAX */
    660     COMPILER_64_UDIV_64(sec, one_sec);
    661     ptp_time->seconds = sec;
    662 
    663     /* nsec = ns % TAS_PTP_TIME_NANOSEC_MAX; */
    664     /* mod(x,y) = x - y*int(x/y) */
    665     COMPILER_64_UMUL_32(sec, TAS_PTP_TIME_NANOSEC_MAX);
    666     COMPILER_64_SUB_64(ns, sec);
    667     COMPILER_64_TO_32_LO(nsec, ns);
    668 
    669     ptp_time->nanoseconds = nsec;
    670 }
    671 
    672 /*
    673  * Function:
    674  *     bcmi_esw_tas_profile_delay_param_get
    675  * Purpose:
    676  *     Helper function to get the device-specific delay paramaters which are
    677  *     used to do the profile entry remap.
    678  *
    679  * Parameters:
    680  *     unit              - (IN) unit number
    681  *     tas_delay_param   - (IN) TAS_DPARAM_xxx to specify which delay param
    682  *     port              - (IN) logical port
    683  *     qmap              - (IN) queue bitmap, optional and valid for type
    684  *                         TAS_DPARAM_TGCR_DYNAMIC.
    685  *     value             - (OUT) value in ns
    686  * Returns:
    687  *     BCM_E_XXX
    688  */
    689 int
    690 bcmi_esw_tas_profile_delay_param_get(
    691     int unit,
    692     int tas_delay_param,
    693     bcm_port_t port,
    694     uint32 qmap,
    695     int *value)
    696 {
    697     bcmi_esw_tas_control_t  *tc = NULL;
    698     const tas_drv_t *td;
    699 
    700     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
    701 
    702     td = tc->tas_drvs;
    703     if (td->tas_profile_delay_param_get != NULL) {
    704         return td->tas_profile_delay_param_get(unit, tas_delay_param, port,
    705                                                qmap, value);
    706     }
    707     return BCM_E_UNAVAIL;
    708 }
    709 
    710 /*
    711  * Function:
    712  *     bcmi_tas_profile_entries_remap
    713  * Purpose:
    714  *     Entry remap function.
    715  *     To mitigate the Tx overrun on gate closure and Hold-Advance when
    716  *     preemption is enabled, extra entries might be added.
    717  *     And the remap algorithm is general but the delay parmeters
    718  *     are device dependent.
    719  *
    720  * Parameters:
    721  *     unit              - (IN) unit number
    722  *     lport             - (IN) logical port
    723  *     num_entries       - (IN) numbers of entries in tas entries
    724  *     entries           - (IN) tas entries
    725  *     num_new_entries   - (OUT) numbers of remapped entries
    726  *     new_entries       - (OUT) remapped tas entries
    727  * Returns:
    728  *     BCM_E_XXX
    729  */
    730 STATIC int
    731 bcmi_tas_profile_entries_remap(
    732     int unit,
    733     bcm_port_t lport,
    734     int num_entries,
    735     bcm_cosq_tas_entry_t *entries,
    736     int *num_new_entries,
    737     bcm_cosq_tas_entry_t **new_entries)
    738 {
    739     bcm_cosq_tas_entry_t *hw_entries = NULL, *tas_entry, *n_tas_entry;
    740     bcm_gport_t gport;
    741     uint8 preemption_enable = 0, last_valid_entry;
    742     int rv = BCM_E_UNAVAIL;
    743     int prop_tgcr, prop_tha, tgcr, tgcr_txpkt, tha, tgcr_ticks, tha_ticks;
    744     int tgcr_fix;
    745     int i, num_hw_entries, ticks, extra_enties, hw_index;
    746     uint32 status, preempt_bmp = 0, o_phold = 0, phold = 0;
    747     uint32 o_qstate, qstate, xor_qstate, qdiff_tgcr, qdiff_tha;
    748 
    749     if (num_new_entries == NULL) {
    750         return BCM_E_PARAM;
    751     }
    752     if (new_entries == NULL) {
    753         return BCM_E_PARAM;
    754     }
    755     BCM_IF_ERROR_RETURN(bcm_esw_port_gport_get(unit, lport, &gport));
    756 
    757     /* Get the soc property */
    758     BCM_IF_ERROR_RETURN(
    759         bcmi_esw_tas_property_get(unit, TAS_PROP_TXOVERRUN, lport,
    760                                   -1, &prop_tgcr));
    761     BCM_IF_ERROR_RETURN(
    762         bcmi_esw_tas_property_get(unit, TAS_PROP_HOLDADVANCE, lport,
    763                                   -1, &prop_tha));
    764     if ((prop_tgcr == 0) && (prop_tha == 0)) {
    765         /* We don't need to do entry remap, simply copy and return */
    766         /* Create remap entries */
    767         num_hw_entries = num_entries;
    768         TAS_ALLOC(unit, hw_entries, bcm_cosq_tas_entry_t,
    769                   sizeof(bcm_cosq_tas_entry_t) * num_hw_entries,
    770                   "tas profile hw entries", 0, rv);
    771         if (BCM_FAILURE(rv)) {
    772             return rv;
    773         }
    774         sal_memcpy(hw_entries, entries,
    775                    sizeof(bcm_cosq_tas_entry_t) * num_hw_entries);
    776         *new_entries = hw_entries;
    777         *num_new_entries = num_hw_entries;
    778         return BCM_E_NONE;
    779     }
    780 
    781     BCM_IF_ERROR_RETURN(
    782         bcm_esw_cosq_tas_control_get(
    783             unit, gport, bcmCosqTASControlGateControlTickInterval,
    784             &ticks));
    785 
    786     /* Check if Preemption is active */
    787     if (soc_feature(unit, soc_feature_preemption)) {
    788         status = bcmPortPreemptStatusTxInactive;
    789         rv = bcm_esw_port_preemption_status_get(unit, gport,
    790                                                 bcmPortPreemptStatusTx,
    791                                                 &status);
    792         if (BCM_SUCCESS(rv) && (status == bcmPortPreemptStatusTxActive)) {
    793             preemption_enable = 1;
    794             BCM_IF_ERROR_RETURN(
    795                 bcm_esw_port_preemption_control_get(
    796                     unit, gport, bcmPortPreemptControlQueueBitmap,
    797                     &preempt_bmp));
    798         }
    799     }
    800 
    801     /* Calculate the number of the extra entries */
    802     /* initialize the old entry state o_qstate = the entry[0] state */
    803     o_qstate = entries[0].state;
    804     extra_enties = 0;
    805     last_valid_entry = 0;
    806     for (i = 1; i < num_entries; i++) {
    807         tas_entry = &entries[i];
    808         if ((tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_GO_FIRST) ||
    809             (last_valid_entry)) {
    810             /* Do not compare with the entry with interval == 0 where the
    811              * entry state will not be referenced.
    812              */
    813             break;
    814         }
    815         if (tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_STAY) {
    816             /*
    817              * For ticks stay entry, its state will be referenced.
    818              * Still need to do the remap. But should leave in the
    819              * next loop.
    820              */
    821             last_valid_entry = 1;
    822         }
    823         qstate = tas_entry->state;
    824         /* Get the 0->1 or 1->0 change bitmap */
    825         xor_qstate = o_qstate ^ qstate;
    826         if (prop_tgcr) {
    827             /* check if any 1 -> 0 change */
    828             qdiff_tgcr = xor_qstate & o_qstate;
    829             if (qdiff_tgcr) {
    830                 extra_enties++;
    831                 o_qstate = qstate;
    832                 continue;
    833             }
    834         }
    835         if (preemption_enable) {
    836             if (prop_tha) {
    837                 /* Tha is required only when preemption is enabled. */
    838                 /* check if any 0 -> 1 change on express queue */
    839                 qdiff_tha = xor_qstate & qstate;
    840                 qdiff_tha &= ~preempt_bmp;
    841                 if (qdiff_tha) {
    842                     extra_enties++;
    843                     o_qstate = qstate;
    844                     continue;
    845                 }
    846             }
    847         }
    848         o_qstate = qstate;
    849     }
    850 
    851     if (prop_tgcr) {
    852         /* Get the fixed tgcr value exclude tgcr_txpkt value which depends on
    853          * the queue */
    854         BCM_IF_ERROR_RETURN(
    855             bcmi_esw_tas_profile_delay_param_get(unit, TAS_DPARAM_TGCR_FIXED,
    856                                                  lport, 0, &tgcr_fix));
    857     }
    858     if (prop_tha && preemption_enable) {
    859         /* Get the Tha value */
    860         BCM_IF_ERROR_RETURN(
    861             bcmi_esw_tas_profile_delay_param_get(unit, TAS_DPARAM_THA,
    862                                                  lport, 0, &tha));
    863     }
    864     /* Create remap entries */
    865     num_hw_entries = num_entries + extra_enties;
    866     TAS_ALLOC(unit, hw_entries, bcm_cosq_tas_entry_t,
    867               sizeof(bcm_cosq_tas_entry_t) * num_hw_entries,
    868               "tas profile hw entries", 0, rv);
    869     if (BCM_FAILURE(rv)) {
    870         return rv;
    871     }
    872     /* Assign the remap entires */
    873     /* Initialize the old entry state o_qstate = the entry[0] state */
    874     o_qstate = entries[0].state;
    875     hw_index = 0;
    876     last_valid_entry = 0;
    877     /* Start from user entry[1] */
    878     for (i = 1; i < num_entries; i++) {
    879         o_phold = 0;
    880         phold = 0;
    881         qdiff_tgcr = 0;
    882         qdiff_tha = 0;
    883         /*
    884          * Remap decision : according to the difference between two continuous
    885          * user entries.
    886          */
    887         n_tas_entry = &entries[i];
    888         tas_entry = &entries[i - 1];
    889         if (last_valid_entry == 1) {
    890             /* When the last valid_entry hit, leave the loop */
    891             break;
    892         }
    893         if (n_tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_GO_FIRST) {
    894             /*
    895              * Do not compare with the entry with interval == 0 where the
    896              * entry state will not be referenced.
    897              * Directly write i-1 entry and leave the for loop.
    898              */
    899             sal_memcpy(&hw_entries[hw_index], tas_entry,
    900                        sizeof(bcm_cosq_tas_entry_t));
    901             hw_index++;
    902             break;
    903         } else {
    904             if (n_tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_STAY) {
    905                 /*
    906                  * For ticks stay entry, its state will be referenced.
    907                  * Still need to do the remap. But should leave in the
    908                  * next loop.
    909                  */
    910                 last_valid_entry = 1;
    911             }
    912             /* Get the next user entry state */
    913             qstate = n_tas_entry->state;
    914             /* Any 0->1 or 1->0 change bitmap */
    915             xor_qstate = o_qstate ^ qstate;
    916             if (prop_tgcr) {
    917                 /*
    918                  * To consider Tgcr case :
    919                  *   Any gate open to close (1 -> 0) change need the Tgcr
    920                  */
    921                 qdiff_tgcr = xor_qstate & o_qstate;
    922             }
    923             if (preemption_enable) {
    924                 /*
    925                  * When preemption is enabled, any expess queue is open,
    926                  * the phold should be 1.
    927                  */
    928                 o_phold = o_qstate & ~preempt_bmp;
    929                 if (prop_tha) {
    930                     /*
    931                      * To consider Tha case :
    932                      *   Tha is required only when preemption is enabled.
    933                      *   Any express queue gate from close to open need Tha.
    934                      *   If any express queue has gate from open to close,
    935                      *   we need to consider Tgcr instead.
    936                      */
    937                     if (qdiff_tgcr & ~preempt_bmp) {
    938                         qdiff_tha = 0;
    939                     } else {
    940                         qdiff_tha = xor_qstate & qstate;
    941                         qdiff_tha &= ~preempt_bmp;
    942                     }
    943                 }
    944                 if (qdiff_tgcr) {
    945                     /*
    946                      * Any express queue has 1->0 change : set phold request
    947                      * to prevent preemptable traffic tx overrun
    948                      */
    949                      phold = qdiff_tgcr & ~preempt_bmp;
    950                 }
    951             }
    952         }
    953 
    954         /* hw_index used to program to remapped(hw) table */
    955         if (hw_index >= num_hw_entries) {
    956             /* There must have something wrong that the hw_index exceed
    957              * num_hw_entries. */
    958             TAS_FREE(unit, hw_entries, 0);
    959             return BCM_E_INTERNAL;
    960         }
    961         /* Tha has higher precedence */
    962         if (qdiff_tha) {
    963             /* Validate the Tha against the entry->ticks */
    964             tha_ticks = (tha + ticks - 1) / ticks;
    965             if (tha_ticks >= tas_entry->ticks) {
    966                 LOG_ERROR(BSL_LS_BCM_TAS,
    967                           (BSL_META_U(unit, "System required Hold Advance time"
    968                                       " Tha tick %d beyond the calendar table "
    969                                       "entry[%d]ticks %d\n"),
    970                            tha_ticks, i, tas_entry->ticks));
    971                 TAS_FREE(unit, hw_entries, 0);
    972                 return BCM_E_PARAM;
    973             }
    974             /*
    975              * Adjust the entries :
    976              * new entry state = previous entry state
    977              * previous entry tick = Ti - Tha
    978              * new entry tick = Tha
    979              * previous entry hold_request = o_phold
    980              * new entry hold_request = 1
    981              */
    982             hw_entries[hw_index].ticks = tas_entry->ticks - tha_ticks;
    983             hw_entries[hw_index].state = tas_entry->state;
    984             if (o_phold) {
    985                 hw_entries[hw_index].flags = tas_entry->flags |
    986                                              BCM_COSQ_TAS_ENTRY_F_PREEMPT;
    987             } else {
    988                 hw_entries[hw_index].flags = tas_entry->flags &
    989                                              ~BCM_COSQ_TAS_ENTRY_F_PREEMPT;
    990             }
    991             hw_index++;
    992             hw_entries[hw_index].ticks = tha_ticks;
    993             hw_entries[hw_index].state = tas_entry->state;
    994             hw_entries[hw_index].flags = tas_entry->flags |
    995                                          BCM_COSQ_TAS_ENTRY_F_PREEMPT;
    996         } else if (qdiff_tgcr) {
    997             /*
    998              * Tgcr dynamic value need to include the tgcr_txpkt vlaue which is
    999              * depending on the specified queue.
   1000              */
   1001             rv = bcmi_esw_tas_profile_delay_param_get(
   1002                     unit, TAS_DPARAM_TGCR_DYNAMIC, lport, qdiff_tgcr,
   1003                     &tgcr_txpkt);
   1004             if (BCM_FAILURE(rv)) {
   1005                 TAS_FREE(unit, hw_entries, 0);
   1006                 return rv;
   1007             }
   1008 
   1009             tgcr = tgcr_fix + tgcr_txpkt;
   1010             tgcr_ticks = (tgcr + ticks - 1) / ticks;
   1011             /* Validate the Tgcr against the entry->ticks */
   1012             if (tgcr_ticks >= tas_entry->ticks) {
   1013                 LOG_ERROR(BSL_LS_BCM_TAS,
   1014                           (BSL_META_U(unit, "System required gate close "
   1015                                       "response time Tgcr tick %d beyond the "
   1016                                       "calendar table entry[%d]ticks %d\n"),
   1017                            tgcr_ticks, i, tas_entry->ticks));
   1018                 TAS_FREE(unit, hw_entries, 0);
   1019                 return BCM_E_PARAM;
   1020             }
   1021             /*
   1022              * Adjust the entries :
   1023              * new entry state = 0 (all closed)
   1024              * previous entry tick = Ti - Tgcr
   1025              * new entry tick = tgcr
   1026              * previous entry hold_request = o_phold
   1027              * new entry hold_request = phold
   1028              */
   1029             hw_entries[hw_index].ticks = tas_entry->ticks - tgcr_ticks;
   1030             hw_entries[hw_index].state = tas_entry->state;
   1031             if (o_phold) {
   1032                 hw_entries[hw_index].flags = tas_entry->flags |
   1033                                              BCM_COSQ_TAS_ENTRY_F_PREEMPT;
   1034             } else {
   1035                 hw_entries[hw_index].flags = tas_entry->flags &
   1036                                              ~BCM_COSQ_TAS_ENTRY_F_PREEMPT;
   1037             }
   1038             hw_index++;
   1039             hw_entries[hw_index].ticks = tgcr_ticks;
   1040             hw_entries[hw_index].state = 0;
   1041             if (phold) {
   1042                 hw_entries[hw_index].flags = tas_entry->flags |
   1043                                              BCM_COSQ_TAS_ENTRY_F_PREEMPT;
   1044             } else {
   1045                 hw_entries[hw_index].flags = tas_entry->flags &
   1046                                              ~BCM_COSQ_TAS_ENTRY_F_PREEMPT;
   1047             }
   1048         } else {
   1049             /* no need to adjust */
   1050             sal_memcpy(&hw_entries[hw_index], tas_entry,
   1051                        sizeof(bcm_cosq_tas_entry_t));
   1052         }
   1053         hw_index++;
   1054         o_qstate = qstate;
   1055     }
   1056 
   1057     if (hw_index >= num_hw_entries) {
   1058         /*
   1059          * There must have something wrong that the hw_index exceed
   1060          * num_hw_entries.
   1061          */
   1062         TAS_FREE(unit, hw_entries, 0);
   1063         return BCM_E_INTERNAL;
   1064     }
   1065     /* Program the last effective entry.
   1066      * We do not compare the last entry with the first one
   1067      */
   1068     if (hw_index == 0) {
   1069         /* Consider the case when num_entries == 1 */
   1070         tas_entry = &entries[0];
   1071     } else {
   1072         /* Update the last entry to HW table */
   1073         if (i < num_entries) {
   1074             /* GO_FIRST or STAY break case */
   1075             tas_entry = &entries[i];
   1076         } else {
   1077             tas_entry = &entries[num_entries - 1];
   1078         }
   1079     }
   1080     sal_memcpy(&hw_entries[hw_index], tas_entry,
   1081                sizeof(bcm_cosq_tas_entry_t));
   1082 
   1083     *new_entries = hw_entries;
   1084     *num_new_entries = num_hw_entries;
   1085 
   1086     return BCM_E_NONE;
   1087 }
   1088 
   1089 /*
   1090  * Function:
   1091  *     bcmi_tas_profile_idx_get
   1092  * Purpose:
   1093  *     Get the inactive hw index. We need to program to the inactive sets
   1094  * Parameters:
   1095  *     unit             - (IN) unit number
   1096  *     lport            - (IN) logical port
   1097  *     config_idx       - (OUT) inactive hw index
   1098  * Returns:
   1099  *     BCM_E_XXX
   1100  */
   1101 STATIC int
   1102 bcmi_tas_profile_idx_get(int unit, bcm_port_t lport, int *config_idx)
   1103 {
   1104     bcmi_esw_tas_control_t  *tc = NULL;
   1105     const tas_drv_t *td;
   1106     int rv = BCM_E_UNAVAIL;
   1107 
   1108     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1109 
   1110     td = tc->tas_drvs;
   1111     if (td->tas_profile_idx_get != NULL) {
   1112         rv = td->tas_profile_idx_get(unit, lport, config_idx);
   1113     }
   1114     return rv;
   1115 }
   1116 
   1117 /*
   1118  * Function:
   1119  *     bcmi_tas_profile_entries_write
   1120  * Purpose:
   1121  *     Program the profile entries to HW
   1122  * Parameters:
   1123  *     unit              - (IN) unit number
   1124  *     lport             - (IN) logical port
   1125  *     config_idx        - (IN) hw config idx
   1126  *     entries           - (IN) profile entries
   1127  *     num_entries       - (IN) number of entries
   1128  * Returns:
   1129  *     BCM_E_XXX
   1130  */
   1131 STATIC int
   1132 bcmi_tas_profile_entries_write(
   1133     int unit,
   1134     bcm_port_t lport,
   1135     int config_idx,
   1136     bcm_cosq_tas_entry_t *entries,
   1137     int num_entries)
   1138 {
   1139     bcmi_esw_tas_control_t  *tc = NULL;
   1140     const tas_drv_t *td;
   1141     int rv = BCM_E_UNAVAIL;
   1142 
   1143     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1144 
   1145     td = tc->tas_drvs;
   1146     if (td->tas_profile_entries_write != NULL) {
   1147         rv = td->tas_profile_entries_write(unit, lport, config_idx, entries,
   1148                                            num_entries);
   1149     }
   1150     return rv;
   1151 }
   1152 
   1153 /*
   1154  * Function:
   1155  *      bcmi_tas_profile_schedule_config
   1156  * Purpose:
   1157  *      Device specific function to schedule the proper time to program the
   1158  *      time information to HW. Also provide the callback function to call when
   1159  *      the time information programmed to HW and kick-off the config change.
   1160  *      In the callback function, the profile state should be changed to
   1161  *      "committed".
   1162  * Parameters:
   1163  *     unit              - (IN) unit number
   1164  *     lport             - (IN) logical port
   1165  *     base_time         - (IN) new base time
   1166  *     cycle_time        - (IN) new cycle time
   1167  *     cycle_extension   - (IN) new cycle extension
   1168  *     cb                - (IN) cb function to call when the time information
   1169  *                              programmed to HW and kick-off the
   1170  *                              config change.
   1171  *     fn_data           - (IN) fn_data to supply in the callback
   1172  * Returns:
   1173  *     BCM_E_XXX
   1174  */
   1175 STATIC int
   1176 bcmi_tas_profile_schedule_config(int unit, bcm_port_t lport,
   1177                                  bcm_ptp_timestamp_t base_time,
   1178                                  uint32 cycle_time, uint32 cycle_extension,
   1179                                  profile_commit_cb_fn cb, void *fn_data)
   1180 {
   1181     bcmi_esw_tas_control_t  *tc = NULL;
   1182     const tas_drv_t *td;
   1183     int rv = BCM_E_UNAVAIL;
   1184 
   1185     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1186 
   1187     td = tc->tas_drvs;
   1188     if (td->tas_profile_schedule_config != NULL) {
   1189         rv = td->tas_profile_schedule_config(unit, lport, base_time,
   1190                                              cycle_time, cycle_extension,
   1191                                              cb, fn_data);
   1192     }
   1193     return rv;
   1194 }
   1195 
   1196 /*
   1197  * Function:
   1198  *  bcmi_tas_profile_change
   1199  * Purpose:
   1200  *  Issue the config change to HW.
   1201  *  Used for non-PTP mode.
   1202  * Parameters:
   1203  *     unit             - (IN) unit number
   1204  *     port             - (IN) logical port
   1205  * Returns:
   1206  *     BCM_E_XXX
   1207  */
   1208 STATIC int
   1209 bcmi_tas_profile_change(int unit, bcm_port_t lport)
   1210 {
   1211     bcmi_esw_tas_control_t  *tc = NULL;
   1212     const tas_drv_t *td;
   1213     int rv = BCM_E_UNAVAIL;
   1214 
   1215     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1216 
   1217     td = tc->tas_drvs;
   1218     if (td->tas_profile_change != NULL) {
   1219         rv = td->tas_profile_change(unit, lport);
   1220     }
   1221     return rv;
   1222 }
   1223 
   1224 /*
   1225  * Function:
   1226  *     tas_pid_get
   1227  * Purpose:
   1228  *     Get the profile id by specifying port
   1229  * Parameters:
   1230  *     unit             - (IN) unit number
   1231  *     lport            - (IN) logical port
   1232  *     pid              - (OUT) profile id
   1233  * Returns:
   1234  *     BCM_E_XXX
   1235  */
   1236 STATIC int
   1237 tas_pid_get(int unit, bcm_port_t lport, bcm_cosq_tas_profile_id_t *pid)
   1238 {
   1239     int max_count; /* Maximum number of pid to try */
   1240     static uint32 last_allocated_pid = 0;
   1241     tas_profile_ctrl_t *tp;
   1242     bcm_cosq_tas_profile_id_t temp_pid;
   1243     int rv = BCM_E_NONE;
   1244 
   1245     /* pid index should be 1 ~ TAS_PID_IDX_MASK */
   1246     max_count = TAS_PID_IDX_MASK;
   1247 
   1248     while (max_count--) {
   1249         /* increse the pid index */
   1250         last_allocated_pid++;
   1251         /* Handle the wrap case */
   1252         if (TAS_PID_IDX_MASK == last_allocated_pid) {
   1253             last_allocated_pid = 1;
   1254         }
   1255         /* Check the pid is used or not */
   1256         temp_pid = last_allocated_pid | (lport << TAS_PID_PORT_START_BIT);
   1257         rv = tas_profile_ctrl_get(unit, temp_pid, &tp);
   1258         if (BCM_E_NOT_FOUND == rv) {
   1259             /* Not used by others, take this as for the new profile */
   1260             *pid = temp_pid;
   1261             return (BCM_E_NONE);
   1262         }
   1263         if (BCM_FAILURE(rv)) {
   1264             return (rv);
   1265         }
   1266     }
   1267     return (BCM_E_RESOURCE);
   1268 }
   1269 
   1270 /*
   1271  * Function:
   1272  *     tas_profile_profile_param_validate
   1273  * Purpose:
   1274  *     Parameter check for bcmi_esw_tas_profile_create
   1275  * Parameters:
   1276  *     unit             - (IN) unit number
   1277  *     port             - (IN) gport
   1278  *     profile          - (IN) bcm profile structure
   1279  * Returns:
   1280  *     BCM_E_XXX
   1281  */
   1282 STATIC int
   1283 tas_profile_profile_param_validate(
   1284     int unit,
   1285     bcm_gport_t port,
   1286     bcm_cosq_tas_profile_t *profile)
   1287 {
   1288     bcm_ptp_timestamp_t *base_time;
   1289     uint32 cycle_time, cycle_extension;
   1290     int ptp_mode, gclt_size;
   1291     bcmi_esw_tas_control_t  *tc = NULL;
   1292     const tas_drv_t *td;
   1293 
   1294     /* TAS(bcmCosqTASControlTASEnable) is not required during profile create
   1295      * Check ptp_mode for time parameter validation.
   1296      * PTP lock (bcmCosqTASControlTASPTPLock) when ptp_mode = 1 is not required
   1297      * during profile create.
   1298      */
   1299     BCM_IF_ERROR_RETURN(
   1300         bcmi_esw_tas_control_get(unit, port, bcmCosqTASControlUsePTPTime,
   1301                                  &ptp_mode));
   1302     base_time = &profile->ptp_base_time;
   1303     cycle_time = profile->ptp_cycle_time;
   1304     cycle_extension = profile->ptp_max_cycle_extension;
   1305     if (ptp_mode) {
   1306         /* ptp_base should be non-zeros. */
   1307         if (COMPILER_64_IS_ZERO(base_time->seconds) &&
   1308             (base_time->nanoseconds == 0)) {
   1309             return BCM_E_PARAM;
   1310         }
   1311         /* cycle_time should > cycle extension time */
   1312         if (cycle_extension >= cycle_time) {
   1313             return BCM_E_PARAM;
   1314         }
   1315     } else {
   1316         /* ptp_base should be zeros. */
   1317         if (!COMPILER_64_IS_ZERO(base_time->seconds) ||
   1318             (base_time->nanoseconds != 0) ||
   1319             (cycle_time != 0) ||
   1320             (cycle_extension != 0)) {
   1321             return BCM_E_PARAM;
   1322         }
   1323     }
   1324 
   1325     BCM_IF_ERROR_RETURN(
   1326         bcmi_esw_tas_status_get(unit, port, bcmCosqTASStatusMaxCalendarEntries,
   1327                                 &gclt_size));
   1328     /* profile->num_entries should <= device GCLT size */
   1329     if (profile->num_entries > gclt_size) {
   1330         return BCM_E_PARAM;
   1331     }
   1332     /* profile->num_entries should > 0 */
   1333     if (profile->num_entries <= 0) {
   1334         return BCM_E_PARAM;
   1335     }
   1336     /* The first entry should not specify GO_FIRST. */
   1337     if (profile->entries[0].ticks ==
   1338         BCM_COSQ_TAS_ENTRY_TICKS_GO_FIRST) {
   1339         return BCM_E_PARAM;
   1340     }
   1341 
   1342     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1343 
   1344     td = tc->tas_drvs;
   1345     if (td->tas_profile_param_check != NULL) {
   1346         return td->tas_profile_param_check(unit, profile);
   1347     }
   1348 
   1349     return BCM_E_NONE;
   1350 }
   1351 
   1352 /*
   1353  * Function:
   1354  *     tas_profile_create
   1355  * Purpose:
   1356  *    The internal profile resource is created in this function.
   1357  *
   1358  * Parameters:
   1359  *     unit             - (IN) unit number
   1360  *     lport            - (IN) logical port
   1361  *     profile          - (IN) bcm profile
   1362  *     pid              - (OUT) profile id
   1363  * Returns:
   1364  *     BCM_E_XXX
   1365  */
   1366 STATIC int
   1367 tas_profile_create(
   1368     int unit,
   1369     bcm_port_t lport,
   1370     bcm_cosq_tas_profile_t *profile,
   1371     bcm_cosq_tas_profile_id_t *pid)
   1372 {
   1373     bcmi_esw_tas_control_t  *tc = NULL;
   1374     tas_profile_ctrl_t  *tp;
   1375     int num_entries, count = 0;
   1376     int rv = BCM_E_NONE;
   1377 
   1378     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1379 
   1380     TAS_LOCK(tc);
   1381 
   1382     TAS_PROFILE_ITER(tc->profile_list, tp, lport) {
   1383         count++;
   1384     }
   1385 
   1386     if (count >= MAX_TAS_PROFILE_CNT) {
   1387         LOG_ERROR(BSL_LS_BCM_TAS,
   1388                   (BSL_META_U(unit, "Exceed supported profile count %d\n"),
   1389                    MAX_TAS_PROFILE_CNT));
   1390         TAS_UNLOCK(tc);
   1391         return BCM_E_RESOURCE;
   1392     }
   1393     /* Create profile structure */
   1394     TAS_ALLOC(unit, tp, tas_profile_ctrl_t,
   1395               sizeof(tas_profile_ctrl_t),
   1396               "tas profile", 0, rv);
   1397     if (BCM_FAILURE(rv)) {
   1398         TAS_UNLOCK(tc);
   1399         return rv;
   1400     }
   1401     /* Get profile id */
   1402     rv = tas_pid_get(unit, lport, pid);
   1403     if (BCM_FAILURE(rv)) {
   1404         TAS_FREE(unit, tp, 0);
   1405         TAS_UNLOCK(tc);
   1406         return rv;
   1407     }
   1408     /* Create profile lock */
   1409     tp->profile_mutex = sal_mutex_create("tas_profile.lock");
   1410     if (NULL == tp->profile_mutex) {
   1411         TAS_FREE(unit, tp, 0);
   1412         TAS_UNLOCK(tc);
   1413         return BCM_E_RESOURCE;
   1414     }
   1415 
   1416     num_entries = profile->num_entries;
   1417     /* Create tp->user_entries */
   1418     TAS_ALLOC(unit, tp->user_entries, bcm_cosq_tas_entry_t,
   1419               sizeof(bcm_cosq_tas_entry_t) * num_entries,
   1420               "tas profile entries", 0, rv);
   1421     if (BCM_FAILURE(rv)) {
   1422         sal_mutex_destroy(tp->profile_mutex);
   1423         TAS_FREE(unit, tp, 0);
   1424         TAS_UNLOCK(tc);
   1425         return rv;
   1426     }
   1427 
   1428     /* Initialize profile id. */
   1429     tp->port = lport;
   1430     tp->pid = *pid;
   1431     tp->pstate = bcmCosqTASProfileInit;
   1432     tp->hw_index = -1;
   1433     tp->num_user_entries = num_entries;
   1434 
   1435     /* copy valid profile->entries to tp->user_entries */
   1436     sal_memcpy(tp->user_entries, profile->entries,
   1437                sizeof(bcm_cosq_tas_entry_t) * num_entries);
   1438 
   1439     sal_memcpy(&tp->base_time, &profile->ptp_base_time,
   1440                sizeof(bcm_ptp_timestamp_t));
   1441 
   1442     tp->cycle_time = profile->ptp_cycle_time;
   1443     tp->cycle_extension = profile->ptp_max_cycle_extension;
   1444 
   1445     /* Insert profile to tas profile set */
   1446     TAS_PROFILE_INSERT(tc->profile_list, tp, lport);
   1447 
   1448     TAS_UNLOCK(tc);
   1449 
   1450     return BCM_E_NONE;
   1451 }
   1452 
   1453 /*
   1454  * Function:
   1455  *     tas_profile_id_validate
   1456  * Purpose:
   1457  *     Validate the profile id
   1458  * Parameters:
   1459  *     unit             - (IN) unit number
   1460  *     port             - (IN) gport
   1461  *     pid              - (IN) profile id
   1462  *     lport            - (OUT) logical port
   1463  * Returns:
   1464  *     BCM_E_XXX
   1465  */
   1466 STATIC int
   1467 tas_profile_id_validate(
   1468     int unit,
   1469     bcm_gport_t port,
   1470     bcm_cosq_tas_profile_id_t pid,
   1471     bcm_port_t *lport)
   1472 {
   1473     bcm_port_t local_port;
   1474 
   1475     BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &local_port));
   1476 
   1477     if (lport != NULL) {
   1478         *lport = local_port;
   1479     }
   1480     if (local_port != ((pid >> TAS_PID_PORT_START_BIT) & TAS_PID_IDX_MASK)) {
   1481         LOG_DEBUG(BSL_LS_BCM_TAS,
   1482                   (BSL_META_U(unit,
   1483                              "Profile id is not associated with the port.")));
   1484         return BCM_E_PARAM;
   1485     }
   1486     return BCM_E_NONE;
   1487 }
   1488 
   1489 /*
   1490  * Function:
   1491  *     tas_gclt_entries_remap
   1492  * Purpose:
   1493  *     Remap the profile user entries and update the rempped one
   1494  *     to internal profile structure
   1495  * Parameters:
   1496  *     unit             - (IN) unit number
   1497  *     pid              - (IN) pid
   1498  * Returns:
   1499  *     BCM_E_XXX
   1500  */
   1501 STATIC int
   1502 tas_gclt_entries_remap(int unit, bcm_cosq_tas_profile_id_t pid)
   1503 {
   1504     tas_profile_ctrl_t  *tp = NULL;
   1505     bcm_cosq_tas_entry_t    *hw_entries;
   1506     int                     num_hw_entries;
   1507     int                     rv = BCM_E_UNAVAIL;
   1508 
   1509     BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp));
   1510 
   1511     rv = bcmi_tas_profile_entries_remap(unit, tp->port,
   1512                                         tp->num_user_entries,
   1513                                         tp->user_entries,
   1514                                         &num_hw_entries,
   1515                                         &hw_entries);
   1516     if (BCM_FAILURE(rv)) {
   1517         return rv;
   1518     }
   1519 
   1520     tp->num_hw_entries = num_hw_entries;
   1521     tp->hw_entries = hw_entries;
   1522 
   1523     return rv;
   1524 }
   1525 
   1526 /*
   1527  * Function:
   1528  *     tas_profile_commit_validate
   1529  * Purpose:
   1530  *     Function to do below validation before commit the profile
   1531  *      1) Check HW configure (TAS enable? PTP mode/locked? )
   1532  *      2) Do entry remap according to the soc property
   1533  *      3) Check pid status(resource)
   1534  * Parameters:
   1535  *     unit             - (IN) unit number
   1536  *     port             - (IN) gport
   1537  *     tp               - (IN) Internal profile structure
   1538  * Returns:
   1539  *     BCM_E_XXX
   1540  */
   1541 STATIC int
   1542 tas_profile_commit_validate(
   1543     int unit,
   1544     bcm_gport_t port, tas_profile_ctrl_t *tp)
   1545 {
   1546     int tas_enable, ptp_mode, ptp_lock;
   1547     int rv = BCM_E_NONE;
   1548 
   1549     /* Check software resource is available */
   1550     if (tp->pstate != bcmCosqTASProfileInit) {
   1551         LOG_ERROR(BSL_LS_BCM_TAS,
   1552                   (BSL_META_U(unit, "Unable to commit profile in state %s\n"),
   1553                    pstate_string[tp->pstate]));
   1554         return BCM_E_CONFIG;
   1555     }
   1556 
   1557     /* Check tas enable */
   1558     BCM_IF_ERROR_RETURN(
   1559         bcmi_esw_tas_control_get(unit, port, bcmCosqTASControlTASEnable,
   1560                                  &tas_enable));
   1561 
   1562     /* check ptp_mode and ptp_lock */
   1563     BCM_IF_ERROR_RETURN(
   1564         bcmi_esw_tas_control_get(unit, port, bcmCosqTASControlUsePTPTime,
   1565                                  &ptp_mode));
   1566     BCM_IF_ERROR_RETURN(
   1567         bcmi_esw_tas_control_get(unit, -1, bcmCosqTASControlTASPTPLock,
   1568                                  &ptp_lock));
   1569     if (ptp_mode) {
   1570         if (!ptp_lock) {
   1571             LOG_ERROR(BSL_LS_BCM_TAS,
   1572                       (BSL_META_U(unit, "PTP need to be locked to run "
   1573                                   "PTP mode.\n")));
   1574             return BCM_E_CONFIG;
   1575         }
   1576         /*
   1577          * Need to validate basetime compare against currnt time
   1578          * when GateEnable = TRUE
   1579          */
   1580         if (tas_enable) {
   1581             const tas_drv_t         *td;
   1582             bcmi_esw_tas_control_t  *tc = NULL;
   1583 
   1584             BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1585             td = tc->tas_drvs;
   1586             rv = BCM_E_NONE;
   1587             if (td->tas_profile_basetime_check != NULL) {
   1588                 rv = td->tas_profile_basetime_check(unit, tp->base_time);
   1589             }
   1590             if (BCM_FAILURE(rv)) {
   1591                 return rv;
   1592             }
   1593         }
   1594     } else {
   1595         /* For non-PTP mode tas has to be enabled */
   1596         if (!tas_enable) {
   1597             LOG_ERROR(BSL_LS_BCM_TAS,
   1598                       (BSL_META_U(unit, "TAS is not enabled !!\n")));
   1599             return BCM_E_DISABLED;
   1600         }
   1601     }
   1602     /*
   1603      * Prepare the HW profile(gclt) entries
   1604      * Allocate hw ertries resource. And do entry remap if requested
   1605      * from soc property.
   1606      */
   1607     BCM_IF_ERROR_RETURN(
   1608         tas_gclt_entries_remap(unit, tp->pid));
   1609 
   1610     return BCM_E_NONE;
   1611 }
   1612 
   1613 /*
   1614  * Function:
   1615  *      bcmi_tas_profile_event_notify
   1616  * Purpose:
   1617  *    Notified by chip tas interrupt handler
   1618  *
   1619  *    Or notified when TAS is disabled to update the profile state.
   1620  *        active -> expired, commit/pending -> error
   1621  * Parameters:
   1622  *     unit             - (IN) unit number
   1623  *     lport            - (IN) logical port
   1624  *     enable           - (IN) tas is enable or disabled
   1625  * Returns:
   1626  *     BCM_E_XXX
   1627  */
   1628 STATIC int
   1629 bcmi_tas_profile_event_notify(
   1630     int unit,
   1631     bcm_port_t lport,
   1632     bcmi_tas_profile_event_type_t event)
   1633 {
   1634     bcmi_esw_tas_control_t  *tc = NULL;
   1635     bcm_cosq_tas_profile_id_t   active_pid, process_pid;
   1636     tas_profile_ctrl_t  *tp_pending = NULL;
   1637     tas_profile_ctrl_t  *tp_active = NULL;
   1638     int rv;
   1639 
   1640     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1641 
   1642     TAS_LOCK(tc);
   1643     active_pid = tc->active_pid[lport];
   1644     process_pid = tc->process_pid[lport];
   1645     TAS_UNLOCK(tc);
   1646     if (active_pid) {
   1647         rv = tas_profile_ctrl_get(unit, active_pid, &tp_active);
   1648         if (BCM_FAILURE(rv)) {
   1649             TAS_UNLOCK(tc);
   1650             return rv;
   1651         }
   1652     }
   1653     if (process_pid) {
   1654         rv = tas_profile_ctrl_get(unit, process_pid, &tp_pending);
   1655         if (BCM_FAILURE(rv)) {
   1656             TAS_UNLOCK(tc);
   1657             return rv;
   1658         }
   1659     }
   1660 
   1661     switch (event) {
   1662     case bcmiTASProfileEventProfileChange:
   1663         /* Must have the valid process_pid */
   1664         if (!process_pid) {
   1665             return BCM_E_INTERNAL;
   1666         }
   1667         TAS_PROFILE_LOCK(tp_pending);
   1668         tp_pending->pstate = bcmCosqTASProfileActive;
   1669         TAS_PROFILE_UNLOCK(tp_pending);
   1670         if (active_pid) {
   1671             TAS_PROFILE_LOCK(tp_active);
   1672             tp_active->pstate = bcmCosqTASProfileExpired;
   1673             tp_active->hw_index = -1;
   1674             TAS_PROFILE_UNLOCK(tp_active);
   1675         }
   1676         TAS_LOCK(tc);
   1677         tc->active_pid[lport] = process_pid;
   1678         tc->process_pid[lport] = 0;
   1679         TAS_UNLOCK(tc);
   1680         break;
   1681     case bcmiTASProfileEventBaseTimeErr:
   1682         /* HW detects that the base time for new scheduler is already passed.
   1683          * It'll abort the change command and continue the old schedule.
   1684          * So keep the active pid, update the pending pid to error state.
   1685          * Must have the valid process_pid
   1686          */
   1687         if (!process_pid) {
   1688             return BCM_E_INTERNAL;
   1689         }
   1690         TAS_PROFILE_LOCK(tp_pending);
   1691         tp_pending->pstate = bcmCosqTASProfileError;
   1692         tp_pending->hw_index = -1;
   1693         TAS_PROFILE_UNLOCK(tp_pending);
   1694         TAS_LOCK(tc);
   1695         tc->process_pid[lport] = 0;
   1696         TAS_UNLOCK(tc);
   1697         break;
   1698     case bcmiTASProfileEventNextCycleTimeErr:
   1699         /* HW detects the next cycle start time is passed.
   1700          * It'll go back to ERR_GATE_STATE after finish the current cycle.
   1701          * So update the active to error.
   1702          */
   1703     case bcmiTASProfileEventECCErr:
   1704         /* HW detect that 2-bit ecc error when read the GCLT.
   1705          * It'll stop execute GCLT and back to ERR_GATE_STATE.
   1706          */
   1707     case bcmiTASProfileEventPtrErr:
   1708         /* HW detect the read pointer over the GCLT size.
   1709          * It'll stop execute GCLT and back to ERR_GATE_STATE.
   1710          * Above cases must have the valid active_pid
   1711          */
   1712         if (!active_pid) {
   1713             return BCM_E_INTERNAL;
   1714         }
   1715         TAS_PROFILE_LOCK(tp_active);
   1716         tp_active->pstate = bcmCosqTASProfileError;
   1717         tp_active->hw_index = -1;
   1718         TAS_PROFILE_UNLOCK(tp_active);
   1719         TAS_LOCK(tc);
   1720         tc->active_pid[lport] = 0;
   1721         TAS_UNLOCK(tc);
   1722         break;
   1723     case bcmiTASProfileEventTASDisable:
   1724         /* Software prgrame the TAS disable via bcm_cosq_tas_control_set. */
   1725         if (process_pid) {
   1726             TAS_PROFILE_LOCK(tp_pending);
   1727             tp_pending->pstate = bcmCosqTASProfileError;
   1728             tp_pending->hw_index = -1;
   1729             TAS_PROFILE_UNLOCK(tp_pending);
   1730         }
   1731         if (active_pid) {
   1732             TAS_PROFILE_LOCK(tp_active);
   1733             tp_active->pstate = bcmCosqTASProfileExpired;
   1734             tp_active->hw_index = -1;
   1735             TAS_PROFILE_UNLOCK(tp_active);
   1736         }
   1737         TAS_LOCK(tc);
   1738         tc->active_pid[lport] = 0;
   1739         tc->process_pid[lport] = 0;
   1740         TAS_UNLOCK(tc);
   1741         break;
   1742     default:
   1743         break;
   1744     }
   1745 
   1746     LOG_DEBUG(BSL_LS_BCM_TAS,
   1747               (BSL_META_UP(unit, lport,
   1748                            "tas_profile_event_notify profile_event %d \n"
   1749                            "Active profile(pid 0x%08x) state = %s \n"
   1750                            "Pending profile (pid 0x%08x) state = %s \n"),
   1751                event, active_pid,
   1752                active_pid ? pstate_string[tp_active->pstate] : "N/A",
   1753                process_pid,
   1754                process_pid ? pstate_string[tp_pending->pstate] : "N/A"));
   1755     return BCM_E_NONE;
   1756 }
   1757 
   1758 /*
   1759  * Function:
   1760  *      bcmi_tas_commit_callback
   1761  * Purpose:
   1762  *      The callback function to notify the information (config_change_time) of
   1763  *      the scheduled commit-profile.
   1764  *      The profile status will be updated accordingly.
   1765  * Parameters:
   1766  *     unit                 - (IN) unit number
   1767  *     lport                - (IN) logical port
   1768  *     config_change_time   - (IN) config change time
   1769  *     fn_data              - (IN) user data
   1770  * Returns:
   1771  *     BCM_E_XXX
   1772  */
   1773 STATIC int
   1774 bcmi_tas_commit_callback(
   1775     int unit,
   1776     bcm_port_t lport,
   1777     bcm_ptp_timestamp_t config_change_time,
   1778     void *fn_data)
   1779 {
   1780     bcm_cosq_tas_profile_id_t pid;
   1781     bcmi_esw_tas_control_t  *tc = NULL;
   1782     tas_profile_ctrl_t  *tp = NULL;
   1783     int rv;
   1784 
   1785     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   1786     TAS_LOCK(tc);
   1787     pid = tc->process_pid[lport];
   1788     TAS_UNLOCK(tc);
   1789     if (!pid) {
   1790         LOG_DEBUG(BSL_LS_BCM_TAS,
   1791                   (BSL_META_UP(unit, lport,
   1792                                "The commit profile pid is dismissed !")));
   1793         return BCM_E_INTERNAL;
   1794     }
   1795     rv = tas_profile_ctrl_get(unit, pid, &tp);
   1796     if (BCM_FAILURE(rv)) {
   1797         TAS_UNLOCK(tc);
   1798         return rv;
   1799     }
   1800     TAS_PROFILE_LOCK(tp);
   1801     sal_memcpy(&tp->config_change_time, &config_change_time,
   1802                sizeof(bcm_ptp_timestamp_t));
   1803     tp->pstate = bcmCosqTASProfilePending;
   1804     TAS_PROFILE_UNLOCK(tp);
   1805     LOG_DEBUG(BSL_LS_BCM_TAS,
   1806               (BSL_META_UP(unit, lport,
   1807                            "bcmi_tas_commit_callback pid 0x%08x state %s\n"),
   1808                pid, pstate_string[tp->pstate]));
   1809 
   1810     return BCM_E_NONE;
   1811 }
   1812 
   1813 /*
   1814  * Function:
   1815  *     tas_profile_schedule
   1816  * Purpose:
   1817  *     Schedule the process to handle the committed profile.
   1818  *     For PTP mode, invoke the device specific schedule function to handle the
   1819  *     the device progamming constrain on time configurations.
   1820  *     For non-PTP mode, invoke the 'profile change' function.
   1821  * Parameters:
   1822  *     unit             - (IN) unit number
   1823  *     tp               - (IN) internal profile
   1824  * Returns:
   1825  *     BCM_E_XXX
   1826  */
   1827 STATIC int
   1828 tas_profile_schedule(int unit, tas_profile_ctrl_t  *tp)
   1829 {
   1830     int rv = BCM_E_UNAVAIL;
   1831 
   1832     if (tp->cycle_time) {
   1833         rv = bcmi_tas_profile_schedule_config(unit, tp->port, tp->base_time,
   1834                                               tp->cycle_time,
   1835                                               tp->cycle_extension,
   1836                                               bcmi_tas_commit_callback,
   1837                                               NULL);
   1838         if (BCM_FAILURE(rv)) {
   1839             return rv;
   1840         }
   1841     } else {
   1842         /* Issue config change */
   1843         rv = bcmi_tas_profile_change(unit, tp->port);
   1844         if (BCM_FAILURE(rv)) {
   1845             LOG_ERROR(BSL_LS_BCM_TAS,
   1846                       (BSL_META_UP(unit, tp->port,
   1847                                    "Fail to issue config change !!\n")));
   1848             tp->pstate = bcmCosqTASProfileError;
   1849             tp->hw_index = -1;
   1850             return rv;
   1851         }
   1852         tp->pstate = bcmCosqTASProfilePending;
   1853     }
   1854 
   1855     return rv;
   1856 }
   1857 
   1858 /*
   1859  * Function:
   1860  *      tas_profile_commit
   1861  * Purpose:
   1862  *      Program the GCLT only.
   1863  *      Config change and time releated configuration are not in this function.
   1864  * Parameters:
   1865  *     unit             - (IN) unit number
   1866  *     tp               - (IN) Internal profile structure
   1867  * Returns:
   1868  *     BCM_E_XXX
   1869  */
   1870 STATIC int
   1871 tas_profile_commit(int unit, tas_profile_ctrl_t  *tp)
   1872 {
   1873     int config_idx;
   1874     int rv = BCM_E_NONE;
   1875 
   1876     rv = bcmi_tas_profile_idx_get(unit, tp->port, &config_idx);
   1877     if (BCM_FAILURE(rv)) {
   1878         return rv;
   1879     }
   1880     rv = bcmi_tas_profile_entries_write(unit, tp->port, config_idx,
   1881                                         tp->hw_entries, tp->num_hw_entries);
   1882     if (BCM_FAILURE(rv)) {
   1883         return rv;
   1884     }
   1885 
   1886     tp->pstate = bcmCosqTASProfileCommitted;
   1887     tp->hw_index = config_idx;
   1888 
   1889     return BCM_E_NONE;
   1890 }
   1891 
   1892 /*
   1893  * Function:
   1894  *      tas_profile_get
   1895  * Purpose:
   1896  *      Helper function for bcmi_esw_tas_profile_get.
   1897  *      Get the bcm profile information from internal profile.
   1898  * Parameters:
   1899  *     unit             - (IN) unit number
   1900  *     tp               - (IN) internal profile
   1901  *     profile          - (OUT) bcm profile
   1902  * Returns:
   1903  *     BCM_E_XXX
   1904  */
   1905 STATIC int
   1906 tas_profile_get(
   1907     int unit,
   1908     tas_profile_ctrl_t *tp,
   1909     bcm_cosq_tas_profile_t *profile)
   1910 {
   1911     if (profile == NULL) {
   1912         return BCM_E_PARAM;
   1913     }
   1914     bcm_cosq_tas_profile_t_init(profile);
   1915     profile->num_entries = tp->num_user_entries;
   1916     sal_memcpy(&profile->entries, tp->user_entries,
   1917                tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t));
   1918     sal_memcpy(&profile->ptp_base_time, &tp->base_time,
   1919                sizeof(bcm_ptp_timestamp_t));
   1920     profile->ptp_cycle_time = tp->cycle_time;
   1921     profile->ptp_max_cycle_extension = tp->cycle_extension;
   1922 
   1923     return BCM_E_NONE;
   1924 }
   1925 
   1926 /*
   1927  * Function:
   1928  *     tas_profile_set
   1929  * Purpose:
   1930  *      Helper function for bcmi_esw_tas_profile_set
   1931  *      Configure the internal profile database(specified via pid) according to
   1932  *      user configured bcm profile information.
   1933  * Parameters:
   1934  *     unit             - (IN) unit number
   1935  *     tp               - (IN) internal profile
   1936  *     profile          - (IN) bcm profile
   1937  * Returns:
   1938  *     BCM_E_XXX
   1939  */
   1940 STATIC int
   1941 tas_profile_set(
   1942     int unit,
   1943     tas_profile_ctrl_t *tp,
   1944     bcm_cosq_tas_profile_t *profile)
   1945 {
   1946     int rv;
   1947 
   1948     /* Check the profile state */
   1949     if ((tp->pstate == bcmCosqTASProfileCommitted) ||
   1950         (tp->pstate == bcmCosqTASProfilePending) ||
   1951         (tp->pstate == bcmCosqTASProfileActive)) {
   1952         LOG_ERROR(BSL_LS_BCM_TAS,
   1953                   (BSL_META_UP(unit, tp->port, "Unable to set profile in state "
   1954                                "%s\n"), pstate_string[tp->pstate]));
   1955         return BCM_E_CONFIG;
   1956     }
   1957 
   1958     if (profile->num_entries != tp->num_user_entries) {
   1959         TAS_FREE(unit, tp->user_entries, 0);
   1960         tp->user_entries = NULL;
   1961         TAS_ALLOC(unit, tp->user_entries, bcm_cosq_tas_entry_t,
   1962                   sizeof(bcm_cosq_tas_entry_t) * profile->num_entries,
   1963                   "tas profile entries", 0, rv);
   1964         if (BCM_FAILURE(rv)) {
   1965             return rv;
   1966         }
   1967     }
   1968 
   1969     tp->pstate = bcmCosqTASProfileInit;
   1970     tp->num_user_entries = profile->num_entries;
   1971     /* copy valid profile->entries to tp->user_entries */
   1972     sal_memcpy(tp->user_entries, profile->entries,
   1973                sizeof(bcm_cosq_tas_entry_t) * profile->num_entries);
   1974     sal_memcpy(&tp->base_time, &profile->ptp_base_time,
   1975                sizeof(bcm_ptp_timestamp_t));
   1976 
   1977     tp->cycle_time = profile->ptp_cycle_time;
   1978     tp->cycle_extension = profile->ptp_max_cycle_extension;
   1979 
   1980     return BCM_E_NONE;
   1981 }
   1982 
   1983 /*
   1984  * Function:
   1985  *     tas_profile_destroy
   1986  * Purpose:
   1987  *     Helper function for bcmi_esw_tas_profile_destroy.
   1988  *     Destroy and free the resource of the internal profile.
   1989  * Parameters:
   1990  *     unit             - (IN) unit number
   1991  *     tp               - (IN) internal profile
   1992  * Returns:
   1993  *     BCM_E_XXX
   1994  */
   1995 STATIC int
   1996 tas_profile_destroy(int unit, tas_profile_ctrl_t  *tp)
   1997 {
   1998     TAS_PROFILE_LOCK(tp);
   1999     if ((tp->pstate == bcmCosqTASProfileCommitted) ||
   2000         (tp->pstate == bcmCosqTASProfilePending) ||
   2001         (tp->pstate == bcmCosqTASProfileActive)) {
   2002         LOG_ERROR(BSL_LS_BCM_TAS,
   2003                   (BSL_META_UP(unit, tp->port, "Unable to destroy profile in "
   2004                                "state %s\n"),
   2005                    pstate_string[tp->pstate]));
   2006         TAS_PROFILE_UNLOCK(tp);
   2007         return BCM_E_CONFIG;
   2008     }
   2009 
   2010     if (tp->user_entries) {
   2011         TAS_FREE(unit, tp->user_entries, 0);
   2012         tp->user_entries = NULL;
   2013     }
   2014     if (tp->hw_entries) {
   2015         TAS_FREE(unit, tp->hw_entries, 0);
   2016         tp->hw_entries = NULL;
   2017     }
   2018     TAS_PROFILE_UNLOCK(tp);
   2019     if (tp->profile_mutex) {
   2020         sal_mutex_destroy(tp->profile_mutex);
   2021         tp->profile_mutex = NULL;
   2022     }
   2023     return BCM_E_NONE;
   2024 }
   2025 
   2026 /*
   2027  * Function:
   2028  *      tas_profile_status_get
   2029  * Purpose:
   2030  *      Helper function to get the profile status by specifing the pid.
   2031  *      Collect the bcm profile status from internal profile database.
   2032  * Parameters:
   2033  *     unit             - (IN) unit number
   2034  *     tp               - (IN) internal profile
   2035  *     status           - (OUT) profile status
   2036  * Returns:
   2037  *     BCM_E_XXX
   2038  */
   2039 STATIC int
   2040 tas_profile_status_get(
   2041     int unit,
   2042     tas_profile_ctrl_t *tp,
   2043     bcm_cosq_tas_profile_status_t *status)
   2044 {
   2045     if (status == NULL) {
   2046         return BCM_E_PARAM;
   2047     }
   2048     bcm_cosq_tas_profile_status_t_init(status);
   2049     status->profile_state = tp->pstate;
   2050     status->num_entries = tp->num_hw_entries;
   2051     if (status->num_entries > 0) {
   2052         sal_memcpy(&status->entries, tp->hw_entries,
   2053                    tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t));
   2054     }
   2055 
   2056     sal_memcpy(&status->config_change_time, &tp->config_change_time,
   2057                sizeof(bcm_ptp_timestamp_t));
   2058 
   2059     return BCM_E_NONE;
   2060 }
   2061 
   2062 /*
   2063  * Function:
   2064  *     bcmi_esw_tas_profile_create
   2065  * Purpose:
   2066  *     Create a profile by specifying the profile settings including calendar
   2067  *     table, ptp time information for PTP mode.
   2068  *     A profile id will be assigned along with the settings.
   2069  * Parameters:
   2070  *     unit             - (IN) unit number
   2071  *     port             - (IN) gport id
   2072  *     profile          - (IN) Pointer to profile structure which specifies
   2073  *                             entries in calendar table, ptp time information
   2074  *                             for PTP mode
   2075  *     pid              - (OUT) profile id
   2076  * Returns:
   2077  *     BCM_E_XXX
   2078  */
   2079 int
   2080 bcmi_esw_tas_profile_create(
   2081     int unit,
   2082     bcm_gport_t port,
   2083     bcm_cosq_tas_profile_t *profile,
   2084     bcm_cosq_tas_profile_id_t *pid)
   2085 {
   2086     bcm_port_t lport;
   2087     bcmi_esw_tas_control_t  *tc = NULL;
   2088     int rv;
   2089 
   2090     if ((pid == NULL) || (profile == NULL)) {
   2091         return BCM_E_PARAM;
   2092     }
   2093 
   2094     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2095 
   2096     /* parameter validate - port */
   2097     BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport));
   2098     /* parameter validate - content of the profile structure */
   2099     rv = tas_profile_profile_param_validate(unit, port, profile);
   2100     if (BCM_FAILURE(rv)) {
   2101         return rv;
   2102     }
   2103 
   2104     /* Create the profile and get the profile id */
   2105     rv = tas_profile_create(unit, lport, profile, pid);
   2106 
   2107     return rv;
   2108 }
   2109 
   2110 /*
   2111  * Function:
   2112  *     bcmi_esw_tas_profile_commit
   2113  * Purpose:
   2114  *     Commit the profile to indicate the profile is ready to write to hardware.
   2115  * Parameters:
   2116  *     unit             - (IN) unit number
   2117  *     port             - (IN) gport id
   2118  *     pid              - (IN) profile id
   2119  * Returns:
   2120  *     BCM_E_XXX
   2121  */
   2122 int
   2123 bcmi_esw_tas_profile_commit(
   2124     int unit,
   2125     bcm_gport_t port,
   2126     bcm_cosq_tas_profile_id_t pid)
   2127 {
   2128     bcmi_esw_tas_control_t  *tc = NULL;
   2129     int rv;
   2130     bcm_port_t lport;
   2131     tas_profile_ctrl_t *tp;
   2132 
   2133     /* parameter validate - port and pid */
   2134     BCM_IF_ERROR_RETURN(
   2135         tas_profile_id_validate(unit, port, pid, &lport));
   2136     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2137     TAS_LOCK(tc);
   2138     /* Check hardware resource is available to do the commit.
   2139      * Currently, only allow one profile in process (either commit or pending)
   2140      *  at one time.
   2141      */
   2142     if (tc->process_pid[lport] != 0) {
   2143         TAS_UNLOCK(tc);
   2144         return BCM_E_RESOURCE;
   2145     }
   2146     tc->process_pid[lport] = pid;
   2147     rv = tas_profile_ctrl_get(unit, pid, &tp);
   2148     if (BCM_FAILURE(rv)) {
   2149         TAS_UNLOCK(tc);
   2150         return rv;
   2151     }
   2152     TAS_UNLOCK(tc);
   2153 
   2154     TAS_PROFILE_LOCK(tp);
   2155     rv = tas_profile_commit_validate(unit, port, tp);
   2156     if (BCM_FAILURE(rv)) {
   2157         tp->pstate = bcmCosqTASProfileError;
   2158         TAS_PROFILE_UNLOCK(tp);
   2159         TAS_LOCK(tc);
   2160         tc->process_pid[lport] = 0;
   2161         TAS_UNLOCK(tc);
   2162         return rv;
   2163     }
   2164 
   2165     rv = tas_profile_commit(unit, tp);
   2166     if (BCM_FAILURE(rv)) {
   2167         tp->pstate = bcmCosqTASProfileError;
   2168         TAS_PROFILE_UNLOCK(tp);
   2169         TAS_LOCK(tc);
   2170         tc->process_pid[lport] = 0;
   2171         TAS_UNLOCK(tc);
   2172         return rv;
   2173     }
   2174 
   2175     rv = tas_profile_schedule(unit, tp);
   2176     if (BCM_FAILURE(rv)) {
   2177         tp->pstate = bcmCosqTASProfileError;
   2178         TAS_PROFILE_UNLOCK(tp);
   2179         TAS_LOCK(tc);
   2180         tc->process_pid[lport] = 0;
   2181         TAS_UNLOCK(tc);
   2182         return rv;
   2183     }
   2184 
   2185     TAS_PROFILE_UNLOCK(tp);
   2186     return rv;
   2187 }
   2188 
   2189 /*
   2190  * Function:
   2191  *     bcmi_esw_tas_profile_destroy
   2192  * Purpose:
   2193  *     Destroy the profile and associated resources.
   2194  * Parameters:
   2195  *     unit             - (IN) unit number
   2196  *     port             - (IN) gport id
   2197  *     pid              - (IN) profile id
   2198  * Returns:
   2199  *     BCM_E_XXX
   2200  */
   2201 int
   2202 bcmi_esw_tas_profile_destroy(
   2203     int unit,
   2204     bcm_gport_t port,
   2205     bcm_cosq_tas_profile_id_t pid)
   2206 {
   2207     bcm_port_t  lport;
   2208     tas_profile_ctrl_t *tp;
   2209     bcmi_esw_tas_control_t  *tc = NULL;
   2210 
   2211     BCM_IF_ERROR_RETURN(
   2212         tas_profile_id_validate(unit, port, pid, &lport));
   2213 
   2214     BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp));
   2215     BCM_IF_ERROR_RETURN(tas_profile_destroy(unit, tp));
   2216 
   2217     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2218 
   2219     TAS_LOCK(tc);
   2220     TAS_PROFILE_REMOVE(tc->profile_list, tas_profile_ctrl_t, tp, lport);
   2221     TAS_FREE(unit, tp, 0);
   2222     TAS_UNLOCK(tc);
   2223 
   2224     return BCM_E_NONE;
   2225 }
   2226 
   2227 /*
   2228  * Function:
   2229  *     bcmi_esw_tas_profile_destroy_all
   2230  * Purpose:
   2231  *     Destroy all the profile associated with the port.
   2232  * Parameters:
   2233  *     unit             - (IN) unit number
   2234  *     port             - (IN) gport
   2235  * Returns:
   2236  *     BCM_E_XXX
   2237  */
   2238 int
   2239 bcmi_esw_tas_profile_destroy_all(
   2240     int unit,
   2241     bcm_gport_t port)
   2242 {
   2243     bcm_port_t lport;
   2244     bcmi_esw_tas_control_t  *tc = NULL;
   2245     tas_profile_ctrl_t *tp;
   2246     int rv = BCM_E_NONE;
   2247 
   2248     BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport));
   2249     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2250     TAS_LOCK(tc);
   2251     TAS_PROFILE_ITER(tc->profile_list, tp, lport) {
   2252         TAS_PROFILE_LOCK(tp);
   2253         rv = tas_profile_destroy(unit, tp);
   2254         if (BCM_FAILURE(rv)) {
   2255             TAS_PROFILE_UNLOCK(tp);
   2256             TAS_UNLOCK(tc);
   2257             return rv;
   2258         }
   2259         TAS_PROFILE_REMOVE(tc->profile_list, tas_profile_ctrl_t, tp, lport);
   2260         TAS_PROFILE_UNLOCK(tp);
   2261         TAS_FREE(unit, tp, 0);
   2262     }
   2263 
   2264     TAS_UNLOCK(tc);
   2265     return rv;
   2266 }
   2267 
   2268 /*
   2269  * Function:
   2270  *     bcmi_esw_tas_profile_get
   2271  * Purpose:
   2272  *     Get the profile information by specifying the profile id.
   2273  * Parameters:
   2274  *     unit             - (IN) unit number
   2275  *     port             - (IN) gport id
   2276  *     pid              - (IN) profile id
   2277  *     profile          - (OUT) pointer to profile structure
   2278  * Returns:
   2279  *     BCM_E_XXX
   2280  */
   2281 int
   2282 bcmi_esw_tas_profile_get(
   2283     int unit,
   2284     bcm_gport_t port,
   2285     bcm_cosq_tas_profile_id_t pid,
   2286     bcm_cosq_tas_profile_t *profile)
   2287 {
   2288     tas_profile_ctrl_t      *tp;
   2289     int rv;
   2290 
   2291     if (profile == NULL) {
   2292         return BCM_E_PARAM;
   2293     }
   2294     BCM_IF_ERROR_RETURN(
   2295         tas_profile_id_validate(unit, port, pid, NULL));
   2296     BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp));
   2297     TAS_PROFILE_LOCK(tp);
   2298     rv = tas_profile_get(unit, tp, profile);
   2299     TAS_PROFILE_UNLOCK(tp);
   2300     return rv;
   2301 }
   2302 
   2303 /*
   2304  * Function:
   2305  *     bcmi_esw_tas_profile_set
   2306  * Purpose:
   2307  *     Modify the profile information
   2308  * Parameters:
   2309  *     unit             - (IN) unit number
   2310  *     port             - (IN) gport id
   2311  *     pid              - (IN) profile id
   2312  *     profile          - (IN) pointer to profile structure
   2313  * Returns:
   2314  *     BCM_E_XXX
   2315  */
   2316 int
   2317 bcmi_esw_tas_profile_set(
   2318     int unit,
   2319     bcm_gport_t port,
   2320     bcm_cosq_tas_profile_id_t pid,
   2321     bcm_cosq_tas_profile_t *profile)
   2322 {
   2323     tas_profile_ctrl_t  *tp = NULL;
   2324     int rv;
   2325 
   2326     if (profile == NULL) {
   2327         return BCM_E_PARAM;
   2328     }
   2329     BCM_IF_ERROR_RETURN(
   2330         tas_profile_id_validate(unit, port, pid, NULL));
   2331     BCM_IF_ERROR_RETURN(
   2332         tas_profile_profile_param_validate(unit, port, profile));
   2333 
   2334     BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp));
   2335     TAS_PROFILE_LOCK(tp);
   2336     rv = tas_profile_set(unit, tp, profile);
   2337     TAS_PROFILE_UNLOCK(tp);
   2338     return rv;
   2339 }
   2340 
   2341 /*
   2342  * Function:
   2343  *     bcmi_esw_tas_profile_traverse
   2344  * Purpose:
   2345  *     Traverse the set of profiles associated with the specified port.
   2346  * Parameters:
   2347  *     unit             - (IN) unit number
   2348  *     port             - (IN) gport id
   2349  *     cb               - (IN) A pointer to callback function to call
   2350  *                             for each profile in the specified gport.
   2351  *     user_data        - (IN) Pointer to user data to supply in the callback
   2352  * Returns:
   2353  *     BCM_E_XXX
   2354  */
   2355 int
   2356 bcmi_esw_tas_profile_traverse(
   2357     int unit,
   2358     bcm_gport_t port,
   2359     bcm_cosq_tas_profile_traverse_cb cb,
   2360     void *user_data)
   2361 {
   2362     bcmi_esw_tas_control_t  *tc = NULL;
   2363     tas_profile_ctrl_t  *tp = NULL;
   2364     bcm_port_t lport;
   2365     int rv;
   2366 
   2367     if (cb == NULL) {
   2368         return BCM_E_PARAM;
   2369     }
   2370     BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport));
   2371     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2372     TAS_LOCK(tc);
   2373     TAS_PROFILE_ITER(tc->profile_list, tp, lport) {
   2374         TAS_PROFILE_LOCK(tp);
   2375         rv = cb(unit, port, tp->pid, user_data);
   2376         if (BCM_FAILURE(rv)) {
   2377             LOG_ERROR(BSL_LS_BCM_TAS,
   2378                       (BSL_META_UP(unit, lport, "Error on user call back with "
   2379                        "pid 0x%x \n"), tp->pid));
   2380             TAS_PROFILE_UNLOCK(tp);
   2381             TAS_UNLOCK(tc);
   2382             return rv;
   2383         }
   2384         TAS_PROFILE_UNLOCK(tp);
   2385     }
   2386     TAS_UNLOCK(tc);
   2387     return BCM_E_NONE;
   2388 }
   2389 
   2390 /*
   2391  * Function:
   2392  *     bcmi_esw_tas_profile_status_get
   2393  * Purpose:
   2394  *     Get the profile status like profile state, config change time and
   2395  *     entries in the hardware calendar table.
   2396  * Parameters:
   2397  *     unit             - (IN) unit number
   2398  *     port             - (IN) gport id
   2399  *     pid              - (IN) profile id
   2400  *     status           - (OUT) pointer to profile status structure
   2401  * Returns:
   2402  *     BCM_E_XXX
   2403  */
   2404 int
   2405 bcmi_esw_tas_profile_status_get(
   2406     int unit,
   2407     bcm_gport_t port,
   2408     bcm_cosq_tas_profile_id_t pid,
   2409     bcm_cosq_tas_profile_status_t *status)
   2410 {
   2411     int rv;
   2412     tas_profile_ctrl_t  *tp = NULL;
   2413 
   2414     BCM_IF_ERROR_RETURN(
   2415         tas_profile_id_validate(unit, port, pid, NULL));
   2416     BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp));
   2417     TAS_PROFILE_LOCK(tp);
   2418     rv = tas_profile_status_get(unit, tp, status);
   2419     TAS_PROFILE_UNLOCK(tp);
   2420     return rv;
   2421 }
   2422 
   2423 /*
   2424  * Function:
   2425  *      tas_profile_destroy_all
   2426  * Purpose:
   2427  *      Helper function for bcmi_esw_tas_profile_destroy_all.
   2428  *      Destroy all allocated resource of the profiles on specified port.
   2429  * Parameters:
   2430  *     unit             - (IN) unit number
   2431  *     lport            - (IN) logical port
   2432  * Returns:
   2433  *     BCM_E_XXX
   2434  */
   2435 STATIC int
   2436 tas_profile_destroy_all(int unit, bcm_port_t lport)
   2437 {
   2438     bcmi_esw_tas_control_t  *tc = NULL;
   2439     tas_profile_ctrl_t  *tp = NULL;
   2440 
   2441     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2442 
   2443     if (tc->profile_list_count <= lport) {
   2444         return BCM_E_NONE;
   2445     }
   2446     TAS_PROFILE_ITER(tc->profile_list, tp, lport) {
   2447         if (tp->user_entries) {
   2448             TAS_FREE(unit, tp->user_entries, 0);
   2449             tp->user_entries = NULL;
   2450         }
   2451         if (tp->hw_entries) {
   2452             TAS_FREE(unit, tp->hw_entries, 0);
   2453             tp->hw_entries = NULL;
   2454         }
   2455         if (tp->profile_mutex) {
   2456             sal_mutex_destroy(tp->profile_mutex);
   2457             tp->profile_mutex = NULL;
   2458         }
   2459     }
   2460     TAS_PROFILE_REMOVE_ALL(tc->profile_list, tas_profile_ctrl_t, lport);
   2461 
   2462     return BCM_E_NONE;
   2463 }
   2464 
   2465 /*
   2466  * Function:
   2467  *     bcmi_esw_tas_cleanup
   2468  * Purpose:
   2469  *     Internal function to clear the resource of the tas module.
   2470  * Parameters:
   2471  *     unit             - (IN) unit number
   2472  * Returns:
   2473  *     BCM_E_XXX
   2474  */
   2475 int
   2476 bcmi_esw_tas_cleanup(int unit)
   2477 {
   2478     bcmi_esw_tas_control_t  *tc = NULL;
   2479     bcm_port_t port;
   2480     int rv;
   2481 
   2482     if (tas_control[unit] != NULL) {
   2483         tc = tas_control[unit];
   2484         if (tc->profile_list) {
   2485             PBMP_ALL_ITER(unit, port) {
   2486                 rv = tas_profile_destroy_all(unit, port);
   2487                 if (BCM_FAILURE (rv)) {
   2488                     return rv;
   2489                 }
   2490             }
   2491         }
   2492         if (tc->active_pid) {
   2493             TAS_FREE(unit, tc->active_pid, 0);
   2494             tc->active_pid = NULL;
   2495         }
   2496         if (tc->process_pid) {
   2497             TAS_FREE(unit, tc->process_pid, 0);
   2498             tc->process_pid = NULL;
   2499         }
   2500         if (tc->tas_properties) {
   2501             TAS_FREE(unit, tc->tas_properties, 0);
   2502             tc->tas_properties = NULL;
   2503         }
   2504         if (tc->tas_mutex != NULL) {
   2505             sal_mutex_destroy(tc->tas_mutex);
   2506             tc->tas_mutex = NULL;
   2507         }
   2508         TAS_FREE(unit, tc, 0);
   2509         tas_control[unit] = NULL;
   2510     }
   2511     return BCM_E_NONE;
   2512 }
   2513 
   2514 /*
   2515  * Function:
   2516  *     bcmi_esw_tas_deinit
   2517  * Purpose:
   2518  *     Internal function to free the resource of the tas module.
   2519  * Parameters:
   2520  *     unit             - (IN) unit number
   2521  * Returns:
   2522  *     BCM_E_XXX
   2523  */
   2524 int
   2525 bcmi_esw_tas_deinit(int unit)
   2526 {
   2527     bcmi_esw_tas_control_t  *tc = NULL;
   2528 
   2529     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2530 
   2531     if (tc->tas_drvs) {
   2532         const tas_drv_t   *td = tc->tas_drvs;
   2533         if (td->tas_profile_deinit != NULL) {
   2534             BCM_IF_ERROR_RETURN(td->tas_profile_deinit(unit));
   2535         }
   2536     }
   2537 
   2538     return bcmi_esw_tas_cleanup(unit);
   2539 }
   2540 
   2541 
   2542 #ifdef BCM_WARM_BOOT_SUPPORT
   2543 STATIC int
   2544 bcmi_esw_tas_scache_alloc(int unit)
   2545 {
   2546     bcmi_esw_tas_control_t  *tc = NULL;
   2547     soc_scache_handle_t scache_handle;
   2548     uint8 *scache_ptr;
   2549     int alloc_size = 0;
   2550     int profile_alloc_size = 0, profile_list_count;
   2551 
   2552     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2553     TAS_LOCK(tc);
   2554     profile_list_count = tc->profile_list_count;
   2555     TAS_UNLOCK(tc);
   2556     /* profile list count */
   2557     alloc_size += sizeof(int);
   2558     /* pid */
   2559     profile_alloc_size += sizeof(bcm_cosq_tas_profile_id_t);
   2560     /* pstate */
   2561     profile_alloc_size += sizeof(bcm_cosq_tas_profile_state_t);
   2562     /* profile hw index */
   2563     profile_alloc_size += sizeof(int);
   2564     /* user entries */
   2565     profile_alloc_size += sizeof(int);
   2566     profile_alloc_size += sizeof(bcm_cosq_tas_entry_t) *
   2567                           BCM_COSQ_MAX_TAS_CALENDAR_TABLE_SIZE;
   2568     /* hw entries */
   2569     profile_alloc_size += sizeof(int);
   2570     profile_alloc_size += sizeof(bcm_cosq_tas_entry_t) *
   2571                           BCM_COSQ_MAX_TAS_CALENDAR_TABLE_SIZE;
   2572     /* base time */
   2573     profile_alloc_size += sizeof(bcm_ptp_timestamp_t);
   2574     /* config change time */
   2575     profile_alloc_size += sizeof(bcm_ptp_timestamp_t);
   2576     /* cycle time */
   2577     profile_alloc_size += sizeof(uint32);
   2578     /* cycle extension time */
   2579     profile_alloc_size += sizeof(uint32);
   2580 
   2581     alloc_size += MAX_TAS_PROFILE_CNT * profile_alloc_size *
   2582                   profile_list_count;
   2583 
   2584     /* profile cnt, active_pid, process_pid */
   2585     alloc_size += (sizeof(uint16) + sizeof(bcm_cosq_tas_profile_id_t) +
   2586                    sizeof(bcm_cosq_tas_profile_id_t)) * profile_list_count;
   2587 
   2588     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ,
   2589                           BCMI_COSQ_WB_SCACHE_PARTITION_TAS);
   2590     BCM_IF_ERROR_RETURN(
   2591         _bcm_esw_scache_ptr_get(unit, scache_handle, 1, alloc_size,
   2592                                 &scache_ptr, BCMI_COSQ_WB_TAS_VERSION_1_0,
   2593                                 NULL));
   2594     return BCM_E_NONE;
   2595 }
   2596 
   2597 int
   2598 bcmi_esw_tas_sync(int unit)
   2599 {
   2600     bcmi_esw_tas_control_t  *tc = NULL;
   2601     tas_profile_ctrl_t  *tp = NULL;
   2602     soc_scache_handle_t scache_handle;
   2603     uint8 *scache_ptr, *temp_ptr;
   2604     int i;
   2605     int rv;
   2606     uint16 profile_cnt; /* profile count per index */
   2607 
   2608     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ,
   2609                           BCMI_COSQ_WB_SCACHE_PARTITION_TAS);
   2610 
   2611     rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 0, 0,
   2612                                  &scache_ptr, BCMI_COSQ_WB_TAS_VERSION_1_0,
   2613                                  NULL);
   2614     if (BCM_FAILURE(rv)) {
   2615         LOG_ERROR(BSL_LS_BCM_TAS,
   2616                   (BSL_META_U(unit, "Fail to get Scahce ptr !\n")));
   2617         return rv;
   2618     }
   2619     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2620     TAS_LOCK(tc);
   2621     /* store profile list count */
   2622     sal_memcpy(scache_ptr, &tc->profile_list_count, sizeof(int));
   2623     scache_ptr += sizeof(int);
   2624 
   2625     for (i = 0; i < tc->profile_list_count; i++) {
   2626         profile_cnt = 0;
   2627         /* reserve the space for the profile_cnt */
   2628         temp_ptr = scache_ptr;
   2629         scache_ptr += sizeof(uint16);
   2630         TAS_PROFILE_ITER(tc->profile_list, tp, i) {
   2631             /* store pid */
   2632             sal_memcpy(scache_ptr, &tp->pid, sizeof(bcm_cosq_tas_profile_id_t));
   2633             scache_ptr += sizeof(bcm_cosq_tas_profile_id_t);
   2634             /* store profile state */
   2635             sal_memcpy(scache_ptr, &tp->pstate,
   2636                        sizeof(bcm_cosq_tas_profile_state_t));
   2637             scache_ptr += sizeof(bcm_cosq_tas_profile_state_t);
   2638             /* store hw_index */
   2639             sal_memcpy(scache_ptr, &tp->hw_index, sizeof(int));
   2640             scache_ptr += sizeof(int);
   2641             /* store num_user_entries */
   2642             sal_memcpy(scache_ptr, &tp->num_user_entries, sizeof(int));
   2643             scache_ptr += sizeof(int);
   2644             /* store user entries */
   2645             sal_memcpy(scache_ptr, tp->user_entries,
   2646                        tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t));
   2647             scache_ptr += tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t);
   2648             /* store num_hw_entries */
   2649             sal_memcpy(scache_ptr, &tp->num_hw_entries, sizeof(int));
   2650             scache_ptr += sizeof(int);
   2651             if (tp->num_hw_entries) {
   2652                 /* store hw entries */
   2653                 sal_memcpy(scache_ptr, tp->hw_entries,
   2654                            tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t));
   2655                 scache_ptr += tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t);
   2656             }
   2657             /* store base_time */
   2658             sal_memcpy(scache_ptr, &tp->base_time, sizeof(bcm_ptp_timestamp_t));
   2659             scache_ptr += sizeof(bcm_ptp_timestamp_t);
   2660             /* store config_change_time */
   2661             sal_memcpy(scache_ptr, &tp->config_change_time,
   2662                        sizeof(bcm_ptp_timestamp_t));
   2663             scache_ptr += sizeof(bcm_ptp_timestamp_t);
   2664             /* store cycle_time */
   2665             sal_memcpy(scache_ptr, &tp->cycle_time, sizeof(uint32));
   2666             scache_ptr += sizeof(uint32);
   2667             /* store cycle_extension */
   2668             sal_memcpy(scache_ptr, &tp->cycle_extension, sizeof(uint32));
   2669             scache_ptr += sizeof(uint32);
   2670             profile_cnt++;
   2671         }
   2672         /* store the profile_cnt to the reseved ptr */
   2673         sal_memcpy(temp_ptr, &profile_cnt, sizeof(uint16));
   2674 
   2675         /* store active_pid */
   2676         sal_memcpy(scache_ptr, &tc->active_pid[i],
   2677                    sizeof(bcm_cosq_tas_profile_id_t));
   2678         scache_ptr += sizeof(bcm_cosq_tas_profile_id_t);
   2679         /* store process_pid */
   2680         sal_memcpy(scache_ptr, &tc->process_pid[i],
   2681                    sizeof(bcm_cosq_tas_profile_id_t));
   2682         scache_ptr += sizeof(bcm_cosq_tas_profile_id_t);
   2683     }
   2684     TAS_UNLOCK(tc);
   2685     return BCM_E_NONE;
   2686 }
   2687 
   2688 STATIC int
   2689 bcmi_esw_tas_recover(int unit, uint8 *scache_ptr)
   2690 {
   2691     bcmi_esw_tas_control_t  *tc = NULL;
   2692     tas_profile_ctrl_t  *tp = NULL;
   2693     int i, j;
   2694     uint16 profile_cnt;
   2695     int rv = BCM_E_NONE;
   2696 
   2697     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2698     TAS_LOCK(tc);
   2699     sal_memcpy(&tc->profile_list_count, scache_ptr, sizeof(int));
   2700     scache_ptr += sizeof(int);
   2701 
   2702     for (i = 0; i < tc->profile_list_count; i++) {
   2703         sal_memcpy(&profile_cnt, scache_ptr, sizeof(uint16));
   2704         scache_ptr += sizeof(uint16);
   2705 
   2706         for (j = 0; j < profile_cnt; j ++) {
   2707             tp = NULL;
   2708             /* Allocate profile structure */
   2709             TAS_ALLOC(unit, tp, tas_profile_ctrl_t,
   2710                       sizeof(tas_profile_ctrl_t),
   2711                       "tas profile", 0, rv);
   2712             if (BCM_FAILURE(rv)) {
   2713                 TAS_UNLOCK(tc);
   2714                 return rv;
   2715             }
   2716             /* Create profile lock */
   2717             tp->profile_mutex = sal_mutex_create("tas_profile.lock");
   2718             if (NULL == tp->profile_mutex) {
   2719                 TAS_FREE(unit, tp, 0);
   2720                 TAS_UNLOCK(tc);
   2721                 return BCM_E_RESOURCE;
   2722             }
   2723             /* restore port */
   2724             tp->port = i;
   2725             /* restore pid */
   2726             sal_memcpy(&tp->pid, scache_ptr, sizeof(bcm_cosq_tas_profile_id_t));
   2727             scache_ptr += sizeof(bcm_cosq_tas_profile_id_t);
   2728             /* restore profile state */
   2729             sal_memcpy(&tp->pstate, scache_ptr,
   2730                        sizeof(bcm_cosq_tas_profile_state_t));
   2731             scache_ptr += sizeof(bcm_cosq_tas_profile_state_t);
   2732             /* restore hw_index */
   2733             sal_memcpy(&tp->hw_index, scache_ptr, sizeof(int));
   2734             scache_ptr += sizeof(int);
   2735             /* restore num_user_entries */
   2736             sal_memcpy(&tp->num_user_entries, scache_ptr, sizeof(int));
   2737             scache_ptr += sizeof(int);
   2738             /* Allocate tp->user_entries */
   2739             TAS_ALLOC(unit, tp->user_entries, bcm_cosq_tas_entry_t,
   2740                       sizeof(bcm_cosq_tas_entry_t) * tp->num_user_entries,
   2741                       "tas profile entries", 0, rv);
   2742             if (BCM_FAILURE(rv)) {
   2743                 sal_mutex_destroy(tp->profile_mutex);
   2744                 TAS_FREE(unit, tp, 0);
   2745                 TAS_UNLOCK(tc);
   2746                 return rv;
   2747             }
   2748             /* restore user entries */
   2749             sal_memcpy(tp->user_entries, scache_ptr,
   2750                        tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t));
   2751             scache_ptr += tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t);
   2752             /* restore num_hw_entries */
   2753             sal_memcpy(&tp->num_hw_entries, scache_ptr, sizeof(int));
   2754             scache_ptr += sizeof(int);
   2755             if (tp->num_hw_entries) {
   2756                 /* Allocate tp->user_entries*/
   2757                 TAS_ALLOC(unit, tp->hw_entries, bcm_cosq_tas_entry_t,
   2758                           sizeof(bcm_cosq_tas_entry_t) * tp->num_hw_entries,
   2759                           "tas profile entries", 0, rv);
   2760                 if (BCM_FAILURE(rv)) {
   2761                     TAS_FREE(unit, tp->user_entries, 0);
   2762                     tp->user_entries = NULL;
   2763                     sal_mutex_destroy(tp->profile_mutex);
   2764                     TAS_FREE(unit, tp, 0);
   2765                     TAS_UNLOCK(tc);
   2766                     return rv;
   2767                 }
   2768                 /* restore hw entries */
   2769                 sal_memcpy(tp->hw_entries, scache_ptr,
   2770                            tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t));
   2771                 scache_ptr += tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t);
   2772             }
   2773             /* restore base_time */
   2774             sal_memcpy(&tp->base_time, scache_ptr, sizeof(bcm_ptp_timestamp_t));
   2775             scache_ptr += sizeof(bcm_ptp_timestamp_t);
   2776             /* restore config_change_time */
   2777             sal_memcpy(&tp->config_change_time, scache_ptr,
   2778                        sizeof(bcm_ptp_timestamp_t));
   2779             scache_ptr += sizeof(bcm_ptp_timestamp_t);
   2780             /* restore cycle_time */
   2781             sal_memcpy(&tp->cycle_time, scache_ptr, sizeof(uint32));
   2782             scache_ptr += sizeof(uint32);
   2783             /* restore cycle_extension */
   2784             sal_memcpy(&tp->cycle_extension, scache_ptr, sizeof(uint32));
   2785             scache_ptr += sizeof(uint32);
   2786             /* Insert profile to tas profile set */
   2787             TAS_PROFILE_INSERT(tc->profile_list, tp, i);
   2788         }
   2789         /* store active_pid */
   2790         sal_memcpy(&tc->active_pid[i], scache_ptr,
   2791                    sizeof(bcm_cosq_tas_profile_id_t));
   2792         scache_ptr += sizeof(bcm_cosq_tas_profile_id_t);
   2793         /* store process_pid */
   2794         sal_memcpy(&tc->process_pid[i], scache_ptr,
   2795                    sizeof(bcm_cosq_tas_profile_id_t));
   2796         scache_ptr += sizeof(bcm_cosq_tas_profile_id_t);
   2797     }
   2798     TAS_UNLOCK(tc);
   2799     return BCM_E_NONE;
   2800 }
   2801 
   2802 /* The pending profile might become active during the warmboot
   2803  * Update the profile state of the process_id and active_id.
   2804  */
   2805 STATIC int
   2806 bcmi_esw_tas_wb_profile_update(int unit)
   2807 {
   2808     bcmi_esw_tas_control_t  *tc = NULL;
   2809     tas_profile_ctrl_t  *tp_active = NULL, *tp_process = NULL;
   2810     int i, config_idx;
   2811     bcm_cosq_tas_profile_id_t active_pid, process_pid;
   2812     int rv;
   2813 
   2814     BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc));
   2815     TAS_LOCK(tc);
   2816     for (i = 0; i < tc->profile_list_count; i++) {
   2817         if (!BCM_PBMP_MEMBER(PBMP_PORT_ALL(unit), i)) {
   2818             continue;
   2819         }
   2820         rv = bcmi_tas_profile_idx_get(unit, i, &config_idx);
   2821         if (BCM_FAILURE(rv)) {
   2822             TAS_UNLOCK(tc);
   2823             return rv;
   2824         }
   2825         process_pid = tc->process_pid[i];
   2826         if (process_pid) {
   2827             rv = tas_profile_ctrl_get(unit, tc->process_pid[i], &tp_process);
   2828             if (BCM_FAILURE(rv)) {
   2829                 TAS_UNLOCK(tc);
   2830                 return rv;
   2831             }
   2832             if (tp_process->hw_index != -1) {
   2833                 if (tp_process->hw_index != config_idx) {
   2834                     /*
   2835                      * hw_index != config_idx means the process pid
   2836                      * become active.
   2837                      * Note: Config change time can not be recovered since
   2838                      *       it happened after leaving SDK and before WARMBOOT.
   2839                      */
   2840                     tp_process->pstate = bcmCosqTASProfileActive;
   2841 
   2842                     active_pid = tc->active_pid[i];
   2843                     if (active_pid) {
   2844                         rv = tas_profile_ctrl_get(unit, tc->active_pid[i],
   2845                                                   &tp_active);
   2846                         if (BCM_FAILURE(rv)) {
   2847                             TAS_UNLOCK(tc);
   2848                             return rv;
   2849                         }
   2850                         tp_active->pstate = bcmCosqTASProfileExpired;
   2851                         tp_active->hw_index = -1;
   2852                     }
   2853                     tc->active_pid[i] = process_pid;
   2854                     tc->process_pid[i] = 0;
   2855                 } else {
   2856                     /*
   2857                      * Clean up the process pid profile state which was
   2858                      * committed but not schedule to HW yet.
   2859                      */
   2860                     tp_process->pstate = bcmCosqTASProfileError;
   2861                     tp_process->hw_index = -1;
   2862                     tc->process_pid[i] = 0;
   2863                 }
   2864             }
   2865         }
   2866     }
   2867     TAS_UNLOCK(tc);
   2868 
   2869     return BCM_E_NONE;
   2870 }
   2871 
   2872 int
   2873 bcmi_esw_tas_reinit(int unit)
   2874 {
   2875     soc_scache_handle_t scache_handle;
   2876     int stable_size;
   2877     uint8 *tas_scache;
   2878     bcm_ptp_timestamp_t current_time;
   2879 
   2880     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   2881 
   2882     /* In case  WARM BOOT level 2 store is not configured return from here. */
   2883     if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) && (stable_size > 0)) {
   2884         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ,
   2885                               BCMI_COSQ_WB_SCACHE_PARTITION_TAS);
   2886         BCM_IF_ERROR_RETURN(
   2887             _bcm_esw_scache_ptr_get(unit, scache_handle, 0, 0,
   2888                                     &tas_scache, BCMI_COSQ_WB_TAS_VERSION_1_0,
   2889                                     NULL));
   2890         BCM_IF_ERROR_RETURN(bcmi_esw_tas_recover(unit, tas_scache));
   2891         BCM_IF_ERROR_RETURN(bcmi_esw_tas_wb_profile_update(unit));
   2892     }
   2893 
   2894     if (soc_feature(unit, soc_feature_use_local_1588)) {
   2895         /* Get currnet time to initiate the time interface id */
   2896         (void)bcmi_tas_current_time(unit, &current_time);
   2897     }
   2898 
   2899     return BCM_E_NONE;
   2900 }
   2901 #endif /* BCM_WARM_BOOT_SUPPORT */
   2902 
   2903 /*
   2904  * Function:
   2905  *     bcmi_esw_tas_init
   2906  * Purpose:
   2907  *     Internal function to initialize the software database of the tas module.
   2908  *     Device specific functions should also be registered in this function.
   2909  * Parameters:
   2910  *     unit             - (IN) unit number
   2911  * Returns:
   2912  *     BCM_E_XXX
   2913  */
   2914 int
   2915 bcmi_esw_tas_init(int unit)
   2916 {
   2917     bcmi_esw_tas_control_t  *tc = NULL;
   2918     int rv = BCM_E_NONE;
   2919     bcm_pbmp_t  all_pbmp;
   2920     int count, port;
   2921     const tas_drv_t   *td;
   2922 
   2923     /* clean up the resource */
   2924     if (tas_control[unit] != NULL) {
   2925         rv = bcmi_esw_tas_cleanup(unit);
   2926         if (BCM_FAILURE(rv)) {
   2927             return rv;
   2928         }
   2929     }
   2930 
   2931     /* Allocate TAS control memeory for this unit. */
   2932     TAS_ALLOC(unit, tc, bcmi_esw_tas_control_t,
   2933               sizeof(bcmi_esw_tas_control_t),
   2934               "TAS control", 0, rv);
   2935     if (BCM_FAILURE(rv)) {
   2936         return rv;
   2937     }
   2938 
   2939     /* Set up the unit TAS control structure. */
   2940     tas_control[unit] = tc;
   2941 
   2942     /* Create protection mutex. */
   2943     tc->tas_mutex = sal_mutex_create("tas_control.lock");
   2944     if (NULL == tc->tas_mutex) {
   2945         bcmi_esw_tas_cleanup(unit);
   2946         return (BCM_E_INTERNAL);
   2947     }
   2948 
   2949     /* Device specific information is required */
   2950 #ifdef BCM_GREYHOUND2_SUPPORT
   2951     if (SOC_IS_GREYHOUND2(unit)) {
   2952         rv = bcmi_gh2_tas_drv_init(unit, &tc->tas_drvs);
   2953     } else
   2954 #endif
   2955     {
   2956         rv = BCM_E_UNAVAIL;
   2957     }
   2958     if (BCM_FAILURE(rv)) {
   2959         bcmi_esw_tas_cleanup(unit);
   2960         return (rv);
   2961     }
   2962 
   2963     count = 0;
   2964     BCM_PBMP_CLEAR(all_pbmp);
   2965     /* Get the all valid port map */
   2966     BCM_PBMP_ASSIGN(all_pbmp, PBMP_ALL(unit));
   2967     /* Iterate the bitmap to get the maximum port number */
   2968     BCM_PBMP_ITER(all_pbmp, port) {
   2969         count = port;
   2970     }
   2971     /* Total port counts should be (maximum port number + 1) */
   2972     count++;
   2973     /* port basis profile list */
   2974     tc->profile_list_count = count;
   2975     /* Allocate tc->profile_list */
   2976     TAS_ALLOC(unit, tc->profile_list, tas_profile_ctrl_t *,
   2977               count * sizeof(tas_profile_ctrl_t *),
   2978               "tas profiles set", 0, rv);
   2979     if (BCM_FAILURE(rv)) {
   2980         bcmi_esw_tas_cleanup(unit);
   2981         return (BCM_E_MEMORY);
   2982     }
   2983     /* Allocate tc->active_pid */
   2984     TAS_ALLOC(unit, tc->active_pid, bcm_cosq_tas_profile_id_t,
   2985               count * sizeof(bcm_cosq_tas_profile_id_t),
   2986               "tas current pid set", 0, rv);
   2987     if (BCM_FAILURE(rv)) {
   2988         bcmi_esw_tas_cleanup(unit);
   2989         return (BCM_E_MEMORY);
   2990     }
   2991     /* Allocate tc->process_pid */
   2992     TAS_ALLOC(unit, tc->process_pid, bcm_cosq_tas_profile_id_t,
   2993               count * sizeof(bcm_cosq_tas_profile_id_t),
   2994               "tas current pid set", 0, rv);
   2995     if (BCM_FAILURE(rv)) {
   2996         bcmi_esw_tas_cleanup(unit);
   2997         return (BCM_E_MEMORY);
   2998     }
   2999     /* Allocate property software cache */
   3000     TAS_ALLOC(unit, tc->tas_properties,
   3001               tas_prop_info_t,
   3002               sizeof(tas_prop_info_t) * (tc->profile_list_count + 1),
   3003               "TAS properties cache ", 0, rv);
   3004     if (BCM_FAILURE(rv)) {
   3005         bcmi_esw_tas_cleanup(unit);
   3006         return (BCM_E_MEMORY);
   3007     }
   3008     /* Fill up the cache */
   3009     rv = bcmi_esw_tas_property_cache_init(unit);
   3010     if (BCM_FAILURE(rv)) {
   3011         bcmi_esw_tas_cleanup(unit);
   3012         return rv;
   3013     }
   3014 #ifdef BCM_WARM_BOOT_SUPPORT
   3015     if (!SOC_WARM_BOOT(unit)) {
   3016         bcmi_esw_tas_scache_alloc(unit);
   3017     }
   3018     if (SOC_WARM_BOOT(unit)) {
   3019         rv = bcmi_esw_tas_reinit(unit);
   3020         if (BCM_FAILURE(rv)) {
   3021             bcmi_esw_tas_cleanup(unit);
   3022             return rv;
   3023         }
   3024     }
   3025 #endif /* BCM_WARM_BOOT_SUPPORT */
   3026 
   3027     td = tc->tas_drvs;
   3028     /* Allocate/init profile resource and register the profile event callback */
   3029     if (td->tas_profile_init != NULL) {
   3030         rv = td->tas_profile_init(unit, bcmi_tas_profile_event_notify);
   3031     }
   3032     return rv;
   3033 }
   3034 #endif /* BCM_TAS_SUPPORT */