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