1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <math.h> 35 #include "rte_red.h" 36 #include <rte_random.h> 37 #include <rte_common.h> 38 39 #ifdef __INTEL_COMPILER 40 #pragma warning(disable:2259) /* conversion may lose significant bits */ 41 #endif 42 43 static int rte_red_init_done = 0; /**< Flag to indicate that global initialisation is done */ 44 uint32_t rte_red_rand_val = 0; /**< Random value cache */ 45 uint32_t rte_red_rand_seed = 0; /**< Seed for random number generation */ 46 47 /** 48 * table[i] = log2(1-Wq) * Scale * -1 49 * Wq = 1/(2^i) 50 */ 51 uint16_t rte_red_log2_1_minus_Wq[RTE_RED_WQ_LOG2_NUM]; 52 53 /** 54 * table[i] = 2^(i/16) * Scale 55 */ 56 uint16_t rte_red_pow2_frac_inv[16]; 57 58 /** 59 * @brief Initialize tables used to compute average 60 * queue size when queue is empty. 61 */ 62 static void 63 __rte_red_init_tables(void) 64 { 65 uint32_t i = 0; 66 double scale = 0.0; 67 double table_size = 0.0; 68 69 scale = (double)(1 << RTE_RED_SCALING); 70 table_size = (double)(RTE_DIM(rte_red_pow2_frac_inv)); 71 72 for (i = 0; i < RTE_DIM(rte_red_pow2_frac_inv); i++) { 73 double m = (double)i; 74 75 rte_red_pow2_frac_inv[i] = (uint16_t) round(scale / pow(2, m / table_size)); 76 } 77 78 scale = 1024.0; 79 80 RTE_ASSERT(RTE_RED_WQ_LOG2_NUM == RTE_DIM(rte_red_log2_1_minus_Wq)); 81 82 for (i = RTE_RED_WQ_LOG2_MIN; i <= RTE_RED_WQ_LOG2_MAX; i++) { 83 double n = (double)i; 84 double Wq = pow(2, -n); 85 uint32_t index = i - RTE_RED_WQ_LOG2_MIN; 86 87 rte_red_log2_1_minus_Wq[index] = (uint16_t) round(-1.0 * scale * log2(1.0 - Wq)); 88 /** 89 * Table entry of zero, corresponds to a Wq of zero 90 * which is not valid (avg would remain constant no 91 * matter how long the queue is empty). So we have 92 * to check for zero and round up to one. 93 */ 94 if (rte_red_log2_1_minus_Wq[index] == 0) { 95 rte_red_log2_1_minus_Wq[index] = 1; 96 } 97 } 98 } 99 100 int 101 rte_red_rt_data_init(struct rte_red *red) 102 { 103 if (red == NULL) 104 return -1; 105 106 red->avg = 0; 107 red->count = 0; 108 red->q_time = 0; 109 return 0; 110 } 111 112 int 113 rte_red_config_init(struct rte_red_config *red_cfg, 114 const uint16_t wq_log2, 115 const uint16_t min_th, 116 const uint16_t max_th, 117 const uint16_t maxp_inv) 118 { 119 if (red_cfg == NULL) { 120 return -1; 121 } 122 if (max_th > RTE_RED_MAX_TH_MAX) { 123 return -2; 124 } 125 if (min_th >= max_th) { 126 return -3; 127 } 128 if (wq_log2 > RTE_RED_WQ_LOG2_MAX) { 129 return -4; 130 } 131 if (wq_log2 < RTE_RED_WQ_LOG2_MIN) { 132 return -5; 133 } 134 if (maxp_inv < RTE_RED_MAXP_INV_MIN) { 135 return -6; 136 } 137 if (maxp_inv > RTE_RED_MAXP_INV_MAX) { 138 return -7; 139 } 140 141 /** 142 * Initialize the RED module if not already done 143 */ 144 if (!rte_red_init_done) { 145 rte_red_rand_seed = rte_rand(); 146 rte_red_rand_val = rte_fast_rand(); 147 __rte_red_init_tables(); 148 rte_red_init_done = 1; 149 } 150 151 red_cfg->min_th = ((uint32_t) min_th) << (wq_log2 + RTE_RED_SCALING); 152 red_cfg->max_th = ((uint32_t) max_th) << (wq_log2 + RTE_RED_SCALING); 153 red_cfg->pa_const = (2 * (max_th - min_th) * maxp_inv) << RTE_RED_SCALING; 154 red_cfg->maxp_inv = maxp_inv; 155 red_cfg->wq_log2 = wq_log2; 156 157 return 0; 158 } 159