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_mv2_ovsb.c (73355B)


      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 #define TDM_MV2_HPIPE_STATIC_MAPPING_ENABLE 1
     17 
     18 
     19 /**
     20 @name: tdm_mv2_ovsb_apply_constraints
     21 @param:
     22 
     23 Partition OVSB PMs into 2 halfpipes
     24  */
     25 int
     26 tdm_mv2_ovsb_apply_constraints(tdm_mod_t *_tdm)
     27 {
     28     int pm_num, ln_num, i, pm_num_lo, pm_num_hi, pms_per_pipe;
     29     int num_of_speeds, phy_base_port, phy_port;
     30     int speed_en_mtx[MV2_NUM_PHY_PM][MV2_PORT_SPEED_INDX_SIZE];
     31     int speed_en_mtx_reduced[MV2_PORT_SPEED_INDX_SIZE];
     32     /* <speed_indx> 0: 10G; 1: 20G; 2: 25G; 3: 40G; 4: 50G; 5: 100G */
     33     int param_pipe_id,param_pm_lanes, param_pm_num;
     34     int *param_pm_hpipe;
     35     enum port_speed_e *param_speeds;
     36 
     37     param_pipe_id  = _tdm->_core_data.vars_pkg.cal_id;
     38     param_pm_lanes = _tdm->_chip_data.soc_pkg.pmap_num_lanes;
     39     param_pm_num   = _tdm->_chip_data.soc_pkg.pm_num_phy_modules;
     40     param_pm_hpipe = _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe;
     41     param_speeds   = _tdm->_chip_data.soc_pkg.speed;
     42 
     43     pms_per_pipe = param_pm_num / MV2_NUM_PIPE;
     44     pm_num_lo = param_pipe_id * pms_per_pipe;
     45     pm_num_hi = (param_pipe_id + 1) * pms_per_pipe - 1;
     46 
     47     /* initialize variables */
     48     for (i=0; i<MV2_PORT_SPEED_INDX_SIZE; i++) {
     49         for (pm_num=0; pm_num<MV2_NUM_PHY_PM; pm_num++) {
     50             speed_en_mtx[pm_num][i]=0;
     51         }
     52         speed_en_mtx_reduced[i]=0;
     53     }
     54     for (pm_num = pm_num_lo; pm_num <= pm_num_hi; pm_num++) {
     55         /* Coding rule for param_pm_hpipe:
     56          *       -1 : not OVSB;
     57          *        2 : OVSB but not assigned
     58          *        0 : Half Pipe 0
     59          *        1 : Half Pipe 1
     60          */
     61         param_pm_hpipe[pm_num] = -1;
     62         phy_base_port = MV2_NUM_PM_LNS * pm_num + 1;
     63         for (ln_num = 0; ln_num < param_pm_lanes; ln_num++) {
     64             phy_port = phy_base_port + ln_num;
     65             if (tdm_mv2_cmn_chk_port_is_os(phy_port, _tdm) == BOOL_TRUE) {
     66                 param_pm_hpipe[pm_num] = 2;
     67                 break;
     68             }
     69         }
     70     }
     71 
     72     /* Construct speed_en_mtx matrix */
     73     for (pm_num = pm_num_lo; pm_num <= pm_num_hi; pm_num++) {
     74         if (param_pm_hpipe[pm_num] == 2) {
     75             phy_base_port = MV2_NUM_PM_LNS * pm_num + 1;
     76             for (ln_num = 0; ln_num < param_pm_lanes; ln_num++) {
     77                 phy_port = phy_base_port + ln_num;
     78                 if (tdm_mv2_cmn_chk_port_is_os(phy_port, _tdm) == BOOL_TRUE) {
     79                     switch(param_speeds[phy_port]) {
     80                         case SPEED_10G : 
     81                             speed_en_mtx[pm_num][MV2_SPEED_IDX_10G] = 1; break;
     82                         case SPEED_20G : 
     83                             speed_en_mtx[pm_num][MV2_SPEED_IDX_20G] = 1; break;
     84                         case SPEED_25G : 
     85                             speed_en_mtx[pm_num][MV2_SPEED_IDX_25G] = 1; break;
     86                         case SPEED_40G : 
     87                             speed_en_mtx[pm_num][MV2_SPEED_IDX_40G] = 1; break;
     88                         case SPEED_50G : 
     89                             speed_en_mtx[pm_num][MV2_SPEED_IDX_50G] = 1; break;
     90                         case SPEED_100G : 
     91                             speed_en_mtx[pm_num][MV2_SPEED_IDX_100G]= 1; break;
     92                         default : break;
     93                     }
     94                 }
     95             }
     96             for(i = 0; i < MV2_PORT_SPEED_INDX_SIZE; i++) {
     97                 speed_en_mtx_reduced[i] = (speed_en_mtx[pm_num][i] == 1) ? 1 :
     98                                           speed_en_mtx_reduced[i];
     99             }
    100         }
    101     }
    102 
    103     num_of_speeds = 0;
    104     for (i = 0; i < MV2_PORT_SPEED_INDX_SIZE; i++) {
    105         if (speed_en_mtx_reduced[i] > 0) {
    106             num_of_speeds++;
    107         }
    108     }
    109 
    110     /* Restriction 13:
    111      * No port configs with more than 4 port speed classes are supported.
    112      */
    113     if (num_of_speeds > 5) {
    114         TDM_ERROR3("%s PIPE %d, speed_types=%d, max_speed_types=4\n",
    115                    "[ovsb_halfpipe_constraints] Invalid port config,",
    116                    param_pipe_id, num_of_speeds);
    117     }
    118     /* Restriction 14:
    119      * The only supported port configs with 4 port speed classes are:
    120      *       10G/20G/40G/100G
    121      *       10G/25G/50G/100G
    122      * Rule: Group PMs with 25G/50G ports in HP0 and PMs with 20G/40G in HP1.
    123      */
    124     else if (num_of_speeds == 4) {
    125         if ((speed_en_mtx_reduced[MV2_SPEED_IDX_20G] ||
    126              speed_en_mtx_reduced[MV2_SPEED_IDX_40G]) &&
    127             (speed_en_mtx_reduced[MV2_SPEED_IDX_25G] ||
    128              speed_en_mtx_reduced[MV2_SPEED_IDX_50G])) {
    129             TDM_PRINT2("%s PIPE %d applying Restriction 14 \n",
    130                        "[ovsb_halfpipe_constraints]", param_pipe_id);
    131             for (pm_num = pm_num_lo; pm_num <= pm_num_hi; pm_num++) {
    132                 if (speed_en_mtx[pm_num][MV2_SPEED_IDX_25G] ||
    133                     speed_en_mtx[pm_num][MV2_SPEED_IDX_50G]) {
    134                     param_pm_hpipe[pm_num] = 0;
    135                 } else if (speed_en_mtx[pm_num][MV2_SPEED_IDX_20G] ||
    136                            speed_en_mtx[pm_num][MV2_SPEED_IDX_40G]) {
    137                     param_pm_hpipe[pm_num] = 1;
    138                 }
    139             }
    140         }
    141     }
    142     /* Restriction 15:
    143      * All port configs with 1-3 port speed classes are supported,
    144      * except configs that contain both 20G and 25G port speeds.
    145      * Rule: Group PMs with 25G/50G ports in HP0 and PMs with 20G/40G in HP1
    146      */
    147     else if (num_of_speeds > 1) {
    148         if (speed_en_mtx_reduced[MV2_SPEED_IDX_20G] &&
    149             speed_en_mtx_reduced[MV2_SPEED_IDX_25G]) {
    150             TDM_PRINT2("%s PIPE %d applying Restriction 15 \n",
    151                        "[ovsb_halfpipe_constraints]", param_pipe_id);
    152             for (pm_num = pm_num_lo; pm_num <= pm_num_hi; pm_num++) {
    153                 if (speed_en_mtx[pm_num][MV2_SPEED_IDX_25G]) {
    154                     param_pm_hpipe[pm_num] = 0;
    155                 } else if (speed_en_mtx[pm_num][MV2_SPEED_IDX_20G]) {
    156                     param_pm_hpipe[pm_num] = 1;
    157                 }
    158             }
    159         }
    160     }
    161     else {
    162         /* Do nothing; no constraints # of speeds is 0*/
    163     }
    164 
    165     return PASS;
    166 }
    167 
    168 
    169 /**
    170 @name: tdm_mv2_ovsb_pm_2_hpipe_mapping
    171 @param:
    172      0: half pipe 0 
    173      1: half pipe 0 
    174     -1: invalid
    175 Return halfpipe number of the given port (STATIC MAPPING)
    176  */
    177 int
    178 tdm_mv2_ovsb_pm_2_hpipe_mapping(int pipe_id, int port)
    179 {
    180     int hpipe_num = -1, port_lo, port_hi;
    181 
    182     /*  Static PM_2_HalfPipe mapping for MV2
    183      *      Pipe 0 -- halfpipe 0:  1 - 40
    184      *      Pipe 0 -- halfpipe 1: 41 - 80
    185      */
    186     if (pipe_id < MV2_NUM_PIPE) {
    187         port_lo = pipe_id * MV2_NUM_PHY_PORTS_PER_PIPE + 1;
    188         port_hi = (pipe_id + 1) * MV2_NUM_PHY_PORTS_PER_PIPE;
    189         if (port >= port_lo && port <= port_hi) {
    190             hpipe_num = ((port - 1) % MV2_NUM_PHY_PORTS_PER_PIPE) /
    191                         MV2_NUM_PHY_PORTS_PER_HPIPE;
    192         }
    193     }
    194     if (hpipe_num != 0 && hpipe_num != 1) {
    195         TDM_ERROR3("Invalid hpipe_num %0d for port %d in pipe %d\n",
    196                     hpipe_num, port, pipe_id);
    197     }
    198     return hpipe_num;
    199 }
    200 
    201 
    202 /**
    203 @name: tdm_mv2_ovsb_part_halfpipe
    204 @param:
    205 
    206 Partition OVSB PMs into 2 halfpipes
    207  */
    208 int
    209 tdm_mv2_ovsb_part_halfpipe(tdm_mod_t *_tdm)
    210 {
    211     int pms_per_pipe, pipe_id, tmp;
    212     int pm_speed[MV2_NUM_PMS_PER_PIPE];
    213     int pm_num_subports[MV2_NUM_PMS_PER_PIPE];
    214     int pm_num_sort[MV2_NUM_PMS_PER_PIPE];
    215     int pm_num, ln_num, pm_indx, i, j;
    216     int phy_base_port, phy_port;
    217     int hp0_speed, hp1_speed;
    218     int no_pms_hp0, no_pms_hp1;
    219     int *param_pm_hpipe;
    220     enum port_speed_e *param_speeds;
    221 
    222     param_pm_hpipe = _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe;
    223     param_speeds   = _tdm->_chip_data.soc_pkg.speed;
    224 
    225     pipe_id      = _tdm->_core_data.vars_pkg.cal_id;
    226     pms_per_pipe = _tdm->_chip_data.soc_pkg.pm_num_phy_modules/MV2_NUM_PIPE;
    227 
    228     for (pm_indx = 0; pm_indx < MV2_NUM_PMS_PER_PIPE; pm_indx++) {
    229         pm_speed[pm_indx] = 0;
    230         pm_num_subports[pm_indx] = 0;
    231         pm_num_sort[pm_indx] = 0;
    232     }
    233     TDM_PRINT2("tdm_mv2_avs_part_halfpipe1() pipe_id=%d pms_per_pipe=%d \n",pipe_id, pms_per_pipe);
    234 
    235     /* Calculate PM speeds for all PMs in the current pipe */
    236     pm_indx=0;
    237     for (pm_num=pipe_id*pms_per_pipe; pm_num<(pipe_id+1)*pms_per_pipe; pm_num++) {
    238         phy_base_port = MV2_NUM_PM_LNS*pm_num+1;
    239         for (ln_num=0; ln_num<_tdm->_chip_data.soc_pkg.pmap_num_lanes; ln_num++) {
    240             phy_port = phy_base_port+ln_num;
    241             if (tdm_mv2_cmn_chk_port_is_os(phy_port, _tdm) == BOOL_TRUE) {
    242                 TDM_PRINT5("%s pm_num=%2d ln_num=%0d port=%3d speed=%0dG\n",
    243                            "[ovsb_part_pm]",
    244                            pm_num, ln_num, phy_port,
    245                            param_speeds[phy_port]/1000);
    246                 pm_speed[pm_indx] = pm_speed[pm_indx] + param_speeds[phy_port]/1000;
    247                 pm_num_subports[pm_indx]++;
    248             }
    249         }
    250         pm_num_sort[pm_indx] = pm_num;
    251         pm_indx = (pm_indx + 1) % MV2_NUM_PMS_PER_PIPE;
    252     }
    253     /* print PM speed info and lanes info */
    254     for (pm_indx = 0; pm_indx < MV2_NUM_PMS_PER_PIPE; pm_indx++) {
    255         TDM_PRINT5("%s pm_indx=%2d pm_num=%2d pm_speed=%3dG pm_lanes=%d\n",
    256                    "[ovsb_part_pm]",
    257                    pm_indx, pm_num_sort[pm_indx], pm_speed[pm_indx],
    258                    pm_num_subports[pm_indx]);
    259     }
    260 
    261     /* Sort speeds of the PMs in descending order - bubble sort*/
    262     for (i=0; i<pms_per_pipe-1; i++) {
    263         for (j=pms_per_pipe-1; j>i; j--) {
    264             /* swap j with j-1*/
    265             if ((pm_speed[j] > pm_speed[j-1]) ||
    266                 ((pm_speed[j] == pm_speed[j-1]) &&
    267                  (pm_num_subports[j] > pm_num_subports[j-1]))) {
    268                 tmp = pm_num_sort[j];
    269                 pm_num_sort[j] = pm_num_sort[j-1];
    270                 pm_num_sort[j-1] = tmp;
    271                 tmp = pm_speed[j];
    272                 pm_speed[j] = pm_speed[j-1];
    273                 pm_speed[j-1] = tmp;
    274                 tmp = pm_num_subports[j];
    275                 pm_num_subports[j] = pm_num_subports[j-1];
    276                 pm_num_subports[j-1] = tmp;			
    277             }
    278         }
    279     }
    280 
    281     hp0_speed=0;
    282     hp1_speed=0;
    283     no_pms_hp0=0;
    284     no_pms_hp1=0;
    285     /* Compute HP 0 & 1 BW based on already allocated PMs in constraints*/
    286     for (i=0; i<pms_per_pipe; i++) {
    287         pm_num = pm_num_sort[i];
    288         if (param_pm_hpipe[pm_num] == 0) {
    289             hp0_speed += pm_speed[i];
    290             no_pms_hp0++;
    291         }
    292         if (param_pm_hpipe[pm_num] == 1) {
    293             hp1_speed += pm_speed[i];
    294             no_pms_hp1++;
    295         }
    296     }
    297 
    298     /* Do partition of the PMs into two half pipes */
    299     for (i=0; i<pms_per_pipe; i++) {
    300         pm_num = pm_num_sort[i];
    301         if (param_pm_hpipe[pm_num] == 2) { /* is OVSB unallocated PM */
    302             if (((no_pms_hp1 < (pms_per_pipe/2)) && (hp0_speed > hp1_speed)) ||
    303                 (no_pms_hp0 >= (pms_per_pipe/2)) ) {
    304                 hp1_speed = hp1_speed + pm_speed[i];
    305                 param_pm_hpipe[pm_num] = 1;
    306                 no_pms_hp1++;
    307             } else {
    308                 hp0_speed = hp0_speed + pm_speed[i];
    309                 param_pm_hpipe[pm_num] = 0;
    310                 no_pms_hp0++;
    311             }
    312         }
    313     }
    314     TDM_PRINT2("[ovsb_part_pm] hp0_bw=%d hp1_bw=%d\n",
    315                hp0_speed, hp1_speed);
    316     return PASS;
    317 }
    318 
    319 
    320 /**
    321 @name: tdm_mv2_ovsb_fill_group
    322 @param:
    323 
    324 Partition OVSB PMs into 2 halfpipes
    325  */
    326 int
    327 tdm_mv2_ovsb_fill_group(tdm_mod_t *_tdm)
    328 {
    329     int pms_per_pipe, pipe_id, tmp;
    330     int pm_num_subports[MV2_NUM_PMS_PER_PIPE];
    331     int pm_num_sort[MV2_NUM_PMS_PER_PIPE];
    332     int pm_num, ln_num, pm_indx, i, j;
    333 
    334     int pms_with_grp_speed;
    335     int grp_speed;
    336     int half_pipe_num;
    337     int speed_max_num_ports_per_pm;
    338     int min_num_ovs_groups;
    339     tdm_calendar_t *cal;
    340     int start_ovs_group;
    341     
    342     int start_group;
    343     int grp_index[MV2_OS_VBS_GRP_NUM];
    344     int phy_base_port;
    345     int phy_port;
    346     
    347     int t_ovs_grp_num;
    348     
    349     pipe_id       = _tdm->_core_data.vars_pkg.cal_id;
    350     half_pipe_num = _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num;
    351     grp_speed     = _tdm->_chip_data.soc_pkg.soc_vars.mv2.grp_speed;
    352     pms_per_pipe  = _tdm->_chip_data.soc_pkg.pm_num_phy_modules/MV2_NUM_PIPE;
    353 
    354     for (pm_indx = 0; pm_indx < MV2_NUM_PMS_PER_PIPE; pm_indx++) {
    355         pm_num_subports[pm_indx] = 0;
    356         pm_num_sort[pm_indx] = 0;
    357     }
    358 
    359     /* Count the number of subports per PM with grp_speed for PMs that belongs to this half pipe*/
    360     pm_indx=0;
    361     pms_with_grp_speed = 0;
    362     for (pm_num=pipe_id*pms_per_pipe; pm_num<(pipe_id+1)*pms_per_pipe; pm_num++) {
    363         phy_base_port = MV2_NUM_PM_LNS*pm_num+1;
    364         if (_tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe[pm_num] == half_pipe_num){
    365             for (ln_num=0; ln_num<_tdm->_chip_data.soc_pkg.pmap_num_lanes; ln_num++) {
    366                 phy_port = phy_base_port+ln_num;
    367                 if(_tdm->_chip_data.soc_pkg.speed[phy_port] == grp_speed) {
    368                     pm_num_subports[pm_indx]++;
    369                 }
    370             }
    371             if (pm_num_subports[pm_indx] > 0) {pms_with_grp_speed++;}
    372         }
    373         pm_num_sort[pm_indx] = pm_num;
    374         pm_indx = (pm_indx + 1) % MV2_NUM_PMS_PER_PIPE;
    375     }
    376 
    377     /* Compute  the minimum number of oversub groups required for the group speed*/
    378     switch (grp_speed) {
    379         case SPEED_10G:	 speed_max_num_ports_per_pm=4; break;
    380         case SPEED_20G:	 speed_max_num_ports_per_pm=2; break;
    381         case SPEED_40G:	 speed_max_num_ports_per_pm=2; break;
    382         case SPEED_25G:	 speed_max_num_ports_per_pm=4; break;
    383         case SPEED_50G:	 speed_max_num_ports_per_pm=2; break;
    384         case SPEED_100G: speed_max_num_ports_per_pm=1; break;
    385         default:													
    386             TDM_PRINT1("[speed group partition] Invalid group speed %0d\n",
    387                        grp_speed);
    388             return FAIL;							
    389     }
    390     /* ceil [(speed_max_num_ports_per_pm*pms_with_grp_speed) / MV2_OS_VBS_GRP_LEN ]*/
    391     min_num_ovs_groups = ((speed_max_num_ports_per_pm*pms_with_grp_speed) + MV2_OS_VBS_GRP_LEN-1) / MV2_OS_VBS_GRP_LEN;
    392 
    393     /* Execute only if ports with this speed exist*/
    394     if (min_num_ovs_groups > 0) {
    395         /* Sort PMs in descending order of their number of subports with grp_speed*/
    396         for (i=0; i<pms_per_pipe-1; i++) {
    397             for (j=pms_per_pipe-1; j>i; j--) {
    398                 /* swap j with j-1*/
    399                 if ( pm_num_subports[j] > pm_num_subports[j-1]) {
    400                     tmp = pm_num_sort[j];
    401                     pm_num_sort[j] = pm_num_sort[j-1];
    402                     pm_num_sort[j-1] = tmp;
    403                     tmp = pm_num_subports[j];
    404                     pm_num_subports[j] = pm_num_subports[j-1];
    405                     pm_num_subports[j-1] = tmp;			
    406                 }
    407             }
    408         }
    409 
    410         /* Find the first empty ovs group*/
    411         switch (_tdm->_core_data.vars_pkg.cal_id) {
    412             case 0:	cal=(&(_tdm->_chip_data.cal_0)); break;
    413             case 1:	cal=(&(_tdm->_chip_data.cal_1)); break;
    414             case 2:	cal=(&(_tdm->_chip_data.cal_2)); break;
    415             case 3:	cal=(&(_tdm->_chip_data.cal_3)); break;
    416             case 4:	cal=(&(_tdm->_chip_data.cal_4)); break;
    417             case 5:	cal=(&(_tdm->_chip_data.cal_5)); break;
    418             case 6:	cal=(&(_tdm->_chip_data.cal_6)); break;
    419             case 7:	cal=(&(_tdm->_chip_data.cal_7)); break;
    420             default:
    421                 TDM_PRINT1("[speed group partition] Invalid calendar ID - %0d\n",
    422                             _tdm->_core_data.vars_pkg.cal_id);
    423                 return FAIL;
    424         }
    425         start_ovs_group = half_pipe_num*(MV2_OS_VBS_GRP_NUM/2);
    426         start_group = start_ovs_group;
    427         for (i=start_group; i< (start_group+(MV2_OS_VBS_GRP_NUM/2)); i++) {
    428             if (cal->cal_grp[i][0] != MV2_NUM_EXT_PORTS) {
    429                 start_ovs_group++;
    430             } else {
    431                 break;
    432             }
    433         }
    434         
    435         /* Fill ovs groups with ports having grp_speed*/
    436         for (i=0; i< MV2_OS_VBS_GRP_NUM; i++) { grp_index[i] = 0;}
    437         for (i=0; i<pms_with_grp_speed; i++) {
    438             pm_num = pm_num_sort[i];
    439             phy_base_port = MV2_NUM_PM_LNS*pm_num+1;
    440             if (_tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe[pm_num] == half_pipe_num){
    441                 for (ln_num=0; ln_num<_tdm->_chip_data.soc_pkg.pmap_num_lanes; ln_num++) {
    442                     phy_port = phy_base_port+ln_num;
    443                     if(_tdm->_chip_data.soc_pkg.speed[phy_port] == grp_speed) {
    444                         t_ovs_grp_num = start_ovs_group + (i % min_num_ovs_groups);
    445                         cal->cal_grp[t_ovs_grp_num][grp_index[t_ovs_grp_num]] = phy_port;
    446                         grp_index[t_ovs_grp_num]++;
    447                     }
    448                 }
    449             }
    450         }
    451     }
    452 
    453     return PASS;
    454 }
    455 
    456 
    457 /**
    458 @name: tdm_mv2_ovsb_pkt_shaper_per_pm
    459 @param:
    460 
    461 Populates Pkt shaper calendar - per PM
    462  */
    463 int
    464 tdm_mv2_ovsb_pkt_shaper_per_pm(tdm_mod_t *_tdm, int shift_step)
    465 {
    466     int pms_per_pipe, pms_per_hpipe, pms_per_hpipe_max;
    467     int pm_num, i, pm_done;
    468     int port_phy;
    469     int half_pipe_num;
    470 
    471     int pkt_shpr_pm_indx;
    472     int pm_slot_tbl[MV2_NUM_PKT_SLOTS_PER_PM];
    473     int *pkt_shed_cal;
    474     int pkt_sched_repetitions;
    475 
    476     int pm_port_lo, block_num, lane_offset, pm_offset, block_offset;
    477     int lane, cal_pos, tbl_offset;
    478     enum port_speed_e *param_speeds;
    479     param_speeds   = _tdm->_chip_data.soc_pkg.speed;
    480 
    481     port_phy = _tdm->_core_data.vars_pkg.port;
    482     pm_num = (port_phy-1)/MV2_NUM_PM_LNS;
    483     half_pipe_num = _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe[pm_num];
    484 
    485     pms_per_pipe  = _tdm->_chip_data.soc_pkg.pm_num_phy_modules/MV2_NUM_PIPE;
    486     pms_per_hpipe = pms_per_pipe / 2;
    487     pms_per_hpipe_max = MV2_SHAPING_GRP_LEN / MV2_NUM_PKT_SLOTS_PER_PM;
    488     /* constraint: max PMs for pkt_scheduler, x*20 <= 160 */
    489     if (pms_per_hpipe > pms_per_hpipe_max) {
    490         pms_per_hpipe = pms_per_hpipe_max;
    491     }
    492 
    493     /* number of slots per port: 5 = 200/10/4 (MV2) */
    494     pkt_sched_repetitions = MV2_SHAPING_GRP_LEN/pms_per_hpipe/MV2_NUM_PM_LNS;
    495 
    496     for (i=0; i<MV2_NUM_PKT_SLOTS_PER_PM; i++) {
    497         pm_slot_tbl[i] = MV2_NUM_EXT_PORTS;
    498     }
    499 
    500     /* Determine the pm_indx in pkt shceduler calendar - 0 to 7*/
    501     pkt_shpr_pm_indx = tdm_mv2_ovsb_pkt_shaper_find_pm_indx(_tdm);
    502 
    503     /* allocate slots for PM */
    504     pm_done = BOOL_TRUE;
    505     pm_port_lo = MV2_NUM_PM_LNS * pm_num + 1;
    506     switch (param_speeds[port_phy]) {
    507         case SPEED_10G:
    508             /* 10G SINGLE */
    509             if ((param_speeds[pm_port_lo + 1] == SPEED_0) &&
    510                 (param_speeds[pm_port_lo + 2] == SPEED_0) &&
    511                 (param_speeds[pm_port_lo + 3] == SPEED_0)) {
    512                 tbl_offset = 0;
    513                 pm_slot_tbl[(tbl_offset + 0) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    514                 pm_slot_tbl[(tbl_offset + 8) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    515             }
    516             /* 10G QUAD */
    517             else if ((param_speeds[pm_port_lo + 1] == SPEED_10G) &&
    518                      (param_speeds[pm_port_lo + 2] == SPEED_10G) &&
    519                      (param_speeds[pm_port_lo + 3] == SPEED_10G)) {
    520                 tbl_offset = (shift_step % 5) * 4;
    521                 /* tbl_offset = 0; */
    522                 pm_slot_tbl[(tbl_offset + 0 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    523                 pm_slot_tbl[(tbl_offset + 8 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    524                 pm_slot_tbl[(tbl_offset + 10) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 1;
    525                 pm_slot_tbl[(tbl_offset + 18) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 1;
    526                 pm_slot_tbl[(tbl_offset + 5 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    527                 pm_slot_tbl[(tbl_offset + 13) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    528                 pm_slot_tbl[(tbl_offset + 3 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 3;
    529                 pm_slot_tbl[(tbl_offset + 15) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 3;
    530             }
    531             else {
    532                 pm_done = BOOL_FALSE;
    533             }
    534             break;
    535         case SPEED_20G:
    536             /* 20G SINGLE */
    537             if ((param_speeds[pm_port_lo + 1] == SPEED_0) &&
    538                 (param_speeds[pm_port_lo + 2] == SPEED_0) &&
    539                 (param_speeds[pm_port_lo + 3] == SPEED_0)) {
    540                 tbl_offset = 0;
    541                 pm_slot_tbl[(tbl_offset + 0 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    542                 pm_slot_tbl[(tbl_offset + 4 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    543                 pm_slot_tbl[(tbl_offset + 10) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    544                 pm_slot_tbl[(tbl_offset + 14) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    545             }
    546             /* 20G DUAL */
    547             else if ((param_speeds[pm_port_lo + 1] == SPEED_0) &&
    548                      (param_speeds[pm_port_lo + 2] == SPEED_20G) &&
    549                      (param_speeds[pm_port_lo + 3] == SPEED_0)) {
    550                 pm_slot_tbl[(0 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    551                 pm_slot_tbl[(4 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    552                 pm_slot_tbl[(10) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    553                 pm_slot_tbl[(14) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    554                 pm_slot_tbl[(1 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    555                 pm_slot_tbl[(5 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    556                 pm_slot_tbl[(11) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    557                 pm_slot_tbl[(15) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    558             }
    559             else {
    560                 pm_done = BOOL_FALSE;
    561             }
    562             break;
    563         case SPEED_40G:
    564             /* 40G SINGLE: 40G_0_0_0 */
    565             if (param_speeds[pm_port_lo]     == SPEED_40G &&
    566                 param_speeds[pm_port_lo + 1] == SPEED_0   &&
    567                 param_speeds[pm_port_lo + 2] == SPEED_0   &&
    568                 param_speeds[pm_port_lo + 3] == SPEED_0) {
    569                 tbl_offset = 0;
    570                 pm_slot_tbl[(tbl_offset + 0 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    571                 pm_slot_tbl[(tbl_offset + 2 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    572                 pm_slot_tbl[(tbl_offset + 4)  % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    573                 pm_slot_tbl[(tbl_offset + 6)  % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    574                 pm_slot_tbl[(tbl_offset + 10) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    575                 pm_slot_tbl[(tbl_offset + 12) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    576                 pm_slot_tbl[(tbl_offset + 14) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    577                 pm_slot_tbl[(tbl_offset + 16) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    578             }
    579             /* 40G SINGLE: 0_0_40G_0 */
    580             else if (param_speeds[pm_port_lo]     == SPEED_0   &&
    581                      param_speeds[pm_port_lo + 1] == SPEED_0   &&
    582                      param_speeds[pm_port_lo + 2] == SPEED_40G &&
    583                      param_speeds[pm_port_lo + 3] == SPEED_0) {
    584                 tbl_offset = 0;
    585                 pm_slot_tbl[(tbl_offset + 1 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    586                 pm_slot_tbl[(tbl_offset + 3 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    587                 pm_slot_tbl[(tbl_offset + 5 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    588                 pm_slot_tbl[(tbl_offset + 7 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    589                 pm_slot_tbl[(tbl_offset + 11) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    590                 pm_slot_tbl[(tbl_offset + 13) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    591                 pm_slot_tbl[(tbl_offset + 15) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    592                 pm_slot_tbl[(tbl_offset + 17) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    593             }
    594             /* 40G DUAL */
    595             else if (param_speeds[pm_port_lo]     == SPEED_40G &&
    596                      param_speeds[pm_port_lo + 1] == SPEED_0   &&
    597                      param_speeds[pm_port_lo + 2] == SPEED_40G &&
    598                      param_speeds[pm_port_lo + 3] == SPEED_0) {
    599                 tbl_offset = 0;
    600                 pm_slot_tbl[(tbl_offset + 0 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    601                 pm_slot_tbl[(tbl_offset + 2 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    602                 pm_slot_tbl[(tbl_offset + 4) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    603                 pm_slot_tbl[(tbl_offset + 6) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    604                 pm_slot_tbl[(tbl_offset + 10) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    605                 pm_slot_tbl[(tbl_offset + 12) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    606                 pm_slot_tbl[(tbl_offset + 14) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    607                 pm_slot_tbl[(tbl_offset + 16) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    608                 pm_slot_tbl[(tbl_offset + 1 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    609                 pm_slot_tbl[(tbl_offset + 3 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    610                 pm_slot_tbl[(tbl_offset + 5 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    611                 pm_slot_tbl[(tbl_offset + 7 ) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    612                 pm_slot_tbl[(tbl_offset + 11) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    613                 pm_slot_tbl[(tbl_offset + 13) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    614                 pm_slot_tbl[(tbl_offset + 15) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    615                 pm_slot_tbl[(tbl_offset + 17) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    616             }
    617             else {
    618                 pm_done = BOOL_FALSE;
    619             }
    620             break;
    621         case SPEED_25G:
    622             /* 25G QUAD: 25G_25G_25G_25G */
    623             if ((param_speeds[pm_port_lo + 1] == SPEED_25G) &&
    624                 (param_speeds[pm_port_lo + 2] == SPEED_25G) &&
    625                 (param_speeds[pm_port_lo + 3] == SPEED_25G)) {
    626                 for (i = 0; i < pkt_sched_repetitions; i++) {
    627                     pm_slot_tbl[(i * 4 + 0) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    628                     pm_slot_tbl[(i * 4 + 2) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 1;
    629                     pm_slot_tbl[(i * 4 + 1) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    630                     pm_slot_tbl[(i * 4 + 3) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 3;
    631                 }
    632             }
    633             /* 25G DUAL: 25G_0_25G_0 */
    634             else if ((param_speeds[pm_port_lo + 1] == SPEED_0) &&
    635                      (param_speeds[pm_port_lo + 2] == SPEED_25G) &&
    636                      (param_speeds[pm_port_lo + 3] == SPEED_0)) {
    637                 for (i = 0; i < pkt_sched_repetitions; i++) {
    638                     pm_slot_tbl[(i * 4 + 0) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    639                     pm_slot_tbl[(i * 4 + 1) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    640                 }
    641             }
    642             /* 25G SINGLE: 25G_0_0_0 */
    643             else if ((param_speeds[pm_port_lo + 1] == SPEED_0) &&
    644                      (param_speeds[pm_port_lo + 2] == SPEED_0) &&
    645                      (param_speeds[pm_port_lo + 3] == SPEED_0)) {
    646                 for (i = 0; i < pkt_sched_repetitions; i++) {
    647                     pm_slot_tbl[(i * 4 + 0) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    648                     pm_slot_tbl[(i * 4 + 1) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    649                 }
    650             }
    651             /* 25G others: 25G_25G_0_0 */
    652             else if ((param_speeds[pm_port_lo + 1] == SPEED_25G) &&
    653                      (param_speeds[pm_port_lo + 2] == SPEED_0) &&
    654                      (param_speeds[pm_port_lo + 3] == SPEED_0)) {
    655                 for (i = 0; i < pkt_sched_repetitions; i++) {
    656                     pm_slot_tbl[(i * 4 + 0) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    657                     pm_slot_tbl[(i * 4 + 2) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 1;
    658                 }
    659             }
    660             else {
    661                 pm_done = BOOL_FALSE;
    662             }
    663             break;
    664         case SPEED_50G:
    665             /* 50G SINGLE */
    666             if ((param_speeds[pm_port_lo + 1] == SPEED_0) &&
    667                 (param_speeds[pm_port_lo + 2] == SPEED_0) &&
    668                 (param_speeds[pm_port_lo + 3] == SPEED_0)) {
    669                 tbl_offset = 0;
    670                 for (i = 0; i < 10; i++) {
    671                     pm_slot_tbl[(tbl_offset + i*2) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    672                 }
    673             }
    674             /* 50G DUAL */
    675             else if ((param_speeds[pm_port_lo + 1] == SPEED_0) &&
    676                      (param_speeds[pm_port_lo + 2] == SPEED_50G) &&
    677                      (param_speeds[pm_port_lo + 3] == SPEED_0)) {
    678                 for (i = 0; i < 10; i++) {
    679                     pm_slot_tbl[(i * 2)     % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo;
    680                     pm_slot_tbl[(i * 2 + 1) % MV2_NUM_PKT_SLOTS_PER_PM] = pm_port_lo + 2;
    681                 }
    682             }
    683             else {
    684                 pm_done = BOOL_FALSE;
    685             }
    686             break;
    687         case SPEED_100G:
    688             /* 100G SINGLE */
    689             for (i = 0; i < MV2_NUM_PKT_SLOTS_PER_PM; i++) {
    690                 pm_slot_tbl[i] = pm_port_lo;
    691             }
    692             break;
    693         default:
    694             pm_done = BOOL_FALSE;
    695             break;							
    696     }
    697     if (pm_done == BOOL_FALSE) {
    698         TDM_ERROR1("[pkt_shaper_per_pm] Invalid PM config, PM %0d\n", pm_num);
    699     }
    700 
    701     /* Get the right pkt scheduler calendar*/
    702     switch (_tdm->_core_data.vars_pkg.cal_id) {
    703         case 0:	pkt_shed_cal = _tdm->_chip_data.cal_0.cal_grp[MV2_SHAPING_GRP_IDX_0+half_pipe_num]; break;
    704         case 1:	pkt_shed_cal = _tdm->_chip_data.cal_1.cal_grp[MV2_SHAPING_GRP_IDX_0+half_pipe_num]; break;
    705         case 2:	pkt_shed_cal = _tdm->_chip_data.cal_2.cal_grp[MV2_SHAPING_GRP_IDX_0+half_pipe_num]; break;
    706         case 3:	pkt_shed_cal = _tdm->_chip_data.cal_3.cal_grp[MV2_SHAPING_GRP_IDX_0+half_pipe_num]; break;
    707         default:
    708             TDM_PRINT1("[pkt_shaper_per_pm] Invalid calendar ID - %0d\n",_tdm->_core_data.vars_pkg.cal_id);
    709             return FAIL;
    710             break;
    711     }
    712 
    713     /* Populate pkt scheduler calendar */
    714     pm_offset = pkt_shpr_pm_indx;
    715     for (i=0; i<MV2_NUM_PKT_SLOTS_PER_PM; i++) {
    716         if (pm_slot_tbl[i] != MV2_NUM_EXT_PORTS) {
    717             lane = i % MV2_NUM_PM_LNS;
    718             switch (lane) {
    719                 case 0:  lane_offset = 0;                       break; /* subport 0 */
    720                 case 1:  lane_offset = 1*MV2_NUM_PMS_PER_HPIPE; break; /* subport 2 */
    721                 case 2:  lane_offset = 2*MV2_NUM_PMS_PER_HPIPE; break; /* subport 1 */
    722                 default: lane_offset = 3*MV2_NUM_PMS_PER_HPIPE; break; /* subport 3 */
    723             }
    724             block_num = (i / MV2_NUM_PM_LNS) % pkt_sched_repetitions;
    725             /* block_offset = block_num * 40; */
    726             block_offset = block_num * MV2_NUM_PHY_PORTS_PER_HPIPE;
    727             cal_pos = (block_offset + lane_offset + pm_offset) % MV2_SHAPING_GRP_LEN;
    728             pkt_shed_cal[cal_pos] = pm_slot_tbl[i];
    729         }
    730     }
    731 
    732     return (PASS);
    733 }
    734 
    735 
    736 /**
    737 @name: tdm_mv2_ovsb_chk_same_spd_port
    738 @param:
    739 
    740 Return BOOL_TRUE if two input ports have the same speed,
    741 otherwise, return BOOL_FALSE.
    742  */
    743 int
    744 tdm_mv2_ovsb_chk_same_spd_port(tdm_mod_t *_tdm, int port1, int port2)
    745 {
    746     int param_phy_lo, param_phy_hi;
    747     enum port_speed_e *param_speeds;
    748 
    749     param_phy_lo = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo;
    750     param_phy_hi = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi;
    751     param_speeds = _tdm->_chip_data.soc_pkg.speed;
    752     if (port1 >= param_phy_lo && port1 <= param_phy_hi &&
    753         port2 >= param_phy_lo && port2 <= param_phy_hi) {
    754         if (param_speeds[port1] == param_speeds[port2]) {
    755             return BOOL_TRUE;
    756         }
    757     }
    758     return BOOL_FALSE;
    759 }
    760 
    761 
    762 /**
    763 @name: tdm_mv2_ovsb_pkt_shaper
    764 @param:
    765 
    766 Populates Pkt shaper calendar
    767  */
    768 int
    769 tdm_mv2_ovsb_pkt_shaper(tdm_mod_t *_tdm)
    770 {
    771     int pms_per_pipe, pipe_id;
    772     int pm_num, ln_num;
    773     int pm_s, pm_e;
    774     int port_phy, port_phy_base;
    775     int shift_step;
    776     int param_pm_lanes;
    777 
    778     param_pm_lanes = _tdm->_chip_data.soc_pkg.pmap_num_lanes;
    779 
    780     pipe_id      = _tdm->_core_data.vars_pkg.cal_id;
    781     pms_per_pipe = _tdm->_chip_data.soc_pkg.pm_num_phy_modules/MV2_NUM_PIPE;
    782 
    783     pm_s = pipe_id*pms_per_pipe;
    784     pm_e = (pipe_id+1)*pms_per_pipe;
    785 
    786     for (pm_num=pm_s; pm_num<pm_e; pm_num++) {
    787         port_phy_base = param_pm_lanes * pm_num + 1;
    788         shift_step = 0;
    789         for (ln_num=0; ln_num<param_pm_lanes; ln_num++) {
    790             port_phy = port_phy_base + ln_num;
    791             if (tdm_mv2_cmn_chk_port_is_os(port_phy, _tdm) == BOOL_TRUE) {
    792                 _tdm->_core_data.vars_pkg.port = port_phy;
    793                 tdm_mv2_ovsb_pkt_shaper_per_pm(_tdm, shift_step);
    794                 break;
    795             }
    796         }
    797     }
    798 
    799     return (PASS);
    800 }
    801 
    802 
    803 /**
    804 @name: tdm_mv2_ovsb_pkt_shaper_find_pm_indx
    805 @param:
    806 
    807 Find an existing or available pm_indx in pkt_shaper
    808  */
    809 int
    810 tdm_mv2_ovsb_pkt_shaper_find_pm_indx(tdm_mod_t *_tdm)
    811 {
    812     int pm_num, half_pipe_num;
    813     int i, j, pm_num_t;
    814     int phy_port;
    815     int *pkt_shed_cal;
    816     int pkt_shpr_pm_indx, pms_per_pipe, pms_per_hpipe, pms_per_hpipe_max;
    817     int pm_indx_avail[MV2_NUM_PMS_PER_HPIPE];
    818     int max_start_indx;
    819     int distance;
    820     int max_distance;
    821 
    822     phy_port = _tdm->_core_data.vars_pkg.port;
    823     pm_num = _tdm->_core_exec[TDM_CORE_EXEC__PM_SCAN](_tdm);
    824     half_pipe_num = _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe[pm_num];
    825     pms_per_pipe  = _tdm->_chip_data.soc_pkg.pm_num_phy_modules/MV2_NUM_PIPE;
    826     pms_per_hpipe = pms_per_pipe / 2;
    827     pms_per_hpipe_max = MV2_SHAPING_GRP_LEN / MV2_NUM_PKT_SLOTS_PER_PM;
    828     if (pms_per_hpipe > pms_per_hpipe_max) {
    829         pms_per_hpipe = pms_per_hpipe_max;
    830     }
    831 
    832     /* Get the right pkt scheduler calendar*/
    833     switch (_tdm->_core_data.vars_pkg.cal_id) {
    834         case 0:	pkt_shed_cal = _tdm->_chip_data.cal_0.cal_grp[MV2_SHAPING_GRP_IDX_0+half_pipe_num]; break;
    835         case 1:	pkt_shed_cal = _tdm->_chip_data.cal_1.cal_grp[MV2_SHAPING_GRP_IDX_0+half_pipe_num]; break;
    836         case 2:	pkt_shed_cal = _tdm->_chip_data.cal_2.cal_grp[MV2_SHAPING_GRP_IDX_0+half_pipe_num]; break;
    837         case 3:	pkt_shed_cal = _tdm->_chip_data.cal_3.cal_grp[MV2_SHAPING_GRP_IDX_0+half_pipe_num]; break;
    838         default:
    839             TDM_PRINT1("Invalid calendar ID - %0d\n",_tdm->_core_data.vars_pkg.cal_id);
    840             return FAIL;
    841     }
    842 
    843     /* Two cases possible: 
    844     1. there are sister ports of this port already in the pkt scheduler; 
    845        which means find that PM and place phy_port in the corresponding lanes
    846     2. there is no sister port of this port already in the pkt scheduler; 
    847        which means find an empty PM and place phy_port in the corresponding lanes*/
    848 
    849     pkt_shpr_pm_indx = -1;
    850     for (i=0; i<MV2_SHAPING_GRP_LEN; i++) {
    851         if (pkt_shed_cal[i] != _tdm->_chip_data.soc_pkg.num_ext_ports) {
    852             _tdm->_core_data.vars_pkg.port = pkt_shed_cal[i];
    853             pm_num_t = _tdm->_core_exec[TDM_CORE_EXEC__PM_SCAN](_tdm);
    854             if (pm_num == pm_num_t) { /* Found that PM is already placed */
    855                 pkt_shpr_pm_indx = (i% pms_per_hpipe);
    856                 break;
    857             }
    858         }
    859     }
    860 
    861     /* Case 2: there is no sister port of this port already in the pkt scheduler; 
    862        which means find an empty PM and place phy_port in the corresponding lanes 
    863        Find an available PM */
    864     if (pkt_shpr_pm_indx == -1) {
    865         for (i=0; i<pms_per_hpipe && i<MV2_NUM_PMS_PER_HPIPE; i++){
    866             pm_indx_avail[i]=1;
    867             for (j=0; j<(MV2_SHAPING_GRP_LEN/pms_per_hpipe); j++){
    868                 if (pkt_shed_cal[j*pms_per_hpipe+i] != _tdm->_chip_data.soc_pkg.num_ext_ports) {
    869                     pm_indx_avail[i]=0;
    870                     break;
    871                 }
    872             }
    873         }
    874 
    875         /* Find the biggest clump of 1's in pm_indx_avail array and choose the pm_indx in the middle of the clump*/
    876         max_start_indx = 0;
    877         distance=0;
    878         max_distance =  0;	    
    879         for (i=0; i<pms_per_hpipe && i<MV2_NUM_PMS_PER_HPIPE; i++){
    880             if (pm_indx_avail[i]==1) {
    881                 distance=0;
    882                 for (j=0; j<pms_per_hpipe; j++){
    883                     if (pm_indx_avail[(i+j)%pms_per_hpipe]==1) {
    884                         distance++;
    885                     } else {
    886                         break;
    887                     }
    888                 }
    889                 if (distance > max_distance) {
    890                     max_start_indx = i;
    891                     max_distance = distance;
    892                 }
    893             }
    894         }
    895         /* If all available make it 0, else middle of the clump*/
    896         pkt_shpr_pm_indx = (max_distance==pms_per_hpipe) ? 0 : ((max_start_indx + (max_distance/2)) % pms_per_hpipe);
    897         if (pkt_shpr_pm_indx < MV2_NUM_PMS_PER_HPIPE) {
    898             if (pm_indx_avail[pkt_shpr_pm_indx] == 0) {
    899                 pkt_shpr_pm_indx = -1;
    900                 TDM_ERROR3("%s Failed to find an available PM for pm_num=%0d phy_port=%0d\n",
    901                            "[pkt_shaper_find_pm_indx]",
    902                            pm_num, phy_port);
    903             }
    904         }
    905     }
    906 
    907     return pkt_shpr_pm_indx;
    908 }
    909 
    910 
    911 /**
    912 @name: tdm_mv2_ovsb_map_pm_num_to_pblk
    913 @param:
    914 
    915 Maps PM num (block_id) to OVSB pblk id
    916  */
    917 int
    918 tdm_mv2_ovsb_map_pm_num_to_pblk(tdm_mod_t *_tdm)
    919 {
    920     int pms_per_pipe, pipe_id;
    921     int pm_num;
    922     int half_pipe_num;
    923     int pblk_indx[2];
    924 
    925     pipe_id = _tdm->_core_data.vars_pkg.cal_id;
    926     pms_per_pipe  = _tdm->_chip_data.soc_pkg.pm_num_phy_modules/MV2_NUM_PIPE;
    927 
    928     pblk_indx[0]=0;	pblk_indx[1]=0;
    929     for (pm_num=pipe_id*pms_per_pipe; pm_num<(pipe_id+1)*pms_per_pipe; pm_num++) {
    930         _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_num_to_pblk[pm_num] = -1;
    931         half_pipe_num = _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe[pm_num];
    932         if ((half_pipe_num==0) || (half_pipe_num==1)){
    933             /* _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_num_to_pblk[pm_num] = pblk_indx[half_pipe_num]; */
    934             switch (pipe_id) {
    935                 case 0:
    936                     _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_num_to_pblk[pm_num] = pblk_indx[half_pipe_num];
    937                     break;
    938                 case 1:
    939                     /* _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_num_to_pblk[pm_num] = (7 - pblk_indx[half_pipe_num]); */
    940                     _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_num_to_pblk[pm_num] = (9 - pblk_indx[half_pipe_num]);
    941                     break;
    942                 default:
    943                     TDM_ERROR2("%s Invalid Calendar ID %d \n",
    944                               "[map_pm_num_to_pblk]", pipe_id);
    945             }
    946             pblk_indx[half_pipe_num]++;
    947         }
    948     }
    949     return PASS;
    950 }
    951 
    952 
    953 /**
    954 @name: tdm_mv2_ovsb_map_pms_to_hpipe_dynamic
    955 @param:
    956  */
    957 int
    958 tdm_mv2_ovsb_map_pms_to_hpipe_dynamic(tdm_mod_t *_tdm)
    959 {
    960     int param_pipe_id;
    961 
    962     param_pipe_id  = _tdm->_core_data.vars_pkg.cal_id;
    963     /* Pre-Partition PMs into 2 half pipes by applying constraints */
    964     TDM_PRINT1("Apply OVSB constraints on PIPE %d\n", param_pipe_id);
    965     tdm_mv2_ovsb_apply_constraints(_tdm);
    966 
    967     /* Partition all PMs into 2 half pipes */
    968     TDM_PRINT1("Partition PMs into 2 Half Pipes on PIPE %d\n", param_pipe_id);
    969     tdm_mv2_ovsb_part_halfpipe(_tdm);
    970 
    971     return PASS;
    972 }
    973 
    974 
    975 /**
    976 @name: tdm_mv2_ovsb_map_pms_to_hpipe_static
    977 @param:
    978 [pipe 0] 1 - 40: hpipe 0
    979 [pipe 0]41 - 80: hpipe 1
    980  */
    981 int
    982 tdm_mv2_ovsb_map_pms_to_hpipe_static(tdm_mod_t *_tdm)
    983 {
    984     int i, j;
    985     int pm_num_lo, pm_num_hi, port_phy,
    986         pms_per_pipe;
    987     int param_pipe_id, param_phy_lo, param_phy_hi,
    988         param_pm_lanes, param_pm_num;
    989     int *param_pm_hpipe;
    990 
    991     param_pipe_id = _tdm->_core_data.vars_pkg.cal_id;
    992     param_phy_lo  = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo;
    993     param_phy_hi  = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi;
    994     param_pm_lanes= _tdm->_chip_data.soc_pkg.pmap_num_lanes;
    995     param_pm_num  = _tdm->_chip_data.soc_pkg.pm_num_phy_modules;
    996     param_pm_hpipe= _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe;
    997 
    998     pms_per_pipe  = param_pm_num/MV2_NUM_PIPE;
    999     pm_num_lo     = param_pipe_id*pms_per_pipe;
   1000     pm_num_hi     = (param_pipe_id+1)*pms_per_pipe-1;
   1001     for (i=pm_num_lo; i<=pm_num_hi && i<param_pm_num; i++) {
   1002         param_pm_hpipe[i] = -1;
   1003         for (j=0; j<param_pm_lanes; j++) {
   1004             port_phy = i*param_pm_lanes+j+1;
   1005             if (port_phy>=param_phy_lo && port_phy<=param_phy_hi) {
   1006                 if ( (_tdm->_chip_data.soc_pkg.speed[port_phy] != SPEED_0) &&
   1007                      (_tdm->_chip_data.soc_pkg.state[port_phy-1] == PORT_STATE__OVERSUB ||
   1008                       _tdm->_chip_data.soc_pkg.state[port_phy-1] == PORT_STATE__OVERSUB_HG)) {
   1009                     param_pm_hpipe[i] = tdm_mv2_ovsb_pm_2_hpipe_mapping(
   1010                                             param_pipe_id, port_phy);
   1011                     break;
   1012                 }
   1013             }
   1014         }
   1015     }
   1016 
   1017     return PASS;
   1018 }
   1019 
   1020 
   1021 /**
   1022 @name: tdm_mv2_ovsb_map_pms_to_hpipe
   1023 @param:
   1024  */
   1025 int
   1026 tdm_mv2_ovsb_map_pms_to_hpipe(tdm_mod_t *_tdm)
   1027 {
   1028     /* static mapping */
   1029     if (TDM_MV2_HPIPE_STATIC_MAPPING_ENABLE == 1) {
   1030         return(tdm_mv2_ovsb_map_pms_to_hpipe_static(_tdm));
   1031     }
   1032     /* dynamic mapping */
   1033     else {
   1034         return(tdm_mv2_ovsb_map_pms_to_hpipe_dynamic(_tdm));
   1035     }
   1036 }
   1037 
   1038 
   1039 /**
   1040 @name: tdm_mv2_ovsb_gen_spd_grp
   1041 @param:
   1042 
   1043 Partition PMs into 2 half-pipes belonging to the same single pipe,
   1044 and generate oversub speed groups accordingly.
   1045  */
   1046 int
   1047 tdm_mv2_ovsb_gen_spd_grp(tdm_mod_t *_tdm)
   1048 {
   1049     int i, j, num_spd_types;
   1050     int param_phy_lo, param_phy_hi, param_cal_id;
   1051     int port_cnt_1g = 0, port_cnt_10g = 0, port_cnt_20g = 0,
   1052         port_cnt_25g = 0, port_cnt_40g = 0, port_cnt_50g = 0,
   1053         port_cnt_100g = 0, port_cnt_120g = 0;
   1054     tdm_calendar_t *cal;
   1055 
   1056     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
   1057     tdm_mv2_cmn_get_pipe_port_range(param_cal_id, &param_phy_lo,
   1058                                                   &param_phy_hi);
   1059 
   1060     switch (param_cal_id) {
   1061         case 0:	cal=(&(_tdm->_chip_data.cal_0)); break;
   1062         case 1:	cal=(&(_tdm->_chip_data.cal_1)); break;
   1063         case 2:	cal=(&(_tdm->_chip_data.cal_2)); break;
   1064         case 3:	cal=(&(_tdm->_chip_data.cal_3)); break;
   1065         case 4:	cal=(&(_tdm->_chip_data.cal_4)); break;
   1066         case 5:	cal=(&(_tdm->_chip_data.cal_5)); break;
   1067         case 6:	cal=(&(_tdm->_chip_data.cal_6)); break;
   1068         case 7:	cal=(&(_tdm->_chip_data.cal_7)); break;
   1069         default:
   1070             TDM_PRINT1("Invalid calendar ID - %0d\n", param_cal_id);
   1071             return (TDM_EXEC_CORE_SIZE+1);
   1072     }
   1073     for (i=0; i<cal->grp_num; i++) {
   1074         for (j=0; j<cal->grp_len; j++) {
   1075             cal->cal_grp[i][j] = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1076         }
   1077     }
   1078 
   1079     for (i = param_phy_lo; i <= param_phy_hi; i++) {
   1080         if ((_tdm->_chip_data.soc_pkg.speed[i] != SPEED_0) &&
   1081             (_tdm->_chip_data.soc_pkg.state[i-1] == PORT_STATE__OVERSUB ||
   1082              _tdm->_chip_data.soc_pkg.state[i-1] == PORT_STATE__OVERSUB_HG)) {
   1083             switch (_tdm->_chip_data.soc_pkg.speed[i]) {
   1084                 case SPEED_1G  : port_cnt_1g++;   break;
   1085                 case SPEED_10G : port_cnt_10g++;  break;
   1086                 case SPEED_20G : port_cnt_20g++;  break;
   1087                 case SPEED_25G : port_cnt_25g++;  break;
   1088                 case SPEED_40G : port_cnt_40g++;  break;
   1089                 case SPEED_50G : port_cnt_50g++;  break;
   1090                 case SPEED_100G: port_cnt_100g++; break;
   1091                 case SPEED_120G: port_cnt_120g++; break;
   1092                 default: break;
   1093             }
   1094         }
   1095     }
   1096 
   1097     num_spd_types = _tdm->_core_data.vars_pkg.os_1 +
   1098                     _tdm->_core_data.vars_pkg.os_10 +
   1099                     _tdm->_core_data.vars_pkg.os_20 +
   1100                     _tdm->_core_data.vars_pkg.os_25 +
   1101                     _tdm->_core_data.vars_pkg.os_40 +
   1102                     _tdm->_core_data.vars_pkg.os_50 +
   1103                     _tdm->_core_data.vars_pkg.os_100 +
   1104                     _tdm->_core_data.vars_pkg.os_120;
   1105 
   1106     TDM_BIG_BAR
   1107     TDM_SML_BAR
   1108     TDM_PRINT1("  1G ports : %0d\n", port_cnt_1g);
   1109     TDM_PRINT1(" 10G ports : %0d\n", port_cnt_10g);
   1110     TDM_PRINT1(" 20G ports : %0d\n", port_cnt_20g);
   1111     TDM_PRINT1(" 25G ports : %0d\n", port_cnt_25g);
   1112     TDM_PRINT1(" 40G ports : %0d\n", port_cnt_40g);
   1113     TDM_PRINT1(" 50G ports : %0d\n", port_cnt_50g);
   1114     TDM_PRINT1("100G ports : %0d\n", port_cnt_100g);
   1115     TDM_PRINT1("120G ports : %0d\n", port_cnt_120g);
   1116     TDM_PRINT1("Number of speed types: %0d\n", num_spd_types);
   1117 
   1118     if (num_spd_types > cal->grp_num) {
   1119         TDM_ERROR0("Oversub speed type limit exceeded\n");
   1120         return FAIL;
   1121     }
   1122 
   1123     /* Partition OVSB PMs into 2 half pipes */
   1124     tdm_mv2_ovsb_map_pms_to_hpipe(_tdm);
   1125 
   1126     /* Allocate ports into oversub speed groups */
   1127     _tdm->_chip_data.soc_pkg.soc_vars.mv2.grp_speed = SPEED_10G;
   1128     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 0;
   1129     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1130       TDM_PRINT2("10G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num); 
   1131     }
   1132     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 1;
   1133     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1134       TDM_PRINT2("10G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num);
   1135     }
   1136 
   1137     _tdm->_chip_data.soc_pkg.soc_vars.mv2.grp_speed = SPEED_20G;
   1138     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 0;
   1139     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1140       TDM_PRINT2("20G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num); 
   1141     }
   1142     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 1;
   1143     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1144       TDM_PRINT2("20G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num);
   1145     }
   1146 
   1147     _tdm->_chip_data.soc_pkg.soc_vars.mv2.grp_speed = SPEED_25G;
   1148     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 0;
   1149     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1150       TDM_PRINT2("25G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num); 
   1151     }
   1152     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 1;
   1153     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1154       TDM_PRINT2("25G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num);
   1155     }
   1156 
   1157     _tdm->_chip_data.soc_pkg.soc_vars.mv2.grp_speed = SPEED_40G;
   1158     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 0;
   1159     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1160       TDM_PRINT2("40G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num); 
   1161     }
   1162     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 1;
   1163     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1164       TDM_PRINT2("40G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num);
   1165     }
   1166 
   1167     _tdm->_chip_data.soc_pkg.soc_vars.mv2.grp_speed = SPEED_50G;
   1168     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 0;
   1169     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1170       TDM_PRINT2("50G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num); 
   1171     }
   1172     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 1;
   1173     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1174       TDM_PRINT2("50G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num);
   1175     }
   1176 
   1177     _tdm->_chip_data.soc_pkg.soc_vars.mv2.grp_speed = SPEED_100G;
   1178     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 0;
   1179     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1180       TDM_PRINT2("100G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num); 
   1181     }
   1182     _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 1;
   1183     if(tdm_mv2_ovsb_fill_group(_tdm)) {
   1184       TDM_PRINT2("100G OVSB partition for PIPE %d HALF_PIPE=%d DONE\n", _tdm->_core_data.vars_pkg.cal_id,_tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num);
   1185     }
   1186 
   1187     return PASS;
   1188 
   1189     
   1190     
   1191     
   1192 }
   1193 
   1194 
   1195 /**
   1196 @name: tdm_mv2_ovsb_get_grp_spd_slots
   1197 @param:
   1198 
   1199 Return unified slot number of group speed for the given ovsb group.
   1200 If ovsb group is empty, return 0.
   1201  */
   1202 int
   1203 tdm_mv2_ovsb_get_grp_spd_slots(tdm_mod_t *_tdm, int *grp, int grp_len )
   1204 {
   1205     int i, port_phy;
   1206     int grp_spd_slots = 0;
   1207     int param_phy_lo, param_phy_hi;
   1208     enum port_speed_e *param_speeds;
   1209 
   1210     param_phy_lo      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo;
   1211     param_phy_hi      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi;
   1212     param_speeds      = _tdm->_chip_data.soc_pkg.speed;
   1213 
   1214     for (i = 0; i < grp_len; i++) {
   1215         port_phy = grp[i];
   1216         if (port_phy >= param_phy_lo && port_phy <= param_phy_hi) {
   1217             grp_spd_slots = tdm_mv2_cmn_get_speed_slots(param_speeds[port_phy]);
   1218             break;
   1219         }
   1220     }
   1221     return grp_spd_slots;
   1222 }
   1223 
   1224 
   1225 /**
   1226 @name: tdm_mv2_ovsb_get_grp_size
   1227 @param:
   1228 
   1229 Return number of active ports in the given oversub speed group.
   1230 If ovsb group is empty, return 0.
   1231  */
   1232 int
   1233 tdm_mv2_ovsb_get_grp_size(tdm_mod_t *_tdm, int *grp, int grp_len )
   1234 {
   1235     int i, port_phy;
   1236     int grp_size = 0;
   1237     int param_phy_lo, param_phy_hi;
   1238 
   1239     param_phy_lo      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo;
   1240     param_phy_hi      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi;
   1241 
   1242     for (i = 0; i < grp_len; i++) {
   1243         port_phy = grp[i];
   1244         if (port_phy >= param_phy_lo && port_phy <= param_phy_hi) {
   1245             grp_size++;
   1246         }
   1247     }
   1248 
   1249     return grp_size;
   1250 }
   1251 
   1252 
   1253 /**
   1254 @name: tdm_mv2_ovsb_chk_grp_feasible
   1255 @param:
   1256 
   1257 Return BOOL_TRUE if the input speed group can satify speed requirement
   1258 and space requirement; otherwise, return BOOL_FALSE.
   1259  */
   1260 int
   1261 tdm_mv2_ovsb_chk_grp_feasible(tdm_mod_t *_tdm, int *grp, int grp_len,
   1262                               int port_cnt, int port_spd_slots)
   1263 {
   1264     int grp_size, grp_spd_slots, space_required, space_left;
   1265 
   1266     space_required = port_cnt;
   1267     grp_spd_slots = tdm_mv2_ovsb_get_grp_spd_slots(_tdm, grp, grp_len);
   1268     grp_size = tdm_mv2_ovsb_get_grp_size(_tdm, grp, grp_len);
   1269     space_left = grp_len - grp_size;
   1270     if (grp_spd_slots == port_spd_slots &&
   1271         space_required <= space_left) {
   1272         return BOOL_TRUE;
   1273     }
   1274 
   1275     return BOOL_FALSE;
   1276 }
   1277 
   1278 
   1279 /**
   1280 @name: tdm_mv2_ovsb_chk_grp_empty
   1281 @param:
   1282 
   1283 Return BOOL_TRUE if the input speed group is empty;
   1284 otherwise, return BOOL_FALSE.
   1285  */
   1286 int
   1287 tdm_mv2_ovsb_chk_grp_empty(tdm_mod_t *_tdm, int *grp, int grp_len)
   1288 {
   1289     int grp_size, grp_spd_slots;
   1290 
   1291     grp_spd_slots = tdm_mv2_ovsb_get_grp_spd_slots(_tdm, grp, grp_len);
   1292     grp_size = tdm_mv2_ovsb_get_grp_size(_tdm, grp, grp_len);
   1293     if (grp_size == 0 && grp_spd_slots == 0) {
   1294         return BOOL_TRUE;
   1295     }
   1296 
   1297     return BOOL_FALSE;
   1298 }
   1299 
   1300 
   1301 /**
   1302 @name: tdm_mv2_ovsb_find_grp_4_port
   1303 @param:
   1304 
   1305 Find the position (i,j) of one feasible speed group to accommodate input port.
   1306 Return BOOL_TRUE if found, otherwise return BOOL_FALSE.
   1307  */
   1308 int
   1309 tdm_mv2_ovsb_find_grp_4_port(tdm_mod_t *_tdm, int port_phy,
   1310                              tdm_calendar_t *cal,
   1311                              int *pos_i, int *pos_j)
   1312 {
   1313     int i, j, port_pm, port_phy_tmp, port_pm_tmp;
   1314     int port_spd_slots, grp_spd_slots;
   1315     int grp_idx_s, grp_idx_e, grp_idx_i, grp_idx_j;
   1316     int grp_found = BOOL_FALSE;
   1317     int same_spd_sister_exist, same_spd_sister_cnt, same_spd_sister_grp;
   1318     int grp_size, grp_idx, grp_sister_cnt;
   1319     int idx, space_required, space_left;
   1320     int param_cal_id, param_token_empty, param_phy_lo, param_phy_hi,
   1321         param_hpipe_num, param_num_pm_lanes;
   1322     enum port_speed_e *param_speeds;
   1323 
   1324     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
   1325     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1326     param_num_pm_lanes= _tdm->_chip_data.soc_pkg.pmap_num_lanes;
   1327     param_hpipe_num   = _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num;
   1328     param_speeds      = _tdm->_chip_data.soc_pkg.speed;
   1329 
   1330     tdm_mv2_cmn_get_pipe_port_range(param_cal_id, &param_phy_lo, &param_phy_hi);
   1331 
   1332     grp_idx_s = (param_hpipe_num == 0) ? 0 : (cal->grp_num / 2);
   1333     grp_idx_e = (param_hpipe_num == 0) ? (cal->grp_num / 2) : (cal->grp_num);
   1334     grp_idx_i = cal->grp_num;
   1335     grp_idx_j = cal->grp_len;
   1336     grp_idx   = cal->grp_num;
   1337     port_pm   = (port_phy - 1) / MV2_NUM_PM_LNS;
   1338     port_spd_slots = tdm_mv2_cmn_get_speed_slots(param_speeds[port_phy]);
   1339 
   1340     /* check if sister port with same speed exists */
   1341     same_spd_sister_exist = BOOL_FALSE;
   1342     same_spd_sister_cnt = 1;
   1343     for (i = 0; i < param_num_pm_lanes; i++) {
   1344         port_phy_tmp = port_pm * param_num_pm_lanes + i + 1;
   1345         if (port_phy_tmp != port_phy &&
   1346             tdm_mv2_ovsb_chk_same_spd_port(_tdm, port_phy, port_phy_tmp) ==
   1347             BOOL_TRUE) {
   1348             same_spd_sister_exist = BOOL_TRUE;
   1349             same_spd_sister_cnt++;
   1350         }
   1351     }
   1352 
   1353     /* case 1: if same speed sister port exists, then find a speed group that
   1354      *         can accommodate all same speed sister ports.
   1355      *
   1356      *    1.1: same-speed sister port has been allocated.
   1357      *    1.2: same-speed sister port has NOT been allocated.
   1358      */
   1359     if (same_spd_sister_exist == BOOL_TRUE) {
   1360         /* get speed group index of allocated sister port */
   1361         same_spd_sister_grp = cal->grp_num;
   1362         grp_sister_cnt = 0;
   1363         for (i = grp_idx_s; i < grp_idx_e; i++) {
   1364             for (j = 0; j < cal->grp_len; j++) {
   1365                 port_phy_tmp = cal->cal_grp[i][j];
   1366                 port_pm_tmp = (port_phy_tmp - 1) / 4;
   1367                 if (port_pm_tmp == port_pm) {
   1368                     if (BOOL_TRUE == tdm_mv2_ovsb_chk_same_spd_port(
   1369                                             _tdm, port_phy, port_phy_tmp)) {
   1370                         same_spd_sister_grp = i;
   1371                         grp_sister_cnt++;
   1372                     }
   1373                 }
   1374             }
   1375             if (same_spd_sister_grp < cal->grp_num) {
   1376                 break;
   1377             }
   1378         }
   1379         /* 1.1: if exists allocated same-speed sister port */
   1380         if (same_spd_sister_grp < cal->grp_num) {
   1381             grp_size = tdm_mv2_ovsb_get_grp_size(_tdm,
   1382                         cal->cal_grp[same_spd_sister_grp], cal->grp_len);
   1383             space_required = same_spd_sister_cnt - grp_sister_cnt;
   1384             space_left     = cal->grp_len - grp_size;
   1385             /* 1.1.1: if feasible, record the targeted speed group */
   1386             if (space_required <= space_left) {
   1387                 grp_found = BOOL_TRUE;
   1388                 grp_idx = same_spd_sister_grp;
   1389             }
   1390             /* 1.1.2: if infeasible, move allocated same-speed-sister-ports
   1391              * into a feasible speed group
   1392              */
   1393             else {
   1394                 /* find feasible speed group */
   1395                 space_required = same_spd_sister_cnt;
   1396                 for (i = grp_idx_s; i < grp_idx_e; i++) {
   1397                     if (BOOL_TRUE == tdm_mv2_ovsb_chk_grp_feasible(_tdm,
   1398                                         cal->cal_grp[i], cal->grp_len,
   1399                                         space_required, port_spd_slots)) {
   1400                         grp_found = BOOL_TRUE;
   1401                         grp_idx = i;
   1402                         break;
   1403                     }
   1404                 }
   1405                 if (grp_found == BOOL_FALSE) {
   1406                     for (i = grp_idx_s; i < grp_idx_e; i++) {
   1407                         if (BOOL_TRUE == tdm_mv2_ovsb_chk_grp_empty(_tdm,
   1408                                             cal->cal_grp[i], cal->grp_len)) {
   1409                             grp_found = BOOL_TRUE;
   1410                             grp_idx = i;
   1411                             break;
   1412                         }
   1413                     }
   1414                 }
   1415                 /* migrate allocated same-speed sister ports */
   1416                 if (grp_found == BOOL_TRUE) {
   1417                     idx = 0;
   1418                     i = same_spd_sister_grp;
   1419                     for (j = 0; j < cal->grp_len; j++) {
   1420                         port_phy_tmp = cal->cal_grp[i][j];
   1421                         port_pm_tmp = (port_phy_tmp - 1) / 4;
   1422                         if (port_pm_tmp == port_pm) {
   1423                             if (BOOL_TRUE == tdm_mv2_ovsb_chk_same_spd_port(
   1424                                             _tdm, port_phy, port_phy_tmp)) {
   1425                                 while (idx < cal->grp_len) {
   1426                                     if (cal->cal_grp[grp_idx][idx] == param_token_empty) {
   1427                                         cal->cal_grp[grp_idx][idx] = port_phy_tmp;
   1428                                         cal->cal_grp[i][j] = param_token_empty;
   1429                                         break;
   1430                                     }
   1431                                     idx++;
   1432                                 }
   1433                             }
   1434                         }
   1435                     }
   1436                 }
   1437             }
   1438         }
   1439         /* 1.2: find a speed group with enough space for all same-speed sister ports */
   1440         else {
   1441             /* same speed group */
   1442             space_required = same_spd_sister_cnt;
   1443             for (i = grp_idx_s; i < grp_idx_e; i++) {
   1444                 if (BOOL_TRUE == tdm_mv2_ovsb_chk_grp_feasible(_tdm,
   1445                                     cal->cal_grp[i], cal->grp_len,
   1446                                     space_required, port_spd_slots)) {
   1447                     grp_found = BOOL_TRUE;
   1448                     grp_idx = i;
   1449                     break;
   1450                 }
   1451             }
   1452             /* empty speed group */
   1453             if (grp_found == BOOL_FALSE) {
   1454                 for (i=grp_idx_s; i<grp_idx_e; i++) {
   1455                     grp_spd_slots = tdm_mv2_ovsb_get_grp_spd_slots(_tdm,
   1456                                     cal->cal_grp[i], cal->grp_len);
   1457                     if (grp_spd_slots == 0) {
   1458                         grp_found = BOOL_TRUE;
   1459                         grp_idx = i;
   1460                         break;
   1461                     }
   1462                 }
   1463             }
   1464         }
   1465     }
   1466     /* case 2: if same speed sister port does not exist, then find a speed
   1467      *         group that can accommodate .
   1468      */
   1469     else {
   1470         /* same speed group */
   1471         space_required = 1;
   1472         for (i = grp_idx_s; i < grp_idx_e; i++) {
   1473             if (BOOL_TRUE == tdm_mv2_ovsb_chk_grp_feasible(_tdm,
   1474                                 cal->cal_grp[i], cal->grp_len,
   1475                                 space_required, port_spd_slots)) {
   1476                 grp_found = BOOL_TRUE;
   1477                 grp_idx = i;
   1478                 break;
   1479             }
   1480         }
   1481         /* empty speed group */
   1482         if (grp_found == BOOL_FALSE) {
   1483             for (i=grp_idx_s; i<grp_idx_e; i++) {
   1484                 grp_spd_slots = tdm_mv2_ovsb_get_grp_spd_slots(_tdm,
   1485                                 cal->cal_grp[i], cal->grp_len);
   1486                 if (grp_spd_slots == 0) {
   1487                     grp_found = BOOL_TRUE;
   1488                     grp_idx = i;
   1489                     break;
   1490                 }
   1491             }
   1492         }
   1493     }
   1494 
   1495     /* determine pos_i and pos_j */
   1496     if (grp_found == BOOL_TRUE) {
   1497         i = grp_idx;
   1498         for (j = 0; j < cal->grp_len; j++) {
   1499             if (cal->cal_grp[i][j] == param_token_empty) {
   1500                 grp_idx_i = i;
   1501                 grp_idx_j = j;
   1502                 break;
   1503             }
   1504         }
   1505     } else {
   1506         TDM_ERROR2("TDM:[flex] Failed to allocate port %0d speed %0dG\n",
   1507                    port_phy, param_speeds[port_phy]/1000);
   1508     }
   1509     if (pos_i != NULL && pos_j != NULL) {
   1510         (*pos_i) = grp_idx_i;
   1511         (*pos_j) = grp_idx_j;
   1512     }
   1513 
   1514     return grp_found;
   1515 }
   1516 
   1517 
   1518 /**
   1519 @name: tdm_mv2_ovsb_consolidate_spd_grp
   1520 @param:
   1521 
   1522 Minimize the number of oversub speed groups
   1523  */
   1524 int
   1525 tdm_mv2_ovsb_consolidate_spd_grp(tdm_mod_t *_tdm)
   1526 {
   1527     int i, j, k, n;
   1528     int grp_num_s, grp_num_e;
   1529     int grp_spd_k, grp_spd_i, grp_size_k, grp_size_i;
   1530     int param_cal_id, param_token_empty, param_phy_lo, param_phy_hi,
   1531         param_hpipe_num;
   1532     tdm_calendar_t *cal;
   1533 
   1534     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
   1535     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1536     param_hpipe_num   = _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num;
   1537     param_phy_lo      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo;
   1538     param_phy_hi      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi;
   1539 
   1540     tdm_mv2_cmn_get_pipe_port_range(param_cal_id, &param_phy_lo, &param_phy_hi);
   1541 
   1542     switch (param_cal_id) {
   1543         case 0:	cal=(&(_tdm->_chip_data.cal_0)); break;
   1544         case 1:	cal=(&(_tdm->_chip_data.cal_1)); break;
   1545         case 2:	cal=(&(_tdm->_chip_data.cal_2)); break;
   1546         case 3:	cal=(&(_tdm->_chip_data.cal_3)); break;
   1547         case 4:	cal=(&(_tdm->_chip_data.cal_4)); break;
   1548         case 5:	cal=(&(_tdm->_chip_data.cal_5)); break;
   1549         case 6:	cal=(&(_tdm->_chip_data.cal_6)); break;
   1550         case 7:	cal=(&(_tdm->_chip_data.cal_7)); break;
   1551         default:
   1552             TDM_PRINT1("Invalid calendar ID - %0d\n", param_cal_id);
   1553             return (TDM_EXEC_CORE_SIZE+1);
   1554     }
   1555     TDM_PRINT1("TDM: [FLEX] run consolidation for pipe %0d\n", param_cal_id);
   1556 
   1557     grp_num_s = (param_hpipe_num == 0) ? 0 : (cal->grp_num / 2);
   1558     grp_num_e = (param_hpipe_num == 0) ? (cal->grp_num / 2) : (cal->grp_num);
   1559 
   1560     for (k = grp_num_s; k < (grp_num_e - 1); k++) {
   1561         grp_spd_k = tdm_mv2_ovsb_get_grp_spd_slots(_tdm,
   1562                                     cal->cal_grp[k], cal->grp_len);
   1563         grp_size_k = tdm_mv2_ovsb_get_grp_size(_tdm,
   1564                                     cal->cal_grp[k], cal->grp_len);
   1565 		if((grp_spd_k == 0) || (grp_size_k == cal->grp_len)) continue;
   1566 
   1567         /* for each non-empty group, do consolidation */
   1568         for (i = k+1; i < grp_num_e; i++) {
   1569             grp_spd_i = tdm_mv2_ovsb_get_grp_spd_slots(_tdm,
   1570                                             cal->cal_grp[i], cal->grp_len);
   1571             grp_size_i = tdm_mv2_ovsb_get_grp_size(_tdm,
   1572                                             cal->cal_grp[i], cal->grp_len);
   1573 			if(grp_spd_i != grp_spd_k) continue;
   1574 			if((grp_size_i + grp_size_k) > cal->grp_len) continue;
   1575 
   1576             for (j = 0; (j < cal->grp_len) && (grp_size_i > 0); j++) {
   1577 				if(cal->cal_grp[i][j] == param_token_empty) continue;
   1578             	for (n = 0; n < cal->grp_len; n++) {
   1579                     if (cal->cal_grp[k][n] == param_token_empty) {
   1580                         cal->cal_grp[k][n] = cal->cal_grp[i][j];
   1581                         cal->cal_grp[i][j] = param_token_empty;
   1582                         grp_size_k ++;
   1583 						grp_size_i --;
   1584 						break;
   1585 				    }
   1586 				}
   1587 			}
   1588         }
   1589     }
   1590 
   1591     return PASS;
   1592 }
   1593 
   1594 
   1595 /**
   1596 @name: tdm_mv2_ovsb_flex_port_dn
   1597 @param:
   1598 
   1599 Remove down ports from ovsb speed groups
   1600  */
   1601 int
   1602 tdm_mv2_ovsb_flex_port_dn(tdm_mod_t *_tdm)
   1603 {
   1604     int i, j, port_done, port_phy;
   1605     int hpipe0_consolidate_en, hpipe1_consolidate_en;
   1606     int param_cal_id, param_token_empty, param_phy_lo, param_phy_hi;
   1607     enum port_speed_e *param_speeds;
   1608     enum port_state_e *param_states;
   1609     tdm_calendar_t *cal;
   1610 
   1611     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
   1612     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1613     param_phy_lo      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo;
   1614     param_phy_hi      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi;
   1615     param_speeds      = _tdm->_prev_chip_data.soc_pkg.speed;
   1616     param_states      = _tdm->_prev_chip_data.soc_pkg.state;
   1617 
   1618     tdm_mv2_cmn_get_pipe_port_range(param_cal_id, &param_phy_lo, &param_phy_hi);
   1619 
   1620     switch (param_cal_id) {
   1621         case 0:	cal=(&(_tdm->_chip_data.cal_0)); break;
   1622         case 1:	cal=(&(_tdm->_chip_data.cal_1)); break;
   1623         case 2:	cal=(&(_tdm->_chip_data.cal_2)); break;
   1624         case 3:	cal=(&(_tdm->_chip_data.cal_3)); break;
   1625         case 4:	cal=(&(_tdm->_chip_data.cal_4)); break;
   1626         case 5:	cal=(&(_tdm->_chip_data.cal_5)); break;
   1627         case 6:	cal=(&(_tdm->_chip_data.cal_6)); break;
   1628         case 7:	cal=(&(_tdm->_chip_data.cal_7)); break;
   1629         default:
   1630             TDM_PRINT1("Invalid calendar ID - %0d\n", param_cal_id);
   1631             return (TDM_EXEC_CORE_SIZE+1);
   1632     }
   1633 
   1634     hpipe0_consolidate_en = BOOL_FALSE;
   1635     hpipe1_consolidate_en = BOOL_FALSE;
   1636 
   1637     /* remove down_ports and spd_changed_ports */
   1638     for (port_phy = param_phy_lo; port_phy <= param_phy_hi; port_phy++) {
   1639         if (param_states[port_phy-1] == PORT_STATE__FLEX_OVERSUB_DN ||
   1640             param_states[port_phy-1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1641             port_done = BOOL_FALSE;
   1642             for (i=0; i<cal->grp_num; i++) {
   1643                 for (j=0; j<cal->grp_len; j++) {
   1644                     if (cal->cal_grp[i][j] == port_phy) {
   1645                         cal->cal_grp[i][j] = param_token_empty;
   1646                         port_done = BOOL_TRUE;
   1647                         TDM_PRINT5("%s %0d, spd %0dG, grp %0d, pos %0d\n",
   1648                                    "TDM: [FLEX] remove down port",
   1649                                    port_phy, param_speeds[port_phy]/1000,
   1650                                    i, j);
   1651                         if (i / (MV2_OS_VBS_GRP_NUM / 2) == 0) {
   1652                             hpipe0_consolidate_en = BOOL_TRUE;
   1653                         } else {
   1654                             hpipe1_consolidate_en = BOOL_TRUE;
   1655                         }
   1656                         break;
   1657                     }
   1658                 }
   1659                 if (port_done == BOOL_TRUE) {
   1660                     break;
   1661                 }
   1662             }
   1663         }
   1664     }
   1665 
   1666     /* do consolidation */
   1667     if (hpipe0_consolidate_en == BOOL_TRUE) {
   1668         _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 0;
   1669         tdm_mv2_ovsb_consolidate_spd_grp(_tdm);
   1670     }
   1671     if (hpipe1_consolidate_en == BOOL_TRUE) {
   1672         _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num = 1;
   1673         tdm_mv2_ovsb_consolidate_spd_grp(_tdm);
   1674     }
   1675 
   1676     return PASS;
   1677 }
   1678 
   1679 
   1680 /**
   1681 @name: tdm_mv2_ovsb_flex_port_up
   1682 @param:
   1683 
   1684 Add up ports into ovsb speed groups
   1685  */
   1686 int
   1687 tdm_mv2_ovsb_flex_port_up(tdm_mod_t *_tdm)
   1688 {
   1689     int port_phy, port_pm;
   1690     int grp_idx_i, grp_idx_j, grp_found;
   1691     int param_cal_id, param_phy_lo, param_phy_hi;
   1692     enum port_speed_e *param_speeds;
   1693     enum port_state_e *param_states;
   1694     tdm_calendar_t *cal;
   1695 
   1696     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
   1697     param_phy_lo      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_lo;
   1698     param_phy_hi      = _tdm->_chip_data.soc_pkg.soc_vars.fp_port_hi;
   1699     param_speeds      = _tdm->_chip_data.soc_pkg.speed;
   1700     param_states      = _tdm->_prev_chip_data.soc_pkg.state;
   1701 
   1702     tdm_mv2_cmn_get_pipe_port_range(param_cal_id, &param_phy_lo, &param_phy_hi);
   1703 
   1704     switch (param_cal_id) {
   1705         case 0:	cal=(&(_tdm->_chip_data.cal_0)); break;
   1706         case 1:	cal=(&(_tdm->_chip_data.cal_1)); break;
   1707         case 2:	cal=(&(_tdm->_chip_data.cal_2)); break;
   1708         case 3:	cal=(&(_tdm->_chip_data.cal_3)); break;
   1709         case 4:	cal=(&(_tdm->_chip_data.cal_4)); break;
   1710         case 5:	cal=(&(_tdm->_chip_data.cal_5)); break;
   1711         case 6:	cal=(&(_tdm->_chip_data.cal_6)); break;
   1712         case 7:	cal=(&(_tdm->_chip_data.cal_7)); break;
   1713         default:
   1714             TDM_PRINT1("Invalid calendar ID - %0d\n", param_cal_id);
   1715             return (TDM_EXEC_CORE_SIZE+1);
   1716     }
   1717 
   1718     /* add up_ports and spd_changed_ports */
   1719     for (port_phy = param_phy_lo; port_phy <= param_phy_hi; port_phy++) {
   1720         if (param_states[port_phy-1] == PORT_STATE__FLEX_OVERSUB_UP ||
   1721             param_states[port_phy-1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1722             port_pm = (port_phy - 1) / MV2_NUM_PM_LNS;
   1723             _tdm->_chip_data.soc_pkg.soc_vars.mv2.half_pipe_num =
   1724                 _tdm->_chip_data.soc_pkg.soc_vars.mv2.pm_ovs_halfpipe[port_pm];
   1725 
   1726             /* find a feasible pos (i,j) for up_port */
   1727             grp_found = tdm_mv2_ovsb_find_grp_4_port(_tdm, port_phy, cal,
   1728                                                      &grp_idx_i, &grp_idx_j);
   1729             if (grp_found == BOOL_TRUE &&
   1730                 grp_idx_i < cal->grp_num && grp_idx_j < cal->grp_len) {
   1731                 cal->cal_grp[grp_idx_i][grp_idx_j] = port_phy;
   1732                 TDM_PRINT5("%s %0d, spd %0dG, grp %0d, pos %0d\n",
   1733                            "TDM: [FLEX] add up_port",
   1734                            port_phy, param_speeds[port_phy]/1000,
   1735                            grp_idx_i, grp_idx_j);
   1736             } else {
   1737                 TDM_ERROR3("%s %0d, spd %0dG, no available ovsb speed group\n",
   1738                            "TDM: [FLEX] failed to add up_port",
   1739                            port_phy, param_speeds[port_phy]/1000);
   1740             }
   1741         }
   1742     }
   1743 
   1744     return PASS;
   1745 }
   1746 
   1747 
   1748 /**
   1749 @name: tdm_mv2_ovsb_flex
   1750 @param:
   1751 
   1752 Generate sortable weightable groups for oversub round robin arbitration
   1753 Fixed mapping:
   1754 [pipe 0] 1 - 40: hpipe 0
   1755 [pipe 0]41 - 80: hpipe 1
   1756  */
   1757 int
   1758 tdm_mv2_ovsb_flex(tdm_mod_t *_tdm)
   1759 {
   1760     int i, j, port_phy;
   1761     int flex_up = BOOL_FALSE, flex_dn = BOOL_FALSE;
   1762     int prev_grp_empty = 1;
   1763     int param_cal_id, param_token_empty, param_phy_lo, param_phy_hi;
   1764     enum port_state_e *param_states_prev;
   1765     tdm_calendar_t *cal = NULL, *cal_prev = NULL;
   1766 
   1767     param_cal_id      = _tdm->_core_data.vars_pkg.cal_id;
   1768     param_token_empty = _tdm->_chip_data.soc_pkg.num_ext_ports;
   1769     param_states_prev = _tdm->_prev_chip_data.soc_pkg.state;
   1770 
   1771     tdm_mv2_cmn_get_pipe_port_range(param_cal_id, &param_phy_lo, &param_phy_hi);
   1772 
   1773     /* check whether having port to flex up/down */
   1774     for (port_phy = param_phy_lo; port_phy <= param_phy_hi; port_phy++) {
   1775         if (param_states_prev[port_phy-1] == PORT_STATE__FLEX_OVERSUB_UP) {
   1776             flex_up = BOOL_TRUE;
   1777         } else if (param_states_prev[port_phy-1] == PORT_STATE__FLEX_OVERSUB_DN) {
   1778             flex_dn = BOOL_TRUE;
   1779         } else if (param_states_prev[port_phy-1] == PORT_STATE__FLEX_OVERSUB_CH) {
   1780             flex_up = BOOL_TRUE;
   1781             flex_dn = BOOL_TRUE;
   1782         }
   1783     }
   1784 
   1785     /* allocate all but up ports into appropriate speed groups */
   1786     tdm_mv2_ovsb_gen_spd_grp(_tdm);
   1787 
   1788     {
   1789         switch (param_cal_id) {
   1790             case 0:	cal=(&(_tdm->_chip_data.cal_0)); break;
   1791             case 1:	cal=(&(_tdm->_chip_data.cal_1)); break;
   1792             case 2:	cal=(&(_tdm->_chip_data.cal_2)); break;
   1793             case 3:	cal=(&(_tdm->_chip_data.cal_3)); break;
   1794             case 4:	cal=(&(_tdm->_chip_data.cal_4)); break;
   1795             case 5:	cal=(&(_tdm->_chip_data.cal_5)); break;
   1796             case 6:	cal=(&(_tdm->_chip_data.cal_6)); break;
   1797             case 7:	cal=(&(_tdm->_chip_data.cal_7)); break;
   1798             default: break;
   1799         }
   1800         switch (param_cal_id) {
   1801             case 0:	cal_prev=(&(_tdm->_prev_chip_data.cal_0)); break;
   1802             case 1:	cal_prev=(&(_tdm->_prev_chip_data.cal_1)); break;
   1803             case 2:	cal_prev=(&(_tdm->_prev_chip_data.cal_2)); break;
   1804             case 3:	cal_prev=(&(_tdm->_prev_chip_data.cal_3)); break;
   1805             case 4:	cal_prev=(&(_tdm->_prev_chip_data.cal_4)); break;
   1806             case 5:	cal_prev=(&(_tdm->_prev_chip_data.cal_5)); break;
   1807             case 6:	cal_prev=(&(_tdm->_prev_chip_data.cal_6)); break;
   1808             case 7:	cal_prev=(&(_tdm->_prev_chip_data.cal_7)); break;
   1809             default: break;
   1810         }
   1811 
   1812         if (cal != NULL && cal_prev != NULL) {
   1813             for (i=0; i<cal->grp_num; i++) {
   1814                 for (j=0; j<cal->grp_len; j++) {
   1815                     if (cal_prev->cal_grp[i][j] != param_token_empty) {
   1816                         prev_grp_empty = 0;
   1817                         break;
   1818                     }
   1819                 }
   1820             }
   1821             if (!prev_grp_empty) {
   1822                 TDM_PRINT1("TDM: Pipe %0d, init ovsb grp by pre_flex values\n",
   1823                            param_cal_id);
   1824                 for (i=0; i<cal->grp_num; i++) {
   1825                     for (j=0; j<cal->grp_len; j++) {
   1826                         cal->cal_grp[i][j] = cal_prev->cal_grp[i][j];
   1827                     }
   1828                 }
   1829             }
   1830         }
   1831     }
   1832 
   1833     /* remove down_ports */
   1834     if (flex_dn) {
   1835         tdm_mv2_ovsb_flex_port_dn(_tdm);
   1836     }
   1837 
   1838     /* add up_ports */
   1839     if (flex_up) {
   1840         tdm_mv2_ovsb_flex_port_up(_tdm);
   1841     }
   1842 
   1843     return PASS;
   1844 }
   1845 
   1846 /**
   1847 @name: tdm_mv2_vbs_scheduler_ovs
   1848 @param:
   1849 
   1850 */
   1851 int
   1852 tdm_mv2_vbs_scheduler_ovs(tdm_mod_t *_tdm)
   1853 {
   1854     /* generate OVSB groups */
   1855     TDM_PRINT1("TDM: flex_port_en = %0d\n",
   1856            _tdm->_chip_data.soc_pkg.flex_port_en);
   1857     if (_tdm->_chip_data.soc_pkg.flex_port_en == 1) {
   1858         if(tdm_mv2_ovsb_flex(_tdm) != PASS) {
   1859             return FAIL;
   1860         }
   1861     } else {
   1862         if (tdm_mv2_ovsb_gen_spd_grp(_tdm) != PASS) {
   1863             return FAIL;
   1864         }
   1865     }
   1866 
   1867     /* generate PKT scheduler */
   1868     if (tdm_mv2_ovsb_pkt_shaper(_tdm)){
   1869       TDM_PRINT1("OVSB partition for PIPE %d PKT_SHAPER CALENDAR DONE\n", _tdm->_core_data.vars_pkg.cal_id);
   1870     }
   1871     if(tdm_mv2_ovsb_map_pm_num_to_pblk(_tdm)) {
   1872       TDM_PRINT1("OVSB partition for PIPE %d PM_NUM to PBLK mapping DONE\n", _tdm->_core_data.vars_pkg.cal_id);
   1873     }
   1874 
   1875     return PASS;
   1876 }