update Intel copyright years to 2014
[dpdk.git] / lib / librte_sched / rte_sched.c
index a75b4b9..24e8bdf 100644 (file)
@@ -1,35 +1,34 @@
 /*-
  *   BSD LICENSE
  * 
- *   Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
  *   All rights reserved.
  * 
- *   Redistribution and use in source and binary forms, with or without 
- *   modification, are permitted provided that the following conditions 
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
  *   are met:
  * 
- *     * Redistributions of source code must retain the above copyright 
+ *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright 
- *       notice, this list of conditions and the following disclaimer in 
- *       the documentation and/or other materials provided with the 
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
  *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its 
- *       contributors may be used to endorse or promote products derived 
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
  *       from this software without specific prior written permission.
  * 
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
  */
 
 #include <stdio.h>
@@ -118,13 +117,13 @@ struct rte_sched_subport {
        uint32_t tc_period;
        
        /* TC oversubscription */
-       uint32_t tc_ov_period;
-       uint64_t tc_ov_time;
-       uint32_t tc_ov_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+       uint32_t tc_ov_wm;
+       uint32_t tc_ov_wm_min;
+       uint32_t tc_ov_wm_max;
        uint8_t tc_ov_period_id;
-       uint8_t tc_ov[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-       uint32_t tc_ov_n[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-       double tc_ov_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+       uint8_t tc_ov;
+       uint32_t tc_ov_n;
+       double tc_ov_rate;
        
        /* Statistics */
        struct rte_sched_subport_stats stats;
@@ -139,7 +138,7 @@ struct rte_sched_pipe_profile {
        /* Pipe traffic classes */
        uint32_t tc_period;
        uint32_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-       uint8_t tc_ov_weight[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+       uint8_t tc_ov_weight;
        
        /* Pipe queues */
        uint8_t  wrr_cost[RTE_SCHED_QUEUES_PER_PIPE];
@@ -161,12 +160,9 @@ struct rte_sched_pipe {
        uint8_t wrr_tokens[RTE_SCHED_QUEUES_PER_PIPE];
        
        /* TC oversubscription */
-#ifdef RTE_SCHED_SUBPORT_TC_OV
-       uint32_t tc_ov_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+       uint32_t tc_ov_credits;
        uint8_t tc_ov_period_id;
-#else
-       uint64_t reserved;
-#endif
+       uint8_t reserved[3];
 } __rte_cache_aligned;
 
 struct rte_sched_queue {
@@ -219,8 +215,7 @@ struct rte_sched_grinder {
        uint32_t qpos;
        struct rte_mbuf *pkt;
        
-       double ov_coef;
-       
+       /* WRR */
        uint16_t wrr_tokens[RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS];
        uint16_t wrr_mask[RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS];
        uint8_t wrr_cost[RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS];
@@ -231,9 +226,11 @@ struct rte_sched_port {
        uint32_t n_subports_per_port;
        uint32_t n_pipes_per_subport;
        uint32_t rate;
+       uint32_t mtu;
        uint32_t frame_overhead;
        uint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
        uint32_t n_pipe_profiles;
+       uint32_t pipe_tc3_rate_max;
 #ifdef RTE_SCHED_RED
        struct rte_red_config red_config[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE][e_RTE_METER_COLORS];
 #endif
@@ -324,14 +321,19 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
                return -4;
        }
        
+       /* mtu */
+       if (params->mtu == 0) {
+               return -5;
+       }
+       
        /* n_subports_per_port: non-zero, power of 2 */
        if ((params->n_subports_per_port == 0) || (!rte_is_power_of_2(params->n_subports_per_port))) {
-               return -5;
+               return -6;
        }
 
        /* n_pipes_per_subport: non-zero, power of 2 */
        if ((params->n_pipes_per_subport == 0) || (!rte_is_power_of_2(params->n_pipes_per_subport))) {
-               return -6;
+               return -7;
        }
        
        /* qsize: non-zero, power of 2, no bigger than 32K (due to 16-bit read/write pointers) */
@@ -339,7 +341,7 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
                uint16_t qsize = params->qsize[i];
                
                if ((qsize == 0) || (!rte_is_power_of_2(qsize))) {
-                       return -7;
+                       return -8;
                }
        }
        
@@ -347,7 +349,7 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
        if ((params->pipe_profiles == NULL) || 
            (params->n_pipe_profiles == 0) ||
            (params->n_pipe_profiles > RTE_SCHED_PIPE_PROFILES_PER_PORT)) {
-               return -8;
+               return -9;
        }
        
        for (i = 0; i < params->n_pipe_profiles; i ++) {
@@ -355,39 +357,37 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
                
                /* TB rate: non-zero, not greater than port rate */
                if ((p->tb_rate == 0) || (p->tb_rate > params->rate)) {
-                       return -9;
+                       return -10;
                }
                
                /* TB size: non-zero */
                if (p->tb_size == 0) {
-                       return -10;
+                       return -11;
                }
 
                /* TC rate: non-zero, less than pipe rate */
                for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j ++) {
                        if ((p->tc_rate[j] == 0) || (p->tc_rate[j] > p->tb_rate)) {
-                               return -11;
+                               return -12;
                        }
                }
                
                /* TC period: non-zero */
                if (p->tc_period == 0) {
-                       return -12;
+                       return -13;
                }
 
 #ifdef RTE_SCHED_SUBPORT_TC_OV
-               /* TC oversubscription weights: non-zero */
-               for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j ++) {
-                       if (p->tc_ov_weight[j] == 0) {
-                               return -13;
-                       }
+               /* TC3 oversubscription weight: non-zero */
+               if (p->tc_ov_weight == 0) {
+                       return -14;
                }
 #endif
 
                /* Queue WRR weights: non-zero */
                for (j = 0; j < RTE_SCHED_QUEUES_PER_PIPE; j ++) {
                        if (p->wrr_weights[j] == 0) {
-                               return -14;
+                               return -15;
                        }
                }
        }
@@ -501,7 +501,8 @@ rte_sched_port_log_pipe_profile(struct rte_sched_port *port, uint32_t i)
        
        RTE_LOG(INFO, SCHED, "Low level config for pipe profile %u:\n"
                "\tToken bucket: period = %u, credits per period = %u, size = %u\n"
-               "\tTraffic classes: period = %u, credits per period = [%u, %u, %u, %u], ov weights = [%hhu, %hhu, %hhu, %hhu]\n"
+               "\tTraffic classes: period = %u, credits per period = [%u, %u, %u, %u]\n"
+               "\tTraffic class 3 oversubscription: weight = %hhu\n"
                "\tWRR cost: [%hhu, %hhu, %hhu, %hhu], [%hhu, %hhu, %hhu, %hhu], [%hhu, %hhu, %hhu, %hhu], [%hhu, %hhu, %hhu, %hhu]\n",
                i,
                
@@ -516,10 +517,9 @@ rte_sched_port_log_pipe_profile(struct rte_sched_port *port, uint32_t i)
                p->tc_credits_per_period[1],
                p->tc_credits_per_period[2],
                p->tc_credits_per_period[3],
-               p->tc_ov_weight[0],
-               p->tc_ov_weight[1],
-               p->tc_ov_weight[2],
-               p->tc_ov_weight[3],
+               
+               /* Traffic class 3 oversubscription */
+               p->tc_ov_weight,
                
                /* WRR */
                p->wrr_cost[ 0], p->wrr_cost[ 1], p->wrr_cost[ 2], p->wrr_cost[ 3],
@@ -564,9 +564,7 @@ rte_sched_port_config_pipe_profile_table(struct rte_sched_port *port, struct rte
                        dst->tc_credits_per_period[j] = (uint32_t) rte_sched_time_ms_to_bytes(src->tc_period, src->tc_rate[j]);
                }
 #ifdef RTE_SCHED_SUBPORT_TC_OV
-               for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j ++) {
-                       dst->tc_ov_weight[j] = src->tc_ov_weight[j];
-               }
+               dst->tc_ov_weight = src->tc_ov_weight;
 #endif
                
                /* WRR */
@@ -599,6 +597,16 @@ rte_sched_port_config_pipe_profile_table(struct rte_sched_port *port, struct rte
        
                rte_sched_port_log_pipe_profile(port, i);
        }
+
+       port->pipe_tc3_rate_max = 0;
+       for (i = 0; i < port->n_pipe_profiles; i ++) {
+               struct rte_sched_pipe_params *src = params->pipe_profiles + i;
+               uint32_t pipe_tc3_rate = src->tc_rate[3];
+               
+               if (port->pipe_tc3_rate_max < pipe_tc3_rate) {
+                       port->pipe_tc3_rate_max = pipe_tc3_rate;
+               }
+       }
 }
 
 struct rte_sched_port *
@@ -635,6 +643,7 @@ rte_sched_port_config(struct rte_sched_port_params *params)
        port->n_subports_per_port = params->n_subports_per_port;
        port->n_pipes_per_subport = params->n_pipes_per_subport;
        port->rate = params->rate;
+       port->mtu = params->mtu + params->frame_overhead;
        port->frame_overhead = params->frame_overhead;
        memcpy(port->qsize, params->qsize, sizeof(params->qsize));
        port->n_pipe_profiles = params->n_pipe_profiles;
@@ -719,7 +728,8 @@ rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
        
        RTE_LOG(INFO, SCHED, "Low level config for subport %u:\n"       
                "\tToken bucket: period = %u, credits per period = %u, size = %u\n"
-               "\tTraffic classes: period = %u, credits per period = [%u, %u, %u, %u], ov period = %u\n",
+               "\tTraffic classes: period = %u, credits per period = [%u, %u, %u, %u]\n"
+               "\tTraffic class 3 oversubscription: wm min = %u, wm max = %u\n",
                i,
                
                /* Token bucket */
@@ -733,7 +743,10 @@ rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
                s->tc_credits_per_period[1],
                s->tc_credits_per_period[2],
                s->tc_credits_per_period[3],
-               s->tc_ov_period);
+               
+               /* Traffic class 3 oversubscription */
+               s->tc_ov_wm_min,
+               s->tc_ov_wm_max);
 }
 
 int
@@ -768,12 +781,6 @@ rte_sched_subport_config(struct rte_sched_port *port,
        if (params->tc_period == 0) {
                return -5;
        }
-
-#ifdef RTE_SCHED_SUBPORT_TC_OV
-       if ((params->tc_ov_period == 0) || (params->tc_ov_period > params->tc_period)) {
-               return -6;
-       }
-#endif
        
        s = port->subport + subport_id;
        
@@ -803,15 +810,13 @@ rte_sched_subport_config(struct rte_sched_port *port,
        
 #ifdef RTE_SCHED_SUBPORT_TC_OV
        /* TC oversubscription */
-       s->tc_ov_period = (uint32_t) rte_sched_time_ms_to_bytes(params->tc_ov_period, port->rate);
-       s->tc_ov_time = port->time + s->tc_ov_period;
+       s->tc_ov_wm_min = port->mtu;
+       s->tc_ov_wm_max = (uint32_t) rte_sched_time_ms_to_bytes(params->tc_period, port->pipe_tc3_rate_max);
+       s->tc_ov_wm = s->tc_ov_wm_max;
        s->tc_ov_period_id = 0;
-       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
-               s->tc_ov[i] = 0;
-               s->tc_ov_n[i] = 0;
-               s->tc_ov_rate[i] = 0;
-               s->tc_ov_credits[i] = 0;
-       }
+       s->tc_ov = 0;
+       s->tc_ov_n = 0;
+       s->tc_ov_rate = 0;
 #endif
        
        rte_sched_port_log_subport_config(port, subport_id);
@@ -853,11 +858,18 @@ rte_sched_pipe_config(struct rte_sched_port *port,
                params = port->pipe_profiles + p->profile;
 
 #ifdef RTE_SCHED_SUBPORT_TC_OV
+               double subport_tc3_rate = ((double) s->tc_credits_per_period[3]) / ((double) s->tc_period);
+               double pipe_tc3_rate = ((double) params->tc_credits_per_period[3]) / ((double) params->tc_period);
+               uint32_t tc3_ov = s->tc_ov;
+               
                /* Unplug pipe from its subport */
-               for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
-                       s->tc_ov_n[i] -= params->tc_ov_weight[i];
-                       s->tc_ov_rate[i] -= ((double) params->tc_credits_per_period[i]) / ((double) params->tc_period);
-                       s->tc_ov[i] = s->tc_ov_rate[i] > (((double) s->tc_credits_per_period[i]) / ((double) s->tc_period));
+               s->tc_ov_n -= params->tc_ov_weight;
+               s->tc_ov_rate -= pipe_tc3_rate;
+               s->tc_ov = s->tc_ov_rate > subport_tc3_rate;
+               
+               if (s->tc_ov != tc3_ov) {
+                       RTE_LOG(INFO, SCHED, "Subport %u TC3 oversubscription is OFF (%.4lf >= %.4lf)\n", 
+                               subport_id, subport_tc3_rate, s->tc_ov_rate);
                }
 #endif
                
@@ -884,15 +896,22 @@ rte_sched_pipe_config(struct rte_sched_port *port,
        }
        
 #ifdef RTE_SCHED_SUBPORT_TC_OV
-       /* Subport TC oversubscription */
-       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
-               s->tc_ov_n[i] += params->tc_ov_weight[i];
-               s->tc_ov_rate[i] += ((double) params->tc_credits_per_period[i]) / ((double) params->tc_period);
-               s->tc_ov[i] = s->tc_ov_rate[i] > (((double) s->tc_credits_per_period[i]) / ((double) s->tc_period));
-       }
-       p->tc_ov_period_id = s->tc_ov_period_id;
-       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
-               p->tc_ov_credits[i] = 0;
+       {
+               /* Subport TC3 oversubscription */
+               double subport_tc3_rate = ((double) s->tc_credits_per_period[3]) / ((double) s->tc_period);
+               double pipe_tc3_rate = ((double) params->tc_credits_per_period[3]) / ((double) params->tc_period);
+               uint32_t tc3_ov = s->tc_ov;
+                       
+               s->tc_ov_n += params->tc_ov_weight;
+               s->tc_ov_rate += pipe_tc3_rate;
+               s->tc_ov = s->tc_ov_rate > subport_tc3_rate;
+               
+               if (s->tc_ov != tc3_ov) {
+                       RTE_LOG(INFO, SCHED, "Subport %u TC3 oversubscription is ON (%.4lf < %.4lf)\n", 
+                               subport_id, subport_tc3_rate, s->tc_ov_rate);
+               }
+               p->tc_ov_period_id = s->tc_ov_period_id;
+               p->tc_ov_credits = s->tc_ov_wm;
        }
 #endif
        
@@ -906,7 +925,6 @@ rte_sched_subport_read_stats(struct rte_sched_port *port,
        uint32_t *tc_ov)
 {
        struct rte_sched_subport *s;
-       uint32_t mask, i;
        
        /* Check user parameters */
        if ((port == NULL) ||
@@ -922,11 +940,7 @@ rte_sched_subport_read_stats(struct rte_sched_port *port,
        memset(&s->stats, 0, sizeof(struct rte_sched_subport_stats));
        
        /* Subport TC ovesubscription status */
-       mask = 0;
-       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i ++) {
-               mask |= ((uint32_t) s->tc_ov[i]) << i;
-       }
-       *tc_ov = mask;
+       *tc_ov = s->tc_ov;
        
        return 0;
 }
@@ -1465,6 +1479,42 @@ grinder_credits_update(struct rte_sched_port *port, uint32_t pos)
 
 #else
 
+static inline uint32_t
+grinder_tc_ov_credits_update(struct rte_sched_port *port, uint32_t pos)
+{
+       struct rte_sched_grinder *grinder = port->grinder + pos;
+       struct rte_sched_subport *subport = grinder->subport;
+       uint32_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+       uint32_t tc_ov_consumption_max;
+       uint32_t tc_ov_wm = subport->tc_ov_wm;
+       
+       if (subport->tc_ov == 0) {
+               return subport->tc_ov_wm_max;
+       }
+       
+       tc_ov_consumption[0] = subport->tc_credits_per_period[0] - subport->tc_credits[0];
+       tc_ov_consumption[1] = subport->tc_credits_per_period[1] - subport->tc_credits[1];
+       tc_ov_consumption[2] = subport->tc_credits_per_period[2] - subport->tc_credits[2];
+       tc_ov_consumption[3] = subport->tc_credits_per_period[3] - subport->tc_credits[3];
+       
+       tc_ov_consumption_max = subport->tc_credits_per_period[3] - 
+               (tc_ov_consumption[0] + tc_ov_consumption[1] + tc_ov_consumption[2]);
+       
+       if (tc_ov_consumption[3] > (tc_ov_consumption_max - port->mtu)) {
+               tc_ov_wm  -= tc_ov_wm >> 7;
+               if (tc_ov_wm < subport->tc_ov_wm_min) {
+                       tc_ov_wm = subport->tc_ov_wm_min;
+               }
+               return tc_ov_wm;
+       }
+       
+       tc_ov_wm += (tc_ov_wm >> 7) + 1;
+       if (tc_ov_wm > subport->tc_ov_wm_max) {
+               tc_ov_wm = subport->tc_ov_wm_max;
+       }
+       return tc_ov_wm;
+}
+
 static inline void
 grinder_credits_update(struct rte_sched_port *port, uint32_t pos)
 {
@@ -1487,29 +1537,18 @@ grinder_credits_update(struct rte_sched_port *port, uint32_t pos)
        pipe->tb_time += n_periods * params->tb_period;
 
        /* Subport TCs */
-       if (unlikely(port->time >= subport->tc_ov_time)) {
-               uint64_t n_ov_periods;
-               
-               if (unlikely(port->time >= subport->tc_time)) {
-                       subport->tc_credits[0] = subport->tc_credits_per_period[0];
-                       subport->tc_credits[1] = subport->tc_credits_per_period[1];
-                       subport->tc_credits[2] = subport->tc_credits_per_period[2];
-                       subport->tc_credits[3] = subport->tc_credits_per_period[3];
-                       
-                       subport->tc_time = port->time + subport->tc_period;
-               }
-               
-               n_ov_periods = (subport->tc_time - port->time + subport->tc_ov_period - 1) / subport->tc_ov_period;
-               
-               subport->tc_ov_credits[0] = subport->tc_credits[0] / (n_ov_periods * subport->tc_ov_n[0]);
-               subport->tc_ov_credits[1] = subport->tc_credits[1] / (n_ov_periods * subport->tc_ov_n[1]);
-               subport->tc_ov_credits[2] = subport->tc_credits[2] / (n_ov_periods * subport->tc_ov_n[2]);
-               subport->tc_ov_credits[3] = subport->tc_credits[3] / (n_ov_periods * subport->tc_ov_n[3]);
+       if (unlikely(port->time >= subport->tc_time)) {
+               subport->tc_ov_wm = grinder_tc_ov_credits_update(port, pos);
+
+               subport->tc_credits[0] = subport->tc_credits_per_period[0];
+               subport->tc_credits[1] = subport->tc_credits_per_period[1];
+               subport->tc_credits[2] = subport->tc_credits_per_period[2];
+               subport->tc_credits[3] = subport->tc_credits_per_period[3];
                
-               subport->tc_ov_time = port->time + subport->tc_ov_period;
+               subport->tc_time = port->time + subport->tc_period;
                subport->tc_ov_period_id ++;
        }
-       
+
        /* Pipe TCs */
        if (unlikely(port->time >= pipe->tc_time)) {
                pipe->tc_credits[0] = params->tc_credits_per_period[0];
@@ -1518,25 +1557,10 @@ grinder_credits_update(struct rte_sched_port *port, uint32_t pos)
                pipe->tc_credits[3] = params->tc_credits_per_period[3];
                pipe->tc_time = port->time + params->tc_period;
        }
+       
+       /* Pipe TCs - Oversubscription */
        if (unlikely(pipe->tc_ov_period_id != subport->tc_ov_period_id)) {
-               uint32_t pipe_tc_ov_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-               uint32_t tc_mask[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-               uint32_t mask[] = {UINT32_MAX, 0};
-               
-               tc_mask[0] = mask[subport->tc_ov[0]];
-               tc_mask[1] = mask[subport->tc_ov[1]];
-               tc_mask[2] = mask[subport->tc_ov[2]];
-               tc_mask[3] = mask[subport->tc_ov[3]];
-               
-               pipe_tc_ov_credits[0] = subport->tc_ov_credits[0] * params->tc_ov_weight[0];
-               pipe_tc_ov_credits[1] = subport->tc_ov_credits[1] * params->tc_ov_weight[1];
-               pipe_tc_ov_credits[2] = subport->tc_ov_credits[2] * params->tc_ov_weight[2];
-               pipe_tc_ov_credits[3] = subport->tc_ov_credits[3] * params->tc_ov_weight[3];
-               
-               pipe->tc_ov_credits[0] = (tc_mask[0] & pipe->tc_credits[0]) | ((~ tc_mask[0]) & pipe_tc_ov_credits[0]);
-               pipe->tc_ov_credits[1] = (tc_mask[1] & pipe->tc_credits[1]) | ((~ tc_mask[1]) & pipe_tc_ov_credits[1]);
-               pipe->tc_ov_credits[2] = (tc_mask[2] & pipe->tc_credits[2]) | ((~ tc_mask[2]) & pipe_tc_ov_credits[2]);
-               pipe->tc_ov_credits[3] = (tc_mask[3] & pipe->tc_credits[3]) | ((~ tc_mask[3]) & pipe_tc_ov_credits[3]);
+               pipe->tc_ov_credits = subport->tc_ov_wm * params->tc_ov_weight;
                
                pipe->tc_ov_period_id = subport->tc_ov_period_id;
        }
@@ -1544,6 +1568,8 @@ grinder_credits_update(struct rte_sched_port *port, uint32_t pos)
 
 #endif /* RTE_SCHED_TS_CREDITS_UPDATE, RTE_SCHED_SUBPORT_TC_OV */
 
+#if RTE_SCHED_TS_CREDITS_CHECK
+
 #ifndef RTE_SCHED_SUBPORT_TC_OV
 
 static inline int
@@ -1555,13 +1581,17 @@ grinder_credits_check(struct rte_sched_port *port, uint32_t pos)
        struct rte_mbuf *pkt = grinder->pkt;
        uint32_t tc_index = grinder->tc_index;
        uint32_t pkt_len = pkt->pkt.pkt_len + port->frame_overhead;
+       uint32_t subport_tb_credits = subport->tb_credits;
+       uint32_t subport_tc_credits = subport->tc_credits[tc_index];
+       uint32_t pipe_tb_credits = pipe->tb_credits;
+       uint32_t pipe_tc_credits = pipe->tc_credits[tc_index];
        int enough_credits;
 
        /* Check queue credits */
-       enough_credits = (pkt_len <= subport->tb_credits) &&
-               (pkt_len <= subport->tc_credits[tc_index]) &&
-               (pkt_len <= pipe->tb_credits) &&
-               (pkt_len <= pipe->tc_credits[tc_index]);
+       enough_credits = (pkt_len <= subport_tb_credits) &&
+               (pkt_len <= subport_tc_credits) &&
+               (pkt_len <= pipe_tb_credits) &&
+               (pkt_len <= pipe_tc_credits);
        
        if (!enough_credits) {
                return 0;
@@ -1591,7 +1621,9 @@ grinder_credits_check(struct rte_sched_port *port, uint32_t pos)
        uint32_t subport_tc_credits = subport->tc_credits[tc_index];
        uint32_t pipe_tb_credits = pipe->tb_credits;
        uint32_t pipe_tc_credits = pipe->tc_credits[tc_index];
-       uint32_t pipe_tc_ov_credits = pipe->tc_ov_credits[tc_index];
+       uint32_t pipe_tc_ov_mask1[] = {UINT32_MAX, UINT32_MAX, UINT32_MAX, pipe->tc_ov_credits};
+       uint32_t pipe_tc_ov_mask2[] = {0, 0, 0, UINT32_MAX};
+       uint32_t pipe_tc_ov_credits = pipe_tc_ov_mask1[tc_index];
        int enough_credits;
        
        /* Check pipe and subport credits */
@@ -1610,13 +1642,15 @@ grinder_credits_check(struct rte_sched_port *port, uint32_t pos)
        subport->tc_credits[tc_index] -= pkt_len;
        pipe->tb_credits -= pkt_len;
        pipe->tc_credits[tc_index] -= pkt_len;
-       pipe->tc_ov_credits[tc_index] -= pkt_len;
+       pipe->tc_ov_credits -= pipe_tc_ov_mask2[tc_index] & pkt_len;
        
        return 1;
 }
 
 #endif /* RTE_SCHED_SUBPORT_TC_OV */
 
+#endif /* RTE_SCHED_TS_CREDITS_CHECK */
+
 static inline int 
 grinder_schedule(struct rte_sched_port *port, uint32_t pos)
 {