xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/dp_hist.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
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: 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 /*
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