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
dp_hist_tx_hw_delay_str(uint8_t index)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
dp_hist_delay_percentile_str(uint8_t index)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 */
dp_hist_find_bucket_idx(int16_t * bucket_array,int value)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 */
dp_hist_fill_buckets(struct cdp_hist_bucket * hist_bucket,int value)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
dp_hist_update_stats(struct cdp_hist_stats * hist_stats,int value)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
dp_copy_hist_stats(struct cdp_hist_stats * src_hist_stats,struct cdp_hist_stats * dst_hist_stats)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
dp_accumulate_hist_stats(struct cdp_hist_stats * src_hist_stats,struct cdp_hist_stats * dst_hist_stats)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
dp_hist_init(struct cdp_hist_stats * hist_stats,enum cdp_hist_types hist_type)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