xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_medium_assess.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: wlan_hdd_medium_assess.c
20  *
21  * WLAN Host Device Driver medium assess related implementation
22  *
23  */
24 
25 #include "wlan_hdd_medium_assess.h"
26 #include <osif_sync.h>
27 #include <wlan_hdd_main.h>
28 #include <wlan_hdd_object_manager.h>
29 #include <wlan_dcs_ucfg_api.h>
30 #include <wlan_cp_stats_mc_ucfg_api.h>
31 #include <sme_api.h>
32 #include <wma_api.h>
33 #include "wlan_cmn.h"
34 
35 /* define short names for get station info attributes */
36 #define MEDIUM_ASSESS_TYPE \
37 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE
38 #define PERIOD \
39 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD
40 #define TOTAL_CYCLE_COUNT \
41 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT
42 #define IDLE_COUNT \
43 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT
44 #define IBSS_RX_COUNT \
45 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT
46 #define OBSS_RX_COUNT \
47 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT
48 #define MAX_IBSS_RSSI \
49 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI
50 #define MIN_IBSS_RSSI \
51 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI
52 #define CONGESTION_REPORT_ENABLE \
53 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE
54 #define CONGESTION_REPORT_THRESHOLD \
55 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD
56 #define CONGESTION_REPORT_INTERVAL \
57 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL
58 #define CONGESTION_PERCENTAGE \
59 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE
60 #define MEDIUM_ASSESS_MAX \
61 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX
62 
63 #define DEFAULT_CCA_PERIOD 10	/* seconds */
64 #define CCA_GET_RSSI_INTERVAL 1000	/* 1 second */
65 
66 #define REPORT_DISABLE 0
67 #define REPORT_ENABLE 1
68 
69 #define MAX_CONGESTION_THRESHOLD 100
70 #define CYCLE_THRESHOLD 6400000 /* 40000us * 160M */
71 
72 #define MEDIUM_ASSESS_TIMER_INTERVAL 1000 /* 1000ms */
73 static qdf_mc_timer_t hdd_medium_assess_timer;
74 static bool ssr_flag;
75 static bool timer_enable;
76 struct hdd_medium_assess_info medium_assess_info[WLAN_UMAC_MAX_RP_PID];
77 unsigned long stime;
78 
79 const struct nla_policy
80 hdd_medium_assess_policy[MEDIUM_ASSESS_MAX + 1] = {
81 	[MEDIUM_ASSESS_TYPE] = {.type = NLA_U8},
82 	[PERIOD] = {.type = NLA_U32},
83 	[CONGESTION_REPORT_ENABLE] = {.type = NLA_U8},
84 	[CONGESTION_REPORT_THRESHOLD] = {.type = NLA_U8},
85 	[CONGESTION_REPORT_INTERVAL] = {.type = NLA_U8},
86 };
87 
88 /*
89  * get_cca_report_len() - Calculate length for CCA report
90  * to allocate skb buffer
91  *
92  * Return: skb buffer length
93  */
get_cca_report_len(void)94 static int get_cca_report_len(void)
95 {
96 	uint32_t data_len = NLMSG_HDRLEN;
97 
98 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE */
99 	data_len += nla_total_size(sizeof(uint8_t));
100 
101 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT */
102 	data_len += nla_total_size(sizeof(uint32_t));
103 
104 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT */
105 	data_len += nla_total_size(sizeof(uint32_t));
106 
107 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT */
108 	data_len += nla_total_size(sizeof(uint32_t));
109 
110 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT */
111 	data_len += nla_total_size(sizeof(uint32_t));
112 
113 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI */
114 	data_len += nla_total_size(sizeof(uint32_t));
115 
116 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI */
117 	data_len += nla_total_size(sizeof(uint32_t));
118 
119 	return data_len;
120 }
121 
122 /**
123  * hdd_cca_notification_cb() - cca notification callback function
124  * @vdev_id: vdev id
125  * @stats: dcs im stats
126  * @status: status of cca statistics
127  *
128  * Return: None
129  */
hdd_cca_notification_cb(uint8_t vdev_id,struct wlan_host_dcs_im_user_stats * stats,int status)130 static void hdd_cca_notification_cb(uint8_t vdev_id,
131 				    struct wlan_host_dcs_im_user_stats *stats,
132 				    int status)
133 {
134 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
135 	struct wlan_hdd_link_info *link_info;
136 	struct sk_buff *event;
137 
138 	if (wlan_hdd_validate_context(hdd_ctx))
139 		return;
140 
141 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
142 	if (!link_info) {
143 		hdd_err("Failed to find adapter of vdev %d", vdev_id);
144 		return;
145 	}
146 
147 	event = wlan_cfg80211_vendor_event_alloc(
148 				hdd_ctx->wiphy, &link_info->adapter->wdev,
149 				get_cca_report_len(),
150 				QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS_INDEX,
151 				GFP_KERNEL);
152 	if (!event) {
153 		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
154 		return;
155 	}
156 
157 	if (nla_put_u8(event, MEDIUM_ASSESS_TYPE,
158 		       QCA_WLAN_MEDIUM_ASSESS_CCA) ||
159 	    nla_put_u32(event, TOTAL_CYCLE_COUNT, stats->cycle_count) ||
160 	    nla_put_u32(event, IDLE_COUNT,
161 			stats->cycle_count - stats->rxclr_count) ||
162 	    nla_put_u32(event, IBSS_RX_COUNT, stats->my_bss_rx_cycle_count) ||
163 	    nla_put_u32(event, OBSS_RX_COUNT,
164 			stats->rx_frame_count - stats->my_bss_rx_cycle_count) ||
165 	    nla_put_u32(event, MAX_IBSS_RSSI, stats->max_rssi) ||
166 	    nla_put_u32(event, MIN_IBSS_RSSI, stats->min_rssi)) {
167 		hdd_err("nla put failed");
168 		wlan_cfg80211_vendor_free_skb(event);
169 		return;
170 	}
171 
172 	wlan_cfg80211_vendor_event(event, GFP_KERNEL);
173 }
174 
175 /**
176  * hdd_medium_assess_cca() - clear channel assessment
177  * @hdd_ctx: pointer to HDD context
178  * @adapter: pointer to adapter
179  * @tb: list of attributes
180  *
181  * Return: success(0) or reason code for failure
182  */
hdd_medium_assess_cca(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,struct nlattr ** tb)183 static int hdd_medium_assess_cca(struct hdd_context *hdd_ctx,
184 				 struct hdd_adapter *adapter,
185 				 struct nlattr **tb)
186 {
187 	struct wlan_objmgr_vdev *vdev;
188 	uint32_t cca_period = DEFAULT_CCA_PERIOD;
189 	uint8_t mac_id, dcs_enable;
190 	QDF_STATUS status;
191 	int errno = 0;
192 
193 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DCS_ID);
194 	if (!vdev)
195 		return -EINVAL;
196 
197 	status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc,
198 						     adapter->deflink->vdev_id,
199 						     &mac_id);
200 	if (QDF_IS_STATUS_ERROR(status)) {
201 		hdd_err_rl("Failed to get mac_id");
202 		errno = -EINVAL;
203 		goto out;
204 	}
205 
206 	dcs_enable = ucfg_get_dcs_enable(hdd_ctx->psoc, mac_id);
207 	if (!(dcs_enable & WLAN_HOST_DCS_WLANIM)) {
208 		hdd_err_rl("DCS_WLANIM is not enabled");
209 		errno = -EINVAL;
210 		goto out;
211 	}
212 
213 	if (qdf_atomic_read(&adapter->deflink->session.ap.acs_in_progress)) {
214 		hdd_err_rl("ACS is in progress");
215 		errno = -EBUSY;
216 		goto out;
217 	}
218 
219 	if (tb[PERIOD])
220 		cca_period = nla_get_u32(tb[PERIOD]);
221 	if (cca_period == 0)
222 		cca_period = DEFAULT_CCA_PERIOD;
223 
224 	ucfg_dcs_reset_user_stats(hdd_ctx->psoc, mac_id);
225 	ucfg_dcs_register_user_cb(hdd_ctx->psoc, mac_id,
226 				  adapter->deflink->vdev_id,
227 				  hdd_cca_notification_cb);
228 	/* dcs is already enabled and dcs event is reported every second
229 	 * set the user request counter to collect user stats
230 	 */
231 	ucfg_dcs_set_user_request(hdd_ctx->psoc, mac_id, cca_period);
232 
233 out:
234 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_DCS_ID);
235 	return errno;
236 }
237 
238 /*
239  * get_congestion_report_len() - Calculate length for congestion report
240  * to allocate skb buffer
241  *
242  * Return: skb buffer length
243  */
get_congestion_report_len(void)244 static int get_congestion_report_len(void)
245 {
246 	uint32_t data_len = NLMSG_HDRLEN;
247 
248 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE */
249 	data_len += nla_total_size(sizeof(uint8_t));
250 
251 	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE */
252 	data_len += nla_total_size(sizeof(uint8_t));
253 
254 	return data_len;
255 }
256 
257 /**
258  * hdd_congestion_reset_data() - reset/invalid the previous data
259  * @pdev_id: pdev id
260  *
261  * Return: None
262  */
hdd_congestion_reset_data(uint8_t pdev_id)263 static void hdd_congestion_reset_data(uint8_t pdev_id)
264 {
265 	struct hdd_medium_assess_info *mdata;
266 
267 	mdata = &medium_assess_info[pdev_id];
268 	qdf_mem_zero(mdata->data, sizeof(mdata->data));
269 }
270 
271 /**
272  * hdd_congestion_notification_cb() - congestion notification callback function
273  * @vdev_id: vdev id
274  * @data: medium assess data from firmware
275  * @last: indicate whether the callback from final WMI_STATS_EVENT in a series
276  *
277  * Return: None
278  */
hdd_congestion_notification_cb(uint8_t vdev_id,struct medium_assess_data * data,bool last)279 static void hdd_congestion_notification_cb(uint8_t vdev_id,
280 					   struct medium_assess_data *data,
281 					   bool last)
282 {
283 	struct hdd_medium_assess_info *mdata;
284 	uint8_t i;
285 	int32_t index;
286 
287 	/* the cb should not be delay more than 40 ms or drop it */
288 	if (qdf_system_time_after(jiffies, stime)) {
289 		hdd_debug("medium assess interference data drop");
290 		return;
291 	}
292 
293 	for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++) {
294 		mdata = &medium_assess_info[i];
295 
296 		index = mdata->index - 1;
297 		if (index < 0)
298 			index = MEDIUM_ASSESS_NUM - 1;
299 
300 		if (data[i].part1_valid && mdata->data[index].part1_valid) {
301 			if (CYCLE_THRESHOLD > (data[i].cycle_count -
302 			    mdata->data[index].cycle_count))
303 				continue;
304 		}
305 
306 		if (data[i].part1_valid) {
307 			mdata->data[mdata->index].part1_valid = true;
308 			mdata->data[mdata->index].cycle_count =
309 						data[i].cycle_count;
310 			mdata->data[mdata->index].rx_clear_count =
311 						data[i].rx_clear_count;
312 			mdata->data[mdata->index].tx_frame_count =
313 						data[i].tx_frame_count;
314 		}
315 
316 		if (data[i].part2_valid) {
317 			mdata->data[mdata->index].part2_valid = true;
318 			mdata->data[mdata->index].my_rx_count =
319 						data[i].my_rx_count;
320 		}
321 
322 		if (last) {
323 			mdata->index++;
324 			if (mdata->index >= MEDIUM_ASSESS_NUM)
325 				mdata->index = 0;
326 			mdata->data[mdata->index].part1_valid = false;
327 			mdata->data[mdata->index].part2_valid = false;
328 		}
329 	}
330 }
331 
332 /**
333  * hdd_congestion_notification_report() - congestion report function
334  * @vdev_id: vdev id
335  * @congestion: congestion percentage
336  *
337  * Return: None
338  */
hdd_congestion_notification_report(uint8_t vdev_id,uint8_t congestion)339 static void hdd_congestion_notification_report(uint8_t vdev_id,
340 					       uint8_t congestion)
341 {
342 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
343 	struct wlan_hdd_link_info *link_info;
344 	struct sk_buff *event;
345 	enum qca_nl80211_vendor_subcmds_index index =
346 		QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS_INDEX;
347 
348 	if (wlan_hdd_validate_context(hdd_ctx))
349 		return;
350 
351 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
352 	if (!link_info) {
353 		hdd_err("Failed to find adapter of vdev %d", vdev_id);
354 		return;
355 	}
356 
357 	event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
358 						 &link_info->adapter->wdev,
359 						 get_congestion_report_len(),
360 						 index, GFP_KERNEL);
361 	if (!event) {
362 		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
363 		return;
364 	}
365 
366 	if (nla_put_u8(event, MEDIUM_ASSESS_TYPE,
367 		       QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT) ||
368 	    nla_put_u8(event, CONGESTION_PERCENTAGE, congestion)) {
369 		hdd_err("nla put failed");
370 		wlan_cfg80211_vendor_free_skb(event);
371 		return;
372 	}
373 
374 	wlan_cfg80211_vendor_event(event, GFP_KERNEL);
375 }
376 
hdd_medium_assess_ssr_enable_flag(void)377 void hdd_medium_assess_ssr_enable_flag(void)
378 {
379 	uint8_t i;
380 
381 	ssr_flag = true;
382 	for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
383 		hdd_congestion_reset_data(i);
384 
385 	if (timer_enable)
386 		qdf_mc_timer_destroy(&hdd_medium_assess_timer);
387 }
388 
hdd_medium_assess_stop_timer(uint8_t pdev_id,struct hdd_context * hdd_ctx)389 void hdd_medium_assess_stop_timer(uint8_t pdev_id, struct hdd_context *hdd_ctx)
390 {
391 	struct request_info info = {0};
392 	bool pending = false;
393 	uint8_t i, interval = 0;
394 
395 	if (ssr_flag)
396 		return;
397 
398 	medium_assess_info[pdev_id].config.threshold = MAX_CONGESTION_THRESHOLD;
399 	medium_assess_info[pdev_id].config.interval = 0;
400 	medium_assess_info[pdev_id].index = 0;
401 	medium_assess_info[pdev_id].count = 0;
402 	hdd_congestion_reset_data(pdev_id);
403 
404 	for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
405 		interval += medium_assess_info[i].config.interval;
406 
407 	if (!interval && timer_enable) {
408 		ucfg_mc_cp_stats_reset_pending_req(hdd_ctx->psoc,
409 						   TYPE_CONGESTION_STATS,
410 						   &info, &pending);
411 		qdf_mc_timer_stop(&hdd_medium_assess_timer);
412 		hdd_debug("medium assess atimer stop");
413 	} else {
414 		hdd_debug("medium assess timer already disabled");
415 	}
416 }
417 
418 /**
419  * hdd_congestion_notification_calculation() - medium assess congestion
420  * calculation.
421  * @info: structure hdd_medium_assess_info
422  *
423  * Return: None
424  */
425 static void
hdd_congestion_notification_calculation(struct hdd_medium_assess_info * info)426 hdd_congestion_notification_calculation(struct hdd_medium_assess_info *info)
427 {
428 	struct medium_assess_data *h_data, *t_data;
429 	int32_t h_index, t_index;
430 	uint32_t rx_clear_count_delta, tx_frame_count_delta;
431 	uint32_t cycle_count_delta, my_rx_count_delta;
432 	uint32_t congestion = 0;
433 	uint64_t diff;
434 
435 	h_index = info->index - 1;
436 	if (h_index < 0)
437 		h_index = MEDIUM_ASSESS_NUM - 1;
438 
439 	if (h_index >= info->config.interval)
440 		t_index = h_index - info->config.interval;
441 	else
442 		t_index = MEDIUM_ASSESS_NUM - info->config.interval - h_index;
443 
444 	if (h_index < 0 || h_index >= MEDIUM_ASSESS_NUM ||
445 	    t_index < 0 || t_index >= MEDIUM_ASSESS_NUM) {
446 		hdd_err("medium assess index is not valid.");
447 		return;
448 	}
449 
450 	h_data = &info->data[h_index];
451 	t_data = &info->data[t_index];
452 
453 	if (!(h_data->part1_valid || h_data->part2_valid ||
454 	      t_data->part1_valid || t_data->part2_valid)) {
455 		hdd_err("medium assess data is not valid.");
456 		return;
457 	}
458 
459 	if (h_data->rx_clear_count >= t_data->rx_clear_count) {
460 		rx_clear_count_delta = h_data->rx_clear_count -
461 						t_data->rx_clear_count;
462 	} else {
463 		rx_clear_count_delta = U32_MAX - t_data->rx_clear_count;
464 		rx_clear_count_delta += h_data->rx_clear_count;
465 	}
466 
467 	if (h_data->tx_frame_count >= t_data->tx_frame_count) {
468 		tx_frame_count_delta = h_data->tx_frame_count -
469 						t_data->tx_frame_count;
470 	} else {
471 		tx_frame_count_delta = U32_MAX - t_data->tx_frame_count;
472 		tx_frame_count_delta += h_data->tx_frame_count;
473 	}
474 
475 	if (h_data->my_rx_count >= t_data->my_rx_count) {
476 		my_rx_count_delta = h_data->my_rx_count - t_data->my_rx_count;
477 	} else {
478 		my_rx_count_delta = U32_MAX - t_data->my_rx_count;
479 		my_rx_count_delta += h_data->my_rx_count;
480 	}
481 
482 	if (h_data->cycle_count >= t_data->cycle_count) {
483 		cycle_count_delta = h_data->cycle_count - t_data->cycle_count;
484 	} else {
485 		cycle_count_delta = U32_MAX - t_data->cycle_count;
486 		cycle_count_delta += h_data->cycle_count;
487 	}
488 
489 	if (rx_clear_count_delta > tx_frame_count_delta &&
490 	    rx_clear_count_delta - tx_frame_count_delta > my_rx_count_delta) {
491 		diff = rx_clear_count_delta - tx_frame_count_delta
492 		       - my_rx_count_delta;
493 		if (cycle_count_delta)
494 			congestion = qdf_do_div(diff * 100, cycle_count_delta);
495 
496 		if (congestion > 100)
497 			congestion = 100;
498 	}
499 
500 	hdd_debug("pdev: %d, rx_c %u, tx %u myrx %u cycle %u congestion: %u",
501 		  info->pdev_id, rx_clear_count_delta, tx_frame_count_delta,
502 		  my_rx_count_delta, cycle_count_delta, congestion);
503 	if (congestion >= info->config.threshold)
504 		hdd_congestion_notification_report(info->vdev_id, congestion);
505 }
506 
507 /**
508  * hdd_congestion_notification_report_multi() - medium assess report
509  * multi interface.
510  * @pdev_id: pdev id
511  *
512  * Return: None
513  */
hdd_congestion_notification_report_multi(uint8_t pdev_id)514 static void hdd_congestion_notification_report_multi(uint8_t pdev_id)
515 {
516 	struct hdd_medium_assess_info *info;
517 
518 	info = &medium_assess_info[pdev_id];
519 	info->count++;
520 	if (info->count % info->config.interval == 0)
521 		hdd_congestion_notification_calculation(info);
522 }
523 
524 /**
525  * hdd_medium_assess_expire_handler() - timer callback
526  * @arg: argument
527  *
528  * Return: None
529  */
hdd_medium_assess_expire_handler(void * arg)530 static void hdd_medium_assess_expire_handler(void *arg)
531 {
532 	struct wlan_objmgr_vdev *vdev;
533 	struct request_info info = {0};
534 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
535 	struct wlan_hdd_link_info *link_info;
536 	uint8_t vdev_id = INVALID_VDEV_ID, pdev_id;
537 	uint8_t index, i;
538 
539 	if (wlan_hdd_validate_context(hdd_ctx))
540 		return;
541 
542 	for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
543 		if (medium_assess_info[i].config.interval != 0) {
544 			vdev_id = medium_assess_info[i].vdev_id;
545 			pdev_id = medium_assess_info[i].pdev_id;
546 			hdd_congestion_notification_report_multi(pdev_id);
547 
548 			/* ensure events are reveived at the 'same' time */
549 			index = medium_assess_info[i].index;
550 			medium_assess_info[i].data[index].part1_valid = false;
551 			medium_assess_info[i].data[index].part2_valid = false;
552 		}
553 
554 	if (vdev_id == INVALID_VDEV_ID)
555 		return;
556 
557 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
558 	if (!link_info) {
559 		hdd_err("Failed to find adapter of vdev %d", vdev_id);
560 		return;
561 	}
562 
563 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_CP_STATS_ID);
564 	if (!vdev)
565 		return;
566 
567 	info.vdev_id = vdev_id;
568 	info.pdev_id = WMI_HOST_PDEV_ID_SOC;
569 	info.u.congestion_notif_cb = hdd_congestion_notification_cb;
570 	stime = jiffies + msecs_to_jiffies(40);
571 	ucfg_mc_cp_stats_send_stats_request(vdev,
572 					    TYPE_CONGESTION_STATS,
573 					    &info);
574 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_CP_STATS_ID);
575 	qdf_mc_timer_start(&hdd_medium_assess_timer,
576 			   MEDIUM_ASSESS_TIMER_INTERVAL);
577 }
578 
579 /**
580  * hdd_medium_assess_congestion_report() - congestion report
581  * @hdd_ctx: pointer to HDD context
582  * @adapter: pointer to adapter
583  * @tb: list of attributes
584  *
585  * Return: success(0) or reason code for failure
586  */
hdd_medium_assess_congestion_report(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,struct nlattr ** tb)587 static int hdd_medium_assess_congestion_report(struct hdd_context *hdd_ctx,
588 					       struct hdd_adapter *adapter,
589 					       struct nlattr **tb)
590 {
591 	QDF_STATUS status;
592 	struct wlan_objmgr_vdev *vdev;
593 	uint8_t enable, threshold, interval = 0;
594 	uint8_t pdev_id, vdev_id;
595 	int errno = 0;
596 
597 	if (!tb[CONGESTION_REPORT_ENABLE]) {
598 		hdd_err_rl("Congestion report enable is not present");
599 		return -EINVAL;
600 	}
601 
602 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_CP_STATS_ID);
603 	if (!vdev)
604 		return -EINVAL;
605 
606 	vdev_id = adapter->deflink->vdev_id;
607 	status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id,
608 						     &pdev_id);
609 	if (QDF_IS_STATUS_ERROR(status)) {
610 		hdd_err("get mac id failed");
611 		goto out;
612 	}
613 
614 	medium_assess_info[pdev_id].vdev_id = vdev_id;
615 	medium_assess_info[pdev_id].pdev_id = pdev_id;
616 
617 	enable = nla_get_u8(tb[CONGESTION_REPORT_ENABLE]);
618 	switch (enable) {
619 	case REPORT_DISABLE:
620 		hdd_debug("medium assess disable: pdev_id %d, vdev_id: %d",
621 			  pdev_id, vdev_id);
622 		hdd_medium_assess_stop_timer(pdev_id, hdd_ctx);
623 		if (timer_enable &&
624 		    (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) ==
625 		     QDF_TIMER_STATE_STOPPED)) {
626 			qdf_mc_timer_destroy(&hdd_medium_assess_timer);
627 			timer_enable = false;
628 		}
629 		break;
630 	case REPORT_ENABLE:
631 		if (!tb[CONGESTION_REPORT_THRESHOLD]) {
632 			hdd_err_rl("Congestion threshold is not present");
633 			errno = -EINVAL;
634 			goto out;
635 		}
636 		threshold = nla_get_u8(tb[CONGESTION_REPORT_THRESHOLD]);
637 		if (threshold > MAX_CONGESTION_THRESHOLD) {
638 			hdd_err_rl("Invalid threshold %d", threshold);
639 			errno = -EINVAL;
640 			goto out;
641 		}
642 		if (tb[CONGESTION_REPORT_INTERVAL]) {
643 			interval = nla_get_u8(tb[CONGESTION_REPORT_INTERVAL]);
644 			if (interval >= MEDIUM_ASSESS_NUM)
645 				interval = MEDIUM_ASSESS_NUM - 1;
646 		} else {
647 			interval = 1;
648 		}
649 
650 		medium_assess_info[pdev_id].config.threshold = threshold;
651 		medium_assess_info[pdev_id].config.interval = interval;
652 		medium_assess_info[pdev_id].index = 0;
653 		medium_assess_info[pdev_id].count = 0;
654 		hdd_congestion_reset_data(pdev_id);
655 		hdd_debug("medium assess enable: pdev_id %d, vdev_id: %d",
656 			  pdev_id, vdev_id);
657 
658 		if (!timer_enable) {
659 			status =
660 			    qdf_mc_timer_init(&hdd_medium_assess_timer,
661 					      QDF_TIMER_TYPE_SW,
662 					      hdd_medium_assess_expire_handler,
663 					      NULL);
664 			if (QDF_IS_STATUS_ERROR(status)) {
665 				hdd_debug("medium assess init timer failed");
666 				errno = -EINVAL;
667 				goto out;
668 			}
669 			timer_enable = true;
670 		}
671 
672 		if (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) !=
673 		    QDF_TIMER_STATE_RUNNING) {
674 			hdd_debug("medium assess atimer start");
675 			qdf_mc_timer_start(&hdd_medium_assess_timer,
676 					   MEDIUM_ASSESS_TIMER_INTERVAL);
677 		}
678 		break;
679 	default:
680 		hdd_err_rl("Invalid enable: %d", enable);
681 		errno = -EINVAL;
682 		break;
683 	}
684 
685 out:
686 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_CP_STATS_ID);
687 	return errno;
688 }
689 
690 /**
691  * __hdd_cfg80211_medium_assess() - medium assess
692  * @wiphy: pointer to wireless phy
693  * @wdev: wireless device
694  * @data: data
695  * @data_len: data length
696  *
697  * Return: success(0) or reason code for failure
698  */
__hdd_cfg80211_medium_assess(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)699 static int __hdd_cfg80211_medium_assess(struct wiphy *wiphy,
700 					struct wireless_dev *wdev,
701 					const void *data,
702 					int data_len)
703 {
704 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
705 	struct net_device *dev = wdev->netdev;
706 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
707 	enum QDF_GLOBAL_MODE driver_mode = hdd_get_conparam();
708 	struct nlattr *tb[MEDIUM_ASSESS_MAX + 1];
709 	uint8_t type;
710 	int errno;
711 
712 	hdd_enter_dev(dev);
713 
714 	if (driver_mode == QDF_GLOBAL_FTM_MODE ||
715 	    driver_mode == QDF_GLOBAL_MONITOR_MODE) {
716 		hdd_err_rl("Command not allowed in FTM / Monitor mode");
717 		return -EPERM;
718 	}
719 
720 	errno = wlan_hdd_validate_context(hdd_ctx);
721 	if (errno)
722 		return errno;
723 
724 	errno = wlan_cfg80211_nla_parse(tb, MEDIUM_ASSESS_MAX, data, data_len,
725 					hdd_medium_assess_policy);
726 	if (errno) {
727 		hdd_err_rl("Invalid ATTR");
728 		return errno;
729 	}
730 
731 	if (!tb[MEDIUM_ASSESS_TYPE]) {
732 		hdd_err_rl("Medium assess type is not present");
733 		return -EINVAL;
734 	}
735 	type = nla_get_u8(tb[MEDIUM_ASSESS_TYPE]);
736 
737 	switch (type) {
738 	case QCA_WLAN_MEDIUM_ASSESS_CCA:
739 		errno = hdd_medium_assess_cca(hdd_ctx, adapter, tb);
740 		break;
741 	case QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT:
742 		errno = hdd_medium_assess_congestion_report(hdd_ctx, adapter,
743 							     tb);
744 		break;
745 	default:
746 		hdd_err_rl("Invalid medium assess type: %d", type);
747 		return -EINVAL;
748 	}
749 
750 	hdd_exit();
751 
752 	return errno;
753 }
754 
hdd_cfg80211_medium_assess(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)755 int hdd_cfg80211_medium_assess(struct wiphy *wiphy,
756 			       struct wireless_dev *wdev,
757 			       const void *data,
758 			       int data_len)
759 {
760 	struct osif_vdev_sync *vdev_sync;
761 	int errno;
762 
763 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
764 	if (errno)
765 		return errno;
766 
767 	errno = __hdd_cfg80211_medium_assess(wiphy, wdev, data, data_len);
768 
769 	osif_vdev_sync_op_stop(vdev_sync);
770 
771 	return errno;
772 }
773 
hdd_medium_assess_ssr_reinit(void)774 void hdd_medium_assess_ssr_reinit(void)
775 {
776 	QDF_STATUS status;
777 
778 	if (timer_enable && ssr_flag) {
779 		hdd_debug("medium assess init timer in ssr");
780 		status = qdf_mc_timer_init(&hdd_medium_assess_timer,
781 					   QDF_TIMER_TYPE_SW,
782 					   hdd_medium_assess_expire_handler,
783 					   NULL);
784 		if (QDF_IS_STATUS_ERROR(status)) {
785 			hdd_debug("medium assess init timer failed in ssr");
786 			return;
787 		}
788 
789 		ssr_flag = false;
790 		qdf_mc_timer_start(&hdd_medium_assess_timer,
791 				   MEDIUM_ASSESS_TIMER_INTERVAL);
792 	}
793 }
794