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