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 #ifndef WLAN_CONFIG_TX_DELAY 26 /* 27 * dp_hist_sw_enq_dbucket: Sofware enqueue delay bucket in ms 28 * @index_0 = 0_1 ms 29 * @index_1 = 1_2 ms 30 * @index_2 = 2_3 ms 31 * @index_3 = 3_4 ms 32 * @index_4 = 4_5 ms 33 * @index_5 = 5_6 ms 34 * @index_6 = 6_7 ms 35 * @index_7 = 7_8 ms 36 * @index_8 = 8_9 ms 37 * @index_9 = 9_10 ms 38 * @index_10 = 10_11 ms 39 * @index_11 = 11_12 ms 40 * @index_12 = 12+ ms 41 */ 42 static uint16_t dp_hist_sw_enq_dbucket[CDP_HIST_BUCKET_MAX] = { 43 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; 44 45 /* 46 * cdp_hist_fw2hw_dbucket: HW enqueue to Completion Delay 47 * @index_0 = 0_10 ms 48 * @index_1 = 10_20 ms 49 * @index_2 = 20_30ms 50 * @index_3 = 30_40 ms 51 * @index_4 = 40_50 ms 52 * @index_5 = 50_60 ms 53 * @index_6 = 60_70 ms 54 * @index_7 = 70_80 ms 55 * @index_8 = 80_90 ms 56 * @index_9 = 90_100 ms 57 * @index_10 = 100_250 ms 58 * @index_11 = 250_500 ms 59 * @index_12 = 500+ ms 60 */ 61 static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = { 62 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 250, 500}; 63 #else 64 /* 65 * dp_hist_sw_enq_dbucket: Sofware enqueue delay bucket in us 66 * @index_0 = 0_250 us 67 * @index_1 = 250_500 us 68 * @index_2 = 500_750 us 69 * @index_3 = 750_1000 us 70 * @index_4 = 1000_1500 us 71 * @index_5 = 1500_2000 us 72 * @index_6 = 2000_2500 us 73 * @index_7 = 2500_5000 us 74 * @index_8 = 5000_6000 us 75 * @index_9 = 6000_7000 us 76 * @index_10 = 7000_8000 us 77 * @index_11 = 8000_9000 us 78 * @index_12 = 9000+ us 79 */ 80 static uint16_t dp_hist_sw_enq_dbucket[CDP_HIST_BUCKET_MAX] = { 81 0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000}; 82 83 /* 84 * cdp_hist_fw2hw_dbucket: HW enqueue to Completion Delay in us 85 * @index_0 = 0_250 us 86 * @index_1 = 250_500 us 87 * @index_2 = 500_750 us 88 * @index_3 = 750_1000 us 89 * @index_4 = 1000_1500 us 90 * @index_5 = 1500_2000 us 91 * @index_6 = 2000_2500 us 92 * @index_7 = 2500_5000 us 93 * @index_8 = 5000_6000 us 94 * @index_9 = 6000_7000 us 95 * @index_10 = 7000_8000 us 96 * @index_11 = 8000_9000 us 97 * @index_12 = 9000+ us 98 */ 99 100 static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = { 101 0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000}; 102 #endif 103 104 /* 105 * dp_hist_reap2stack_bucket: Reap to stack bucket 106 * @index_0 = 0_5 ms 107 * @index_1 = 5_10 ms 108 * @index_2 = 10_15 ms 109 * @index_3 = 15_20 ms 110 * @index_4 = 20_25 ms 111 * @index_5 = 25_30 ms 112 * @index_6 = 30_35 ms 113 * @index_7 = 35_40 ms 114 * @index_8 = 40_45 ms 115 * @index_9 = 46_50 ms 116 * @index_10 = 51_55 ms 117 * @index_11 = 56_60 ms 118 * @index_12 = 60+ ms 119 */ 120 static uint16_t dp_hist_reap2stack_bucket[CDP_HIST_BUCKET_MAX] = { 121 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60}; 122 123 /* 124 * dp_hist_hw_tx_comp_dbucket: tx hw completion delay bucket in us 125 * @index_0 = 0_250 us 126 * @index_1 = 250_500 us 127 * @index_2 = 500_750 us 128 * @index_3 = 750_1000 us 129 * @index_4 = 1000_1500 us 130 * @index_5 = 1500_2000 us 131 * @index_6 = 2000_2500 us 132 * @index_7 = 2500_5000 us 133 * @index_8 = 5000_6000 us 134 * @index_9 = 6000_7000 us 135 * @index_10 = 7000_8000 us 136 * @index_11 = 8000_9000 us 137 * @index_12 = 9000+ us 138 */ 139 static uint16_t dp_hist_hw_tx_comp_dbucket[CDP_HIST_BUCKET_MAX] = { 140 0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000}; 141 142 static const char *dp_hist_hw_tx_comp_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = { 143 "0 to 250 us", "250 to 500 us", 144 "500 to 750 us", "750 to 1000 us", 145 "1000 to 1500 us", "1500 to 2000 us", 146 "2000 to 2500 us", "2500 to 5000 us", 147 "5000 to 6000 us", "6000 to 7000 ms", 148 "7000 to 8000 us", "8000 to 9000 us", "9000+ us" 149 }; 150 151 const char *dp_hist_tx_hw_delay_str(uint8_t index) 152 { 153 if (index > CDP_HIST_BUCKET_MAX) 154 return "Invalid index"; 155 return dp_hist_hw_tx_comp_dbucket_str[index]; 156 } 157 158 /* 159 * dp_hist_delay_percentile_dbucket: tx hw completion delay bucket in delay 160 * bound percentile 161 * @index_0 = 0_10 162 * @index_1 = 10_20 163 * @index_2 = 20_30 164 * @index_3 = 30_40 165 * @index_4 = 40_50 166 * @index_5 = 50_60 167 * @index_6 = 60_70 168 * @index_7 = 70_80 169 * @index_8 = 80_100 170 * @index_9 = 90_100 171 * @index_10 = 100_150 172 * @index_11 = 150_200 173 * @index_12 = 200+ 174 */ 175 static uint16_t dp_hist_delay_percentile_dbucket[CDP_HIST_BUCKET_MAX] = { 176 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200}; 177 178 static 179 const char *dp_hist_delay_percentile_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = { 180 "0 to 10%", "10 to 20%", 181 "20 to 30%", "30 to 40%", 182 "40 to 50%", "50 to 60%", 183 "60 to 70%", "70 to 80%", 184 "80 to 90% ", "90 to 100%", 185 "100 to 150% ", "150 to 200%", "200+%" 186 }; 187 188 const char *dp_hist_delay_percentile_str(uint8_t index) 189 { 190 if (index > CDP_HIST_BUCKET_MAX) 191 return "Invalid index"; 192 return dp_hist_delay_percentile_dbucket_str[index]; 193 } 194 195 /* 196 * dp_hist_find_bucket_idx: Find the bucket index 197 * @bucket_array: Bucket array 198 * @value: Frequency value 199 * 200 * Return: The bucket index 201 */ 202 static int dp_hist_find_bucket_idx(int16_t *bucket_array, int value) 203 { 204 uint8_t idx = CDP_HIST_BUCKET_0; 205 206 for (; idx < (CDP_HIST_BUCKET_MAX - 1); idx++) { 207 if (value < bucket_array[idx + 1]) 208 break; 209 } 210 211 return idx; 212 } 213 214 /* 215 * dp_hist_fill_buckets: Fill the histogram frequency buckets 216 * @hist_bucket: Histogram bukcets 217 * @value: Frequency value 218 * 219 * Return: void 220 */ 221 static void dp_hist_fill_buckets(struct cdp_hist_bucket *hist_bucket, int value) 222 { 223 enum cdp_hist_types hist_type; 224 int idx = CDP_HIST_BUCKET_MAX; 225 226 if (qdf_unlikely(!hist_bucket)) 227 return; 228 229 hist_type = hist_bucket->hist_type; 230 231 /* Identify the bucket the bucket and update. */ 232 switch (hist_type) { 233 case CDP_HIST_TYPE_SW_ENQEUE_DELAY: 234 idx = dp_hist_find_bucket_idx(&dp_hist_sw_enq_dbucket[0], 235 value); 236 break; 237 case CDP_HIST_TYPE_HW_COMP_DELAY: 238 idx = dp_hist_find_bucket_idx(&dp_hist_fw2hw_dbucket[0], 239 value); 240 break; 241 case CDP_HIST_TYPE_REAP_STACK: 242 idx = dp_hist_find_bucket_idx( 243 &dp_hist_reap2stack_bucket[0], value); 244 break; 245 case CDP_HIST_TYPE_HW_TX_COMP_DELAY: 246 idx = dp_hist_find_bucket_idx( 247 &dp_hist_hw_tx_comp_dbucket[0], value); 248 break; 249 case CDP_HIST_TYPE_DELAY_PERCENTILE: 250 idx = dp_hist_find_bucket_idx( 251 &dp_hist_delay_percentile_dbucket[0], value); 252 break; 253 default: 254 break; 255 } 256 257 if (idx == CDP_HIST_BUCKET_MAX) 258 return; 259 260 hist_bucket->freq[idx]++; 261 } 262 263 /* 264 * dp_hist_update_stats: Update histogram stats 265 * @hist_stats: Hist stats object 266 * @value: Delay value 267 * 268 * Return: void 269 */ 270 void dp_hist_update_stats(struct cdp_hist_stats *hist_stats, int value) 271 { 272 if (qdf_unlikely(!hist_stats)) 273 return; 274 275 /* 276 * Fill the histogram buckets according to the delay 277 */ 278 dp_hist_fill_buckets(&hist_stats->hist, value); 279 280 /* 281 * Compute the min, max and average. Average computed is weighted 282 * average 283 */ 284 if (value < hist_stats->min) 285 hist_stats->min = value; 286 287 if (value > hist_stats->max) 288 hist_stats->max = value; 289 290 if (qdf_unlikely(!hist_stats->avg)) 291 hist_stats->avg = value; 292 else 293 hist_stats->avg = (hist_stats->avg + value) / 2; 294 } 295 296 /* 297 * dp_copy_hist_stats(): Copy the histogram stats 298 * @src_hist_stats: Source histogram stats 299 * @dst_hist_stats: Destination histogram stats 300 * 301 * Return: void 302 */ 303 void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats, 304 struct cdp_hist_stats *dst_hist_stats) 305 { 306 uint8_t index; 307 308 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) 309 dst_hist_stats->hist.freq[index] = 310 src_hist_stats->hist.freq[index]; 311 dst_hist_stats->min = src_hist_stats->min; 312 dst_hist_stats->max = src_hist_stats->max; 313 dst_hist_stats->avg = src_hist_stats->avg; 314 } 315 316 /* 317 * dp_accumulate_hist_stats(): Accumulate the hist src to dst 318 * @src_hist_stats: Source histogram stats 319 * @dst_hist_stats: Destination histogram stats 320 * 321 * Return: void 322 */ 323 void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats, 324 struct cdp_hist_stats *dst_hist_stats) 325 { 326 uint8_t index, hist_stats_valid = 0; 327 328 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) { 329 dst_hist_stats->hist.freq[index] += 330 src_hist_stats->hist.freq[index]; 331 if (src_hist_stats->hist.freq[index]) 332 hist_stats_valid = 1; 333 } 334 /* 335 * If at least one hist-bucket has non-zero count, 336 * proceed with the detailed calculation. 337 */ 338 if (hist_stats_valid) { 339 dst_hist_stats->min = QDF_MIN(src_hist_stats->min, 340 dst_hist_stats->min); 341 dst_hist_stats->max = QDF_MAX(src_hist_stats->max, 342 dst_hist_stats->max); 343 dst_hist_stats->avg = (src_hist_stats->avg + 344 dst_hist_stats->avg) >> 1; 345 } 346 } 347 348 /* 349 * dp_hist_init(): Initialize the histogram object 350 * @hist_stats: Hist stats object 351 * @hist_type: Histogram type 352 */ 353 void dp_hist_init(struct cdp_hist_stats *hist_stats, 354 enum cdp_hist_types hist_type) 355 { 356 qdf_mem_zero(hist_stats, sizeof(*hist_stats)); 357 hist_stats->min = INT_MAX; 358 hist_stats->hist.hist_type = hist_type; 359 } 360