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