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

tdm_td3_ovsb.c (53439B)


      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  * $All Rights Reserved.$
      7  *
      8  * TDM chip based printing and parsing functions
      9  */
     10 #ifdef _TDM_STANDALONE
     11 	#include <tdm_top.h>
     12 #else
     13 	#include <soc/tdm/core/tdm_top.h>
     14 #endif
     15 
     16 
     17 /**
     18 @name: tdm_td3_ovsb_get_pkt_shaper_cal
     19 @param:
     20 @desc: [chip_specific]
     21 
     22 Return pionter of the packet shaper scheduler.
     23  */
     24 int *
     25 tdm_td3_ovsb_get_pkt_shaper_cal(tdm_mod_t *_tdm, int spipe_num)
     26 {
     27     int * cal = NULL;
     28     int cal_offset;
     29 
     30     cal_offset = TD3_SHAPING_GRP_IDX_0 + spipe_num;
     31     switch (_tdm->_core_data.vars_pkg.cal_id) {
     32         case 0:	cal = _tdm->_chip_data.cal_0.cal_grp[cal_offset]; break;
     33         case 1:	cal = _tdm->_chip_data.cal_1.cal_grp[cal_offset]; break;
     34         case 2:	cal = _tdm->_chip_data.cal_2.cal_grp[cal_offset]; break;
     35         case 3:	cal = _tdm->_chip_data.cal_3.cal_grp[cal_offset]; break;
     36         default:
     37             TDM_ERROR2("Invalid calendar ID %0d for %s\n",
     38                        _tdm->_core_data.vars_pkg.cal_id,
     39                        "tdm_td3_ovsb_get_pkt_shaper_cal()");
     40             cal = NULL; break;
     41     }
     42 
     43     return cal;
     44 }
     45 
     46 /**
     47 @name: tdm_td3_ovsb_get_pkt_shaper_cal_prev
     48 @param:
     49 @desc: [chip_specific]
     50 
     51 Return pionter of the previous packet shaper scheduler.
     52  */
     53 int *
     54 tdm_td3_ovsb_get_pkt_shaper_cal_prev(tdm_mod_t *_tdm, int spipe_num)
     55 {
     56     int * cal = NULL;
     57     int cal_offset;
     58 
     59     cal_offset = TD3_SHAPING_GRP_IDX_0 + spipe_num;
     60     switch (_tdm->_core_data.vars_pkg.cal_id) {
     61         case 0:	cal = _tdm->_prev_chip_data.cal_0.cal_grp[cal_offset]; break;
     62         case 1:	cal = _tdm->_prev_chip_data.cal_1.cal_grp[cal_offset]; break;
     63         case 2:	cal = _tdm->_prev_chip_data.cal_2.cal_grp[cal_offset]; break;
     64         case 3:	cal = _tdm->_prev_chip_data.cal_3.cal_grp[cal_offset]; break;
     65         default:
     66             TDM_ERROR2("Invalid calendar ID %0d for %s\n",
     67                        _tdm->_core_data.vars_pkg.cal_id,
     68                        "tdm_td3_ovsb_get_pkt_shaper_cal_prev()");
     69             cal = NULL; break;
     70     }
     71 
     72     return cal;
     73 }
     74 
     75 /**
     76 @name: tdm_td3_ovsb_get_spipe_grp_range
     77 @param:
     78 
     79 Return ovsb group range [grp_lo, grp_hi] for given subpipe.
     80  */
     81 void
     82 tdm_td3_ovsb_get_spipe_grp_range(tdm_mod_t *_tdm, int spipe, int *lo, int *hi)
     83 {
     84     int grp_per_spipe, grp_lo = 0, grp_hi = 0;
     85     tdm_calendar_t *cal;
     86 
     87     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
     88     if (cal != NULL) {
     89         if (spipe >= 0 && spipe < TD3_NUM_SPIPE && cal->grp_num > 0) {
     90             grp_per_spipe = cal->grp_num / TD3_NUM_SPIPE;
     91             grp_lo = (spipe * grp_per_spipe) % cal->grp_num;
     92             grp_hi = (grp_lo + grp_per_spipe - 1) % cal->grp_num;
     93         }
     94     }
     95     (*lo) = grp_lo;
     96     (*hi) = grp_hi;
     97 }
     98 
     99 /**
    100 @name: tdm_td3_ovsb_get_grp_spd
    101 @param:
    102 
    103 Return group speed of the given ovsb group in ethernet speed format.
    104 If ovsb group is empty, return 0.
    105  */
    106 int
    107 tdm_td3_ovsb_get_grp_spd(tdm_mod_t *_tdm, int grp)
    108 {
    109     int prt, pos;
    110     int param_token_empty;
    111     tdm_calendar_t *cal;
    112 
    113     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
    114     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
    115     if (cal == NULL) return 0;
    116 
    117     if (grp >= 0 && grp < cal->grp_num) {
    118         for (pos = 0; pos < cal->grp_len; pos++) {
    119             prt = cal->cal_grp[grp][pos];
    120             if (prt != param_token_empty) {
    121                 return (tdm_td3_cmn_get_port_speed_eth(_tdm, prt));
    122             }
    123         }
    124     }
    125 
    126     return 0;
    127 }
    128 
    129 /**
    130 @name: tdm_td3_ovsb_get_grp_prt_cnt
    131 @param:
    132 
    133 Return number of active ports in the given oversub speed group.
    134 If ovsb group is empty, return 0.
    135  */
    136 int
    137 tdm_td3_ovsb_get_grp_prt_cnt(tdm_mod_t *_tdm, int grp)
    138 {
    139     int prt, pos, prt_cnt = 0;
    140     int param_token_empty;
    141     tdm_calendar_t *cal;
    142 
    143     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
    144     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
    145     if (cal == NULL) return prt_cnt;
    146 
    147     if (grp >= 0 && grp < cal->grp_num) {
    148         for (pos = 0; pos < cal->grp_len; pos++) {
    149             prt = cal->cal_grp[grp][pos];
    150             if (prt != param_token_empty) prt_cnt++;
    151         }
    152     }
    153 
    154     return prt_cnt;
    155 }
    156 
    157 /**
    158 @name: tdm_td3_ovsb_get_grp_empty_cnt
    159 @param:
    160 
    161 Return the number of empty slots in the given ovsb group.
    162  */
    163 int
    164 tdm_td3_ovsb_get_grp_empty_cnt(tdm_mod_t *_tdm, int grp)
    165 {
    166     tdm_calendar_t *cal;
    167 
    168     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
    169     if (cal == NULL) return 0;
    170 
    171     return (cal->grp_len - tdm_td3_ovsb_get_grp_prt_cnt(_tdm, grp));
    172 }
    173 
    174 /**
    175 @name: tdm_td3_ovsb_get_prt_spipe
    176 @param:
    177 
    178 Return subpipe index of the given port.
    179     -1: unassigned
    180      n: subpipe index, 0 <= n < TD3_NUM_SPIPE
    181  */
    182 int
    183 tdm_td3_ovsb_get_prt_spipe(tdm_mod_t *_tdm, int port_token)
    184 {
    185     int pm, spipe = -1;
    186 
    187     pm = tdm_td3_cmn_get_port_pm(_tdm, port_token);
    188     if (pm >= 0 && pm < TD3_NUM_PM_MOD) {
    189         spipe = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe[pm];
    190         /* if (spipe >= 0 && spipe < TD3_NUM_SPIPE) return spipe; */
    191     }
    192 
    193     return spipe;
    194 }
    195 
    196 /**
    197 @name: tdm_td3_ovsb_get_prt_lane
    198 @param:
    199 
    200 Return relative lane index of the given port within PM.
    201  */
    202 int
    203 tdm_td3_ovsb_get_prt_lane(tdm_mod_t *_tdm, int prt)
    204 {
    205     if (prt >= _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo &&
    206         prt <= _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi) {
    207         return ((prt - 1) % TD3_NUM_PM_LNS);
    208     }
    209 
    210     return 0;
    211 }
    212 
    213 /**
    214 @name: tdm_td3_ovsb_get_pm_shaper_prt_stride
    215 @param:
    216 @desc: [chip_specific]
    217 
    218 Return incremental distance between two consecutive port slots in
    219 PM shaper calendar.
    220  */
    221 int
    222 tdm_td3_ovsb_get_pm_shaper_prt_stride(tdm_mod_t *_tdm, int prt)
    223 {
    224     int spd, stride;
    225 
    226     spd = tdm_td3_cmn_get_port_speed_eth(_tdm, prt);
    227     switch (spd) {
    228         case SPEED_10G:  stride = 8; break;
    229         case SPEED_20G:  stride = 4; break;
    230         case SPEED_25G:  stride = 4; break;
    231         case SPEED_40G:  stride = 2; break;
    232         case SPEED_50G:  stride = 2; break;
    233         case SPEED_100G: stride = 1; break;
    234         default:         stride = 0; break;
    235     }
    236     /* for any speed less than 10G, take it as 10G */
    237     if (spd > 0 && spd < SPEED_10G) stride = 8;
    238 
    239     return stride;
    240 }
    241 
    242 /**
    243 @name: tdm_td3_ovsb_get_pm_shaper_prt_offset
    244 @param:
    245 @desc: [chip_specific]
    246 
    247 Return port offset within pseudo PM shaper calendar.
    248  */
    249 int
    250 tdm_td3_ovsb_get_pm_shaper_prt_offset(tdm_mod_t *_tdm, int prt)
    251 {
    252     int ln_base, ln_offset;
    253 
    254     ln_base = tdm_td3_ovsb_get_prt_lane(_tdm, prt);
    255     switch (ln_base) {
    256         case 0: ln_offset = 0; break;
    257         case 1: ln_offset = 2; break;
    258         case 2: ln_offset = 1; break;
    259         case 3: ln_offset = 3; break;
    260         default:ln_offset = 0; break;
    261     }
    262 
    263     return ln_offset;
    264 }
    265 
    266 /**
    267 @name: tdm_td3_ovsb_get_pm_shaper_prt_pos
    268 @param:
    269 @desc: [chip_specific]
    270 
    271 Return the n-th slot pos of the given port in pm shaper calendar.
    272  */
    273 int
    274 tdm_td3_ovsb_get_pm_shaper_prt_pos(tdm_mod_t *_tdm, int prt, int slot_cnt)
    275 {
    276     int pos, prt_offset, prt_stride, prt_spd, ln_base;
    277 
    278     prt_offset = tdm_td3_ovsb_get_pm_shaper_prt_offset(_tdm, prt);
    279     prt_stride = tdm_td3_ovsb_get_pm_shaper_prt_stride(_tdm, prt);
    280 
    281     prt_spd = tdm_td3_cmn_get_port_speed_eth(_tdm, prt);
    282     ln_base = tdm_td3_ovsb_get_prt_lane(_tdm, prt);
    283     /* [chip_specific] (pre-opt) special case: 10G */
    284     if (prt_spd == SPEED_10G) {
    285         switch (ln_base) {
    286             case 1: prt_offset += 2*prt_stride; break;
    287             case 2: prt_offset +=   prt_stride; break;
    288             default: break;
    289         }
    290     }
    291     /* [chip_specific] (pre-opt) special case: 20G */
    292     else if (prt_spd == SPEED_20G) {
    293         if (slot_cnt == 2 || slot_cnt == 3) prt_offset += 2;
    294     }
    295     /* [chip_specific] (pre-opt) special case: 40G */
    296     else if (prt_spd == SPEED_40G) {
    297         if (slot_cnt >= 4 && slot_cnt <= 7) prt_offset += 2;
    298     }
    299 
    300     /* calculate slot position */
    301     pos = (prt_offset + prt_stride * slot_cnt) % TD3_SHAPER_NUM_PM_SLOTS;
    302 
    303     return pos;
    304 }
    305 
    306 /**
    307 @name: tdm_td3_ovsb_get_pkt_shaper_prt_pm_idx
    308 @param:
    309 
    310 Find an existing or available pm_idx in pkt_shaper
    311  */
    312 int
    313 tdm_td3_ovsb_get_pkt_shaper_prt_pm_idx(tdm_mod_t *_tdm, int prt)
    314 {
    315     int i, j, max_start_indx, distance, max_distance;
    316     int prt_spipe, prt_pm, pos, pm_idx;
    317     int *pkt_shaper_cal = NULL;
    318     int pm_indx_avail[TD3_NUM_PMS_PER_SPIPE];
    319     int param_cal_id, param_token_empty;
    320 
    321     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
    322     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
    323     prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt);
    324 
    325     prt_spipe = tdm_td3_ovsb_get_prt_spipe(_tdm, prt);
    326     if (!(prt_spipe >= 0 && prt_spipe < TD3_NUM_SPIPE)) return FAIL;
    327 
    328     pkt_shaper_cal = tdm_td3_ovsb_get_pkt_shaper_cal(_tdm, prt_spipe);
    329     if (pkt_shaper_cal == NULL) return FAIL;
    330 
    331     /* Case 1: there are sister ports of this port already in pkt scheduler,
    332        which means find that PM and place port in the corresponding lanes. */
    333     pm_idx = -1;
    334     for (i = 0; i < TD3_SHAPING_GRP_LEN; i++) {
    335         if (pkt_shaper_cal[i] != param_token_empty) {
    336             if (prt_pm == tdm_td3_cmn_get_port_pm(_tdm, pkt_shaper_cal[i])) {
    337                 /* Find that PM has already been placed */
    338                 pm_idx = i % TD3_NUM_PMS_PER_SPIPE;
    339                 break;
    340             }
    341         }
    342     }
    343 
    344     /* Case 2: there is no sister port of this port already in pkt scheduler,
    345        which means find an empty PM and place port in the corresponding lanes
    346        Find an available PM */
    347     if (pm_idx == -1) {
    348         for (i = 0; i < TD3_NUM_PMS_PER_SPIPE; i++) {
    349             pm_indx_avail[i] = 1;
    350             for (j = 0; j < TD3_NUM_PKT_SLOTS_PER_PM; j++) {
    351                 pos = (j * TD3_NUM_PMS_PER_SPIPE + i) % TD3_SHAPING_GRP_LEN;
    352                 if (pkt_shaper_cal[pos] != param_token_empty) {
    353                     pm_indx_avail[i] = 0;
    354                     break;
    355                 }
    356             }
    357         }
    358 
    359         /* Find the biggest clump of 1's in pm_indx_avail array, and
    360            choose the pm_idx in the middle of the clump */
    361         max_start_indx = 0;
    362         distance       = 0;
    363         max_distance   = 0;
    364         for (i = 0; i < TD3_NUM_PMS_PER_SPIPE; i++) {
    365             if (pm_indx_avail[i] == 1) {
    366                 distance = 0;
    367                 for (j = 0; j < TD3_NUM_PMS_PER_SPIPE; j++){
    368                     if (pm_indx_avail[(i+j) % TD3_NUM_PMS_PER_SPIPE] == 1) {
    369                         distance++;
    370                     } else {
    371                         break;
    372                     }
    373                 }
    374                 if (distance > max_distance) {
    375                     max_start_indx = i;
    376                     max_distance   = distance;
    377                 }
    378             }
    379         }
    380         /* If all available make it 0, else middle of the clump*/
    381         pm_idx = (max_distance == TD3_NUM_PMS_PER_SPIPE) ? 0 :
    382                  ((max_start_indx + TD3_NUM_PMS_PER_SPIPE) % TD3_NUM_PMS_PER_SPIPE);
    383 
    384         if (pm_indx_avail[pm_idx] == 0) {
    385             pm_idx = -1;
    386             TDM_ERROR4("%s, PIPE %d, pm %0d, port %0d\n",
    387                        "Failed to find an available PM",
    388                        param_cal_id, prt_pm, prt);
    389         }
    390     }
    391 
    392     if (pm_idx == -1) {
    393         TDM_ERROR4("%s, PIPE %d, pm %0d, phy_port %0d\n",
    394                    "Failed to find an available PM",
    395                    param_cal_id, prt_pm, prt);
    396     }
    397 
    398     return pm_idx;
    399 }
    400 
    401 /**
    402 @name: tdm_td3_ovsb_get_pkt_shaper_prt_pos
    403 @param:
    404 @desc: [chip_specific]
    405 
    406 For the n-th slot in pm_shaper_calendar, calculate the corresponding slot
    407 postion in packet_shaper_calendar.
    408  */
    409 int
    410 tdm_td3_ovsb_get_pkt_shaper_prt_pos(tdm_mod_t *_tdm, int prt,
    411 int pm_shaper_slot_idx)
    412 {
    413     int pos = -1;
    414     int num_blocks, block_idx = 0, block_offset, lane, lane_offset, pm_offset;
    415 
    416     /* calc block_offset: one block is one minimum repetition pattern */
    417     num_blocks = TD3_SHAPING_GRP_LEN / TD3_NUM_PHY_PORTS_PER_SPIPE;
    418     if (num_blocks > 0) {
    419         block_idx = (pm_shaper_slot_idx / TD3_NUM_PM_LNS) % num_blocks;
    420     }
    421     block_offset = block_idx * TD3_NUM_PHY_PORTS_PER_SPIPE;
    422 
    423     /* calc lane_offset: one subblock contains slots with the same lane num */
    424     lane = pm_shaper_slot_idx % TD3_NUM_PM_LNS; /* lane num in pm_shaper_cal */
    425     switch (lane) {
    426         case 0:  lane_offset = 0;                       break; /* subport 0 */
    427         case 1:  lane_offset = 1*TD3_NUM_PMS_PER_SPIPE; break; /* subport 2 */
    428         case 2:  lane_offset = 2*TD3_NUM_PMS_PER_SPIPE; break; /* subport 1 */
    429         default: lane_offset = 3*TD3_NUM_PMS_PER_SPIPE; break; /* subport 3 */
    430     }
    431 
    432     /* calc pm_offset: within each subblock, slot is determined by pm_offset */
    433     pm_offset = tdm_td3_ovsb_get_pkt_shaper_prt_pm_idx(_tdm, prt);
    434     if (pm_offset == -1) return pos;
    435 
    436     /* calculate slot position of pm shaper slot in packet shaper calendar */
    437     pos = (block_offset + lane_offset + pm_offset) % TD3_SHAPING_GRP_LEN;
    438 
    439     return pos;
    440 }
    441 
    442 /**
    443 @name: tdm_td3_ovsb_apply_constraints_init
    444 @param:
    445 @desc: [chip_specific]
    446 
    447 Partition OVSB PMs into 2 halfpipes
    448  */
    449 int
    450 tdm_td3_ovsb_apply_constraints_init(tdm_mod_t *_tdm)
    451 {
    452     int i, j, prt, prt_pm, num_spd_types = 0, result = PASS;
    453     int param_cal_id;
    454     int *pm2spipe_map = NULL;
    455     m_tdm_pipe_info_t *pipe_info;
    456 
    457     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
    458     pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe;
    459     pipe_info    = &(_tdm->_core_data.vars_pkg.pipe_info);
    460 
    461     for (i = 0; i < MAX_SPEED_TYPES; i++) {
    462         if (pipe_info->os_spd_en[i]) num_spd_types++;
    463     }
    464 
    465     /* check necessary condition */
    466     tdm_cmn_chk_pipe_os_spd_types(_tdm);
    467 
    468     /* Restriction 13: No port configurations with more than 4 port speed
    469      *                 classes are supported.
    470      */
    471     if (num_spd_types > 5) {
    472         result = FAIL;
    473         TDM_ERROR4("%s, PIPE %d, num_spd_types %0d, limit %0d\n",
    474                    "Failed in ovsb partition, number of speed types overflow",
    475                    param_cal_id, num_spd_types, 4);
    476     }
    477     /* Restriction 14: The only supported port configurations with 4 port
    478                        speed classes are:
    479             10G/20G/40G/100G
    480             10G/25G/50G/100G
    481        Rule: Group PMs with 25G/50G ports in HP0 and PMs with 20G/40G in HP1.
    482     */
    483     if (num_spd_types == 4) {
    484         if ((pipe_info->os_spd_en[TDM_SPEED_IDX_10G] &&
    485              pipe_info->os_spd_en[TDM_SPEED_IDX_20G] &&
    486              pipe_info->os_spd_en[TDM_SPEED_IDX_40G] &&
    487              pipe_info->os_spd_en[TDM_SPEED_IDX_100G]) ||
    488             (pipe_info->os_spd_en[TDM_SPEED_IDX_10G] &&
    489              pipe_info->os_spd_en[TDM_SPEED_IDX_25G] &&
    490              pipe_info->os_spd_en[TDM_SPEED_IDX_50G] &&
    491              pipe_info->os_spd_en[TDM_SPEED_IDX_100G])) {
    492             TDM_PRINT0("TDM: Apply [Restriction 14]\n");
    493             for (i = 0; i < MAX_SPEED_TYPES; i++) {
    494                 if (!(pipe_info->os_spd_en[i])) continue;
    495                 if (i == TDM_SPEED_IDX_25G || i == TDM_SPEED_IDX_50G) {
    496                     for (j = 0; j < pipe_info->os_prt_cnt[i]; j++) {
    497                         prt    = pipe_info->os_prt[i][j];
    498                         prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt);
    499                         pm2spipe_map[prt_pm] = 0;
    500                     }
    501                 } else if (i == TDM_SPEED_IDX_20G || i == TDM_SPEED_IDX_40G) {
    502                     for (j = 0; j < pipe_info->os_prt_cnt[i]; j++) {
    503                         prt    = pipe_info->os_prt[i][j];
    504                         prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt);
    505                         pm2spipe_map[prt_pm] = 1;
    506                     }
    507                 }
    508             }
    509         } else {
    510             result = FAIL;
    511             TDM_ERROR1("%s, invalid config with 4 speed types\n",
    512                        "Failed in ovsb partition");
    513         }
    514     }
    515     /* Restriction 15: All port configurations with 1-3 port speed classes
    516      *                 are supported, except configurations that contain both
    517      *                 20G and 25G port speeds.
    518      * Rule: Group PMs with 25G/50G ports in HP0 and PMs with 20G/40G in HP1.
    519      */
    520     if (num_spd_types > 1 && num_spd_types <= 3) {
    521         if ((pipe_info->os_spd_en[TDM_SPEED_IDX_20G] ||
    522              pipe_info->os_spd_en[TDM_SPEED_IDX_40G]) &&
    523             (pipe_info->os_spd_en[TDM_SPEED_IDX_25G] ||
    524              pipe_info->os_spd_en[TDM_SPEED_IDX_50G])) {
    525             TDM_PRINT0("Apply [Restriction 15]\n");
    526             for (i = 0; i < MAX_SPEED_TYPES; i++) {
    527                 if (!(pipe_info->os_spd_en[i])) continue;
    528                 if (i == TDM_SPEED_IDX_25G || i == TDM_SPEED_IDX_50G) {
    529                     for (j = 0; j < pipe_info->os_prt_cnt[i]; j++) {
    530                         prt    = pipe_info->os_prt[i][j];
    531                         prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt);
    532                         pm2spipe_map[prt_pm] = 0;
    533                     }
    534                 } else if (i == TDM_SPEED_IDX_20G || i == TDM_SPEED_IDX_40G) {
    535                     for (j = 0; j < pipe_info->os_prt_cnt[i]; j++) {
    536                         prt    = pipe_info->os_prt[i][j];
    537                         prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt);
    538                         pm2spipe_map[prt_pm] = 1;
    539                     }
    540                 }
    541             }
    542         }
    543     }
    544 
    545     return result;
    546 }
    547 
    548 /**
    549 @name: tdm_td3_ovsb_apply_constraints_flex
    550 @param:
    551 @desc: [chip_specific]
    552 
    553 Partition OVSB PMs into 2 halfpipes.
    554  */
    555 int
    556 tdm_td3_ovsb_apply_constraints_flex(tdm_mod_t *_tdm)
    557 {
    558     int i, prt, prt_pm, num_spd_types = 0, result = PASS;
    559     int spipe, pos, grp, grp_lo = 0, grp_hi = 0;
    560     int param_cal_id, param_token_empty;
    561     int *pm2spipe_map = NULL;
    562     m_tdm_pipe_info_t *pipe_info;
    563     tdm_calendar_t *cal;
    564 
    565     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
    566     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
    567     pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe;
    568     pipe_info    = &(_tdm->_core_data.vars_pkg.pipe_info);
    569 
    570     /* get pipe calendar */
    571     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
    572     if (cal == NULL) return result;
    573 
    574     /* Restriction 13: No port configurations with more than 4 port speed
    575      *                 classes are supported.
    576      */
    577     for (i = 0; i < MAX_SPEED_TYPES; i++) {
    578         if (pipe_info->os_spd_en[i]) num_spd_types++;
    579     }
    580     if (num_spd_types > 4) {
    581         result = FAIL;
    582         TDM_ERROR4("%s, PIPE %d, num_spd_types %0d, limit %0d\n",
    583                    "Failed in ovsb partition, number of speed types overflow",
    584                    param_cal_id, num_spd_types, 4);
    585     }
    586 
    587     /* retrieve subpipe number for allocated PMs */
    588     for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) {
    589         tdm_td3_ovsb_get_spipe_grp_range(_tdm, spipe, &grp_lo, &grp_hi);
    590         for (grp = grp_lo; grp <= grp_hi; grp++) {
    591             for (pos = 0; pos < cal->grp_len; pos++) {
    592                 prt = cal->cal_grp[grp][pos];
    593                 if (prt != param_token_empty) {
    594                     prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt);
    595                     pm2spipe_map[prt_pm] = spipe;
    596                 }
    597             }
    598         }
    599     }
    600 
    601     return result;
    602 }
    603 
    604 /**
    605 @name: tdm_td3_ovsb_init_pmlist
    606 @param:
    607  */
    608 void
    609 tdm_td3_ovsb_init_pmlist(tdm_mod_t *_tdm, tdm_td3_ovsb_pm_t *pmlist, int pmlist_size)
    610 {
    611     int i, spd_idx, pos, prt, pm, spd;
    612     m_tdm_pipe_info_t *pipe_info;
    613 
    614     /* reset pmlist */
    615     for (i = 0; i < pmlist_size; i++) {
    616         pmlist[i].pm_en      = 0;
    617         pmlist[i].pm_num     = 0;
    618         pmlist[i].pm_bw      = 0;
    619         pmlist[i].pm_max_spd = 0;
    620     }
    621 
    622     /* initialize pmlist based pipe_info */
    623     pipe_info = &(_tdm->_core_data.vars_pkg.pipe_info);
    624     for (spd_idx = MAX_SPEED_TYPES - 1; spd_idx >=0 ; spd_idx--) {
    625         if (pipe_info->os_spd_en[spd_idx]) {
    626             for (pos = 0; pos < pipe_info->os_prt_cnt[spd_idx]; pos++) {
    627                 prt = pipe_info->os_prt[spd_idx][pos];
    628                 pm  = tdm_td3_cmn_get_port_pm(_tdm, prt);
    629                 spd = tdm_td3_cmn_get_port_speed(_tdm, prt);
    630                 if (pm >= 0 && pm < pmlist_size && spd > 0) {
    631                     pmlist[pm].pm_en      = 1;
    632                     pmlist[pm].pm_num     = pm;
    633                     pmlist[pm].pm_bw     += spd;
    634                     pmlist[pm].pm_max_spd = (pmlist[pm].pm_max_spd < spd) ?
    635                                             spd : pmlist[pm].pm_max_spd;
    636                 }
    637             }
    638         }
    639     }
    640 }
    641 
    642 /**
    643 @name: tdm_td3_ovsb_swap_pm
    644 @param:
    645  */
    646 void
    647 tdm_td3_ovsb_swap_pm(tdm_mod_t *_tdm, tdm_td3_ovsb_pm_t *pmlist, int src, int dst)
    648 {
    649     tdm_td3_ovsb_pm_t pm_tmp;
    650 
    651     pm_tmp.pm_en      = pmlist[src].pm_en;
    652     pm_tmp.pm_num     = pmlist[src].pm_num;
    653     pm_tmp.pm_bw      = pmlist[src].pm_bw;
    654     pm_tmp.pm_max_spd = pmlist[src].pm_max_spd;
    655 
    656     pmlist[src].pm_en      = pmlist[dst].pm_en;
    657     pmlist[src].pm_num     = pmlist[dst].pm_num;
    658     pmlist[src].pm_bw      = pmlist[dst].pm_bw;
    659     pmlist[src].pm_max_spd = pmlist[dst].pm_max_spd;
    660 
    661     pmlist[dst].pm_en      = pm_tmp.pm_en;
    662     pmlist[dst].pm_num     = pm_tmp.pm_num;
    663     pmlist[dst].pm_bw      = pm_tmp.pm_bw;
    664     pmlist[dst].pm_max_spd = pm_tmp.pm_max_spd;
    665 }
    666 
    667 /**
    668 @name: tdm_td3_ovsb_gen_pm2spipe_map_static
    669 @param:
    670 @desc: [chip_specific]
    671 
    672 Partition each PM into a subpipe.
    673      -- pipe 0,  pm[0 - 7], port[1 -  32]: hpipe 0
    674      -- pipe 0,  pm[8 -15], port[33-  64]: hpipe 1
    675      -- pipe 1,  pm[16-23], port[65-  96]: hpipe 0
    676      -- pipe 1,  pm[24-31], port[97- 128]: hpipe 1
    677  */
    678 int
    679 tdm_td3_ovsb_gen_pm2spipe_map_static(tdm_mod_t *_tdm)
    680 {
    681     int prt, pm, spipe_num, spd_idx, prt_idx;
    682     int pms_per_pipe, pms_per_spipe;
    683     int *pm2spipe_map = NULL;
    684     m_tdm_pipe_info_t *pipe_info;
    685 
    686     /* init variables */
    687     pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe;
    688     pipe_info    = &(_tdm->_core_data.vars_pkg.pipe_info);
    689     pms_per_pipe = _tdm->_chip_data.soc_pkg.pm_num_phy_modules /
    690                     TD3_NUM_PIPE;
    691     pms_per_spipe= pms_per_pipe / TD3_NUM_SPIPE;
    692     for (pm = 0; pm < TD3_NUM_PM_MOD; pm++) {
    693         pm2spipe_map[pm] = -1; /* -1:unassigned, 0:hp0, 1:hp1 */
    694     }
    695 
    696     /* partition PMs into subpipes */
    697     if (pms_per_pipe > 0 && pms_per_spipe > 0) {
    698         for (spd_idx = 0; spd_idx < MAX_SPEED_TYPES; spd_idx++) {
    699             if (pipe_info->os_spd_en[spd_idx]) {
    700                 for (prt_idx = 0; prt_idx < pipe_info->os_prt_cnt[spd_idx];
    701                      prt_idx++) {
    702                     prt = pipe_info->os_prt[spd_idx][prt_idx];
    703                     pm  = tdm_td3_cmn_get_port_pm(_tdm, prt);
    704                     if (pm2spipe_map[pm] == -1) {
    705                         /* [chip_specific]: static mapping rule */
    706                         spipe_num = (pm % pms_per_pipe) / pms_per_spipe;
    707                         pm2spipe_map[pm] = spipe_num;
    708                         TDM_PRINT2("TDM: partition PM %2d to subpipe %0d\n",
    709                                    pm, spipe_num);
    710                     }
    711                 }
    712             }
    713         }
    714     }
    715     TDM_SML_BAR
    716 
    717     return PASS;
    718 }
    719 
    720 /**
    721 @name: tdm_td3_ovsb_gen_pm2spipe_map_dynamic
    722 @param:
    723 
    724 Partition each PM into a subpipe.
    725  */
    726 int
    727 tdm_td3_ovsb_gen_pm2spipe_map_dynamic(tdm_mod_t *_tdm)
    728 {
    729     int i, j, spd_max, idx_src, idx_dst, pm, pm_idx, result = PASS;
    730     int spipe, dst_spipe, dst_spipe_bw, pms_per_spipe;
    731     int spipe_bw[TD3_NUM_SPIPE], spipe_pm_cnt[TD3_NUM_SPIPE];
    732     tdm_td3_ovsb_pm_t pmlist[TD3_NUM_PHY_PM];
    733     int *pm2spipe_map = NULL;
    734 
    735     /* initialize variables */
    736     pm2spipe_map  = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe;
    737     pms_per_spipe = _tdm->_chip_data.soc_pkg.pm_num_phy_modules /
    738                     TD3_NUM_PIPE / TD3_NUM_SPIPE;
    739     for (pm = 0; pm < TD3_NUM_PM_MOD; pm++) {
    740         pm2spipe_map[pm] = -1; /* -1:unassigned, 0:hp0, 1:hp1 */
    741     }
    742     for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) {
    743         spipe_bw[spipe]     = 0;
    744         spipe_pm_cnt[spipe] = 0;
    745     }
    746 
    747     /* step1: apply constraints by grouping certain PMs into same subpipe */
    748     if (_tdm->_chip_data.soc_pkg.flex_port_en == 1) {
    749         if (tdm_td3_ovsb_apply_constraints_flex(_tdm) != PASS) result = FAIL;
    750     } else {
    751         if (tdm_td3_ovsb_apply_constraints_init(_tdm) != PASS) result = FAIL;
    752     }
    753 
    754     /* step2-1: construct pmlist */
    755     tdm_td3_ovsb_init_pmlist(_tdm, pmlist, TD3_NUM_PHY_PM);
    756 
    757     /* step2-2: calculate bw for each subpipe in prepartition */
    758     for (pm = 0; pm < TD3_NUM_PHY_PM && pm < TD3_NUM_PM_MOD; pm++) {
    759         spipe = pm2spipe_map[pm];
    760         if (spipe >= 0 && spipe < TD3_NUM_SPIPE) {
    761             spipe_bw[spipe] += pmlist[pm].pm_bw;
    762             spipe_pm_cnt[spipe]++;
    763         }
    764     }
    765 
    766     /* step2-3: sort pmlist by decreasing pm_max_speed (insert sort) */
    767     for (i = 0; i < TD3_NUM_PHY_PM; i++) {
    768         spd_max = 0;
    769         idx_src = i;
    770         idx_dst = i;
    771         for (j = i; j < TD3_NUM_PHY_PM; j++) {
    772             if (pmlist[j].pm_en && spd_max < pmlist[j].pm_max_spd) {
    773                 spd_max = pmlist[j].pm_max_spd;
    774                 idx_src = j;
    775             }
    776         }
    777         if (idx_src != idx_dst) tdm_td3_ovsb_swap_pm(_tdm, pmlist,
    778                                                      idx_src, idx_dst);
    779         if (idx_src == idx_dst && !pmlist[idx_src].pm_en) break;
    780     }
    781 
    782     /* step2-4: partition PMs into subpipes */
    783     for (pm_idx = 0; pm_idx < TD3_NUM_PHY_PM; pm_idx++) {
    784         if (!pmlist[pm_idx].pm_en) break;
    785         pm = pmlist[pm_idx].pm_num;
    786         if (!(pm >=0 && pm < TD3_NUM_PM_MOD)) continue;
    787         if (pm2spipe_map[pm] != -1) continue;
    788         /* apply worst-fit to partition PM into a subpipe */
    789         dst_spipe    = -1;
    790         dst_spipe_bw = 0;
    791         for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) {
    792             if (spipe_pm_cnt[spipe] < pms_per_spipe) {
    793                 if (dst_spipe == -1 || spipe_bw[spipe] < dst_spipe_bw) {
    794                     dst_spipe   = spipe;
    795                     dst_spipe_bw= spipe_bw[spipe];
    796                 }
    797             }
    798         }
    799         if (dst_spipe != -1) {
    800             spipe_bw[dst_spipe] += pmlist[pm_idx].pm_bw;
    801             pm2spipe_map[pm]     = dst_spipe;
    802             TDM_PRINT2("TDM: partition PM %2d to subpipe %0d\n",
    803                        pm, dst_spipe);
    804         } else {
    805             result = FAIL;
    806             TDM_ERROR1("Failed to map PM %0d to ovsb subpipe\n", pm);
    807         }
    808     }
    809     TDM_SML_BAR
    810 
    811     return result;
    812 }
    813 
    814 /**
    815 @name: tdm_td3_ovsb_gen_pm2spipe_map
    816 @param:
    817     -- mapping_mode: 0->static, 1->dynamic.
    818  */
    819 int
    820 tdm_td3_ovsb_gen_pm2spipe_map(tdm_mod_t *_tdm, int mapping_mode)
    821 {
    822     if (mapping_mode == 0) {
    823         /* static mapping */
    824         return (tdm_td3_ovsb_gen_pm2spipe_map_static(_tdm));
    825     } else {
    826         /* dynamic mapping */
    827         return (tdm_td3_ovsb_gen_pm2spipe_map_dynamic(_tdm));
    828     }
    829 }
    830 
    831 /**
    832 @name: tdm_td3_ovsb_add_prt_to_grp
    833 @param:
    834 
    835 Add port into given ovsb speed group.
    836 If success, return pos of port in given speed group, otherwise return -1.
    837  */
    838 int
    839 tdm_td3_ovsb_add_prt_to_grp(tdm_mod_t *_tdm, int port_token, int grp)
    840 {
    841     int pos;
    842     tdm_calendar_t *cal;
    843     int param_token_empty;
    844 
    845     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
    846 
    847     /* get pipe calendar */
    848     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
    849     if (cal == NULL) return (-1);
    850 
    851     if (grp >= 0 && grp < cal->grp_num) {
    852         for (pos = 0; pos < cal->grp_len; pos++) {
    853             if (cal->cal_grp[grp][pos] == param_token_empty) {
    854                 cal->cal_grp[grp][pos] = port_token;
    855                 return pos;
    856             }
    857         }
    858     }
    859 
    860     return (-1);
    861 }
    862 
    863 /**
    864 @name: tdm_td3_ovsb_migrate_prt
    865 @param:
    866 
    867 Migrate all allocated same-speed sister ports of the given port from
    868 current ovsb grp to an appropriate grp.
    869  */
    870 int
    871 tdm_td3_ovsb_migrate_prt(tdm_mod_t *_tdm, int port_token, int slot_req)
    872 {
    873     int prt_buff[TD3_NUM_PM_LNS];
    874     int port_pm, port_spd;
    875     int prt, prt_sp, prt_cnt, prt_done;
    876     int grp, grp_lo, grp_hi, dst_grp, dst_pos, prev_grp, prev_pos;
    877     int pos;
    878     tdm_calendar_t *cal = NULL, *cal_prev = NULL;
    879     int param_token_empty;
    880 
    881     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
    882     for (prt_cnt = 0; prt_cnt < TD3_NUM_PM_LNS; prt_cnt++) {
    883         prt_buff[prt_cnt] = param_token_empty;
    884     }
    885 
    886     /* get pipe calendar */
    887     cal      = tdm_td3_cmn_get_pipe_cal(_tdm);
    888     cal_prev = tdm_td3_cmn_get_pipe_cal_prev(_tdm);
    889     if (cal == NULL || cal_prev == NULL) return (-1);
    890 
    891     /* case 1: select group containing sister ports with the same speed */
    892     port_pm  = tdm_td3_cmn_get_port_pm(_tdm, port_token);
    893     port_spd = tdm_td3_cmn_get_port_speed_eth(_tdm, port_token);
    894     prt_sp   = tdm_td3_ovsb_get_prt_spipe(_tdm, port_token);
    895     tdm_td3_ovsb_get_spipe_grp_range(_tdm, prt_sp, &grp_lo, &grp_hi);
    896 
    897     /* move same-speed sister ports to prt_buff[] */
    898     prt_cnt = 0;
    899     for (grp = grp_lo; grp <= grp_hi; grp++) {
    900         if (tdm_td3_ovsb_get_grp_spd(_tdm, grp) != port_spd) continue;
    901         for (pos = 0; pos < cal->grp_len; pos++) {
    902             prt = cal->cal_grp[grp][pos];
    903             if (prt != param_token_empty) {
    904                 if (tdm_td3_cmn_get_port_pm(_tdm, prt) == port_pm) {
    905                     if (prt_cnt < TD3_NUM_PM_LNS) {
    906                         prt_buff[prt_cnt] = prt;
    907                         cal->cal_grp[grp][pos] = param_token_empty;
    908                         prt_cnt++;
    909                         TDM_PRINT3("%s, prt %0d, src_grp %0d\n",
    910                                    "TDM: [a] move port from group to buffer",
    911                                    prt, grp);
    912                     }
    913                 }
    914             }
    915         }
    916     }
    917 
    918     /* select a group which can accomodate all same-speed sister ports */
    919     dst_grp = tdm_td3_ovsb_sel_grp_4_prt(_tdm, port_token);
    920     if (dst_grp == -1) return (-1);
    921 
    922     /* move all ports in prt_buff[] to the selected group */
    923     if (dst_grp >= grp_lo && dst_grp <= grp_hi ) {
    924         for (prt_cnt = 0; prt_cnt < TD3_NUM_PM_LNS; prt_cnt++) {
    925             prt      = prt_buff[prt_cnt];
    926             prev_grp = -1;
    927             prev_pos = -1;
    928             dst_pos  = -1;
    929             if (prt == param_token_empty) continue;
    930             /* determine port's grp and pos before flexing */
    931             prt_done = BOOL_FALSE;
    932             for (grp = grp_lo; grp <= grp_hi; grp++) {
    933                 for (pos = 0; pos < cal_prev->grp_len; pos++) {
    934                     if (cal_prev->cal_grp[grp][pos] == prt) {
    935                         prev_grp = grp;
    936                         prev_pos = pos;
    937                         prt_done = BOOL_TRUE;
    938                         break;
    939                     }
    940                 }
    941                 if (prt_done == BOOL_TRUE) break;
    942             }
    943             /* determine port's pos in dst_grp in current calendar */
    944             prt_done = BOOL_FALSE;
    945             if (dst_grp == prev_grp &&
    946                 prev_pos >= 0 && prev_pos < cal->grp_len) {
    947                 if (cal->cal_grp[dst_grp][prev_pos] == param_token_empty) {
    948                     dst_pos = prev_pos;
    949                     prt_done = BOOL_TRUE;
    950                 } else {
    951                     TDM_WARN4("%s, prt %0d, grp_prev %0d, pos_prev %0d\n",
    952                               "OVSB speed group violation on flex",
    953                               prt, prev_grp, prev_pos);
    954                 }
    955             }
    956             if (prt_done  == BOOL_FALSE) {
    957                 for (pos = 0; pos < cal->grp_len; pos++) {
    958                     if (cal->cal_grp[dst_grp][pos] == param_token_empty) {
    959                         dst_pos = pos;
    960                         prt_done = BOOL_TRUE;
    961                         break;
    962                     }
    963                 }
    964             }
    965             /* migrate port to cal_grp[dst_grp][dst_pos] */
    966             if (prt_done == BOOL_TRUE &&
    967                 dst_pos >= 0 && dst_pos < cal->grp_len) {
    968                 cal->cal_grp[dst_grp][dst_pos] = prt;
    969                 TDM_PRINT4("%s, prt %0d, dst_grp %0d, dst_pos %0d\n",
    970                            "TDM: [b] move port from buffer to group",
    971                            prt, dst_grp, dst_pos);
    972             }
    973         }
    974     }
    975 
    976     return dst_grp;
    977 }
    978 
    979 /**
    980 @name: tdm_td3_ovsb_sel_grp_4_prt
    981 @param:
    982 
    983 Select an ovsb group to accommodate given port.
    984 Return group index if found, otherwise return -1.
    985  */
    986 int
    987 tdm_td3_ovsb_sel_grp_4_prt(tdm_mod_t *_tdm, int port_token)
    988 {
    989     int port_pm, port_spd;
    990     int prt, prt_pm, prt_spd, prt_sp, prt_done, prt_lo = 0, prt_hi = 0;
    991     int pos, grp, grp_lo, grp_hi, grp_num, grp_spd;
    992     int slot_req, slot_avail, slot_alloc;
    993     tdm_calendar_t *cal;
    994     int param_token_empty;
    995 
    996     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
    997 
    998     /* get pipe calendar */
    999     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
   1000     if (cal == NULL) return (-1);
   1001 
   1002     /* get range of ovsb groups for the given port */
   1003     prt_sp  = tdm_td3_ovsb_get_prt_spipe(_tdm, port_token);
   1004     tdm_td3_ovsb_get_spipe_grp_range(_tdm, prt_sp, &grp_lo, &grp_hi);
   1005 
   1006     /* count number of ports with the same speed of given port within
   1007        the same PM */
   1008     slot_req = 0;
   1009     port_pm  = tdm_td3_cmn_get_port_pm(_tdm, port_token);
   1010     port_spd = tdm_td3_cmn_get_port_speed_eth(_tdm, port_token);
   1011     tdm_td3_cmn_get_pipe_port_lo_hi(_tdm, &prt_lo, &prt_hi);
   1012     for (prt = prt_lo; prt <= prt_hi; prt++) {
   1013         if ((tdm_td3_cmn_get_port_speed(_tdm, prt) > 0) &&
   1014             (BOOL_TRUE == tdm_td3_cmn_chk_port_is_os(_tdm, prt))) {
   1015             prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt);
   1016             if (prt_pm == port_pm) {
   1017                 prt_spd = tdm_td3_cmn_get_port_speed_eth(_tdm, prt);
   1018                 if (prt_spd == port_spd) slot_req++;
   1019             }
   1020         }
   1021     }
   1022     if (!(slot_req > 0)) return (-1);
   1023 
   1024     /* case 1: select group containing sister ports with the same speed */
   1025     grp_num  = -1;
   1026     prt_done = BOOL_FALSE;
   1027     for (grp = grp_lo; grp <= grp_hi; grp++) {
   1028         slot_alloc = 0;
   1029         grp_spd = tdm_td3_ovsb_get_grp_spd(_tdm, grp);
   1030         if (grp_spd != port_spd) continue;
   1031         /* check if current group contains sister ports */
   1032         for (pos = 0; pos < cal->grp_len; pos++) {
   1033             prt = cal->cal_grp[grp][pos];
   1034             if (prt != param_token_empty) {
   1035                 prt_pm = tdm_td3_cmn_get_port_pm(_tdm, prt);
   1036                 if (prt_pm == port_pm) {
   1037                     grp_num  = grp;
   1038                     prt_done = BOOL_TRUE;
   1039                     slot_alloc++;
   1040                     if (prt == port_token) {
   1041                         grp_num = -1;
   1042                         break;
   1043                     }
   1044                 }
   1045             }
   1046         }
   1047         /* check available resource in selected group */
   1048         if (prt_done == BOOL_TRUE) {
   1049             if (grp_num != -1) {
   1050                 slot_avail = tdm_td3_ovsb_get_grp_empty_cnt(_tdm, grp_num);
   1051                 if (!(slot_avail >= (slot_req - slot_alloc))) {
   1052                     grp_num = tdm_td3_ovsb_migrate_prt(_tdm, port_token,
   1053                                                        slot_req);
   1054                 }
   1055             }
   1056             break;
   1057         }
   1058     }
   1059     if (prt_done == BOOL_TRUE) return grp_num;
   1060 
   1061     /* case 2: select group containing same speed ports */
   1062     grp_num = -1;
   1063     prt_done = BOOL_FALSE;
   1064     for (grp = grp_lo; grp <= grp_hi; grp++) {
   1065         /* find same speed group, and check available resource */
   1066         grp_spd = tdm_td3_ovsb_get_grp_spd(_tdm, grp);
   1067         if (grp_spd == port_spd) {
   1068             slot_avail = tdm_td3_ovsb_get_grp_empty_cnt(_tdm, grp);
   1069             if (slot_avail >= slot_req) {
   1070                 grp_num  = grp;
   1071                 prt_done = BOOL_TRUE;
   1072                 break;
   1073             }
   1074         }
   1075     }
   1076     if (prt_done == BOOL_TRUE) return grp_num;
   1077 
   1078     /* case 3: select group containing no ports (empty group) */
   1079     grp_num  = -1;
   1080     prt_done = BOOL_FALSE;
   1081     for (grp = grp_lo; grp <= grp_hi; grp++) {
   1082         slot_avail = tdm_td3_ovsb_get_grp_empty_cnt(_tdm, grp);
   1083         if (slot_avail == cal->grp_len) {
   1084             grp_num  = grp;
   1085             prt_done = BOOL_TRUE;
   1086             break;
   1087         }
   1088     }
   1089     if (prt_done == BOOL_TRUE) return grp_num;
   1090 
   1091     return (-1);
   1092 }
   1093 
   1094 /**
   1095 @name: tdm_td3_ovsb_fill_os_grps
   1096 @param:
   1097  */
   1098 int
   1099 tdm_td3_ovsb_fill_os_grps(tdm_mod_t *_tdm)
   1100 {
   1101     int prt, prt_idx, pos, spd_idx, spd, grp, result = PASS;
   1102     m_tdm_pipe_info_t *pipe_info;
   1103 
   1104     /* iterate each speed class */
   1105     pipe_info = &(_tdm->_core_data.vars_pkg.pipe_info);
   1106     for (spd_idx = 0; spd_idx < MAX_SPEED_TYPES; spd_idx++) {
   1107         if (!pipe_info->os_spd_en[spd_idx]) continue;
   1108         /* fill all ports in current speed class into ovsb group */
   1109         for (prt_idx=0; prt_idx<pipe_info->os_prt_cnt[spd_idx]; prt_idx++) {
   1110             prt = pipe_info->os_prt[spd_idx][prt_idx];
   1111             spd = tdm_td3_cmn_get_port_speed(_tdm, prt);
   1112             grp = tdm_td3_ovsb_sel_grp_4_prt(_tdm, prt);
   1113             pos = tdm_td3_ovsb_add_prt_to_grp(_tdm, prt, grp);
   1114             if (grp >= 0 && pos >= 0) {
   1115                 TDM_PRINT5("%s, spd %0dG, prt %3d, grp %2d, pos %0d\n",
   1116                            "TDM: add port to ovsb group",
   1117                            (spd / 1000), prt, grp, pos);
   1118             } else {
   1119                 result = FAIL;
   1120                 TDM_ERROR5("%s, spd %0dG, prt %3d, grp %0d, pos %0d\n",
   1121                            "TDM: failed to add port to ovsb group",
   1122                            (spd / 1000), prt, grp, pos);
   1123             }
   1124         }
   1125     }
   1126     TDM_SML_BAR
   1127 
   1128     return result;
   1129 }
   1130 
   1131 /**
   1132 @name: tdm_td3_ovsb_consolidate_spipe
   1133 @param:
   1134 
   1135 Minimize the number of oversub speed groups of the given subpipe.
   1136 Note: All ports belonging to the same subpipe should be considered.
   1137  */
   1138 int
   1139 tdm_td3_ovsb_consolidate_spipe(tdm_mod_t *_tdm, int spipe)
   1140 {
   1141     int grp_lo, grp_hi, grp_dst, grp_src, grp_spd_dst, grp_spd_src,
   1142         grp_size_dst, grp_size_src, idx_dst, idx_src, prt_src;
   1143     int param_token_empty;
   1144     tdm_calendar_t *cal;
   1145 
   1146     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1147 
   1148     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
   1149     if (cal == NULL) return PASS;
   1150 
   1151     TDM_PRINT0("TDM: [FLEX] run consolidation\n");
   1152     tdm_td3_ovsb_get_spipe_grp_range(_tdm, spipe, &grp_lo, &grp_hi);
   1153     for (grp_dst = grp_lo; grp_dst < grp_hi; grp_dst++) {
   1154         grp_spd_dst = tdm_td3_ovsb_get_grp_spd(_tdm, grp_dst);
   1155         grp_size_dst= tdm_td3_ovsb_get_grp_prt_cnt(_tdm, grp_dst);
   1156         /* for each non-empty group, do consolidation */
   1157         if(grp_spd_dst == 0 || grp_size_dst == cal->grp_len) continue;
   1158         for (grp_src = grp_dst + 1; grp_src <= grp_hi; grp_src++) {
   1159             /* find two same speed groups */
   1160             grp_spd_src = tdm_td3_ovsb_get_grp_spd(_tdm, grp_src);
   1161             grp_size_src= tdm_td3_ovsb_get_grp_prt_cnt(_tdm, grp_src);
   1162             if (grp_spd_src != grp_spd_dst) continue;
   1163             if ((grp_size_src + grp_size_dst) > cal->grp_len) continue;
   1164             /* merge two same speed groups into one */
   1165             idx_dst = 0;
   1166             for (idx_src = 0; idx_src < cal->grp_len; idx_src++) {
   1167                 prt_src = cal->cal_grp[grp_src][idx_src];
   1168                 if(prt_src == param_token_empty) continue;
   1169                 while (idx_dst < cal->grp_len) {
   1170                     if (cal->cal_grp[grp_dst][idx_dst] == param_token_empty) {
   1171                         cal->cal_grp[grp_dst][idx_dst] = prt_src;
   1172                         cal->cal_grp[grp_src][idx_src] = param_token_empty;
   1173                         break;
   1174                     }
   1175                     idx_dst++;
   1176                 }
   1177             }
   1178         }
   1179     }
   1180 
   1181     return PASS;
   1182 }
   1183 
   1184 /**
   1185 @name: tdm_td3_ovsb_flex_port_dn
   1186 @param:
   1187 
   1188 Remove down ports from ovsb speed groups
   1189  */
   1190 int
   1191 tdm_td3_ovsb_flex_port_dn(tdm_mod_t *_tdm)
   1192 {
   1193     int pos, prt, prt_done, prt_lo = 0, prt_hi = 0;
   1194     int grp, flex_dn_exist = BOOL_FALSE;
   1195     int param_token_empty;
   1196     enum port_speed_e *param_speeds_prev;
   1197     enum port_state_e *param_states_prev;
   1198     tdm_calendar_t *cal;
   1199 
   1200     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1201     param_speeds_prev = _tdm->_prev_chip_data.soc_pkg.speed;
   1202     param_states_prev = _tdm->_prev_chip_data.soc_pkg.state;
   1203 
   1204     /* check whether exists down port in current pipe */
   1205     tdm_td3_cmn_get_pipe_port_lo_hi(_tdm, &prt_lo, &prt_hi);
   1206     for (prt = prt_lo; prt <= prt_hi; prt++) {
   1207         if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_DN ||
   1208             param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1209             flex_dn_exist = BOOL_TRUE;
   1210             break;
   1211         }
   1212     }
   1213     if (flex_dn_exist == BOOL_FALSE) return PASS;
   1214 
   1215     TDM_PRINT0("TDM: Flex DOWN ports\n");
   1216     /* remove down_ports and spd_changed_ports */
   1217     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
   1218     if (cal == NULL) return PASS;
   1219     for (prt = prt_lo; prt <= prt_hi; prt++) {
   1220         if (param_states_prev[prt-1] == PORT_STATE__FLEX_OVERSUB_DN ||
   1221             param_states_prev[prt-1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1222             prt_done = BOOL_FALSE;
   1223             for (grp = 0; grp <= cal->grp_num; grp++) {
   1224                 for (pos = 0; pos < cal->grp_len; pos++) {
   1225                     if (cal->cal_grp[grp][pos] == prt) {
   1226                         cal->cal_grp[grp][pos] = param_token_empty;
   1227                         prt_done = BOOL_TRUE;
   1228                         TDM_PRINT5("%s %0d, spd %0dG, grp %0d, pos %0d\n",
   1229                                    "TDM: [FLEX DN] remove down port",
   1230                                    prt, param_speeds_prev[prt]/1000,
   1231                                    grp, pos);
   1232                         break;
   1233                     }
   1234                 }
   1235                 if (prt_done == BOOL_TRUE) break;
   1236             }
   1237         }
   1238     }
   1239     TDM_SML_BAR
   1240 
   1241     return PASS;
   1242 }
   1243 
   1244 /**
   1245 @name: tdm_td3_ovsb_flex_port_up
   1246 @param:
   1247 
   1248 Add up ports into ovsb speed groups
   1249  */
   1250 int
   1251 tdm_td3_ovsb_flex_port_up(tdm_mod_t *_tdm)
   1252 {
   1253     int prt_lo, prt_hi, prt, prt_spd, pos, grp, spipe, result = PASS;
   1254     int spipe_done[TD3_NUM_SPIPE];
   1255     int flex_up_exist = BOOL_FALSE;
   1256     enum port_state_e *param_states_prev;
   1257 
   1258     param_states_prev = _tdm->_prev_chip_data.soc_pkg.state;
   1259     for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) spipe_done[spipe] = 0;
   1260     tdm_td3_cmn_get_pipe_port_lo_hi(_tdm, &prt_lo, &prt_hi);
   1261 
   1262     /* check whether exists up port in current pipe */
   1263     for (prt = prt_lo; prt <= prt_hi; prt++) {
   1264         if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_UP ||
   1265             param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1266             flex_up_exist = BOOL_TRUE;
   1267             break;
   1268         }
   1269     }
   1270     if (flex_up_exist == BOOL_FALSE) return result;
   1271     TDM_PRINT0("TDM: Flex UP ports\n");
   1272 
   1273     /* do consolidation */
   1274     
   1275     for (prt = prt_lo; prt <= prt_hi; prt++) {
   1276         if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_UP ||
   1277             param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1278             spipe = tdm_td3_ovsb_get_prt_spipe(_tdm, prt);
   1279             if (spipe >= 0 && spipe < TD3_NUM_SPIPE) {
   1280                 if (spipe_done[spipe] == 0) {
   1281                     tdm_td3_ovsb_consolidate_spipe(_tdm, spipe);
   1282                     spipe_done[spipe] = 1;
   1283                 }
   1284             }
   1285         }
   1286     }
   1287 
   1288     /* add up_ports and spd_changed_ports */
   1289     for (prt = prt_lo; prt <= prt_hi; prt++) {
   1290         if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_UP ||
   1291             param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1292             prt_spd = tdm_td3_cmn_get_port_speed(_tdm, prt);
   1293             grp = tdm_td3_ovsb_sel_grp_4_prt(_tdm, prt);
   1294             pos = tdm_td3_ovsb_add_prt_to_grp(_tdm, prt, grp);
   1295             if (grp != -1 && pos != -1) {
   1296                 TDM_PRINT5("%s, prt %0d, spd %0dG, grp %0d, pos %0d\n",
   1297                            "TDM: [FLEX] add up_port",
   1298                            prt, (prt_spd / 1000), grp, pos);
   1299             } else {
   1300                 result = FAIL;
   1301                 TDM_ERROR3("%s, prt %0d, spd %0dG, no available ovsb speed group\n",
   1302                            "TDM: [FLEX] failed to add up_port",
   1303                            prt, (prt_spd / 1000));
   1304             }
   1305         }
   1306     }
   1307     TDM_SML_BAR
   1308 
   1309     return result;
   1310 }
   1311 
   1312 /**
   1313 @name: tdm_td3_ovsb_gen_os_grps_init
   1314 @param:
   1315  */
   1316 int
   1317 tdm_td3_ovsb_gen_os_grps_init(tdm_mod_t *_tdm)
   1318 {
   1319     int result = PASS;
   1320 
   1321     /* partition PMs into subpipes */
   1322     if (tdm_td3_ovsb_gen_pm2spipe_map(_tdm, 0) != PASS) result = FAIL;
   1323 
   1324     /* allocate ports into ovsb groups based on partitioned subpipes */
   1325     if (tdm_td3_ovsb_fill_os_grps(_tdm) != PASS) result = FAIL;
   1326 
   1327     return result;
   1328 }
   1329 
   1330 /**
   1331 @name: tdm_td3_ovsb_gen_os_grps_flex
   1332 @param:
   1333  */
   1334 int
   1335 tdm_td3_ovsb_gen_os_grps_flex(tdm_mod_t *_tdm)
   1336 {
   1337     int grp, pos, result = PASS;
   1338     tdm_calendar_t *cal = NULL, *cal_prev = NULL;
   1339 
   1340     /* step 1: copy ovsb grps from cal_prev into cal */
   1341     TDM_PRINT0("TDM: Restore ovsb grps by pre_flex values\n");
   1342     cal      = tdm_td3_cmn_get_pipe_cal(_tdm);
   1343     cal_prev = tdm_td3_cmn_get_pipe_cal_prev(_tdm);
   1344     if (cal == NULL || cal_prev == NULL) return FAIL;
   1345     for (grp = 0; grp < cal->grp_num; grp++) {
   1346         for (pos=0; pos<cal->grp_len; pos++) {
   1347             cal->cal_grp[grp][pos] = cal_prev->cal_grp[grp][pos];
   1348         }
   1349     }
   1350 
   1351     /* step 2: partition PMs into subpipes */
   1352     if (tdm_td3_ovsb_gen_pm2spipe_map(_tdm, 0) != PASS) result = FAIL;
   1353 
   1354     /* step 3: flex up-ports */
   1355     if (tdm_td3_ovsb_flex_port_dn(_tdm) != PASS) result = FAIL;
   1356 
   1357     /* step 4: flex down-ports */
   1358     if (tdm_td3_ovsb_flex_port_up(_tdm) != PASS) result = FAIL;
   1359 
   1360     return result;
   1361 }
   1362 
   1363 /**
   1364 @name: tdm_td3_ovsb_gen_os_grps
   1365 @param:
   1366  */
   1367 int
   1368 tdm_td3_ovsb_gen_os_grps(tdm_mod_t *_tdm)
   1369 {
   1370     if (_tdm->_chip_data.soc_pkg.flex_port_en == 1) {
   1371         return (tdm_td3_ovsb_gen_os_grps_flex(_tdm));
   1372     } else {
   1373         return (tdm_td3_ovsb_gen_os_grps_init(_tdm));
   1374     }
   1375 }
   1376 
   1377 /**
   1378 @name: tdm_td3_ovsb_gen_pkt_shaper_per_prt
   1379 @param:
   1380 
   1381 Populates Pkt shaper calendar - per port
   1382  */
   1383 int
   1384 tdm_td3_ovsb_gen_pkt_shaper_per_prt(tdm_mod_t *_tdm, int prt)
   1385 {
   1386     int i, pos, prt_slots, prt_pm, prt_spipe, slot_cnt, result = PASS;
   1387     int pm_shaper_tbl[TD3_SHAPER_NUM_PM_SLOTS];
   1388     int *pkt_shaper_cal, *pm2spipe_map;
   1389     int param_token_empty;
   1390 
   1391     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1392     pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe;
   1393 
   1394     for (i = 0; i < TD3_SHAPER_NUM_PM_SLOTS; i++)
   1395         pm_shaper_tbl[i] = param_token_empty;
   1396 
   1397     /* generate pm shaper calendar for the current port */
   1398     prt_slots = tdm_td3_cmn_get_port_speed_eth(_tdm, prt) /
   1399                 TD3_SHAPER_SLOT_UNIT;
   1400     for (slot_cnt = 0; slot_cnt < prt_slots; slot_cnt++) {
   1401         pos = tdm_td3_ovsb_get_pm_shaper_prt_pos(_tdm, prt, slot_cnt) %
   1402               TD3_SHAPER_NUM_PM_SLOTS;
   1403         pm_shaper_tbl[pos] = prt;
   1404     }
   1405 
   1406     TDM_PRINT1("TDM: prt %3d, pm_shaper_cal[", prt);
   1407     for (pos = 0; pos < TD3_SHAPER_NUM_PM_SLOTS; pos++) {
   1408         TDM_PRINT2("%0d:%0d, ", pos, pm_shaper_tbl[pos]);
   1409     }
   1410     TDM_PRINT0("]\n");
   1411 
   1412     /* Get the right pkt scheduler calendar*/
   1413     prt_pm    = tdm_td3_cmn_get_port_pm(_tdm, prt);
   1414     prt_spipe = pm2spipe_map[prt_pm];
   1415     pkt_shaper_cal = tdm_td3_ovsb_get_pkt_shaper_cal(_tdm, prt_spipe);
   1416     if (pkt_shaper_cal == NULL) return FAIL;
   1417 
   1418     /* Populate pkt scheduler calendar */
   1419     slot_cnt = 0;
   1420     for (i = 0; i < TD3_SHAPER_NUM_PM_SLOTS; i++) {
   1421         if (pm_shaper_tbl[i] != param_token_empty) {
   1422             pos = tdm_td3_ovsb_get_pkt_shaper_prt_pos(_tdm, prt, i);
   1423             slot_cnt++;
   1424             if (pos >=0 && pos < TD3_SHAPING_GRP_LEN) {
   1425                 pkt_shaper_cal[pos] = pm_shaper_tbl[i];
   1426                 TDM_PRINT4("%s, prt %3d, slot_cnt %0d, index %0d\n",
   1427                            "TDM: [pkt_shaper_cal]",
   1428                            pm_shaper_tbl[i], slot_cnt, pos);
   1429             } else {
   1430                 result = FAIL;
   1431                 TDM_ERROR3("%s, prt %3d, slot_cnt %0d\n",
   1432                            "[pkt_shaper_cal] Failed to allocate port slots",
   1433                            prt, slot_cnt);
   1434             }
   1435         }
   1436     }
   1437 
   1438     return result;
   1439 }
   1440 
   1441 /**
   1442 @name: tdm_td3_ovsb_gen_pkt_shaper_init
   1443 @param:
   1444 
   1445 Populates Pkt shaper calendar
   1446  */
   1447 int
   1448 tdm_td3_ovsb_gen_pkt_shaper_init(tdm_mod_t *_tdm)
   1449 {
   1450     int spipe, grp, grp_lo, grp_hi, pos, prt;
   1451     tdm_calendar_t *cal;
   1452     int param_token_empty;
   1453 
   1454     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1455     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
   1456     if (cal == NULL) return FAIL;
   1457 
   1458     for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) {
   1459         tdm_td3_ovsb_get_spipe_grp_range(_tdm, spipe, &grp_lo, &grp_hi);
   1460         for (grp = grp_lo; grp <= grp_hi; grp++) {
   1461             for (pos = 0; pos < cal->grp_len; pos++) {
   1462                 prt = cal->cal_grp[grp][pos];
   1463                 if (prt != param_token_empty)
   1464                     tdm_td3_ovsb_gen_pkt_shaper_per_prt(_tdm, prt);
   1465             }
   1466         }
   1467     }
   1468     TDM_SML_BAR
   1469 
   1470     return PASS;
   1471 }
   1472 
   1473 /**
   1474 @name: tdm_td3_ovsb_gen_pkt_shaper_flex
   1475 @param:
   1476 
   1477 Populates Pkt shaper calendar
   1478  */
   1479 int
   1480 tdm_td3_ovsb_gen_pkt_shaper_flex(tdm_mod_t *_tdm)
   1481 {
   1482     int i, spipe, grp, grp_lo, grp_hi, pos, prt;
   1483     int port_done[TD3_NUM_EXT_PORTS];
   1484     tdm_calendar_t *cal;
   1485     int *pkt_cal, *pkt_cal_prev;
   1486     int param_token_empty;
   1487     enum port_state_e *param_states_prev;
   1488 
   1489     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1490     param_states_prev = _tdm->_prev_chip_data.soc_pkg.state;
   1491     cal = tdm_td3_cmn_get_pipe_cal(_tdm);
   1492     if (cal == NULL) return FAIL;
   1493     for (i = 0; i < TD3_NUM_EXT_PORTS; i++) port_done[i] = 0;
   1494 
   1495     /* step 1: copy pkt shaper calendar from pkt_cal_prev into pkt_cal */
   1496     for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) {
   1497         pkt_cal      = tdm_td3_ovsb_get_pkt_shaper_cal(_tdm, spipe);
   1498         pkt_cal_prev = tdm_td3_ovsb_get_pkt_shaper_cal_prev(_tdm, spipe);
   1499         if (pkt_cal == NULL || pkt_cal_prev == NULL) continue;
   1500         for (i = 0; i < TD3_SHAPING_GRP_LEN; i++) {
   1501             prt = pkt_cal_prev[i];
   1502             if (param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_DN ||
   1503                 param_states_prev[prt - 1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1504                 prt = param_token_empty;
   1505             }
   1506             pkt_cal[i] = prt;
   1507             if (prt!=param_token_empty && prt>0 && prt<TD3_NUM_EXT_PORTS) {
   1508                 port_done[prt] = 1;
   1509             }
   1510         }
   1511     }
   1512 
   1513     /* step 2: allocate slots for up-ports in pkt shaper calendar */
   1514     for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) {
   1515         tdm_td3_ovsb_get_spipe_grp_range(_tdm, spipe, &grp_lo, &grp_hi);
   1516         for (grp = grp_lo; grp <= grp_hi; grp++) {
   1517             for (pos = 0; pos < cal->grp_len; pos++) {
   1518                 prt = cal->cal_grp[grp][pos];
   1519                 if (prt != param_token_empty &&
   1520                     prt > 0 && prt < TD3_NUM_EXT_PORTS) {
   1521                     if (port_done[prt] == 0) {
   1522                         tdm_td3_ovsb_gen_pkt_shaper_per_prt(_tdm, prt);
   1523                         port_done[prt] = 1;
   1524                     }
   1525                 }
   1526             }
   1527         }
   1528     }
   1529     TDM_SML_BAR
   1530 
   1531     return PASS;
   1532 }
   1533 
   1534 /**
   1535 @name: tdm_td3_ovsb_gen_pkt_shaper
   1536 @param:
   1537 
   1538 Populates Pkt shaper calendar
   1539  */
   1540 int
   1541 tdm_td3_ovsb_gen_pkt_shaper(tdm_mod_t *_tdm)
   1542 {
   1543     if (_tdm->_chip_data.soc_pkg.flex_port_en == 1) {
   1544         return (tdm_td3_ovsb_gen_pkt_shaper_flex(_tdm));
   1545         /* return (tdm_td3_ovsb_gen_pkt_shaper_init(_tdm)); */
   1546     } else {
   1547         return (tdm_td3_ovsb_gen_pkt_shaper_init(_tdm));
   1548     }
   1549 
   1550     return PASS;
   1551 }
   1552 
   1553 /**
   1554 @name: tdm_td3_ovsb_gen_pm2pblk_map
   1555 @param:
   1556 @desc: [chip_specific]
   1557 
   1558 Maps PM num (block_id) to OVSB pblk id
   1559  */
   1560 int
   1561 tdm_td3_ovsb_gen_pm2pblk_map(tdm_mod_t *_tdm)
   1562 {
   1563     int pm, pm_lo, pm_hi, spipe;
   1564     int pblk_idx[TD3_NUM_SPIPE];
   1565     int *pm2pblk_map = NULL, *pm2spipe_map = NULL;
   1566 
   1567     pm2pblk_map  = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_num_to_pblk;
   1568     pm2spipe_map = _tdm->_chip_data.soc_pkg.soc_vars.td3.pm_ovs_halfpipe;
   1569     tdm_td3_cmn_get_pipe_pm_lo_hi(_tdm, &pm_lo, &pm_hi);
   1570     for (spipe = 0; spipe < TD3_NUM_SPIPE; spipe++) pblk_idx[spipe] = 0;
   1571 
   1572     for (pm = pm_lo; pm <= pm_hi && pm < TD3_NUM_PM_MOD; pm++) {
   1573         pm2pblk_map[pm] = -1;
   1574         spipe = pm2spipe_map[pm];
   1575         if (spipe >= 0 && spipe < TD3_NUM_SPIPE) {
   1576             /* [chip_specific] halpipe 0 uses increment order: [0,1,...7]
   1577              *                 halpipe 1 uses decrement order: [7,6,...0]
   1578              */
   1579             if (spipe == 0) {
   1580                 pm2pblk_map[pm] = pblk_idx[spipe];
   1581             } else {
   1582                 pm2pblk_map[pm] = TD3_NUM_PMS_PER_SPIPE - pblk_idx[spipe] - 1;
   1583             }
   1584             pblk_idx[spipe]++;
   1585             TDM_PRINT3("TDM: map pm %2d to subpipe %0d pblk %0d\n",
   1586                        pm, spipe, pm2pblk_map[pm]);
   1587         }
   1588     }
   1589     TDM_SML_BAR
   1590 
   1591     return PASS;
   1592 }
   1593 
   1594 /**
   1595 @name: tdm_td3_vbs_scheduler_ovs_2
   1596 @param:
   1597  */
   1598 int
   1599 tdm_td3_vbs_scheduler_ovs(tdm_mod_t *_tdm)
   1600 {
   1601     int result = PASS;
   1602     int param_cal_id = _tdm->_core_data.vars_pkg.cal_id;
   1603 
   1604     /* generate ovsb groups */
   1605     TDM_PRINT1("Generating OVSB groups for PIPE %0d\n\n", param_cal_id);
   1606     if (tdm_td3_ovsb_gen_os_grps(_tdm) != PASS) result = FAIL;
   1607 
   1608     /* generate PKT scheduler */
   1609     TDM_PRINT1("Generating OVSB PKT Scheduler for PIPE %0d\n\n", param_cal_id);
   1610     /* if (tdm_td3_ovsb_pkt_shaper_new(_tdm) != PASS) result = FAIL; */
   1611     if (tdm_td3_ovsb_gen_pkt_shaper(_tdm) != PASS) result = FAIL;
   1612 
   1613     /* generate PM_NUM to PBLK mapping */
   1614     TDM_PRINT1("Generating OVSB PM2PBLK mapping for PIPE %0d\n\n", param_cal_id);
   1615     if(tdm_td3_ovsb_gen_pm2pblk_map(_tdm) != PASS) result = FAIL;
   1616 
   1617     return result;
   1618 }