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 (66124B)


      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:     Greyhound2 specific TAS driver
      9  */
     10 
     11 #include <shared/bsl.h>
     12 #include <soc/drv.h>
     13 #include <soc/greyhound2.h>
     14 #include <bcm/cosq.h>
     15 #include <bcm_int/esw_dispatch.h>
     16 #include <bcm_int/esw/tas.h>
     17 #include <bcm_int/esw/cosq.h>
     18 #include <bcm_int/esw/greyhound2.h>
     19 
     20 #if defined(BCM_GREYHOUND2_SUPPORT) && defined(BCM_TAS_SUPPORT)
     21 /* GCLT time interval resolution : 8 ns */
     22 #define GH2_TAS_GCLT_TICKS  (8)
     23 /* GCLT table size */
     24 #define GH2_TAS_GCLT_ENTRIES  (128)
     25 /* Maximum logical port */
     26 #define GH2_TAS_MAX_PORTCNT (66)
     27 /* Maximum physical port */
     28 #define GH2_MAX_PHY_PORTS   (90)
     29 
     30 /* Delay parameters for Hold Advance */
     31 /* Fixed tha overhead in bytes : SMD 8B, IPG 12B, Hold recognition time 12B */
     32 #define FIXED_THA_OVERHEAD  (8 + 12 + 12)
     33 
     34 /* Delay parameter for Gate Close Response time */
     35 /* Delay of CLMAC TXFIFO in Bytes : 4 x 48B = 192B */
     36 #define TGCR_CLMAC_TXFIFO  (192)
     37 /* Delay of XLMAC TXFIFO in Bytes : 4 x 32B = 128B */
     38 #define TGCR_XLMAC_TXFIFO  (128)
     39 /* Delay of UNIMAC TXFIFO in Bytes : 4 x 32Bytes + 16 x 128bits = 384B */
     40 #define TGCR_UNIMAC_TXFIFO (384)
     41 
     42 /* software static data structure initialize indicator */
     43 static uint8 gh2_profile_initialized = 0;
     44 
     45 /* GH2 TAS related interrupt/event information */
     46 typedef struct gh2_tas_event_info_s {
     47     bcmi_tas_profile_event_type_t p_event; /* tas internal profile event */
     48     bcm_cosq_event_type_t event;  /* bcm layer cosq event */
     49     soc_field_t mask_field; /* mask field of MEMFAILINTMASKr */
     50     soc_field_t status_field; /* status field of MEMFAILINTSTATUSr */
     51     soc_field_t clear_field; /* clear field of MEMFAILINT_CLRr */
     52     soc_reg_t   sts_regs[3]; /* sub status registers to
     53                                 indicate individual status */
     54     soc_reg_t   clr_regs[3]; /* sub clear registers to
     55                                 clear individual status */
     56 } gh2_tas_event_info_t;
     57 
     58 /* The table lists GH2 support TAS interrupts and events */
     59 STATIC gh2_tas_event_info_t gh2_tas_event_info[] =
     60 {
     61     /* ToD Window event is internally used for PTP mode time caculation to fit
     62      * the device HW program constrain.
     63      */
     64     {bcmiTASProfileEventTODWindow , -1,
     65      TOD_WINDOW_INTERRUPT_INTMASKf,
     66      TOD_WINDOW_INTERRUPTf,
     67      TOD_WINDOW_INTERRUPT_CLRf,
     68      {-1},
     69      {-1},
     70     },
     71     {bcmiTASProfileEventProfileChange, bcmCosqEventTASProfileChange,
     72      TAS_TBL_SWITCH_DONE_INTMASKf,
     73      TAS_TBL_SWITCH_DONEf,
     74      TAS_TBL_SWITCH_DONE_CLRf,
     75      {TAS_TBL_SWITCH_DONE_0r, TAS_TBL_SWITCH_DONE_1r, TAS_TBL_SWITCH_DONE_2r},
     76      {TAS_TBL_SWITCH_DONE_CLR_0r, TAS_TBL_SWITCH_DONE_CLR_1r,
     77       TAS_TBL_SWITCH_DONE_CLR_2r},
     78      },
     79     {bcmiTASProfileEventECCErr, bcmCosqEventTASECCErr,
     80      TAS_PARITY_ERR_INTMASKf,
     81      TAS_PARITY_ERRf,
     82      TAS_PARITY_ERR_CLRf,
     83      {TAS_PARITY_ERR_VLD_0r, TAS_PARITY_ERR_VLD_1r, TAS_PARITY_ERR_VLD_2r},
     84      {TAS_PARITY_ERR_CLR_0r, TAS_PARITY_ERR_CLR_1r, TAS_PARITY_ERR_CLR_2r}
     85     },
     86     {bcmiTASProfileEventNextCycleTimeErr, bcmCosqEventTASNextCycleTimeErr,
     87      SET_NEXT_CYCLE_TIME_ERROR_INTMASKf,
     88      SET_NEXT_CYCLE_TIME_ERRORf,
     89      SET_NEXT_CYCLE_TIME_ERROR_CLRf,
     90      {SET_NEXT_CYCLE_TIME_ERROR_0r, SET_NEXT_CYCLE_TIME_ERROR_1r,
     91       SET_NEXT_CYCLE_TIME_ERROR_2r},
     92      {SET_NEXT_CYCLE_TIME_ERROR_CLR_0r, SET_NEXT_CYCLE_TIME_ERROR_CLR_1r,
     93       SET_NEXT_CYCLE_TIME_ERROR_CLR_2r},
     94     },
     95     {bcmiTASProfileEventBaseTimeErr, bcmCosqEventTASBaseTimeErr,
     96      SET_BASE_TIME_ERROR_INTMASKf,
     97      SET_BASE_TIME_ERRORf,
     98      SET_BASE_TIME_ERROR_CLRf,
     99      {SET_BASE_TIME_ERROR_0r, SET_BASE_TIME_ERROR_1r, SET_BASE_TIME_ERROR_2r},
    100      {SET_BASE_TIME_ERROR_CLR_0r, SET_BASE_TIME_ERROR_CLR_1r,
    101       SET_BASE_TIME_ERROR_CLR_2r}
    102     },
    103     {bcmiTASProfileEventPtrErr, bcmCosqEventTASProfilePtrErr,
    104      TAS_CTL_TBL_PTR_ERR_INTMASKf,
    105      TAS_CTL_TBL_PTR_ERRf,
    106      TAS_CTL_TBL_PTR_ERR_CLRf,
    107      {TAS_CTL_TBL_PTR_ERR_0r, TAS_CTL_TBL_PTR_ERR_1r, TAS_CTL_TBL_PTR_ERR_2r},
    108      {TAS_CTL_TBL_PTR_ERR_CLR_0r, TAS_CTL_TBL_PTR_ERR_CLR_1r,
    109       TAS_CTL_TBL_PTR_ERR_CLR_2r}
    110     },
    111     /* bcm layer cosq event, no corresponding HW settings.
    112      * Notified by software when 'PTP out of sync' is configured.*/
    113     {-1, bcmCosqEventTASPTPOutOfSyncErr,
    114      -1
    115     },
    116     /* End of table, both intr_type == -1 && event == -1*/
    117     {-1, -1}
    118 };
    119 
    120 /* Track the configured bcm cosq event and internal profile event since both
    121  * events access the same interrupt resources. */
    122 typedef struct gh2_tas_event_ctrl_s {
    123     sal_mutex_t event_lock;
    124     SHR_BITDCL  cosq_event_pbmp[_SHR_BITDCLSIZE(bcmCosqEventCount)];
    125     SHR_BITDCL  tas_event_pbmp[_SHR_BITDCLSIZE(bcmiTASProfileEventCount)];
    126 } gh2_tas_event_ctrl_t;
    127 
    128 STATIC gh2_tas_event_ctrl_t *gh2_tas_event_ctrl[BCM_MAX_NUM_UNITS];
    129 
    130 STATIC profile_event_cb_fn gh2_profile_event_notify[BCM_MAX_NUM_UNITS] = {NULL};
    131 
    132 #define GH2_TAS_EVENT_LOCK(tec) \
    133         sal_mutex_take((tec)->event_lock, sal_mutex_FOREVER);
    134 #define GH2_TAS_EVENT_UNLOCK(tec) \
    135         sal_mutex_give((tec)->event_lock);
    136 
    137 /* Essential profile information to identify the valid process interval (tod_id)
    138  * and parameters used to program to HW.
    139  */
    140 typedef struct gh2_tod_event_info_s {
    141     uint64  tod_id; /* ptp sec time divid 64 (2^6) */
    142     bcm_ptp_timestamp_t base_time;
    143     uint32  old_cycle_time;
    144     uint32  new_cycle_time;
    145     uint32  new_cycle_extension;
    146     int     config_idx;
    147     profile_commit_cb_fn cb;
    148     void    *fn_data;
    149 } gh2_tod_event_info_t;
    150 
    151 /* Port based ToD event tracking to keep the profile information which is
    152  * committed but not program to HW yet.
    153  */
    154 typedef struct gh2_tod_event_control_s {
    155     sal_mutex_t tod_lock;
    156     gh2_tod_event_info_t  *gh2_tod_event[GH2_TAS_MAX_PORTCNT];
    157     SHR_BITDCL tod_event_pbmp[_SHR_BITDCLSIZE(GH2_TAS_MAX_PORTCNT)];
    158 } gh2_tod_event_control_t;
    159 
    160 STATIC gh2_tod_event_control_t *gh2_tod_event_control[BCM_MAX_NUM_UNITS];
    161 
    162 #define GH2_TOD_EVENT_LOCK(tec) \
    163         sal_mutex_take((tec)->tod_lock, sal_mutex_FOREVER);
    164 #define GH2_TOD_EVENT_UNLOCK(tec) \
    165         sal_mutex_give((tec)->tod_lock);
    166 
    167 STATIC int
    168 bcmi_gh2_tas_profile_change(int unit, bcm_port_t lport);
    169 STATIC int
    170 bcmi_gh2_tas_profile_idx_get(int unit, bcm_port_t lport, int *config_idx);
    171 STATIC int
    172 bcmi_gh2_tas_control_get(int unit, bcm_port_t port, bcm_cosq_tas_control_t type,
    173                          int *arg);
    174 
    175 /* HW need 500 us / 500000 ns to reflect the register settings */
    176 #define GH2_TAS_HW_REG_RESPONSE_TIME    500000 /* 500000 ns */
    177 
    178 /* GH2 only support 6 bit second value */
    179 #define GH2_TAS_BASETIME_SEC_MASK   (0x3F)
    180 
    181 /* Assuem GH2 need take 1 sec software process to calculate and program the
    182  * required time information.
    183  */
    184 #define GH2_TAS_SW_PROCESS_TIME  1 /* 1 sec */
    185 
    186 STATIC int
    187 bcmi_gh2_tas_tod_handler(int unit);
    188 /*
    189  * Function:
    190  *     bcmi_gh2_tas_profile_event_mask_set
    191  * Purpose:
    192  *     Configue the TAS related interrupt mask by specifying the internal
    193  *     profile event.
    194  *     For value=0 case, will be programmed when no bcm cos event reference it.
    195  * Parameters:
    196  *     unit             - (IN) unit number
    197  *     p_event          - (IN) internal profile event
    198  *     val              - (IN) mask value
    199  * Returns:
    200  *     BCM_E_XXX
    201  */
    202 STATIC int
    203 bcmi_gh2_tas_profile_event_mask_set(
    204     int unit,
    205     bcmi_tas_profile_event_type_t p_event,
    206     int val)
    207 {
    208     gh2_tas_event_info_t *e_info;
    209     int i, rv = BCM_E_NONE;
    210     uint32 rval;
    211     gh2_tas_event_ctrl_t *tec = NULL;
    212 
    213     if ((tec = gh2_tas_event_ctrl[unit]) == NULL) {
    214         return BCM_E_INTERNAL;
    215     }
    216 
    217     if ((p_event < bcmiTASProfileEventTODWindow) ||
    218         (p_event >= bcmiTASProfileEventCount)) {
    219         return BCM_E_PARAM;
    220     }
    221     GH2_TAS_EVENT_LOCK(tec);
    222     if (val) {
    223         SHR_BITSET(tec->tas_event_pbmp, p_event);
    224     } else {
    225         SHR_BITCLR(tec->tas_event_pbmp, p_event);
    226     }
    227     for (i = 0; ; i++) {
    228         e_info = &gh2_tas_event_info[i];
    229         if ((e_info->p_event == -1) && (e_info->event == -1)) {
    230             /* End of table */
    231             break;
    232         }
    233 
    234         if (e_info->p_event == p_event) {
    235             if (e_info->event != -1) {
    236                 if (SHR_BITGET(tec->cosq_event_pbmp, e_info->event) &&
    237                     (val == 0)) {
    238                     /* Do not set 0 if other event referece it */
    239                     break;
    240                 }
    241             }
    242             rv = READ_MEMFAILINTMASKr(unit, &rval);
    243             if (BCM_FAILURE(rv)) {
    244                 break;
    245             }
    246             soc_reg_field_set(unit, MEMFAILINTMASKr, &rval,
    247                               e_info->mask_field, val);
    248             rv = WRITE_MEMFAILINTMASKr(unit, rval);
    249             break;
    250         }
    251     }
    252     GH2_TAS_EVENT_UNLOCK(gh2_tas_event_ctrl[unit]);
    253 
    254     return BCM_E_NONE;
    255 }
    256 
    257 /*
    258  * Function:
    259  *     bcmi_gh2_tas_tod_attach
    260  * Purpose:
    261  *     Attach the profile to tod event list.
    262  * Parameters:
    263  *     unit             - (IN) unit number
    264  *     lport            - (IN) logical port
    265  *     base_time        - (IN) new base time
    266  *     old_cycle_time   - (IN) old cycle time
    267  *     new_cycle_time   - (IN) new cycle time
    268  *     new_cycle_extension - (IN) new cycle extension time
    269  *     config_idx       - (IN) inactive hw index
    270  *     cb               - (IN) cb function to call when the time information
    271  *                             programmed to HW and kick-off the
    272  *                             config change.
    273  *     fn_data          - (IN) fn_data to supply in the callback
    274  * Returns:
    275  *     BCM_E_XXX
    276  */
    277 STATIC int
    278 bcmi_gh2_tas_tod_attach(
    279     int unit,
    280     bcm_port_t lport,
    281     bcm_ptp_timestamp_t base_time,
    282     uint32 old_cycle_time,
    283     uint32 new_cycle_time,
    284     uint32 new_cycle_extension,
    285     int config_idx,
    286     profile_commit_cb_fn cb,
    287     void *fn_data)
    288 {
    289     gh2_tod_event_control_t *tec = gh2_tod_event_control[unit];
    290     int rv = BCM_E_NONE;
    291     gh2_tod_event_info_t *tod_event = NULL;
    292     uint64 sec_hi;
    293     uint32 sec_lo;
    294     uint32 ns;
    295 
    296     if (tec == NULL) {
    297         return BCM_E_INTERNAL;
    298     }
    299 
    300     if (tec->gh2_tod_event[lport]) {
    301         LOG_ERROR(BSL_LS_BCM_TAS,
    302                   (BSL_META_U(unit,
    303                               "gh2 tod event has been attached !\n")));
    304         return BCM_E_BUSY;
    305     }
    306     TAS_ALLOC(unit, tod_event, gh2_tod_event_info_t ,
    307               sizeof(gh2_tod_event_info_t),
    308               "gh2 tod event", 0, rv);
    309 
    310     COMPILER_64_COPY(sec_hi, base_time.seconds);
    311     sec_lo = COMPILER_64_LO(base_time.seconds);
    312     /* GH2 TOD window 6-bit seconds */
    313     sec_lo &= GH2_TAS_BASETIME_SEC_MASK; /* take the lowest 6 bit */
    314     /* Right shift 6 bit as the tod_id (ToD Window id) */
    315     COMPILER_64_SHR(sec_hi, 6); /* >> 6 */
    316 
    317     /*
    318      * Caculate the target valid tod_id :
    319      * At least 2 x old_cycle_time ahead new base_time to switch to new cycle
    320      */
    321     ns = base_time.nanoseconds + 2 * old_cycle_time;
    322     if (ns >= TAS_PTP_TIME_NANOSEC_MAX) {
    323         /* wrap to 1 second */
    324         sec_lo += 1;
    325         if (sec_lo > GH2_TAS_BASETIME_SEC_MASK) {
    326             /* wrap to next TOD window */
    327             COMPILER_64_ADD_32(sec_hi, 1);
    328         }
    329     }
    330     /* Prepare the related parameters */
    331     tod_event->tod_id = sec_hi;
    332     memcpy(&tod_event->base_time, &base_time, sizeof(bcm_ptp_timestamp_t));
    333     tod_event->old_cycle_time = old_cycle_time;
    334     tod_event->new_cycle_time = new_cycle_time;
    335     tod_event->new_cycle_extension = new_cycle_extension;
    336     tod_event->config_idx = config_idx;
    337     tod_event->cb = cb;
    338     tod_event->fn_data = fn_data;
    339 
    340     GH2_TOD_EVENT_LOCK(tec);
    341     /* Enable TOD interrupt when tod_event_pbmp is empty */
    342     if (SHR_BITNULL_RANGE(tec->tod_event_pbmp, 0, GH2_TAS_MAX_PORTCNT)) {
    343         rv = bcmi_gh2_tas_profile_event_mask_set(
    344                  unit, bcmiTASProfileEventTODWindow, 1);
    345         if (BCM_FAILURE(rv)) {
    346             TAS_FREE(unit, tod_event, 0);
    347             GH2_TOD_EVENT_UNLOCK(tec);
    348             return rv;
    349         }
    350     }
    351     /* Attach to the tod event list */
    352     tec->gh2_tod_event[lport] = tod_event;
    353     SHR_BITSET(tec->tod_event_pbmp, lport);
    354     GH2_TOD_EVENT_UNLOCK(tec);
    355 
    356     (void)bcmi_gh2_tas_tod_handler(unit);
    357     return rv;
    358 }
    359 
    360 /*
    361  * Function:
    362  *     bcmi_gh2_tas_tod_detach
    363  * Purpose:
    364  *     Detach the profile from tod event list.
    365  * Parameters:
    366  *     unit             - (IN) unit number
    367  *     lport            - (IN) logical port
    368  *
    369  * Returns:
    370  *     BCM_E_XXX
    371  */
    372 STATIC int
    373 bcmi_gh2_tas_tod_detach(int unit, bcm_port_t lport)
    374 {
    375     gh2_tod_event_info_t    *tod_event;
    376     gh2_tod_event_control_t *tec = gh2_tod_event_control[unit];
    377     int                     rv = BCM_E_NONE;
    378 
    379     if (tec == NULL) {
    380         return BCM_E_INTERNAL;
    381     }
    382     GH2_TOD_EVENT_LOCK(tec);
    383     tod_event = tec->gh2_tod_event[lport];
    384     if (tod_event) {
    385         TAS_FREE(unit, tod_event, 0);
    386         tec->gh2_tod_event[lport] = NULL;
    387     }
    388     SHR_BITCLR(tec->tod_event_pbmp, lport);
    389     /* Disable TOD interrupt when tod_event_pbmp is empty */
    390     if (SHR_BITNULL_RANGE(tec->tod_event_pbmp, 0, GH2_TAS_MAX_PORTCNT)) {
    391         rv = bcmi_gh2_tas_profile_event_mask_set(
    392                  unit, bcmiTASProfileEventTODWindow, 0);
    393     }
    394     GH2_TOD_EVENT_UNLOCK(tec);
    395     return rv;
    396 }
    397 
    398 /*
    399  * Function:
    400  *     bcmi_gh2_tas_tod_handler
    401  * Purpose:
    402  *      Invoked from ToDWindow interrupt.
    403  *      Caculate the proper config_change_time according to current time,
    404  *      base_time and device limitation.
    405  *      The config_change_time would be (base_time + n * cycle_time)
    406  *      And program the time information to HW.
    407  * Parameters:
    408  *     unit             - (IN) unit number
    409  *     lport            - (IN) logical port
    410  *
    411  * Returns:
    412  *     BCM_E_XXX
    413  */
    414 STATIC int
    415 bcmi_gh2_tas_tod_handler(int unit)
    416 {
    417     gh2_tod_event_control_t *tec = gh2_tod_event_control[unit];
    418     int i, rv, tas_enable;
    419     gh2_tod_event_info_t tod;
    420     bcm_ptp_timestamp_t cur_time, config_change_time;
    421     uint64 cur_sec_hi, cur_sec_lo;
    422     uint32 cur_ns, tmp32;
    423     uint64 bt_in_ns, ct_in_ns, sec_mask;
    424     SHR_BITDCL tod_event_pbmp[_SHR_BITDCLSIZE(GH2_TAS_MAX_PORTCNT)];
    425 
    426     if (tec == NULL) {
    427         return BCM_E_INTERNAL;
    428     }
    429 
    430     GH2_TOD_EVENT_LOCK(tec);
    431     SHR_BITCOPY_RANGE(tod_event_pbmp, 0,
    432                       tec->tod_event_pbmp, 0,
    433                       GH2_TAS_MAX_PORTCNT);
    434     GH2_TOD_EVENT_UNLOCK(tec);
    435 
    436     /* Iter the valid entry form tod event list */
    437     SHR_BIT_ITER(tod_event_pbmp, GH2_TAS_MAX_PORTCNT, i) {
    438         BCM_IF_ERROR_RETURN(
    439             bcmi_gh2_tas_control_get(unit, i, bcmCosqTASControlTASEnable,
    440                                      &tas_enable));
    441         if (!tas_enable) {
    442             continue;
    443         }
    444         GH2_TOD_EVENT_LOCK(tec);
    445         if (tec->gh2_tod_event[i]) {
    446             sal_memcpy(&tod, tec->gh2_tod_event[i],
    447                        sizeof(gh2_tod_event_info_t));
    448         } else {
    449             GH2_TOD_EVENT_UNLOCK(tec);
    450             continue;
    451         }
    452         GH2_TOD_EVENT_UNLOCK(tec);
    453         /* Get the current time */
    454         rv = bcmi_tas_current_time(unit, &cur_time);
    455         if (BCM_FAILURE(rv)) {
    456             LOG_ERROR(BSL_LS_BCM_TAS,
    457                       (BSL_META_U(unit,
    458                                   "Fatal error: "
    459                                   "Fail to get current time !\n")));
    460             break;
    461         }
    462         COMPILER_64_COPY(cur_sec_hi, cur_time.seconds);
    463         /* Right shift 6 bit as the current tod_id */
    464         COMPILER_64_SHR(cur_sec_hi, 6);
    465 
    466         /* Check if the event need to process in this Tod Window */
    467         /* current tod_id >= target todid : process the event */
    468         if (COMPILER_64_GE(cur_sec_hi, tod.tod_id)) {
    469             COMPILER_64_COPY(cur_sec_lo, cur_time.seconds);
    470             COMPILER_64_SET(sec_mask, 0, GH2_TAS_BASETIME_SEC_MASK);
    471             COMPILER_64_AND(cur_sec_lo, sec_mask); /* take the lowest 6 bit */
    472             ct_in_ns = bcmi_tas_ptp_to_ns(cur_time);
    473             /* Need 2 x old cycle time to do the config change */
    474             cur_ns = cur_time.nanoseconds + 2 * tod.old_cycle_time;
    475             if (cur_ns >= TAS_PTP_TIME_NANOSEC_MAX) {
    476                 COMPILER_64_ADD_32(cur_sec_lo, 1);
    477                 if (COMPILER_64_GT(cur_sec_lo, sec_mask)) {
    478                     LOG_DEBUG(BSL_LS_BCM_TAS,
    479                               (BSL_META_U(unit,
    480                                           "Skip this time(tod: %d lport:%d)\n"),
    481                                u64_L(tod.tod_id), i));
    482                     continue;
    483                 }
    484                 cur_ns -= TAS_PTP_TIME_NANOSEC_MAX;
    485             }
    486             COMPILER_64_ADD_32(ct_in_ns, 2 * tod.old_cycle_time);
    487             /* consider HW response time */
    488             cur_ns += GH2_TAS_HW_REG_RESPONSE_TIME;
    489             if (cur_ns >= TAS_PTP_TIME_NANOSEC_MAX) {
    490                 COMPILER_64_ADD_32(cur_sec_lo, 1);
    491                 if (COMPILER_64_GT(cur_sec_lo, sec_mask)) {
    492                     LOG_DEBUG(BSL_LS_BCM_TAS,
    493                               (BSL_META_U(unit,
    494                                           "Skip this time(tod: %d lport:%d)\n"),
    495                                u64_L(tod.tod_id), i));
    496                     continue;
    497                 }
    498             }
    499             COMPILER_64_ADD_32(ct_in_ns, GH2_TAS_HW_REG_RESPONSE_TIME);
    500 
    501             /* consider software process time */
    502             COMPILER_64_ADD_32(cur_sec_lo, GH2_TAS_SW_PROCESS_TIME);
    503             if (COMPILER_64_GT(cur_sec_lo, sec_mask)) {
    504                 LOG_DEBUG(BSL_LS_BCM_TAS,
    505                           (BSL_META_U(unit,
    506                                       "Skip this time(tod: %d lport:%d)\n"),
    507                            u64_L(tod.tod_id), i));
    508                 continue;
    509             }
    510             COMPILER_64_ADD_32(ct_in_ns,
    511                                GH2_TAS_SW_PROCESS_TIME *
    512                                TAS_PTP_TIME_NANOSEC_MAX);
    513             bt_in_ns = bcmi_tas_ptp_to_ns(tod.base_time);
    514 
    515             /* Add N x new_cycle_time until > current time */
    516             while (COMPILER_64_LT(bt_in_ns, ct_in_ns)) {
    517                 COMPILER_64_ADD_32(bt_in_ns, tod.new_cycle_time);
    518             }
    519             bcmi_tas_ns_to_ptp(bt_in_ns, &config_change_time);
    520 
    521             /* Program to HW */
    522             tmp32 = COMPILER_64_LO(config_change_time.seconds);
    523             tmp32 &= GH2_TAS_BASETIME_SEC_MASK;
    524             BCM_IF_ERROR_RETURN(
    525                 WRITE_BASE_TIME_SECr(unit, i, tod.config_idx,
    526                                      tmp32));
    527             BCM_IF_ERROR_RETURN(
    528                 WRITE_BASE_TIME_FRACr(unit, i, tod.config_idx,
    529                                       config_change_time.nanoseconds));
    530             BCM_IF_ERROR_RETURN(
    531                 WRITE_CYCLE_TIMEr(unit, i, tod.config_idx,
    532                                   tod.new_cycle_time));
    533             BCM_IF_ERROR_RETURN(
    534                 WRITE_CYCLE_TIME_EXTENSIONr(unit, i, tod.config_idx,
    535                                             tod.new_cycle_extension));
    536             /* Issue config change */
    537             BCM_IF_ERROR_RETURN(bcmi_gh2_tas_profile_change(unit, i));
    538 
    539             /*
    540              * Notify the actual config change time to common profile
    541              * management layer.
    542              */
    543             if (tod.cb) {
    544                 BCM_IF_ERROR_RETURN(
    545                     tod.cb(unit, i, config_change_time, tod.fn_data));
    546             }
    547             /* Detach from TOD event list */
    548             BCM_IF_ERROR_RETURN(bcmi_gh2_tas_tod_detach(unit, i));
    549         }
    550     }
    551     return BCM_E_NONE;
    552 }
    553 
    554 /*
    555  * Function:
    556  *      bcmi_gh2_tas_profile_schedule_config
    557  * Purpose:
    558  *      Device specific function to schedule the proper time to program the
    559  *      time information to HW. Also provide the callback function to call when
    560  *      the time information programmed to HW and kick-off the config change.
    561  *
    562  * Parameters:
    563  *     unit              - (IN) unit number
    564  *     lport             - (IN) logical port
    565  *     base_time         - (IN) new base time
    566  *     cycle_time        - (IN) new cycle time
    567  *     cycle_extension   - (IN) new cycle extension
    568  *     cb                - (IN) cb function to call when the time information
    569  *                              programmed to HW and kick-off the
    570  *                              config change.
    571  *     fn_data           - (IN) fn_data to supply in the callback
    572  *
    573  * Returns:
    574  *     BCM_E_XXX
    575  */
    576 STATIC int
    577 bcmi_gh2_tas_profile_schedule_config(
    578     int unit, bcm_port_t lport,
    579     bcm_ptp_timestamp_t base_time,
    580     uint32 cycle_time,
    581     uint32 cycle_extension,
    582     profile_commit_cb_fn cb,
    583     void *fn_data)
    584 {
    585     int config_idx;
    586     uint32 old_cycle_time;
    587 
    588     BCM_IF_ERROR_RETURN(
    589         bcmi_gh2_tas_profile_idx_get(unit, lport, &config_idx));
    590 
    591     /* Need the old cycle time to calculate the config change time */
    592     BCM_IF_ERROR_RETURN(
    593         READ_CYCLE_TIMEr(unit, lport, config_idx, &old_cycle_time));
    594 
    595     /* Attach the profile to ToD event list */
    596     return bcmi_gh2_tas_tod_attach(unit, lport, base_time, old_cycle_time,
    597                                    cycle_time, cycle_extension, config_idx,
    598                                    cb, fn_data);
    599 }
    600 
    601 /*
    602  * Check if the port is enabled 2-level scheduling
    603  * Disable it since checking mechanism is not settled yet.
    604  */
    605 #define CHECK_64Q  (0)
    606 /*
    607  * Function:
    608  *     bcmi_gh2_tas_port_validate
    609  * Purpose:
    610  *     Helper function to check if the port has TAS capability.
    611  * Parameters:
    612  *     unit             - (IN) unit number
    613  * Returns:
    614  *     BCM_E_XXX
    615  */
    616 int
    617 bcmi_gh2_tas_port_validate(int unit, bcm_port_t port)
    618 {
    619 #if CHECK_64Q
    620     int is_64q_port = 0;
    621 
    622     /* check 2-level scheduling property */
    623     if (true) {
    624         soc_gh2_64q_port_check(int unit, port, *is_64q_port);
    625         if (is_64q_port) {
    626             /* unable to support TAS on 64Q port */
    627             return BCM_E_PARAM;
    628         }
    629     }
    630 #endif
    631 
    632     return BCM_E_NONE;
    633 }
    634 
    635 /*
    636  * Function:
    637  *     bcmi_gh2_tas_disable_notify
    638  * Purpose:
    639  *     Helper function to process what should be done when TAS is disabled.
    640  * Parameters:
    641  *     unit             - (IN) unit number
    642  *     port             - (IN) logical port
    643  * Returns:
    644  *     BCM_E_XXX
    645  */
    646 STATIC int
    647 bcmi_gh2_tas_disable_notify(int unit, bcm_port_t port)
    648 {
    649     /* Notify that active profile should be expired and
    650      * dismiss the process profile.
    651      */
    652     if (gh2_profile_event_notify[unit]) {
    653         BCM_IF_ERROR_RETURN(
    654             gh2_profile_event_notify[unit](unit, port,
    655                                            bcmiTASProfileEventTASDisable));
    656     }
    657     BCM_IF_ERROR_RETURN(bcmi_gh2_tas_tod_detach(unit, port));
    658     return BCM_E_NONE;
    659 }
    660 
    661 /*
    662  * Function:
    663  *     bcmi_gh2_tas_control_set
    664  * Purpose:
    665  *     Set various configurations for TAS.
    666  * Parameters:
    667  *     unit             - (IN) unit number
    668  *     port             - (IN) logical port
    669  *     type             - (IN) tas control type defined in bcm_cos_tas_control_t
    670  *     arg              - (IN) tas control value
    671  * Returns:
    672  *     BCM_E_XXX
    673  */
    674 STATIC int
    675 bcmi_gh2_tas_control_set(
    676     int unit,
    677     bcm_port_t port,
    678     bcm_cosq_tas_control_t type,
    679     int arg)
    680 {
    681     uint32 rval, period, ptp_mode;
    682 
    683     BCM_IF_ERROR_RETURN(bcmi_gh2_tas_port_validate(unit, port));
    684 
    685     switch (type) {
    686     case bcmCosqTASControlTASEnable:
    687         /* GH2 valid value 0 or 1 */
    688         if ((arg < 0) || (arg > 1)) {
    689             return BCM_E_PARAM;
    690         }
    691         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval));
    692         soc_reg_field_set(unit, TAS_CONFIG_0r, &rval,
    693                           GATE_ENABLEDf, arg);
    694         BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_0r(unit, port, rval));
    695         if (arg == 0) {
    696             BCM_IF_ERROR_RETURN(bcmi_gh2_tas_disable_notify(unit, port));
    697         } else {
    698             (void)bcmi_gh2_tas_tod_handler(unit);
    699         }
    700         break;
    701     case bcmCosqTASControlUsePTPTime:
    702         /* GH2 valid value 0 or 1 */
    703         if ((arg < 0) || (arg > 1)) {
    704             return BCM_E_PARAM;
    705         }
    706         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval));
    707         soc_reg_field_set(unit, TAS_CONFIG_0r, &rval,
    708                           PTP_ACTIVEf, arg);
    709         BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_0r(unit, port, rval));
    710         break;
    711     case bcmCosqTASControlInitGateState:
    712         /* GH2 valid value to specify 8 queue in bitmap */
    713         if ((arg > 0xFF) || (arg < 0)) {
    714             return BCM_E_PARAM;
    715         }
    716         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_2r(unit, port, &rval));
    717         soc_reg_field_set(unit, TAS_CONFIG_2r, &rval,
    718                           INIT_GATE_STATEf, arg);
    719         BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_2r(unit, port, rval));
    720         break;
    721     case bcmCosqTASControlErrGateState:
    722         /* GH2 valid value to specify 8 queue in bitmap */
    723         if (arg > 0xFF) {
    724             return BCM_E_PARAM;
    725         }
    726         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_2r(unit, port, &rval));
    727         soc_reg_field_set(unit, TAS_CONFIG_2r, &rval,
    728                           ERR_GATE_STATEf, arg);
    729         BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_2r(unit, port, rval));
    730         break;
    731     case bcmCosqTASControlGatePurgeEnable:
    732         /* GH2 valid value 0 or 1 */
    733         if ((arg < 0) || (arg > 1)) {
    734             return BCM_E_PARAM;
    735         }
    736         BCM_IF_ERROR_RETURN(READ_TAS_GATE_PURGE_ENABLEr(unit, port, &rval));
    737         soc_reg_field_set(unit, TAS_GATE_PURGE_ENABLEr, &rval,
    738                           TAS_GATE_PURGE_ENABLEf, arg);
    739         BCM_IF_ERROR_RETURN(WRITE_TAS_GATE_PURGE_ENABLEr(unit, port, rval));
    740         break;
    741     case bcmCosqTASControlGateControlTickInterval:
    742         /* GH2 valid ragne 8ns ~ 8192 ns */
    743         if ((arg < 8) || (arg > 8192)) {
    744             return BCM_E_PARAM;
    745         }
    746         /* From Arch document, period should be STATIC config and not allowed
    747            to be changed when TAS is enabled. */
    748         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval));
    749         if (soc_reg_field_get(unit, TAS_CONFIG_0r, rval, GATE_ENABLEDf)) {
    750             LOG_ERROR(BSL_LS_BCM_TAS,
    751                       (BSL_META_UP(unit, port, "Tick Interval is not allowed "
    752                                    "to be changed when TAS is enabled.\n")));
    753             return BCM_E_BUSY;
    754         }
    755         period = (arg / GH2_TAS_GCLT_TICKS) - 1;
    756         BCM_IF_ERROR_RETURN(READ_GATE_CTRL_PERIODr(unit, port, &rval));
    757         soc_reg_field_set(unit, GATE_CTRL_PERIODr, &rval,
    758                           PERIODf, period);
    759         BCM_IF_ERROR_RETURN(WRITE_GATE_CTRL_PERIODr(unit, port, rval));
    760         break;
    761     case bcmCosqTASControlTASPTPLock:
    762         ptp_mode = 0;
    763         /* check if any tas enabled port is using ptp time */
    764         PBMP_PORT_ITER(unit, port) {
    765             BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval));
    766             if (soc_reg_field_get(unit, TAS_CONFIG_0r, rval, GATE_ENABLEDf)) {
    767                 ptp_mode = soc_reg_field_get(unit, TAS_CONFIG_0r,
    768                                              rval, PTP_ACTIVEf);
    769                 if (ptp_mode) {
    770                     break;
    771                 }
    772             }
    773         }
    774         BCM_IF_ERROR_RETURN(READ_PTP_LOCKr(unit, &rval));
    775         soc_reg_field_set(unit, PTP_LOCKr, &rval,
    776                           PTP_LOCKf, arg);
    777         BCM_IF_ERROR_RETURN(WRITE_PTP_LOCKr(unit, rval));
    778         if ((arg == 0) && (ptp_mode == 1)) {
    779             /* Notify PTP out of sync */
    780             (void)bcmi_esw_cosq_handle_interrupt(
    781                     unit, bcmCosqEventTASPTPOutOfSyncErr, -1, -1);
    782         }
    783         break;
    784     default:
    785         return BCM_E_PARAM;
    786     }
    787 
    788     return BCM_E_NONE;
    789  }
    790 
    791 /*
    792  * Function:
    793  *     bcmi_gh2_tas_control_get
    794  * Purpose:
    795  *     Get various configurations for TAS
    796  * Parameters:
    797  *     unit             - (IN) unit number
    798  *     port             - (IN) gport id
    799  *     type             - (IN) tas control type defined in bcm_cos_tas_control_t
    800  *     arg              - (OUT) tas control value
    801  * Returns:
    802  *     BCM_E_XXX
    803  */
    804 STATIC int
    805 bcmi_gh2_tas_control_get(
    806     int unit,
    807     bcm_port_t port,
    808     bcm_cosq_tas_control_t type,
    809     int *arg)
    810 {
    811     uint32 rval, period;
    812 
    813     BCM_IF_ERROR_RETURN(bcmi_gh2_tas_port_validate(unit, port));
    814 
    815     switch (type) {
    816     case bcmCosqTASControlTASEnable:
    817         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval));
    818         *arg = soc_reg_field_get(unit, TAS_CONFIG_0r, rval, GATE_ENABLEDf);
    819         break;
    820     case bcmCosqTASControlUsePTPTime:
    821         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval));
    822         *arg = soc_reg_field_get(unit, TAS_CONFIG_0r, rval, PTP_ACTIVEf);
    823         break;
    824     case bcmCosqTASControlInitGateState:
    825         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_2r(unit, port, &rval));
    826         *arg = soc_reg_field_get(unit, TAS_CONFIG_2r, rval, INIT_GATE_STATEf);
    827         break;
    828     case bcmCosqTASControlErrGateState:
    829         BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_2r(unit, port, &rval));
    830         *arg = soc_reg_field_get(unit, TAS_CONFIG_2r, rval, ERR_GATE_STATEf);
    831         break;
    832     case bcmCosqTASControlGatePurgeEnable:
    833         BCM_IF_ERROR_RETURN(READ_TAS_GATE_PURGE_ENABLEr(unit, port, &rval));
    834         *arg = soc_reg_field_get(unit, TAS_GATE_PURGE_ENABLEr, rval,
    835                                  TAS_GATE_PURGE_ENABLEf);
    836         break;
    837     case bcmCosqTASControlGateControlTickInterval:
    838         BCM_IF_ERROR_RETURN(READ_GATE_CTRL_PERIODr(unit, port, &rval));
    839         period = soc_reg_field_get(unit, GATE_CTRL_PERIODr, rval, PERIODf);
    840         *arg = (period + 1) * GH2_TAS_GCLT_TICKS;
    841         break;
    842     case bcmCosqTASControlTASPTPLock:
    843         BCM_IF_ERROR_RETURN(READ_PTP_LOCKr(unit, &rval));
    844         *arg = soc_reg_field_get(unit, PTP_LOCKr, rval, PTP_LOCKf);
    845         break;
    846     default:
    847         return BCM_E_PARAM;
    848     }
    849     return BCM_E_NONE;
    850 }
    851 
    852 /*
    853  * Function:
    854  *     bcmi_gh2_tas_status_get
    855  * Purpose:
    856  *     Get TAS status by specifying the type.
    857  * Parameters:
    858  *     unit             - (IN) unit number
    859  *     port             - (IN) gport id
    860  *     type             - (IN) tas status type defined in bcm_cos_tas_status_t
    861  *     arg              - (OUT) tas status value
    862  * Returns:
    863  *     BCM_E_XXX
    864  */
    865 STATIC int
    866 bcmi_gh2_tas_status_get(
    867     int unit,
    868     bcm_port_t port,
    869     bcm_cosq_tas_status_t type,
    870     int *arg)
    871 {
    872     uint32 rval;
    873     int auto_adjust_txoverrun = 0, auto_adjust_phold = 0;
    874 
    875     BCM_IF_ERROR_RETURN(bcmi_gh2_tas_port_validate(unit, port));
    876 
    877     switch (type) {
    878     case bcmCosqTASStatusGateQueueState:
    879         BCM_IF_ERROR_RETURN(READ_COS_QUEUEr(unit, port, &rval));
    880         *arg = soc_reg_field_get(unit, COS_QUEUEr, rval, GATE_STATEf);
    881         break;
    882     case bcmCosqTASStatusGateStateSet:
    883         BCM_IF_ERROR_RETURN(READ_COS_QUEUEr(unit, port, &rval));
    884         *arg = soc_reg_field_get(unit, COS_QUEUEr, rval, GATE_STATE_SELECTf);
    885         break;
    886     case bcmCosqTASStatusTickGranularity:
    887         *arg = GH2_TAS_GCLT_TICKS;
    888         break;
    889     case bcmCosqTASStatusMaxCalendarEntries:
    890         bcmi_esw_tas_property_get(unit, TAS_PROP_TXOVERRUN,
    891                                   port, -1, &auto_adjust_txoverrun);
    892         bcmi_esw_tas_property_get(unit, TAS_PROP_HOLDADVANCE,
    893                                   port, -1, &auto_adjust_phold);
    894         if (auto_adjust_txoverrun || auto_adjust_phold) {
    895             *arg = GH2_TAS_GCLT_ENTRIES / 2;
    896         } else {
    897             *arg = GH2_TAS_GCLT_ENTRIES;
    898         }
    899         break;
    900     default:
    901         return BCM_E_PARAM;
    902     }
    903     return BCM_E_NONE;
    904 }
    905 
    906 /*
    907  * Purpose:
    908  *  Get the hold advance time in ns
    909  * Description:
    910  * Tha = (Thrt - Tgor) where Thrt is the hold response time which depends on
    911  * Min_final_fragment_size and Min_non_final_fragment_size.
    912  * The minimum of Tgor(gate open response time) has to be considered in order to
    913  * make sure a preemptable frame never delays an express frame
    914  */
    915  STATIC int
    916 bcmi_gh2_tas_tha_get(
    917     int unit,
    918     bcm_port_t lport,
    919     int *tha)
    920 {
    921     bcm_gport_t gport;
    922     int speed, bit_tick_ps;
    923     uint32 non_final_frag_size, final_frag_size;
    924 
    925     if (tha == NULL) {
    926         return BCM_E_PARAM;
    927     }
    928     /* Get port speed -> caculate bit time in picosecond */
    929     BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, lport, &speed));
    930     if (!speed) {
    931         BCM_IF_ERROR_RETURN(bcm_esw_port_speed_max(unit, lport, &speed));
    932     }
    933     if (!speed) {
    934         speed = SOC_CONTROL(unit)->info.port_speed_max[lport];
    935     }
    936     /* speed in Mbps, bit time in ps: 10^6/speed */
    937     bit_tick_ps = 1000000 / speed;
    938 
    939     BCM_IF_ERROR_RETURN(bcm_esw_port_gport_get(unit, lport, &gport));
    940     BCM_IF_ERROR_RETURN(
    941         bcm_esw_port_preemption_control_get(
    942             unit, gport, bcmPortPreemptControlNonFinalFragSizeTx,
    943             &non_final_frag_size));
    944     BCM_IF_ERROR_RETURN(
    945         bcm_esw_port_preemption_control_get(
    946             unit, gport, bcmPortPreemptControlFinalFragSizeTx,
    947             &final_frag_size));
    948     /* Fixed time : SMD 8B, IPG 12B, Hold recognition time 12B */
    949     *tha = FIXED_THA_OVERHEAD * 8 * bit_tick_ps / 1000;
    950     /* Variable time : according to frag size */
    951     *tha += (non_final_frag_size + final_frag_size) * 8 * bit_tick_ps / 1000;
    952 
    953     LOG_DEBUG(BSL_LS_BCM_TAS,
    954               (BSL_META_U(unit, "Tha (speed %d, non-frag %d frag %d ) %d ns\n"),
    955                speed, non_final_frag_size, final_frag_size, *tha));
    956      return BCM_E_NONE;
    957 }
    958 
    959 /*
    960  * Get the bytes in the edatabuf to compute worst case value of
    961  * T-edatabuf (flush time to cleanup the fifo)
    962  */
    963 STATIC int
    964 bcmi_gh2_tas_tgcr_edatabuf_fifo_get(
    965     int unit,
    966     bcm_port_t port,
    967     int *pkt_bytes)
    968 {
    969     soc_info_t *si;
    970     int phy_port, sub_ports, pkt_cnt, shift, group, start, pkt_size;
    971     SHR_BITDCL pbmp[_SHR_BITDCLSIZE(GH2_MAX_PHY_PORTS)];
    972 
    973     if (pkt_bytes == NULL) {
    974         return BCM_E_PARAM;
    975     }
    976     BCM_IF_ERROR_RETURN(
    977         READ_EGR_TDM_PORT_MAPm(unit, MEM_BLOCK_ALL, 0, (void *)&pbmp));
    978 
    979     si = &SOC_INFO(unit);
    980     phy_port = si->port_l2p_mapping[port];
    981 
    982     /*
    983      * phy port group in EGR_TDM_PORT_MAPm bitmap
    984      * GE0:2-9, GE1:10-17, GE2:18-25, GE3:26-33, ... GE6: 50-57
    985      * XL0:58-59, XL1:60-61 ......XL13:84-85
    986      * CL0: 86-89
    987      */
    988     if (phy_port < 58) {
    989         /* < 58 : GE port, start from 2, 8 ports as a group.*/
    990         shift = 2;
    991         group = 8;
    992     } else if (phy_port < 86) {
    993         /* >=58, < 86: XL port, start from 58, 2 ports as a group */
    994         shift = 58;
    995         group = 2;
    996     } else if (phy_port < 90) {
    997         /* >= 86, < 90: CL port, start from 86, 4 ports as a group */
    998         shift = 86;
    999         group = 4;
   1000     } else {
   1001         return BCM_E_PARAM;
   1002     }
   1003     /* Find port belongs to which group and find the start of it */
   1004     start = (((phy_port - shift) / group) * group) + shift;
   1005     /* Caculate how many ports are valid in this group */
   1006     SHR_BITCOUNT_RANGE(pbmp, sub_ports, start, group);
   1007 
   1008     /*
   1009      * For Edatabuf FIFO flush time, under different configurations
   1010      * (sub-port count), the total packets be sent (pkt.cnt * pkt.size) are
   1011      * listed below.
   1012      * The data is for express packets only. If preempt packets are considered,
   1013      * the time should be doubled. For time caculation, we assume the case of
   1014      * express packet.
   1015      *
   1016      * port-group sub-port pkt.cnt pkt.size
   1017      *  GE         8         5       224
   1018      *  GE         4        10       224
   1019      *  GE         2        20       224
   1020      *  GE         1        24       224
   1021      *  XL         2        14       224
   1022      *  XL         1        24       224
   1023      *  CL         4        20       288
   1024      *  CL         2        24       288
   1025      *  CL         1        24       288
   1026      */
   1027     if (phy_port < 58) {
   1028         /* GE port case */
   1029         if (sub_ports == 8) {
   1030             pkt_cnt = 5;
   1031         } else if (sub_ports == 4) {
   1032             pkt_cnt = 10;
   1033         } else if (sub_ports == 2) {
   1034             pkt_cnt = 20;
   1035         } else {
   1036             pkt_cnt = 24;
   1037         }
   1038         pkt_size = 224;
   1039     } else if (phy_port < 86) {
   1040         /* XL port case phy_port < 86 */
   1041         if (sub_ports == 2) {
   1042             pkt_cnt = 14;
   1043         } else {
   1044             pkt_cnt = 24;
   1045         }
   1046         pkt_size = 224;
   1047     } else {
   1048         /* The invalid phy_port check has been done.*/
   1049         if (sub_ports == 4) {
   1050             pkt_cnt = 20;
   1051         } else if (sub_ports == 2) {
   1052             pkt_cnt = 24;
   1053         } else {
   1054             pkt_cnt = 24;
   1055         }
   1056         pkt_size = 288;
   1057     }
   1058     *pkt_bytes = pkt_cnt * pkt_size;
   1059 
   1060     LOG_DEBUG(BSL_LS_BCM_TAS,
   1061               (BSL_META_U(unit,
   1062                           "tgcr_edatabuf_fifo phy_port %d subport %d "
   1063                           "pkt_bytes %d \n"),
   1064                phy_port, sub_ports, *pkt_bytes));
   1065     return BCM_E_NONE;
   1066 }
   1067 
   1068 /* T-txpkt (depends on queueMaxSDU) */
   1069 /*
   1070  * Get the bit time(in ns) of the maximum value of MaxSDU(maximum service data
   1071  * unit) among the specified queue map.
   1072  */
   1073 STATIC int
   1074 bcmi_gh2_tas_tgcr_txpkt_get(
   1075     int unit,
   1076     bcm_port_t port,
   1077     uint32 qmap,
   1078     int *tgcr_txpkt)
   1079 {
   1080     int c;
   1081     int prop;
   1082     int maxsdu = 0;
   1083     int speed, bit_tick_ps;
   1084 
   1085     if (tgcr_txpkt == NULL) {
   1086         return BCM_E_PARAM;
   1087     }
   1088     for (c = 0; c < BCM_COS_COUNT; c++) {
   1089         if (qmap & (1 << c)) {
   1090             BCM_IF_ERROR_RETURN(
   1091                 bcmi_esw_tas_property_get(unit, TAS_PROP_MAXSDU, port,
   1092                                           c, &prop));
   1093             /* keep the largest one */
   1094             if (prop > maxsdu) {
   1095                 maxsdu = prop;
   1096             }
   1097         }
   1098     }
   1099     /* Get port speed -> caculate bit time in picosecond */
   1100     BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, port, &speed));
   1101     if (!speed) {
   1102         BCM_IF_ERROR_RETURN(bcm_esw_port_speed_max(unit, port, &speed));
   1103     }
   1104     if (!speed) {
   1105         speed = SOC_CONTROL(unit)->info.port_speed_max[port];
   1106     }
   1107 
   1108     /* speed in Mbps, bit time in ps: 10^6/speed */
   1109     bit_tick_ps = 1000000 / speed;
   1110 
   1111     *tgcr_txpkt = maxsdu * 8 * bit_tick_ps / 1000;
   1112 
   1113     LOG_DEBUG(BSL_LS_BCM_TAS,
   1114               (BSL_META_U(unit,
   1115                           "Dynamic tgcr (speed %d, Qmap %08x, max_sdu %d) "
   1116                           "%d ns \n"),
   1117                speed, qmap, maxsdu, *tgcr_txpkt));
   1118     return BCM_E_NONE;
   1119 }
   1120 
   1121 /*
   1122  * Get the Tgcr exclude the T-txpkt which could be queue-dependent.
   1123  * The 'fixed' means its queue-independent, the port speed and attribute
   1124  * decide the tgcr_fixed. This value is fixed across entries in calendar table.
   1125  */
   1126 STATIC int
   1127 bcmi_gh2_tas_tgcr_fixed_get(int unit, bcm_port_t port, int *tgcr_fixed)
   1128 {
   1129     soc_info_t *si;
   1130     int delay_param;
   1131     int freq, core_tick_ns;
   1132     int speed, bit_tick_ps;
   1133     int tdm_size, txpfc_enable, edatabuf_bytes, pkt_bytes, top_fifo_delay;
   1134 
   1135     if (tgcr_fixed == NULL) {
   1136         return BCM_E_PARAM;
   1137     }
   1138     si = &SOC_INFO(unit);
   1139     /* Get core clock freq in MHz */
   1140     freq = si->frequency;
   1141     /* core tick in ns : 10^3/freq */
   1142     core_tick_ns = 1000 / freq;
   1143 
   1144     /* Get port speed -> caculate bit time in picosecond */
   1145     BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, port, &speed));
   1146     if (!speed) {
   1147         BCM_IF_ERROR_RETURN(bcm_esw_port_speed_max(unit, port, &speed));
   1148     }
   1149     if (!speed) {
   1150         speed = SOC_CONTROL(unit)->info.port_speed_max[port];
   1151     }
   1152 
   1153     /* speed in Mbps, bit time in ps: 10^6/speed */
   1154     bit_tick_ps = 1000000 / speed;
   1155 
   1156     /* T-gs-async-fifo  = 3 core clk */
   1157     delay_param = 3 * core_tick_ns;
   1158 
   1159     /* T-egr-tdm : Worst TDM miss penalty for MMU dequeue =
   1160      * (Max TDM interval - 1) x Cycle Time(ns) */
   1161     BCM_IF_ERROR_RETURN(soc_gh2_tdm_size_get(unit, &tdm_size));
   1162     delay_param += (tdm_size - 1) * core_tick_ns;
   1163 
   1164     /* T-edatabuf */
   1165     BCM_IF_ERROR_RETURN(
   1166         bcmi_gh2_tas_tgcr_edatabuf_fifo_get(unit, port, &edatabuf_bytes));
   1167     delay_param += edatabuf_bytes * 8 * bit_tick_ps / 1000;
   1168 
   1169     /* T-mactxfifo */
   1170     if (IS_CL_PORT(unit, port)) {
   1171         /* 4 x 48B = 192B */
   1172         pkt_bytes = TGCR_CLMAC_TXFIFO;
   1173         /* PM 4x25_top fifo delay = 15.51 ns */
   1174         top_fifo_delay = 16;
   1175     } else if (IS_XL_PORT(unit, port)) {
   1176         /* 4 x 32B = 128B */
   1177         pkt_bytes = TGCR_XLMAC_TXFIFO;
   1178         /* PM 4x10_top fifo delay = 15.51 ns */
   1179         top_fifo_delay = 16;
   1180     } else if (IS_GE_PORT(unit, port)) {
   1181         /* 4 x 32B  + 16 x 128b = 384B */
   1182         pkt_bytes = TGCR_UNIMAC_TXFIFO;
   1183         top_fifo_delay = 0;
   1184     } else {
   1185         return BCM_E_PARAM;
   1186     }
   1187     /* also consider the 80/64 encoding */
   1188     delay_param += pkt_bytes * 8 * 80 / 64 * bit_tick_ps / 1000;
   1189     delay_param += top_fifo_delay;
   1190 
   1191     /* T-pfc */
   1192     BCM_IF_ERROR_RETURN(
   1193         bcm_esw_port_control_get(unit, port, bcmPortControlPFCTransmit,
   1194                                  &txpfc_enable));
   1195     if (txpfc_enable) {
   1196         /* pfc frame size = 64B */
   1197         delay_param += 64 * 8 * bit_tick_ps / 1000;
   1198     }
   1199     *tgcr_fixed = delay_param;
   1200 
   1201     LOG_DEBUG(BSL_LS_BCM_TAS,
   1202               (BSL_META_U(unit, "Fixed tgcr (core clk %d, tdm size %d, "
   1203                                 "speed %d, pfc enable %d, "
   1204                                 "edatabuf fifo %d, port fifo %d, "
   1205                                 "port top fifo %d) %d ns \n"),
   1206                freq, tdm_size, speed, txpfc_enable, edatabuf_bytes,
   1207                pkt_bytes, top_fifo_delay, *tgcr_fixed));
   1208     return BCM_E_NONE;
   1209 }
   1210 
   1211 /*
   1212  * Function:
   1213  *     bcmi_gh2_tas_profile_delay_param_get
   1214  * Purpose:
   1215  *     Helper function to get the device-specific delay parameters which are
   1216  *     used to do the profile entry remap.
   1217  *
   1218  * Parameters:
   1219  *     unit              - (IN) unit number
   1220  *     tas_delay_param   - (IN) TAS_DPARAM_xxx to specify which delay param
   1221  *     port              - (IN) logical port
   1222  *     qmap              - (IN) queue bitmap, optional and valid for type
   1223  *                         TAS_DPARAM_TGCR_DYNAMIC.
   1224  *     value             - (OUT) value in ns
   1225  * Returns:
   1226  *     BCM_E_XXX
   1227  */
   1228 STATIC int
   1229 bcmi_gh2_tas_profile_delay_param_get(
   1230     int unit,
   1231     int tas_delay_param,
   1232     bcm_port_t port,
   1233     uint32 qmap,
   1234     int *value)
   1235 {
   1236     int rv = BCM_E_NONE;
   1237 
   1238     if (value == NULL) {
   1239         return BCM_E_PARAM;
   1240     }
   1241     BCM_IF_ERROR_RETURN(bcmi_gh2_tas_port_validate(unit, port));
   1242 
   1243     switch (tas_delay_param) {
   1244         case (TAS_DPARAM_TGCR_FIXED):
   1245             rv = bcmi_gh2_tas_tgcr_fixed_get(unit, port, value);
   1246             break;
   1247         case (TAS_DPARAM_TGCR_DYNAMIC):
   1248             rv = bcmi_gh2_tas_tgcr_txpkt_get(unit, port, qmap, value);
   1249             break;
   1250         case (TAS_DPARAM_THA):
   1251             rv = bcmi_gh2_tas_tha_get(unit, port, value);
   1252             break;
   1253         default:
   1254             return BCM_E_UNAVAIL;
   1255     }
   1256     return rv;
   1257 }
   1258 
   1259 /*
   1260  * Basetime compare against CurrentTime + Tmargin
   1261  *  if Basetime < CurrentTime + Tmargin  return BCM_E_NONE
   1262  *  otherwise return BCM_E_TIMEOUT which is for user application to increase
   1263  *  the config change error)
   1264  */
   1265 STATIC int
   1266 bcmi_gh2_tas_profile_basetime_check(int unit, bcm_ptp_timestamp_t basetime)
   1267 {
   1268     bcm_ptp_timestamp_t cur_time;
   1269     uint64 bt_in_ns, ct_in_ns, tmargin;
   1270     int len;
   1271     uint32 max_cycle_time;
   1272 
   1273     if (BCM_FAILURE(bcmi_tas_current_time(unit, &cur_time))) {
   1274         LOG_ERROR(BSL_LS_BCM_TAS,
   1275                   (BSL_META_U(unit,
   1276                               "Fatal error: "
   1277                               "Fail to get current time !\n")));
   1278         return BCM_E_INTERNAL;
   1279     }
   1280     ct_in_ns = bcmi_tas_ptp_to_ns(cur_time);
   1281     bt_in_ns = bcmi_tas_ptp_to_ns(basetime);
   1282 
   1283     COMPILER_64_ZERO(tmargin);
   1284     /* worse case of the 2 times of cycle time */
   1285     len = soc_reg_field_length(unit, CYCLE_TIMEr, CYCLE_TIMEf);
   1286     max_cycle_time = (1 << len) - 1;
   1287     COMPILER_64_ADD_32(tmargin, 2 * max_cycle_time);
   1288     COMPILER_64_ADD_32(tmargin, GH2_TAS_HW_REG_RESPONSE_TIME);
   1289     COMPILER_64_ADD_32(tmargin,
   1290                        GH2_TAS_SW_PROCESS_TIME * TAS_PTP_TIME_NANOSEC_MAX);
   1291 
   1292     LOG_DEBUG(BSL_LS_BCM_TAS,
   1293               (BSL_META_U(unit, "Tmargin in GH2 {0x%x 0x%x} \n"),
   1294                COMPILER_64_HI(tmargin), COMPILER_64_LO(tmargin)));
   1295 
   1296     COMPILER_64_ADD_64(ct_in_ns, tmargin);
   1297     if (COMPILER_64_GT(ct_in_ns, bt_in_ns)) {
   1298         return BCM_E_TIMEOUT;
   1299     }
   1300     return BCM_E_NONE;
   1301 }
   1302 
   1303 /*
   1304  * Function:
   1305  *     bcmi_gh2_tas_profile_idx_get
   1306  * Purpose:
   1307  *     Get the inactive hw index. We need to program to the inactive sets
   1308  * Parameters:
   1309  *     unit             - (IN) unit number
   1310  *     lport            - (IN) logical port
   1311  *     config_idx       - (OUT) inactive hw index
   1312  * Returns:
   1313  *     BCM_E_XXX
   1314  */
   1315 STATIC int
   1316 bcmi_gh2_tas_profile_idx_get(int unit, bcm_port_t lport, int *config_idx)
   1317 {
   1318     uint32 rval;
   1319     int active_idx;
   1320 
   1321     BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_1r(unit, lport, &rval));
   1322     active_idx = soc_reg_field_get(unit, TAS_CONFIG_1r, rval, ACTIVE_SETf);
   1323     *config_idx = 1 - active_idx;
   1324     return BCM_E_NONE;
   1325 }
   1326 
   1327 /*
   1328  * gh2_mmu_gate_ctl_tbl :
   1329  * valid port 2-65, valid idx 0-1
   1330 */
   1331 static const soc_mem_t gh2_mmu_gate_ctl_tbl[66][2] =
   1332 {
   1333     {INVALIDm, INVALIDm},
   1334     {INVALIDm, INVALIDm},
   1335     {MMU_GATE_CTL_TBL0_P2m, MMU_GATE_CTL_TBL1_P2m},
   1336     {MMU_GATE_CTL_TBL0_P3m, MMU_GATE_CTL_TBL1_P3m},
   1337     {MMU_GATE_CTL_TBL0_P4m, MMU_GATE_CTL_TBL1_P4m},
   1338     {MMU_GATE_CTL_TBL0_P5m, MMU_GATE_CTL_TBL1_P5m},
   1339     {MMU_GATE_CTL_TBL0_P6m, MMU_GATE_CTL_TBL1_P6m},
   1340     {MMU_GATE_CTL_TBL0_P7m, MMU_GATE_CTL_TBL1_P7m},
   1341     {MMU_GATE_CTL_TBL0_P8m, MMU_GATE_CTL_TBL1_P8m},
   1342     {MMU_GATE_CTL_TBL0_P9m, MMU_GATE_CTL_TBL1_P9m},
   1343     {MMU_GATE_CTL_TBL0_P10m, MMU_GATE_CTL_TBL1_P10m},
   1344     {MMU_GATE_CTL_TBL0_P11m, MMU_GATE_CTL_TBL1_P11m},
   1345     {MMU_GATE_CTL_TBL0_P12m, MMU_GATE_CTL_TBL1_P12m},
   1346     {MMU_GATE_CTL_TBL0_P13m, MMU_GATE_CTL_TBL1_P13m},
   1347     {MMU_GATE_CTL_TBL0_P14m, MMU_GATE_CTL_TBL1_P14m},
   1348     {MMU_GATE_CTL_TBL0_P15m, MMU_GATE_CTL_TBL1_P15m},
   1349     {MMU_GATE_CTL_TBL0_P16m, MMU_GATE_CTL_TBL1_P16m},
   1350     {MMU_GATE_CTL_TBL0_P17m, MMU_GATE_CTL_TBL1_P17m},
   1351     {MMU_GATE_CTL_TBL0_P18m, MMU_GATE_CTL_TBL1_P18m},
   1352     {MMU_GATE_CTL_TBL0_P19m, MMU_GATE_CTL_TBL1_P19m},
   1353     {MMU_GATE_CTL_TBL0_P20m, MMU_GATE_CTL_TBL1_P20m},
   1354     {MMU_GATE_CTL_TBL0_P21m, MMU_GATE_CTL_TBL1_P21m},
   1355     {MMU_GATE_CTL_TBL0_P22m, MMU_GATE_CTL_TBL1_P22m},
   1356     {MMU_GATE_CTL_TBL0_P23m, MMU_GATE_CTL_TBL1_P23m},
   1357     {MMU_GATE_CTL_TBL0_P24m, MMU_GATE_CTL_TBL1_P24m},
   1358     {MMU_GATE_CTL_TBL0_P25m, MMU_GATE_CTL_TBL1_P25m},
   1359     {MMU_GATE_CTL_TBL0_P26m, MMU_GATE_CTL_TBL1_P26m},
   1360     {MMU_GATE_CTL_TBL0_P27m, MMU_GATE_CTL_TBL1_P27m},
   1361     {MMU_GATE_CTL_TBL0_P28m, MMU_GATE_CTL_TBL1_P28m},
   1362     {MMU_GATE_CTL_TBL0_P29m, MMU_GATE_CTL_TBL1_P29m},
   1363     {MMU_GATE_CTL_TBL0_P30m, MMU_GATE_CTL_TBL1_P30m},
   1364     {MMU_GATE_CTL_TBL0_P31m, MMU_GATE_CTL_TBL1_P31m},
   1365     {MMU_GATE_CTL_TBL0_P32m, MMU_GATE_CTL_TBL1_P32m},
   1366     {MMU_GATE_CTL_TBL0_P33m, MMU_GATE_CTL_TBL1_P33m},
   1367     {MMU_GATE_CTL_TBL0_P34m, MMU_GATE_CTL_TBL1_P34m},
   1368     {MMU_GATE_CTL_TBL0_P35m, MMU_GATE_CTL_TBL1_P35m},
   1369     {MMU_GATE_CTL_TBL0_P36m, MMU_GATE_CTL_TBL1_P36m},
   1370     {MMU_GATE_CTL_TBL0_P37m, MMU_GATE_CTL_TBL1_P37m},
   1371     {MMU_GATE_CTL_TBL0_P38m, MMU_GATE_CTL_TBL1_P38m},
   1372     {MMU_GATE_CTL_TBL0_P39m, MMU_GATE_CTL_TBL1_P39m},
   1373     {MMU_GATE_CTL_TBL0_P40m, MMU_GATE_CTL_TBL1_P40m},
   1374     {MMU_GATE_CTL_TBL0_P41m, MMU_GATE_CTL_TBL1_P41m},
   1375     {MMU_GATE_CTL_TBL0_P42m, MMU_GATE_CTL_TBL1_P42m},
   1376     {MMU_GATE_CTL_TBL0_P43m, MMU_GATE_CTL_TBL1_P43m},
   1377     {MMU_GATE_CTL_TBL0_P44m, MMU_GATE_CTL_TBL1_P44m},
   1378     {MMU_GATE_CTL_TBL0_P45m, MMU_GATE_CTL_TBL1_P45m},
   1379     {MMU_GATE_CTL_TBL0_P46m, MMU_GATE_CTL_TBL1_P46m},
   1380     {MMU_GATE_CTL_TBL0_P47m, MMU_GATE_CTL_TBL1_P47m},
   1381     {MMU_GATE_CTL_TBL0_P48m, MMU_GATE_CTL_TBL1_P48m},
   1382     {MMU_GATE_CTL_TBL0_P49m, MMU_GATE_CTL_TBL1_P49m},
   1383     {MMU_GATE_CTL_TBL0_P50m, MMU_GATE_CTL_TBL1_P50m},
   1384     {MMU_GATE_CTL_TBL0_P51m, MMU_GATE_CTL_TBL1_P51m},
   1385     {MMU_GATE_CTL_TBL0_P52m, MMU_GATE_CTL_TBL1_P52m},
   1386     {MMU_GATE_CTL_TBL0_P53m, MMU_GATE_CTL_TBL1_P53m},
   1387     {MMU_GATE_CTL_TBL0_P54m, MMU_GATE_CTL_TBL1_P54m},
   1388     {MMU_GATE_CTL_TBL0_P55m, MMU_GATE_CTL_TBL1_P55m},
   1389     {MMU_GATE_CTL_TBL0_P56m, MMU_GATE_CTL_TBL1_P56m},
   1390     {MMU_GATE_CTL_TBL0_P57m, MMU_GATE_CTL_TBL1_P57m},
   1391     {MMU_GATE_CTL_TBL0_P58m, MMU_GATE_CTL_TBL1_P58m},
   1392     {MMU_GATE_CTL_TBL0_P59m, MMU_GATE_CTL_TBL1_P59m},
   1393     {MMU_GATE_CTL_TBL0_P60m, MMU_GATE_CTL_TBL1_P60m},
   1394     {MMU_GATE_CTL_TBL0_P61m, MMU_GATE_CTL_TBL1_P61m},
   1395     {MMU_GATE_CTL_TBL0_P62m, MMU_GATE_CTL_TBL1_P62m},
   1396     {MMU_GATE_CTL_TBL0_P63m, MMU_GATE_CTL_TBL1_P63m},
   1397     {MMU_GATE_CTL_TBL0_P64m, MMU_GATE_CTL_TBL1_P64m},
   1398     {MMU_GATE_CTL_TBL0_P65m, MMU_GATE_CTL_TBL1_P65m},
   1399 };
   1400 /*
   1401  * Function:
   1402  *     bcmi_gh2_tas_profile_param_check
   1403  * Purpose:
   1404  *     Validate the parameters in bcm profile structure
   1405  * Parameters:
   1406  *     unit             - (IN) unit number
   1407  *     profile          - (IN) bcm tas profile structure
   1408  *
   1409  * Returns:
   1410  *     BCM_E_XXX
   1411  */
   1412 STATIC int
   1413 bcmi_gh2_tas_profile_param_check(int unit, bcm_cosq_tas_profile_t *profile)
   1414 {
   1415     soc_mem_t gclt_mem = MMU_GATE_CTL_TBL0_P2m;
   1416     bcm_cosq_tas_entry_t *tas_entry;
   1417     int i, field_len;
   1418 
   1419     for (i = 0; i < profile->num_entries; i++) {
   1420         tas_entry = &profile->entries[i];
   1421         if (tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_STAY) {
   1422             field_len = soc_mem_field_length(unit, gclt_mem, TIME_INTERVALf);
   1423             /* AND the 0xFFF for ticks_stay value */
   1424             tas_entry->ticks &= (1 << field_len) - 1;
   1425         }
   1426         BCM_IF_ERROR_RETURN(soc_mem_field32_fit(unit, gclt_mem, TIME_INTERVALf,
   1427                                                 tas_entry->ticks));
   1428         BCM_IF_ERROR_RETURN(soc_mem_field32_fit(unit, gclt_mem, GATE_STATEf,
   1429                                                 tas_entry->state));
   1430     }
   1431 
   1432     BCM_IF_ERROR_RETURN(
   1433         soc_reg_field_validate(unit, CYCLE_TIMEr, CYCLE_TIMEf,
   1434                                profile->ptp_cycle_time));
   1435     BCM_IF_ERROR_RETURN(
   1436         soc_reg_field_validate(unit, CYCLE_TIME_EXTENSIONr,
   1437                                CYCLE_TIME_EXTENSIONf,
   1438                                profile->ptp_max_cycle_extension));
   1439 
   1440     return BCM_E_NONE;
   1441 }
   1442 
   1443 /*
   1444  * Function:
   1445  *     bcmi_gh2_tas_profile_entries_write
   1446  * Purpose:
   1447  *     Program the profile entries to HW
   1448  * Parameters:
   1449  *     unit             - (IN) unit number
   1450  *     lport             - (IN) logical port
   1451  *     config_idx        - (IN) hw config idx
   1452  *     entries           - (IN) profile entries
   1453  *     num_entries       - (IN) number of entries
   1454  *
   1455  * Returns:
   1456  *     BCM_E_XXX
   1457  */
   1458 STATIC int
   1459 bcmi_gh2_tas_profile_entries_write(
   1460     int unit,
   1461     bcm_port_t lport,
   1462     int config_idx,
   1463     bcm_cosq_tas_entry_t *entries,
   1464     int num_entries)
   1465 {
   1466     int i, idx_max;
   1467     mmu_gate_ctl_tbl0_p2_entry_t *gclt_entry;
   1468     uint8 *gclt_buf = NULL;
   1469     uint8 phold = 0;
   1470     int rv;
   1471     soc_mem_t gclt_mem = MMU_GATE_CTL_TBL0_P2m;
   1472     soc_memacc_t memacc_phold, memacc_interval, memacc_gstate;
   1473     bcm_cosq_tas_entry_t *tas_entry;
   1474     soc_info_t *si;
   1475     int phy_port, mmu_port;
   1476 
   1477     if ((soc_memacc_init(unit, gclt_mem, PHOLD_REQf, &memacc_phold)) ||
   1478         (soc_memacc_init(unit, gclt_mem, TIME_INTERVALf, &memacc_interval)) ||
   1479         (soc_memacc_init(unit, gclt_mem, GATE_STATEf, &memacc_gstate))) {
   1480           return BCM_E_PARAM;
   1481     }
   1482 
   1483     TAS_ALLOC(unit, gclt_buf, uint8,
   1484               num_entries * sizeof(mmu_gate_ctl_tbl0_p2_entry_t),
   1485               "TAS GCLT buffer", 1, rv);
   1486     if (BCM_FAILURE(rv)) {
   1487         return rv;
   1488     }
   1489 
   1490     idx_max = num_entries;
   1491     for (i = 0; i < idx_max; i++) {
   1492         tas_entry = &entries[i];
   1493         if (tas_entry->flags & BCM_COSQ_TAS_ENTRY_F_PREEMPT) {
   1494             phold = 1;
   1495         } else {
   1496             phold = 0;
   1497         }
   1498         gclt_entry =
   1499             soc_mem_table_idx_to_pointer(unit, gclt_mem,
   1500                                          mmu_gate_ctl_tbl0_p2_entry_t *,
   1501                                          gclt_buf,
   1502                                          i);
   1503         soc_memacc_field32_set(&memacc_gstate, gclt_entry, tas_entry->state);
   1504         soc_memacc_field32_set(&memacc_phold, gclt_entry, phold);
   1505         soc_memacc_field32_set(&memacc_interval, gclt_entry, tas_entry->ticks);
   1506 
   1507     }
   1508 
   1509     si = &SOC_INFO(unit);
   1510     phy_port = si->port_l2p_mapping[lport];
   1511     mmu_port = si->port_p2m_mapping[phy_port];
   1512     rv = soc_mem_write_range(unit, gh2_mmu_gate_ctl_tbl[mmu_port][config_idx],
   1513                              MEM_BLOCK_ALL, 0, (idx_max - 1), gclt_buf);
   1514     if (BCM_FAILURE(rv)) {
   1515         TAS_FREE(unit, gclt_buf, 1);
   1516         return rv;
   1517     }
   1518     TAS_FREE(unit, gclt_buf, 1);
   1519 
   1520     return BCM_E_NONE;
   1521 }
   1522 
   1523 /*
   1524  * Function:
   1525  *      bcmi_gh2_tas_profile_change
   1526  * Purpose:
   1527  *      Issue config change to start switching to new profile.
   1528  * Parameters:
   1529  *     unit             - (IN) unit number
   1530  *     lport            - (IN) logical port
   1531  * Returns:
   1532  *     BCM_E_XXX
   1533  */
   1534 STATIC int
   1535 bcmi_gh2_tas_profile_change(int unit, bcm_port_t lport)
   1536 {
   1537     uint32  rval;
   1538 
   1539     /* HW detect 0 to 1 change to start switching to new cycles.*/
   1540     BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, lport, &rval));
   1541     soc_reg_field_set(unit, TAS_CONFIG_0r, &rval, CONFIG_CHANGEf, 0);
   1542     BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_0r(unit, lport, rval));
   1543     soc_reg_field_set(unit, TAS_CONFIG_0r, &rval, CONFIG_CHANGEf, 1);
   1544     BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_0r(unit, lport, rval));
   1545 
   1546     return BCM_E_NONE;
   1547 }
   1548 
   1549 /*
   1550  * Function:
   1551  *      bcmi_gh2_tas_handle_interrupt
   1552  * Purpose:
   1553  *      Invoked when TAS related interrupts happen.
   1554  *      Dispatch to corresponding callback according to the interrupt.
   1555  * Parameters:
   1556  *     unit             - (IN) unit number
   1557  *     lport            - (IN) logical port
   1558  * Returns:
   1559  *     BCM_E_XXX
   1560  */
   1561 STATIC int
   1562 bcmi_gh2_tas_handle_interrupt(int unit)
   1563 {
   1564     int i, group, p;
   1565     uint32 rval, sts;
   1566     gh2_tas_event_info_t *e_info;
   1567     gh2_tas_event_ctrl_t *tec = NULL;
   1568     SHR_BITDCL  cosq_event_pbmp[_SHR_BITDCLSIZE(bcmCosqEventCount)];
   1569     SHR_BITDCL  tas_event_pbmp[_SHR_BITDCLSIZE(bcmiTASProfileEventCount)];
   1570     bcm_port_t lport, mmu_port, phy_port;
   1571     soc_reg_t sts_reg, clr_reg;
   1572     soc_info_t *si;
   1573     uint8 event_cb = 0, intr_cb = 0;
   1574 
   1575     si = &SOC_INFO(unit);
   1576     if ((tec = gh2_tas_event_ctrl[unit]) == NULL) {
   1577         return BCM_E_INTERNAL;
   1578     }
   1579 
   1580     rval = 0;
   1581     BCM_IF_ERROR_RETURN(READ_MEMFAILINTSTATUSr(unit, &rval));
   1582 
   1583     if (bsl_check(bslLayerBcm, bslSourceTas, bslSeverityDebug, unit)) {
   1584         bcm_ptp_timestamp_t cur_time;
   1585         (void)bcmi_tas_current_time (unit, &cur_time);
   1586         LOG_DEBUG(BSL_LS_BCM_TAS,
   1587                   (BSL_META_U(unit, "intr sts 0x%x \n"), rval));
   1588     }
   1589 
   1590     GH2_TAS_EVENT_LOCK(tec);
   1591     SHR_BITCOPY_RANGE(cosq_event_pbmp, 0,
   1592                       tec->cosq_event_pbmp, 0,
   1593                       bcmCosqEventCount);
   1594     SHR_BITCOPY_RANGE(tas_event_pbmp, 0,
   1595                       tec->tas_event_pbmp, 0,
   1596                       bcmiTASProfileEventCount);
   1597     GH2_TAS_EVENT_UNLOCK(tec);
   1598 
   1599     for (i = 0; ; i++) {
   1600         e_info = &gh2_tas_event_info[i];
   1601         if ((e_info->p_event == -1) && (e_info->event == -1)) {
   1602             /* End of table */
   1603             break;
   1604         }
   1605         /*
   1606          * PTP outofsync is not triggered by interrupt.
   1607          * For this event, when user config the bcmCosqTASControlTASPTPLock = 0,
   1608          * bcmi_esw_cosq_handle_interrupt will be notified from that.
   1609          */
   1610         if (e_info->p_event == -1) {
   1611             continue;
   1612         }
   1613         /* Check the status to see which event causes the interrupt. */
   1614         if (!soc_reg_field_get(unit, MEMFAILINTSTATUSr, rval,
   1615                                e_info->status_field)) {
   1616             continue;
   1617         }
   1618         if (e_info->event != -1) {
   1619             if (SHR_BITGET(cosq_event_pbmp, e_info->event)) {
   1620                 event_cb = 1;
   1621             }
   1622         }
   1623         if (SHR_BITGET(tas_event_pbmp, e_info->p_event)) {
   1624             intr_cb = 1;
   1625         }
   1626 
   1627         if ((sts_reg = e_info->sts_regs[0]) != -1) {
   1628             /* Report the event by port */
   1629             for (group = 0; group < 3; group++) {
   1630                 sts_reg = e_info->sts_regs[group];
   1631                 clr_reg = e_info->clr_regs[group];
   1632                 sts = 0;
   1633                 /* Check the per event status register to get
   1634                  * which port causes the interrupt.
   1635                  */
   1636                 soc_reg32_get(unit, sts_reg, REG_PORT_ANY, 0, &sts);
   1637                 if (sts == 0) {
   1638                     continue;
   1639                 }
   1640                 for (p = 0; p < 32; p++) {
   1641                     if (sts & (1 << p)) {
   1642                         mmu_port = group * 32 + p;
   1643                         phy_port = si->port_m2p_mapping[mmu_port];
   1644                         lport = si->port_p2l_mapping[phy_port];
   1645                         if (event_cb) {
   1646                             (void)bcmi_esw_cosq_handle_interrupt(
   1647                                     unit, e_info->event, lport,
   1648                                     BCM_COS_INVALID);
   1649                         }
   1650                         if (intr_cb) {
   1651                             /* profile change event */
   1652                             (void)gh2_profile_event_notify[unit](
   1653                                     unit, lport, e_info->p_event);
   1654                         }
   1655                     }
   1656                 }
   1657                 /* Clear sub status (write 1 clear) */
   1658                 soc_reg32_set(unit, clr_reg, REG_PORT_ANY, 0, sts);
   1659             }
   1660         } else {
   1661             /* TOD Window system event */
   1662             if (intr_cb) {
   1663                 (void)bcmi_gh2_tas_tod_handler(unit);
   1664             }
   1665         }
   1666         /* Clear status (write 1 clear) */
   1667         rval = 0;
   1668         BCM_IF_ERROR_RETURN(READ_MEMFAILINT_CLRr(unit, &rval));
   1669         soc_reg_field_set(unit, MEMFAILINT_CLRr, &rval,
   1670                           e_info->clear_field, 1);
   1671         BCM_IF_ERROR_RETURN(WRITE_MEMFAILINT_CLRr(unit, rval));
   1672     }
   1673     return BCM_E_NONE;
   1674 }
   1675 
   1676 /*
   1677  * Function:
   1678  *     bcmi_gh2_cosq_event_mask_set
   1679  * Purpose:
   1680  *     Configue the TAS related interrupt mask by specifying bcm cosq event.
   1681  *     For value=0 case, will be programmed when no other internal profile event
   1682  *     reference it.
   1683  * Parameters:
   1684  *     unit             - (IN) unit number
   1685  *     event_type       - (IN) bcm cosq event
   1686  *     val              - (IN) mask value
   1687  * Returns:
   1688  *     BCM_E_XXX
   1689  */
   1690 int
   1691 bcmi_gh2_cosq_event_mask_set(
   1692     int unit,
   1693     bcm_cosq_event_type_t event_type,
   1694     int val)
   1695 {
   1696     gh2_tas_event_info_t *e_info;
   1697     int i, rv = BCM_E_NONE;
   1698     uint32 rval;
   1699     gh2_tas_event_ctrl_t *tec = NULL;
   1700 
   1701     if ((tec = gh2_tas_event_ctrl[unit]) == NULL) {
   1702         return BCM_E_INTERNAL;
   1703     }
   1704 
   1705     GH2_TAS_EVENT_LOCK(tec);
   1706     if (val) {
   1707         SHR_BITSET(tec->cosq_event_pbmp, event_type);
   1708     } else {
   1709         SHR_BITCLR(tec->cosq_event_pbmp, event_type);
   1710     }
   1711 
   1712     for (i = 0; ; i++) {
   1713         e_info = &gh2_tas_event_info[i];
   1714         if ((e_info->p_event == -1) && (e_info->event == -1)) {
   1715             /* End of table */
   1716             break;
   1717         }
   1718         if (e_info->event == bcmCosqEventTASPTPOutOfSyncErr) {
   1719             continue;
   1720         }
   1721         if (e_info->event == event_type) {
   1722             if (e_info->p_event != -1) {
   1723                 if (SHR_BITGET(tec->tas_event_pbmp, e_info->p_event) &&
   1724                     (val == 0)) {
   1725                     /* Donot set 0 if other event referece it */
   1726                     break;
   1727               }
   1728             }
   1729             rv = READ_MEMFAILINTMASKr(unit, &rval);
   1730             if (BCM_FAILURE(rv)) {
   1731                 break;
   1732             }
   1733             soc_reg_field_set(unit, MEMFAILINTMASKr, &rval,
   1734                               e_info->mask_field, val);
   1735             rv = WRITE_MEMFAILINTMASKr(unit, rval);
   1736             break;
   1737         }
   1738     }
   1739 
   1740     GH2_TAS_EVENT_UNLOCK(tec);
   1741 
   1742     return BCM_E_NONE;
   1743 }
   1744 /*
   1745  * Device specific function for bcmi_esw_cosq_event_validate.
   1746  */
   1747 int
   1748 bcmi_gh2_cosq_events_validate(int unit, bcm_cosq_event_types_t event_types)
   1749 {
   1750     bcm_cosq_event_type_t  e_type;
   1751     gh2_tas_event_info_t *e_info;
   1752     int i, rv = BCM_E_NONE;
   1753 
   1754     if (!soc_feature(unit, soc_feature_tas)) {
   1755         return BCM_E_UNAVAIL;
   1756     }
   1757 
   1758     for (e_type = 0; e_type < bcmCosqEventCount; ++e_type) {
   1759         if (BCM_COSQ_EVENT_TYPE_GET(event_types, e_type)) {
   1760             for (i = 0; ; i++) {
   1761                 e_info = &gh2_tas_event_info[i];
   1762                 if ((e_info->p_event == -1) && (e_info->event == -1)) {
   1763                     /* End of table */
   1764                     break;
   1765                 }
   1766                 if (e_info->event == e_type) {
   1767                     break;
   1768                 }
   1769             }
   1770         }
   1771     }
   1772 
   1773     return rv;
   1774 }
   1775 
   1776 /*
   1777  * Function:
   1778  *     bcmi_gh2_tas_profile_deinit
   1779  * Purpose:
   1780  *     Free the resource associated with the tas internal profile
   1781  * Parameters:
   1782  *     unit             - (IN) unit number
   1783  * Returns:
   1784  *     BCM_E_XXX
   1785  */
   1786 STATIC int
   1787 bcmi_gh2_tas_profile_deinit(int unit)
   1788 {
   1789     int i, rv;
   1790     gh2_tas_event_info_t *e_info;
   1791 
   1792     /* Disable the profile change interrupt */
   1793     gh2_profile_event_notify[unit] = NULL;
   1794 
   1795     if (gh2_tod_event_control[unit] != NULL) {
   1796         /* detach all TOD event */
   1797         for (i = 0; i < GH2_TAS_MAX_PORTCNT; i++) {
   1798             (void)bcmi_gh2_tas_tod_detach(unit, i);
   1799         }
   1800         if (gh2_tod_event_control[unit]->tod_lock) {
   1801             sal_mutex_destroy(gh2_tod_event_control[unit]->tod_lock);
   1802             gh2_tod_event_control[unit]->tod_lock = NULL;
   1803         }
   1804         TAS_FREE(unit, gh2_tod_event_control[unit], 0);
   1805         gh2_tod_event_control[unit] = NULL;
   1806     }
   1807 
   1808     if (gh2_tas_event_ctrl[unit] != NULL) {
   1809         /* Disable the profile event interrupt */
   1810         for (i = 0; ; i++) {
   1811             e_info = &gh2_tas_event_info[i];
   1812             if (e_info->p_event == -1) {
   1813                 /* End of table */
   1814                 break;
   1815             }
   1816             rv = bcmi_gh2_tas_profile_event_mask_set(
   1817                      unit, e_info->p_event, 0);
   1818             if (BCM_FAILURE(rv)) {
   1819                 return rv;
   1820             }
   1821         }
   1822         if (gh2_tas_event_ctrl[unit]->event_lock) {
   1823             sal_mutex_destroy(gh2_tas_event_ctrl[unit]->event_lock);
   1824             gh2_tas_event_ctrl[unit]->event_lock = NULL;
   1825         }
   1826         TAS_FREE(unit, gh2_tas_event_ctrl[unit], 0);
   1827         gh2_tas_event_ctrl[unit] = NULL;
   1828     }
   1829     return BCM_E_NONE;
   1830 }
   1831 /*
   1832  * Function:
   1833  *     bcmi_gh2_tas_profile_init
   1834  * Purpose:
   1835  *     initialize the tas internal profile
   1836  * Parameters:
   1837  *     unit             - (IN) unit number
   1838  *     cb               - (IN) callback function for profile event notification
   1839  * Returns:
   1840  *     BCM_E_XXX
   1841  */
   1842 STATIC int
   1843 bcmi_gh2_tas_profile_init(int unit, profile_event_cb_fn cb)
   1844 {
   1845     int i, rv;
   1846     gh2_tas_event_info_t *e_info;
   1847 
   1848     /* Initialize the structure, function ptr to NULL */
   1849     if (gh2_profile_initialized == 0) {
   1850         for (i = 0; i < BCM_MAX_NUM_UNITS; i++) {
   1851             gh2_profile_event_notify[i] = NULL;
   1852             gh2_tod_event_control[i] = NULL;
   1853             gh2_tas_event_ctrl[i] = NULL;
   1854         }
   1855         gh2_profile_initialized = 1;
   1856     }
   1857 
   1858     /* Allocate/initialize the GH2 tas profile event control structure */
   1859     if (gh2_tas_event_ctrl[unit] == NULL) {
   1860         TAS_ALLOC(unit, gh2_tas_event_ctrl[unit],
   1861                   gh2_tas_event_ctrl_t, sizeof(gh2_tas_event_ctrl_t),
   1862                   "GH2 TAS event control ", 0, rv);
   1863         if (BCM_FAILURE(rv)) {
   1864             return BCM_E_INIT;
   1865         }
   1866         gh2_tas_event_ctrl[unit]->event_lock =
   1867             sal_mutex_create("tas_event.lock");
   1868         if (gh2_tas_event_ctrl[unit]->event_lock == NULL) {
   1869             bcmi_gh2_tas_profile_deinit(unit);
   1870             return BCM_E_INIT;
   1871         }
   1872     }
   1873 
   1874     /* Assign the profile event notify callback */
   1875     gh2_profile_event_notify[unit] = cb;
   1876 
   1877     /* Allocate/initialize the GH2 tas TOD event control structure */
   1878     if (gh2_tod_event_control[unit] == NULL) {
   1879         TAS_ALLOC(unit, gh2_tod_event_control[unit],
   1880                   gh2_tod_event_control_t, sizeof(gh2_tod_event_control_t),
   1881                   "TOD event handler ", 0, rv);
   1882         if (BCM_FAILURE(rv)) {
   1883             bcmi_gh2_tas_profile_deinit(unit);
   1884             return BCM_E_INIT;
   1885         }
   1886         gh2_tod_event_control[unit]->tod_lock =
   1887             sal_mutex_create("tas_tod.lock");
   1888         if (gh2_tod_event_control[unit]->tod_lock == NULL) {
   1889             bcmi_gh2_tas_profile_deinit(unit);
   1890             return BCM_E_INIT;
   1891         }
   1892         for (i = 0; i < GH2_TAS_MAX_PORTCNT; i++) {
   1893             gh2_tod_event_control[unit]->gh2_tod_event[i] = NULL;
   1894         }
   1895         sal_memset(gh2_tod_event_control[unit]->tod_event_pbmp, 0,
   1896                    _SHR_BITDCLSIZE(GH2_TAS_MAX_PORTCNT) * sizeof(SHR_BITDCL));
   1897     }
   1898 
   1899     /* Enable the profile event interrupt */
   1900     for (i = 0; ; i++) {
   1901         e_info = &gh2_tas_event_info[i];
   1902         if (e_info->p_event == -1) {
   1903             /* End of table */
   1904             break;
   1905         }
   1906         /* Skip the TOD event during init enable it when required */
   1907         if (e_info->p_event == bcmiTASProfileEventTODWindow) {
   1908             continue;
   1909         }
   1910         rv = bcmi_gh2_tas_profile_event_mask_set(
   1911                  unit, e_info->p_event, 1);
   1912         if (BCM_FAILURE(rv)) {
   1913             bcmi_gh2_tas_profile_deinit(unit);
   1914             return rv;
   1915         }
   1916     }
   1917 
   1918     return BCM_E_NONE;
   1919 }
   1920 
   1921 /* Driver functions to implement device-specific operations.
   1922  * dispatched from common layer functions.
   1923  */
   1924 STATIC const tas_drv_t gh2_tas_drv = {
   1925         bcmi_gh2_tas_control_set,
   1926         bcmi_gh2_tas_control_get,
   1927         bcmi_gh2_tas_status_get,
   1928         bcmi_gh2_tas_profile_init,
   1929         bcmi_gh2_tas_profile_deinit,
   1930         bcmi_gh2_tas_profile_param_check,
   1931         bcmi_gh2_tas_profile_basetime_check,
   1932         bcmi_gh2_tas_profile_delay_param_get,
   1933         bcmi_gh2_tas_profile_idx_get,
   1934         bcmi_gh2_tas_profile_entries_write,
   1935         bcmi_gh2_tas_profile_schedule_config,
   1936         bcmi_gh2_tas_profile_change
   1937 };
   1938 
   1939 /*
   1940  * Function:
   1941  *     bcmi_gh2_tas_drv_init
   1942  * Purpose:
   1943  *     initialize the tas device-driver
   1944  * Parameters:
   1945  *     unit             - (IN) unit number
   1946  * Returns:
   1947  *     BCM_E_XXX
   1948  */
   1949 int
   1950 bcmi_gh2_tas_drv_init(int unit, const tas_drv_t **tas_drv)
   1951 {
   1952 
   1953     *tas_drv = &gh2_tas_drv;
   1954     BCM_IF_ERROR_RETURN(
   1955         soc_gh2_cosq_event_handler_register(
   1956             unit, bcmi_gh2_tas_handle_interrupt));
   1957 
   1958     return BCM_E_NONE;
   1959 }
   1960 #endif /* BCM_GREYHOUND2_SUPPORT && BCM_TAS_SUPPORT */