1 /* 2 * Copyright (c) 2020 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <qdf_util.h> 20 #include <qdf_mem.h> 21 #include <cdp_txrx_hist_struct.h> 22 #include "dp_hist.h" 23 24 /* 25 * dp_hist_sw_enq_dbucket: Sofware enqueue delay bucket in ms 26 * @index_0 = 0_1 ms 27 * @index_1 = 1_2 ms 28 * @index_2 = 2_3 ms 29 * @index_3 = 3_4 ms 30 * @index_4 = 4_5 ms 31 * @index_5 = 5_6 ms 32 * @index_6 = 6_7 ms 33 * @index_7 = 7_8 ms 34 * @index_8 = 8_9 ms 35 * @index_8 = 9+ ms 36 */ 37 static uint16_t dp_hist_sw_enq_dbucket[CDP_HIST_BUCKET_MAX] = { 38 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 39 40 /* 41 * cdp_hist_fw2hw_dbucket: HW enqueue to Completion Delay 42 * @index_0 = 0_10 ms 43 * @index_1 = 10_20 ms 44 * @index_2 = 20_30ms 45 * @index_3 = 30_40 ms 46 * @index_4 = 40_50 ms 47 * @index_5 = 50_60 ms 48 * @index_6 = 60_70 ms 49 * @index_7 = 70_80 ms 50 * @index_8 = 80_90 ms 51 * @index_9 = 90+ ms 52 */ 53 static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = { 54 0, 10, 20, 30, 40, 50, 60, 70, 80, 90}; 55 56 /* 57 * dp_hist_reap2stack_bucket: Reap to stack bucket 58 * @index_0 = 0_5 ms 59 * @index_1 = 5_10 ms 60 * @index_2 = 10_15 ms 61 * @index_3 = 15_20 ms 62 * @index_4 = 20_25 ms 63 * @index_5 = 25_30 ms 64 * @index_6 = 30_35 ms 65 * @index_7 = 35_40 ms 66 * @index_8 = 40_45 ms 67 * @index_9 = 45+ ms 68 */ 69 static uint16_t dp_hist_reap2stack_bucket[CDP_HIST_BUCKET_MAX] = { 70 0, 5, 10, 15, 20, 25, 30, 35, 40, 45}; 71 72 /* 73 * dp_hist_find_bucket_idx: Find the bucket index 74 * @bucket_array: Bucket array 75 * @value: Frequency value 76 * 77 * Return: The bucket index 78 */ 79 static int dp_hist_find_bucket_idx(int16_t *bucket_array, int value) 80 { 81 uint8_t idx = CDP_HIST_BUCKET_0; 82 83 for (; idx < (CDP_HIST_BUCKET_MAX - 1); idx++) { 84 if (value < bucket_array[idx + 1]) 85 break; 86 } 87 88 return idx; 89 } 90 91 /* 92 * dp_hist_fill_buckets: Fill the histogram frequency buckets 93 * @hist_bucket: Histogram bukcets 94 * @value: Frequency value 95 * 96 * Return: void 97 */ 98 static void dp_hist_fill_buckets(struct cdp_hist_bucket *hist_bucket, int value) 99 { 100 enum cdp_hist_types hist_type; 101 int idx = CDP_HIST_BUCKET_MAX; 102 103 if (qdf_unlikely(!hist_bucket)) 104 return; 105 106 hist_type = hist_bucket->hist_type; 107 108 /* Identify the bucket the bucket and update. */ 109 switch (hist_type) { 110 case CDP_HIST_TYPE_SW_ENQEUE_DELAY: 111 idx = dp_hist_find_bucket_idx(&dp_hist_sw_enq_dbucket[0], 112 value); 113 break; 114 case CDP_HIST_TYPE_HW_COMP_DELAY: 115 idx = dp_hist_find_bucket_idx(&dp_hist_fw2hw_dbucket[0], 116 value); 117 break; 118 case CDP_HIST_TYPE_REAP_STACK: 119 idx = dp_hist_find_bucket_idx( 120 &dp_hist_reap2stack_bucket[0], value); 121 break; 122 default: 123 break; 124 } 125 126 if (idx == CDP_HIST_BUCKET_MAX) 127 return; 128 129 hist_bucket->freq[idx]++; 130 } 131 132 /* 133 * dp_hist_update_stats: Update histogram stats 134 * @hist_stats: Hist stats object 135 * @value: Delay value 136 * 137 * Return: void 138 */ 139 void dp_hist_update_stats(struct cdp_hist_stats *hist_stats, int value) 140 { 141 if (qdf_unlikely(!hist_stats)) 142 return; 143 144 /* 145 * Fill the histogram buckets according to the delay 146 */ 147 dp_hist_fill_buckets(&hist_stats->hist, value); 148 149 /* 150 * Compute the min, max and average. Average computed is weighted 151 * average 152 */ 153 if (value < hist_stats->min) 154 hist_stats->min = value; 155 156 if (value > hist_stats->max) 157 hist_stats->max = value; 158 159 if (qdf_unlikely(!hist_stats->avg)) 160 hist_stats->avg = value; 161 else 162 hist_stats->avg = hist_stats->avg + 163 ((value - hist_stats->avg) >> HIST_AVG_WEIGHT_DENOM); 164 } 165 166 /* 167 * dp_copy_hist_stats(): Copy the histogram stats 168 * @src_hist_stats: Source histogram stats 169 * @dst_hist_stats: Destination histogram stats 170 * 171 * Return: void 172 */ 173 void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats, 174 struct cdp_hist_stats *dst_hist_stats) 175 { 176 uint8_t index; 177 178 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) 179 dst_hist_stats->hist.freq[index] = 180 src_hist_stats->hist.freq[index]; 181 dst_hist_stats->min = src_hist_stats->min; 182 dst_hist_stats->max = src_hist_stats->max; 183 dst_hist_stats->avg = src_hist_stats->avg; 184 } 185 186 /* 187 * dp_accumulate_hist_stats(): Accumulate the hist src to dst 188 * @src_hist_stats: Source histogram stats 189 * @dst_hist_stats: Destination histogram stats 190 * 191 * Return: void 192 */ 193 void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats, 194 struct cdp_hist_stats *dst_hist_stats) 195 { 196 uint8_t index; 197 198 for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) 199 dst_hist_stats->hist.freq[index] += 200 src_hist_stats->hist.freq[index]; 201 dst_hist_stats->min = QDF_MIN(src_hist_stats->min, dst_hist_stats->min); 202 dst_hist_stats->max = QDF_MAX(src_hist_stats->max, dst_hist_stats->max); 203 dst_hist_stats->avg = (src_hist_stats->avg + dst_hist_stats->avg) >> 1; 204 } 205 206 /* 207 * dp_hist_init(): Initialize the histogram object 208 * @hist_stats: Hist stats object 209 * @hist_type: Histogram type 210 */ 211 void dp_hist_init(struct cdp_hist_stats *hist_stats, 212 enum cdp_hist_types hist_type) 213 { 214 qdf_mem_zero(hist_stats, sizeof(*hist_stats)); 215 hist_stats->hist.hist_type = hist_type; 216 } 217