xref: /wlan-driver/qca-wifi-host-cmn/dp/wifi3.0/dp_hist.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name #include <qdf_util.h>
21*5113495bSYour Name #include <qdf_mem.h>
22*5113495bSYour Name #include <cdp_txrx_hist_struct.h>
23*5113495bSYour Name #include "dp_hist.h"
24*5113495bSYour Name 
25*5113495bSYour Name #ifndef WLAN_CONFIG_TX_DELAY
26*5113495bSYour Name /*
27*5113495bSYour Name  * dp_hist_sw_enq_dbucket: Software enqueue delay bucket in ms
28*5113495bSYour Name  * @index_0 = 0_1 ms
29*5113495bSYour Name  * @index_1 = 1_2 ms
30*5113495bSYour Name  * @index_2 = 2_3 ms
31*5113495bSYour Name  * @index_3 = 3_4 ms
32*5113495bSYour Name  * @index_4 = 4_5 ms
33*5113495bSYour Name  * @index_5 = 5_6 ms
34*5113495bSYour Name  * @index_6 = 6_7 ms
35*5113495bSYour Name  * @index_7 = 7_8 ms
36*5113495bSYour Name  * @index_8 = 8_9 ms
37*5113495bSYour Name  * @index_9 = 9_10 ms
38*5113495bSYour Name  * @index_10 = 10_11 ms
39*5113495bSYour Name  * @index_11 = 11_12 ms
40*5113495bSYour Name  * @index_12 = 12+ ms
41*5113495bSYour Name  */
42*5113495bSYour Name static uint16_t dp_hist_sw_enq_dbucket[CDP_HIST_BUCKET_MAX] = {
43*5113495bSYour Name 	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
44*5113495bSYour Name 
45*5113495bSYour Name /*
46*5113495bSYour Name  * cdp_hist_fw2hw_dbucket: HW enqueue to Completion Delay
47*5113495bSYour Name  * @index_0 = 0_10 ms
48*5113495bSYour Name  * @index_1 = 10_20 ms
49*5113495bSYour Name  * @index_2 = 20_30ms
50*5113495bSYour Name  * @index_3 = 30_40 ms
51*5113495bSYour Name  * @index_4 = 40_50 ms
52*5113495bSYour Name  * @index_5 = 50_60 ms
53*5113495bSYour Name  * @index_6 = 60_70 ms
54*5113495bSYour Name  * @index_7 = 70_80 ms
55*5113495bSYour Name  * @index_8 = 80_90 ms
56*5113495bSYour Name  * @index_9 = 90_100 ms
57*5113495bSYour Name  * @index_10 = 100_250 ms
58*5113495bSYour Name  * @index_11 = 250_500 ms
59*5113495bSYour Name  * @index_12 = 500+ ms
60*5113495bSYour Name  */
61*5113495bSYour Name static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = {
62*5113495bSYour Name 	0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 250, 500};
63*5113495bSYour Name #else
64*5113495bSYour Name /*
65*5113495bSYour Name  * dp_hist_sw_enq_dbucket: Software enqueue delay bucket in us
66*5113495bSYour Name  * @index_0 = 0_250 us
67*5113495bSYour Name  * @index_1 = 250_500 us
68*5113495bSYour Name  * @index_2 = 500_750 us
69*5113495bSYour Name  * @index_3 = 750_1000 us
70*5113495bSYour Name  * @index_4 = 1000_1500 us
71*5113495bSYour Name  * @index_5 = 1500_2000 us
72*5113495bSYour Name  * @index_6 = 2000_2500 us
73*5113495bSYour Name  * @index_7 = 2500_5000 us
74*5113495bSYour Name  * @index_8 = 5000_6000 us
75*5113495bSYour Name  * @index_9 = 6000_7000 us
76*5113495bSYour Name  * @index_10 = 7000_8000 us
77*5113495bSYour Name  * @index_11 = 8000_9000 us
78*5113495bSYour Name  * @index_12 = 9000+ us
79*5113495bSYour Name  */
80*5113495bSYour Name static uint16_t dp_hist_sw_enq_dbucket[CDP_HIST_BUCKET_MAX] = {
81*5113495bSYour Name 	0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000};
82*5113495bSYour Name 
83*5113495bSYour Name /*
84*5113495bSYour Name  * cdp_hist_fw2hw_dbucket: HW enqueue to Completion Delay in us
85*5113495bSYour Name  * @index_0 = 0_250 us
86*5113495bSYour Name  * @index_1 = 250_500 us
87*5113495bSYour Name  * @index_2 = 500_750 us
88*5113495bSYour Name  * @index_3 = 750_1000 us
89*5113495bSYour Name  * @index_4 = 1000_1500 us
90*5113495bSYour Name  * @index_5 = 1500_2000 us
91*5113495bSYour Name  * @index_6 = 2000_2500 us
92*5113495bSYour Name  * @index_7 = 2500_5000 us
93*5113495bSYour Name  * @index_8 = 5000_6000 us
94*5113495bSYour Name  * @index_9 = 6000_7000 us
95*5113495bSYour Name  * @index_10 = 7000_8000 us
96*5113495bSYour Name  * @index_11 = 8000_9000 us
97*5113495bSYour Name  * @index_12 = 9000+ us
98*5113495bSYour Name  */
99*5113495bSYour Name 
100*5113495bSYour Name static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = {
101*5113495bSYour Name 	0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000};
102*5113495bSYour Name #endif
103*5113495bSYour Name 
104*5113495bSYour Name /*
105*5113495bSYour Name  * dp_hist_reap2stack_bucket: Reap to stack bucket
106*5113495bSYour Name  * @index_0 = 0_5 ms
107*5113495bSYour Name  * @index_1 = 5_10 ms
108*5113495bSYour Name  * @index_2 = 10_15 ms
109*5113495bSYour Name  * @index_3 = 15_20 ms
110*5113495bSYour Name  * @index_4 = 20_25 ms
111*5113495bSYour Name  * @index_5 = 25_30 ms
112*5113495bSYour Name  * @index_6 = 30_35 ms
113*5113495bSYour Name  * @index_7 = 35_40 ms
114*5113495bSYour Name  * @index_8 = 40_45 ms
115*5113495bSYour Name  * @index_9 = 46_50 ms
116*5113495bSYour Name  * @index_10 = 51_55 ms
117*5113495bSYour Name  * @index_11 = 56_60 ms
118*5113495bSYour Name  * @index_12 = 60+ ms
119*5113495bSYour Name  */
120*5113495bSYour Name static uint16_t dp_hist_reap2stack_bucket[CDP_HIST_BUCKET_MAX] = {
121*5113495bSYour Name 	0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60};
122*5113495bSYour Name 
123*5113495bSYour Name /*
124*5113495bSYour Name  * dp_hist_hw_tx_comp_dbucket: tx hw completion delay bucket in us
125*5113495bSYour Name  * @index_0 = 0_250 us
126*5113495bSYour Name  * @index_1 = 250_500 us
127*5113495bSYour Name  * @index_2 = 500_750 us
128*5113495bSYour Name  * @index_3 = 750_1000 us
129*5113495bSYour Name  * @index_4 = 1000_1500 us
130*5113495bSYour Name  * @index_5 = 1500_2000 us
131*5113495bSYour Name  * @index_6 = 2000_2500 us
132*5113495bSYour Name  * @index_7 = 2500_5000 us
133*5113495bSYour Name  * @index_8 = 5000_6000 us
134*5113495bSYour Name  * @index_9 = 6000_7000 us
135*5113495bSYour Name  * @index_10 = 7000_8000 us
136*5113495bSYour Name  * @index_11 = 8000_9000 us
137*5113495bSYour Name  * @index_12 = 9000+ us
138*5113495bSYour Name  */
139*5113495bSYour Name static uint16_t dp_hist_hw_tx_comp_dbucket[CDP_HIST_BUCKET_MAX] = {
140*5113495bSYour Name 	0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000};
141*5113495bSYour Name 
142*5113495bSYour Name static const char *dp_hist_hw_tx_comp_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = {
143*5113495bSYour Name 	"0 to 250 us", "250 to 500 us",
144*5113495bSYour Name 	"500 to 750 us", "750 to 1000 us",
145*5113495bSYour Name 	"1000 to 1500 us", "1500 to 2000 us",
146*5113495bSYour Name 	"2000 to 2500 us", "2500 to 5000 us",
147*5113495bSYour Name 	"5000 to 6000 us", "6000 to 7000 ms",
148*5113495bSYour Name 	"7000 to 8000 us", "8000 to 9000 us", "9000+ us"
149*5113495bSYour Name };
150*5113495bSYour Name 
dp_hist_tx_hw_delay_str(uint8_t index)151*5113495bSYour Name const char *dp_hist_tx_hw_delay_str(uint8_t index)
152*5113495bSYour Name {
153*5113495bSYour Name 	if (index > CDP_HIST_BUCKET_MAX)
154*5113495bSYour Name 		return "Invalid index";
155*5113495bSYour Name 	return dp_hist_hw_tx_comp_dbucket_str[index];
156*5113495bSYour Name }
157*5113495bSYour Name 
158*5113495bSYour Name /*
159*5113495bSYour Name  * dp_hist_delay_percentile_dbucket: tx hw completion delay bucket in delay
160*5113495bSYour Name  * bound percentile
161*5113495bSYour Name  * @index_0 = 0_10
162*5113495bSYour Name  * @index_1 = 10_20
163*5113495bSYour Name  * @index_2 = 20_30
164*5113495bSYour Name  * @index_3 = 30_40
165*5113495bSYour Name  * @index_4 = 40_50
166*5113495bSYour Name  * @index_5 = 50_60
167*5113495bSYour Name  * @index_6 = 60_70
168*5113495bSYour Name  * @index_7 = 70_80
169*5113495bSYour Name  * @index_8 = 80_100
170*5113495bSYour Name  * @index_9 = 90_100
171*5113495bSYour Name  * @index_10 = 100_150
172*5113495bSYour Name  * @index_11 = 150_200
173*5113495bSYour Name  * @index_12 = 200+
174*5113495bSYour Name  */
175*5113495bSYour Name static uint16_t dp_hist_delay_percentile_dbucket[CDP_HIST_BUCKET_MAX] = {
176*5113495bSYour Name 	0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200};
177*5113495bSYour Name 
178*5113495bSYour Name static
179*5113495bSYour Name const char *dp_hist_delay_percentile_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = {
180*5113495bSYour Name 	"0 to 10%", "10 to 20%",
181*5113495bSYour Name 	"20 to  30%", "30 to 40%",
182*5113495bSYour Name 	"40 to 50%", "50 to 60%",
183*5113495bSYour Name 	"60 to 70%", "70 to 80%",
184*5113495bSYour Name 	"80 to 90% ", "90 to 100%",
185*5113495bSYour Name 	"100 to 150% ", "150 to 200%", "200+%"
186*5113495bSYour Name };
187*5113495bSYour Name 
dp_hist_delay_percentile_str(uint8_t index)188*5113495bSYour Name const char *dp_hist_delay_percentile_str(uint8_t index)
189*5113495bSYour Name {
190*5113495bSYour Name 	if (index > CDP_HIST_BUCKET_MAX)
191*5113495bSYour Name 		return "Invalid index";
192*5113495bSYour Name 	return dp_hist_delay_percentile_dbucket_str[index];
193*5113495bSYour Name }
194*5113495bSYour Name 
195*5113495bSYour Name /**
196*5113495bSYour Name  * dp_hist_find_bucket_idx() - Find the bucket index
197*5113495bSYour Name  * @bucket_array: Bucket array
198*5113495bSYour Name  * @value: Frequency value
199*5113495bSYour Name  *
200*5113495bSYour Name  * Return: The bucket index
201*5113495bSYour Name  */
dp_hist_find_bucket_idx(int16_t * bucket_array,int value)202*5113495bSYour Name static int dp_hist_find_bucket_idx(int16_t *bucket_array, int value)
203*5113495bSYour Name {
204*5113495bSYour Name 	uint8_t idx = CDP_HIST_BUCKET_0;
205*5113495bSYour Name 
206*5113495bSYour Name 	for (; idx < (CDP_HIST_BUCKET_MAX - 1); idx++) {
207*5113495bSYour Name 		if (value < bucket_array[idx + 1])
208*5113495bSYour Name 			break;
209*5113495bSYour Name 	}
210*5113495bSYour Name 
211*5113495bSYour Name 	return idx;
212*5113495bSYour Name }
213*5113495bSYour Name 
214*5113495bSYour Name /**
215*5113495bSYour Name  * dp_hist_fill_buckets() - Fill the histogram frequency buckets
216*5113495bSYour Name  * @hist_bucket: Histogram bukcets
217*5113495bSYour Name  * @value: Frequency value
218*5113495bSYour Name  *
219*5113495bSYour Name  * Return: void
220*5113495bSYour Name  */
dp_hist_fill_buckets(struct cdp_hist_bucket * hist_bucket,int value)221*5113495bSYour Name static void dp_hist_fill_buckets(struct cdp_hist_bucket *hist_bucket, int value)
222*5113495bSYour Name {
223*5113495bSYour Name 	enum cdp_hist_types hist_type;
224*5113495bSYour Name 	int idx = CDP_HIST_BUCKET_MAX;
225*5113495bSYour Name 
226*5113495bSYour Name 	if (qdf_unlikely(!hist_bucket))
227*5113495bSYour Name 		return;
228*5113495bSYour Name 
229*5113495bSYour Name 	hist_type = hist_bucket->hist_type;
230*5113495bSYour Name 
231*5113495bSYour Name 	/* Identify the bucket the bucket and update. */
232*5113495bSYour Name 	switch (hist_type) {
233*5113495bSYour Name 	case CDP_HIST_TYPE_SW_ENQEUE_DELAY:
234*5113495bSYour Name 		idx =  dp_hist_find_bucket_idx(&dp_hist_sw_enq_dbucket[0],
235*5113495bSYour Name 					       value);
236*5113495bSYour Name 		break;
237*5113495bSYour Name 	case CDP_HIST_TYPE_HW_COMP_DELAY:
238*5113495bSYour Name 		idx =  dp_hist_find_bucket_idx(&dp_hist_fw2hw_dbucket[0],
239*5113495bSYour Name 					       value);
240*5113495bSYour Name 		break;
241*5113495bSYour Name 	case CDP_HIST_TYPE_REAP_STACK:
242*5113495bSYour Name 		idx =  dp_hist_find_bucket_idx(
243*5113495bSYour Name 				&dp_hist_reap2stack_bucket[0], value);
244*5113495bSYour Name 		break;
245*5113495bSYour Name 	case CDP_HIST_TYPE_HW_TX_COMP_DELAY:
246*5113495bSYour Name 		idx =  dp_hist_find_bucket_idx(
247*5113495bSYour Name 				&dp_hist_hw_tx_comp_dbucket[0], value);
248*5113495bSYour Name 		break;
249*5113495bSYour Name 	case CDP_HIST_TYPE_DELAY_PERCENTILE:
250*5113495bSYour Name 		idx =  dp_hist_find_bucket_idx(
251*5113495bSYour Name 				&dp_hist_delay_percentile_dbucket[0], value);
252*5113495bSYour Name 		break;
253*5113495bSYour Name 	default:
254*5113495bSYour Name 		break;
255*5113495bSYour Name 	}
256*5113495bSYour Name 
257*5113495bSYour Name 	if (idx == CDP_HIST_BUCKET_MAX)
258*5113495bSYour Name 		return;
259*5113495bSYour Name 
260*5113495bSYour Name 	hist_bucket->freq[idx]++;
261*5113495bSYour Name }
262*5113495bSYour Name 
dp_hist_update_stats(struct cdp_hist_stats * hist_stats,int value)263*5113495bSYour Name void dp_hist_update_stats(struct cdp_hist_stats *hist_stats, int value)
264*5113495bSYour Name {
265*5113495bSYour Name 	if (qdf_unlikely(!hist_stats))
266*5113495bSYour Name 		return;
267*5113495bSYour Name 
268*5113495bSYour Name 	/*
269*5113495bSYour Name 	 * Fill the histogram buckets according to the delay
270*5113495bSYour Name 	 */
271*5113495bSYour Name 	dp_hist_fill_buckets(&hist_stats->hist, value);
272*5113495bSYour Name 
273*5113495bSYour Name 	/*
274*5113495bSYour Name 	 * Compute the min, max and average. Average computed is weighted
275*5113495bSYour Name 	 * average
276*5113495bSYour Name 	 */
277*5113495bSYour Name 	if (value < hist_stats->min)
278*5113495bSYour Name 		hist_stats->min = value;
279*5113495bSYour Name 
280*5113495bSYour Name 	if (value > hist_stats->max)
281*5113495bSYour Name 		hist_stats->max = value;
282*5113495bSYour Name 
283*5113495bSYour Name 	if (qdf_unlikely(!hist_stats->avg))
284*5113495bSYour Name 		hist_stats->avg = value;
285*5113495bSYour Name 	else
286*5113495bSYour Name 		hist_stats->avg = (hist_stats->avg + value) / 2;
287*5113495bSYour Name }
288*5113495bSYour Name 
dp_copy_hist_stats(struct cdp_hist_stats * src_hist_stats,struct cdp_hist_stats * dst_hist_stats)289*5113495bSYour Name void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats,
290*5113495bSYour Name 			struct cdp_hist_stats *dst_hist_stats)
291*5113495bSYour Name {
292*5113495bSYour Name 	uint8_t index;
293*5113495bSYour Name 
294*5113495bSYour Name 	for (index = 0; index < CDP_HIST_BUCKET_MAX; index++)
295*5113495bSYour Name 		dst_hist_stats->hist.freq[index] =
296*5113495bSYour Name 			src_hist_stats->hist.freq[index];
297*5113495bSYour Name 	dst_hist_stats->min = src_hist_stats->min;
298*5113495bSYour Name 	dst_hist_stats->max = src_hist_stats->max;
299*5113495bSYour Name 	dst_hist_stats->avg = src_hist_stats->avg;
300*5113495bSYour Name }
301*5113495bSYour Name 
dp_accumulate_hist_stats(struct cdp_hist_stats * src_hist_stats,struct cdp_hist_stats * dst_hist_stats)302*5113495bSYour Name void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats,
303*5113495bSYour Name 			      struct cdp_hist_stats *dst_hist_stats)
304*5113495bSYour Name {
305*5113495bSYour Name 	uint8_t index, hist_stats_valid = 0;
306*5113495bSYour Name 
307*5113495bSYour Name 	for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) {
308*5113495bSYour Name 		dst_hist_stats->hist.freq[index] +=
309*5113495bSYour Name 			src_hist_stats->hist.freq[index];
310*5113495bSYour Name 		if (src_hist_stats->hist.freq[index])
311*5113495bSYour Name 			hist_stats_valid = 1;
312*5113495bSYour Name 	}
313*5113495bSYour Name 	/*
314*5113495bSYour Name 	 * If at least one hist-bucket has non-zero count,
315*5113495bSYour Name 	 * proceed with the detailed calculation.
316*5113495bSYour Name 	 */
317*5113495bSYour Name 	if (hist_stats_valid) {
318*5113495bSYour Name 		dst_hist_stats->min = QDF_MIN(src_hist_stats->min,
319*5113495bSYour Name 					      dst_hist_stats->min);
320*5113495bSYour Name 		dst_hist_stats->max = QDF_MAX(src_hist_stats->max,
321*5113495bSYour Name 					      dst_hist_stats->max);
322*5113495bSYour Name 		dst_hist_stats->avg = (src_hist_stats->avg +
323*5113495bSYour Name 				       dst_hist_stats->avg) >> 1;
324*5113495bSYour Name 	}
325*5113495bSYour Name }
326*5113495bSYour Name 
dp_hist_init(struct cdp_hist_stats * hist_stats,enum cdp_hist_types hist_type)327*5113495bSYour Name void dp_hist_init(struct cdp_hist_stats *hist_stats,
328*5113495bSYour Name 		  enum cdp_hist_types hist_type)
329*5113495bSYour Name {
330*5113495bSYour Name 	qdf_mem_zero(hist_stats, sizeof(*hist_stats));
331*5113495bSYour Name 	hist_stats->min =  INT_MAX;
332*5113495bSYour Name 	hist_stats->hist.hist_type = hist_type;
333*5113495bSYour Name }
334