1 /* 2 * Copyright (c) 2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <qdf_util.h> 21 #include <qdf_mem.h> 22 #include <cdp_txrx_hist_struct.h> 23 #include "dp_hist.h" 24 25 /* 26 * dp_hist_sw_enq_dbucket: Sofware enqueue delay bucket in ms 27 * @index_0 = 0_1 ms 28 * @index_1 = 1_2 ms 29 * @index_2 = 2_3 ms 30 * @index_3 = 3_4 ms 31 * @index_4 = 4_5 ms 32 * @index_5 = 5_6 ms 33 * @index_6 = 6_7 ms 34 * @index_7 = 7_8 ms 35 * @index_8 = 8_9 ms 36 * @index_9 = 9_10 ms 37 * @index_10 = 10_11 ms 38 * @index_11 = 11_12 ms 39 * @index_12 = 12+ ms 40 */ 41 static uint16_t dp_hist_sw_enq_dbucket[CDP_HIST_BUCKET_MAX] = { 42 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; 43 44 /* 45 * cdp_hist_fw2hw_dbucket: HW enqueue to Completion Delay 46 * @index_0 = 0_10 ms 47 * @index_1 = 10_20 ms 48 * @index_2 = 20_30ms 49 * @index_3 = 30_40 ms 50 * @index_4 = 40_50 ms 51 * @index_5 = 50_60 ms 52 * @index_6 = 60_70 ms 53 * @index_7 = 70_80 ms 54 * @index_8 = 80_90 ms 55 * @index_9 = 90_100 ms 56 * @index_10 = 100_250 ms 57 * @index_11 = 250_500 ms 58 * @index_12 = 500+ ms 59 */ 60 static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = { 61 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 250, 500}; 62 63 /* 64 * dp_hist_reap2stack_bucket: Reap to stack bucket 65 * @index_0 = 0_5 ms 66 * @index_1 = 5_10 ms 67 * @index_2 = 10_15 ms 68 * @index_3 = 15_20 ms 69 * @index_4 = 20_25 ms 70 * @index_5 = 25_30 ms 71 * @index_6 = 30_35 ms 72 * @index_7 = 35_40 ms 73 * @index_8 = 40_45 ms 74 * @index_9 = 46_50 ms 75 * @index_10 = 51_55 ms 76 * @index_11 = 56_60 ms 77 * @index_12 = 60+ ms 78 */ 79 static uint16_t dp_hist_reap2stack_bucket[CDP_HIST_BUCKET_MAX] = { 80 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60}; 81 82 /* 83 * dp_hist_hw_tx_comp_dbucket: Tx HW Completion Delay bucket in us 84 * @index_0 = 0_250 us 85 * @index_1 = 250_500 us 86 * @index_2 = 500_750 us 87 * @index_3 = 750_1000 us 88 * @index_4 = 1000_1500 us 89 * @index_5 = 1500_2000 us 90 * @index_6 = 2000_2500 us 91 * @index_7 = 2500_5000 us 92 * @index_8 = 5000_6000 us 93 * @index_9 = 6000_7000 us 94 * @index_10 = 7000_8000 us 95 * @index_11 = 8000_9000 us 96 * @index_12 = 9000+ us 97 */ 98 static uint16_t dp_hist_hw_tx_comp_dbucket[CDP_HIST_BUCKET_MAX] = { 99 0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000}; 100 101 static const char *dp_hist_hw_tx_comp_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = { 102 "0 to 250 us", "250 to 500 us", 103 "500 to 750 us", "750 to 1000 us", 104 "1000 to 1500 us", "1500 to 2000 us", 105 "2000 to 2500 us", "2500 to 5000 us", 106 "5000 to 6000 us", "6000 to 7000 ms", 107 "7000 to 8000 us", "8000 to 9000 us", "9000+ us" 108 }; 109 110 const char *dp_hist_tx_hw_delay_str(uint8_t index) 111 { 112 if (index > CDP_HIST_BUCKET_MAX) 113 return "Invalid index"; 114 return dp_hist_hw_tx_comp_dbucket_str[index]; 115 } 116 117 /* 118 * dp_hist_find_bucket_idx: Find the bucket index 119 * @bucket_array: Bucket array 120 * @value: Frequency value 121 * 122 * Return: The bucket index 123 */ 124 static int dp_hist_find_bucket_idx(int16_t *bucket_array, int value) 125 { 126 uint8_t idx = CDP_HIST_BUCKET_0; 127 128 for (; idx < (CDP_HIST_BUCKET_MAX - 1); idx++) { 129 if (value < bucket_array[idx + 1]) 130 break; 131 } 132 133 return idx; 134 } 135 136 /* 137 * dp_hist_fill_buckets: Fill the histogram frequency buckets 138 * @hist_bucket: Histogram bukcets 139 * @value: Frequency value 140 * 141 * Return: void 142 */ 143 static void dp_hist_fill_buckets(struct cdp_hist_bucket *hist_bucket, int value) 144 { 145 enum cdp_hist_types hist_type; 146 int idx = CDP_HIST_BUCKET_MAX; 147 148 if (qdf_unlikely(!hist_bucket)) 149 return; 150 151 hist_type = hist_bucket->hist_type; 152 153 /* Identify the bucket the bucket and update. */ 154 switch (hist_type) { 155 case CDP_HIST_TYPE_SW_ENQEUE_DELAY: 156 idx = dp_hist_find_bucket_idx(&dp_hist_sw_enq_dbucket[0], 157 value); 158 break; 159 case CDP_HIST_TYPE_HW_COMP_DELAY: 160 idx = dp_hist_find_bucket_idx(&dp_hist_fw2hw_dbucket[0], 161 value); 162 break; 163 case CDP_HIST_TYPE_REAP_STACK: 164 idx = dp_hist_find_bucket_idx( 165 &dp_hist_reap2stack_bucket[0], value); 166 break; 167 case CDP_HIST_TYPE_HW_TX_COMP_DELAY: 168 idx = dp_hist_find_bucket_idx( 169 &dp_hist_hw_tx_comp_dbucket[0], value); 170 break; 171 default: 172 break; 173 } 174 175 if (idx == CDP_HIST_BUCKET_MAX) 176 return; 177 178 hist_bucket->freq[idx]++; 179 } 180 181 /* 182 * dp_hist_update_stats: Update histogram stats 183 * @hist_stats: Hist stats object 184 * @value: Delay value 185 * 186 * Return: void 187 */ 188 void dp_hist_update_stats(struct cdp_hist_stats *hist_stats, int value) 189 { 190 if (qdf_unlikely(!hist_stats)) 191 return; 192 193 /* 194 * Fill the histogram buckets according to the delay 195 */ 196 dp_hist_fill_buckets(&hist_stats->hist, value); 197 198 /* 199 * Compute the min, max and average. Average computed is weighted 200 * average 201 */ 202 if (value < hist_stats->min) 203 hist_stats->min = value; 204 205 if (value > hist_stats->max) 206 hist_stats->max = value; 207 208 if (qdf_unlikely(!hist_stats->avg)) 209 hist_stats->avg = value; 210 else 211 hist_stats->avg = (hist_stats->avg + value) / 2; 212 } 213 214 /* 215 * dp_copy_hist_stats(): Copy the histogram stats 216 * @src_hist_stats: Source histogram stats 217 * @dst_hist_stats: Destination histogram stats 218 * 219 * Return: void 220 */ 221 void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats, 222 struct cdp_hist_stats *dst_hist_stats) 223 { 224 uint8_t index; 225 226 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) 227 dst_hist_stats->hist.freq[index] = 228 src_hist_stats->hist.freq[index]; 229 dst_hist_stats->min = src_hist_stats->min; 230 dst_hist_stats->max = src_hist_stats->max; 231 dst_hist_stats->avg = src_hist_stats->avg; 232 } 233 234 /* 235 * dp_accumulate_hist_stats(): Accumulate the hist src to dst 236 * @src_hist_stats: Source histogram stats 237 * @dst_hist_stats: Destination histogram stats 238 * 239 * Return: void 240 */ 241 void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats, 242 struct cdp_hist_stats *dst_hist_stats) 243 { 244 uint8_t index, hist_stats_valid = 0; 245 246 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) { 247 dst_hist_stats->hist.freq[index] += 248 src_hist_stats->hist.freq[index]; 249 if (src_hist_stats->hist.freq[index]) 250 hist_stats_valid = 1; 251 } 252 /* 253 * If at least one hist-bucket has non-zero count, 254 * proceed with the detailed calculation. 255 */ 256 if (hist_stats_valid) { 257 dst_hist_stats->min = QDF_MIN(src_hist_stats->min, 258 dst_hist_stats->min); 259 dst_hist_stats->max = QDF_MAX(src_hist_stats->max, 260 dst_hist_stats->max); 261 dst_hist_stats->avg = (src_hist_stats->avg + 262 dst_hist_stats->avg) >> 1; 263 } 264 } 265 266 /* 267 * dp_hist_init(): Initialize the histogram object 268 * @hist_stats: Hist stats object 269 * @hist_type: Histogram type 270 */ 271 void dp_hist_init(struct cdp_hist_stats *hist_stats, 272 enum cdp_hist_types hist_type) 273 { 274 qdf_mem_zero(hist_stats, sizeof(*hist_stats)); 275 hist_stats->min = INT_MAX; 276 hist_stats->hist.hist_type = hist_type; 277 } 278