1 /* 2 * Copyright (c) 2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 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: Software 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: Software 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 void dp_hist_update_stats(struct cdp_hist_stats *hist_stats, int value) 264 { 265 if (qdf_unlikely(!hist_stats)) 266 return; 267 268 /* 269 * Fill the histogram buckets according to the delay 270 */ 271 dp_hist_fill_buckets(&hist_stats->hist, value); 272 273 /* 274 * Compute the min, max and average. Average computed is weighted 275 * average 276 */ 277 if (value < hist_stats->min) 278 hist_stats->min = value; 279 280 if (value > hist_stats->max) 281 hist_stats->max = value; 282 283 if (qdf_unlikely(!hist_stats->avg)) 284 hist_stats->avg = value; 285 else 286 hist_stats->avg = (hist_stats->avg + value) / 2; 287 } 288 289 void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats, 290 struct cdp_hist_stats *dst_hist_stats) 291 { 292 uint8_t index; 293 294 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) 295 dst_hist_stats->hist.freq[index] = 296 src_hist_stats->hist.freq[index]; 297 dst_hist_stats->min = src_hist_stats->min; 298 dst_hist_stats->max = src_hist_stats->max; 299 dst_hist_stats->avg = src_hist_stats->avg; 300 } 301 302 void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats, 303 struct cdp_hist_stats *dst_hist_stats) 304 { 305 uint8_t index, hist_stats_valid = 0; 306 307 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) { 308 dst_hist_stats->hist.freq[index] += 309 src_hist_stats->hist.freq[index]; 310 if (src_hist_stats->hist.freq[index]) 311 hist_stats_valid = 1; 312 } 313 /* 314 * If at least one hist-bucket has non-zero count, 315 * proceed with the detailed calculation. 316 */ 317 if (hist_stats_valid) { 318 dst_hist_stats->min = QDF_MIN(src_hist_stats->min, 319 dst_hist_stats->min); 320 dst_hist_stats->max = QDF_MAX(src_hist_stats->max, 321 dst_hist_stats->max); 322 dst_hist_stats->avg = (src_hist_stats->avg + 323 dst_hist_stats->avg) >> 1; 324 } 325 } 326 327 void dp_hist_init(struct cdp_hist_stats *hist_stats, 328 enum cdp_hist_types hist_type) 329 { 330 qdf_mem_zero(hist_stats, sizeof(*hist_stats)); 331 hist_stats->min = INT_MAX; 332 hist_stats->hist.hist_type = hist_type; 333 } 334