xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/dp_hist.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
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_find_bucket_idx: Find the bucket index
119  * @bucket_array: Bucket array
120  * @value: Frequency value
121  *
122  * Return: The bucket index
123  */
124 static int dp_hist_find_bucket_idx(int16_t *bucket_array, int value)
125 {
126 	uint8_t idx = CDP_HIST_BUCKET_0;
127 
128 	for (; idx < (CDP_HIST_BUCKET_MAX - 1); idx++) {
129 		if (value < bucket_array[idx + 1])
130 			break;
131 	}
132 
133 	return idx;
134 }
135 
136 /*
137  * dp_hist_fill_buckets: Fill the histogram frequency buckets
138  * @hist_bucket: Histogram bukcets
139  * @value: Frequency value
140  *
141  * Return: void
142  */
143 static void dp_hist_fill_buckets(struct cdp_hist_bucket *hist_bucket, int value)
144 {
145 	enum cdp_hist_types hist_type;
146 	int idx = CDP_HIST_BUCKET_MAX;
147 
148 	if (qdf_unlikely(!hist_bucket))
149 		return;
150 
151 	hist_type = hist_bucket->hist_type;
152 
153 	/* Identify the bucket the bucket and update. */
154 	switch (hist_type) {
155 	case CDP_HIST_TYPE_SW_ENQEUE_DELAY:
156 		idx =  dp_hist_find_bucket_idx(&dp_hist_sw_enq_dbucket[0],
157 					       value);
158 		break;
159 	case CDP_HIST_TYPE_HW_COMP_DELAY:
160 		idx =  dp_hist_find_bucket_idx(&dp_hist_fw2hw_dbucket[0],
161 					       value);
162 		break;
163 	case CDP_HIST_TYPE_REAP_STACK:
164 		idx =  dp_hist_find_bucket_idx(
165 				&dp_hist_reap2stack_bucket[0], value);
166 		break;
167 	case CDP_HIST_TYPE_HW_TX_COMP_DELAY:
168 		idx =  dp_hist_find_bucket_idx(
169 				&dp_hist_hw_tx_comp_dbucket[0], value);
170 		break;
171 	default:
172 		break;
173 	}
174 
175 	if (idx == CDP_HIST_BUCKET_MAX)
176 		return;
177 
178 	hist_bucket->freq[idx]++;
179 }
180 
181 /*
182  * dp_hist_update_stats: Update histogram stats
183  * @hist_stats: Hist stats object
184  * @value: Delay value
185  *
186  * Return: void
187  */
188 void dp_hist_update_stats(struct cdp_hist_stats *hist_stats, int value)
189 {
190 	if (qdf_unlikely(!hist_stats))
191 		return;
192 
193 	/*
194 	 * Fill the histogram buckets according to the delay
195 	 */
196 	dp_hist_fill_buckets(&hist_stats->hist, value);
197 
198 	/*
199 	 * Compute the min, max and average. Average computed is weighted
200 	 * average
201 	 */
202 	if (value < hist_stats->min)
203 		hist_stats->min = value;
204 
205 	if (value > hist_stats->max)
206 		hist_stats->max = value;
207 
208 	if (qdf_unlikely(!hist_stats->avg))
209 		hist_stats->avg = value;
210 	else
211 		hist_stats->avg = (hist_stats->avg + value) / 2;
212 }
213 
214 /*
215  * dp_copy_hist_stats(): Copy the histogram stats
216  * @src_hist_stats: Source histogram stats
217  * @dst_hist_stats: Destination histogram stats
218  *
219  * Return: void
220  */
221 void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats,
222 			struct cdp_hist_stats *dst_hist_stats)
223 {
224 	uint8_t index;
225 
226 	for (index = 0; index < CDP_HIST_BUCKET_MAX; index++)
227 		dst_hist_stats->hist.freq[index] =
228 			src_hist_stats->hist.freq[index];
229 	dst_hist_stats->min = src_hist_stats->min;
230 	dst_hist_stats->max = src_hist_stats->max;
231 	dst_hist_stats->avg = src_hist_stats->avg;
232 }
233 
234 /*
235  * dp_accumulate_hist_stats(): Accumulate the hist src to dst
236  * @src_hist_stats: Source histogram stats
237  * @dst_hist_stats: Destination histogram stats
238  *
239  * Return: void
240  */
241 void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats,
242 			      struct cdp_hist_stats *dst_hist_stats)
243 {
244 	uint8_t index, hist_stats_valid = 0;
245 
246 	for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) {
247 		dst_hist_stats->hist.freq[index] +=
248 			src_hist_stats->hist.freq[index];
249 		if (src_hist_stats->hist.freq[index])
250 			hist_stats_valid = 1;
251 	}
252 	/*
253 	 * If at least one hist-bucket has non-zero count,
254 	 * proceed with the detailed calculation.
255 	 */
256 	if (hist_stats_valid) {
257 		dst_hist_stats->min = QDF_MIN(src_hist_stats->min,
258 					      dst_hist_stats->min);
259 		dst_hist_stats->max = QDF_MAX(src_hist_stats->max,
260 					      dst_hist_stats->max);
261 		dst_hist_stats->avg = (src_hist_stats->avg +
262 				       dst_hist_stats->avg) >> 1;
263 	}
264 }
265 
266 /*
267  * dp_hist_init(): Initialize the histogram object
268  * @hist_stats: Hist stats object
269  * @hist_type: Histogram type
270  */
271 void dp_hist_init(struct cdp_hist_stats *hist_stats,
272 		  enum cdp_hist_types hist_type)
273 {
274 	qdf_mem_zero(hist_stats, sizeof(*hist_stats));
275 	hist_stats->min =  INT_MAX;
276 	hist_stats->hist.hist_type = hist_type;
277 }
278