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