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_delay_percentile_dbucket: tx hw completion delay bucket in delay 119 * bound percentile 120 * @index_0 = 0_10 121 * @index_1 = 10_20 122 * @index_2 = 20_30 123 * @index_3 = 30_40 124 * @index_4 = 40_50 125 * @index_5 = 50_60 126 * @index_6 = 60_70 127 * @index_7 = 70_80 128 * @index_8 = 80_100 129 * @index_9 = 90_100 130 * @index_10 = 100_150 131 * @index_11 = 150_200 132 * @index_12 = 200+ 133 */ 134 static uint16_t dp_hist_delay_percentile_dbucket[CDP_HIST_BUCKET_MAX] = { 135 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200}; 136 137 static 138 const char *dp_hist_delay_percentile_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = { 139 "0 to 10%", "10 to 20%", 140 "20 to 30%", "30 to 40%", 141 "40 to 50%", "50 to 60%", 142 "60 to 70%", "70 to 80%", 143 "80 to 90% ", "90 to 100%", 144 "100 to 150% ", "150 to 200%", "200+%" 145 }; 146 147 const char *dp_hist_delay_percentile_str(uint8_t index) 148 { 149 if (index > CDP_HIST_BUCKET_MAX) 150 return "Invalid index"; 151 return dp_hist_delay_percentile_dbucket_str[index]; 152 } 153 154 /* 155 * dp_hist_find_bucket_idx: Find the bucket index 156 * @bucket_array: Bucket array 157 * @value: Frequency value 158 * 159 * Return: The bucket index 160 */ 161 static int dp_hist_find_bucket_idx(int16_t *bucket_array, int value) 162 { 163 uint8_t idx = CDP_HIST_BUCKET_0; 164 165 for (; idx < (CDP_HIST_BUCKET_MAX - 1); idx++) { 166 if (value < bucket_array[idx + 1]) 167 break; 168 } 169 170 return idx; 171 } 172 173 /* 174 * dp_hist_fill_buckets: Fill the histogram frequency buckets 175 * @hist_bucket: Histogram bukcets 176 * @value: Frequency value 177 * 178 * Return: void 179 */ 180 static void dp_hist_fill_buckets(struct cdp_hist_bucket *hist_bucket, int value) 181 { 182 enum cdp_hist_types hist_type; 183 int idx = CDP_HIST_BUCKET_MAX; 184 185 if (qdf_unlikely(!hist_bucket)) 186 return; 187 188 hist_type = hist_bucket->hist_type; 189 190 /* Identify the bucket the bucket and update. */ 191 switch (hist_type) { 192 case CDP_HIST_TYPE_SW_ENQEUE_DELAY: 193 idx = dp_hist_find_bucket_idx(&dp_hist_sw_enq_dbucket[0], 194 value); 195 break; 196 case CDP_HIST_TYPE_HW_COMP_DELAY: 197 idx = dp_hist_find_bucket_idx(&dp_hist_fw2hw_dbucket[0], 198 value); 199 break; 200 case CDP_HIST_TYPE_REAP_STACK: 201 idx = dp_hist_find_bucket_idx( 202 &dp_hist_reap2stack_bucket[0], value); 203 break; 204 case CDP_HIST_TYPE_HW_TX_COMP_DELAY: 205 idx = dp_hist_find_bucket_idx( 206 &dp_hist_hw_tx_comp_dbucket[0], value); 207 break; 208 case CDP_HIST_TYPE_DELAY_PERCENTILE: 209 idx = dp_hist_find_bucket_idx( 210 &dp_hist_delay_percentile_dbucket[0], value); 211 break; 212 default: 213 break; 214 } 215 216 if (idx == CDP_HIST_BUCKET_MAX) 217 return; 218 219 hist_bucket->freq[idx]++; 220 } 221 222 /* 223 * dp_hist_update_stats: Update histogram stats 224 * @hist_stats: Hist stats object 225 * @value: Delay value 226 * 227 * Return: void 228 */ 229 void dp_hist_update_stats(struct cdp_hist_stats *hist_stats, int value) 230 { 231 if (qdf_unlikely(!hist_stats)) 232 return; 233 234 /* 235 * Fill the histogram buckets according to the delay 236 */ 237 dp_hist_fill_buckets(&hist_stats->hist, value); 238 239 /* 240 * Compute the min, max and average. Average computed is weighted 241 * average 242 */ 243 if (value < hist_stats->min) 244 hist_stats->min = value; 245 246 if (value > hist_stats->max) 247 hist_stats->max = value; 248 249 if (qdf_unlikely(!hist_stats->avg)) 250 hist_stats->avg = value; 251 else 252 hist_stats->avg = (hist_stats->avg + value) / 2; 253 } 254 255 /* 256 * dp_copy_hist_stats(): Copy the histogram stats 257 * @src_hist_stats: Source histogram stats 258 * @dst_hist_stats: Destination histogram stats 259 * 260 * Return: void 261 */ 262 void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats, 263 struct cdp_hist_stats *dst_hist_stats) 264 { 265 uint8_t index; 266 267 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) 268 dst_hist_stats->hist.freq[index] = 269 src_hist_stats->hist.freq[index]; 270 dst_hist_stats->min = src_hist_stats->min; 271 dst_hist_stats->max = src_hist_stats->max; 272 dst_hist_stats->avg = src_hist_stats->avg; 273 } 274 275 /* 276 * dp_accumulate_hist_stats(): Accumulate the hist src to dst 277 * @src_hist_stats: Source histogram stats 278 * @dst_hist_stats: Destination histogram stats 279 * 280 * Return: void 281 */ 282 void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats, 283 struct cdp_hist_stats *dst_hist_stats) 284 { 285 uint8_t index, hist_stats_valid = 0; 286 287 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) { 288 dst_hist_stats->hist.freq[index] += 289 src_hist_stats->hist.freq[index]; 290 if (src_hist_stats->hist.freq[index]) 291 hist_stats_valid = 1; 292 } 293 /* 294 * If at least one hist-bucket has non-zero count, 295 * proceed with the detailed calculation. 296 */ 297 if (hist_stats_valid) { 298 dst_hist_stats->min = QDF_MIN(src_hist_stats->min, 299 dst_hist_stats->min); 300 dst_hist_stats->max = QDF_MAX(src_hist_stats->max, 301 dst_hist_stats->max); 302 dst_hist_stats->avg = (src_hist_stats->avg + 303 dst_hist_stats->avg) >> 1; 304 } 305 } 306 307 /* 308 * dp_hist_init(): Initialize the histogram object 309 * @hist_stats: Hist stats object 310 * @hist_type: Histogram type 311 */ 312 void dp_hist_init(struct cdp_hist_stats *hist_stats, 313 enum cdp_hist_types hist_type) 314 { 315 qdf_mem_zero(hist_stats, sizeof(*hist_stats)); 316 hist_stats->min = INT_MAX; 317 hist_stats->hist.hist_type = hist_type; 318 } 319