1 /* 2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2024 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 /** 21 * DOC: wlan_hdd_power.c 22 * 23 * WLAN power management functions 24 * 25 */ 26 27 /* Include files */ 28 29 #include <linux/pm.h> 30 #include <linux/wait.h> 31 #include <linux/cpu.h> 32 #include "osif_sync.h" 33 #include <wlan_hdd_includes.h> 34 #if defined(CONFIG_HAS_WAKELOCK) 35 #include <linux/wakelock.h> 36 #endif 37 #include "qdf_types.h" 38 #include "sme_api.h" 39 #include <cds_api.h> 40 #include <cds_sched.h> 41 #include <mac_init_api.h> 42 #include <wlan_qct_sys.h> 43 #include <wlan_hdd_main.h> 44 #include <wlan_hdd_assoc.h> 45 #include <wlan_nlink_srv.h> 46 #include <wlan_hdd_misc.h> 47 #include <wlan_hdd_power.h> 48 #include <wlan_hdd_host_offload.h> 49 #include <dbglog_host.h> 50 #include <wlan_hdd_trace.h> 51 #include <wlan_hdd_p2p.h> 52 53 #include <linux/semaphore.h> 54 #include <wlan_hdd_hostapd.h> 55 56 #include <linux/inetdevice.h> 57 #include <wlan_hdd_cfg.h> 58 #include <wlan_hdd_scan.h> 59 #include <wlan_hdd_stats.h> 60 #include <wlan_hdd_cfg80211.h> 61 #include <net/addrconf.h> 62 #include <wlan_hdd_lpass.h> 63 64 #include <wma_types.h> 65 #include <ol_txrx_osif_api.h> 66 #include <ol_defines.h> 67 #include "hif.h" 68 #include "hif_unit_test_suspend.h" 69 #include "sme_power_save_api.h" 70 #include "wlan_policy_mgr_api.h" 71 #include "cdp_txrx_flow_ctrl_v2.h" 72 #include "pld_common.h" 73 #include "wlan_hdd_driver_ops.h" 74 #include <wlan_logging_sock_svc.h> 75 #include "scheduler_api.h" 76 #include "cds_utils.h" 77 #include "wlan_hdd_packet_filter_api.h" 78 #include "wlan_cfg80211_scan.h" 79 #include "wlan_ipa_ucfg_api.h" 80 #include <wlan_cfg80211_mc_cp_stats.h> 81 #include "wlan_p2p_ucfg_api.h" 82 #include "wlan_mlme_ucfg_api.h" 83 #include "wlan_osif_request_manager.h" 84 #include <wlan_hdd_sar_limits.h> 85 #include "wlan_pkt_capture_ucfg_api.h" 86 #include "wlan_hdd_thermal.h" 87 #include "wlan_hdd_object_manager.h" 88 #include <linux/igmp.h> 89 #include "qdf_types.h" 90 #include <linux/cpuidle.h> 91 #include <cdp_txrx_ctrl.h> 92 #include <wlan_cp_stats_mc_ucfg_api.h> 93 #include "wlan_dp_ucfg_api.h" 94 95 /* Preprocessor definitions and constants */ 96 #ifdef QCA_WIFI_EMULATION 97 #define HDD_SSR_BRING_UP_TIME 3000000 98 #else 99 #define HDD_SSR_BRING_UP_TIME 30000 100 #endif 101 102 /* Type declarations */ 103 104 #ifdef FEATURE_WLAN_DIAG_SUPPORT hdd_wlan_suspend_resume_event(uint8_t state)105 void hdd_wlan_suspend_resume_event(uint8_t state) 106 { 107 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend); 108 qdf_mem_zero(&suspend_state, sizeof(suspend_state)); 109 110 suspend_state.state = state; 111 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME); 112 } 113 114 /** 115 * hdd_wlan_offload_event() - send offloads event 116 * @type: offload type 117 * @state: enabled or disabled 118 * 119 * This Function send offloads enable/disable diag event 120 * 121 * Return: void. 122 */ 123 hdd_wlan_offload_event(uint8_t type,uint8_t state)124 void hdd_wlan_offload_event(uint8_t type, uint8_t state) 125 { 126 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req); 127 qdf_mem_zero(&host_offload, sizeof(host_offload)); 128 129 host_offload.offload_type = type; 130 host_offload.state = state; 131 132 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ); 133 } 134 #endif 135 136 #ifdef WLAN_DP_LEGACY_OL_RX_THREAD 137 138 /* timeout in msec to wait for RX_THREAD to suspend */ 139 #define HDD_RXTHREAD_SUSPEND_TIMEOUT 200 140 wlan_hdd_rx_thread_resume(struct hdd_context * hdd_ctx)141 void wlan_hdd_rx_thread_resume(struct hdd_context *hdd_ctx) 142 { 143 if (hdd_ctx->is_ol_rx_thread_suspended) { 144 cds_resume_rx_thread(); 145 hdd_ctx->is_ol_rx_thread_suspended = false; 146 } 147 } 148 wlan_hdd_rx_thread_suspend(struct hdd_context * hdd_ctx)149 int wlan_hdd_rx_thread_suspend(struct hdd_context *hdd_ctx) 150 { 151 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); 152 int rc; 153 154 if (!cds_sched_context) 155 return 0; 156 157 /* Suspend tlshim rx thread */ 158 set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag); 159 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue); 160 rc = wait_for_completion_timeout(&cds_sched_context-> 161 ol_suspend_rx_event, 162 msecs_to_jiffies 163 (HDD_RXTHREAD_SUSPEND_TIMEOUT) 164 ); 165 if (!rc) { 166 clear_bit(RX_SUSPEND_EVENT, 167 &cds_sched_context->ol_rx_event_flag); 168 hdd_err("Failed to stop tl_shim rx thread"); 169 return -EINVAL; 170 } 171 hdd_ctx->is_ol_rx_thread_suspended = true; 172 173 return 0; 174 } 175 #endif /* WLAN_DP_LEGACY_OL_RX_THREAD */ 176 177 /** 178 * hdd_enable_gtk_offload() - enable GTK offload 179 * @vdev: VDEV objmgr pointer 180 * 181 * Central function to enable GTK offload. 182 * 183 * Return: nothing 184 */ hdd_enable_gtk_offload(struct wlan_objmgr_vdev * vdev)185 static void hdd_enable_gtk_offload(struct wlan_objmgr_vdev *vdev) 186 { 187 QDF_STATUS status; 188 189 status = ucfg_pmo_enable_gtk_offload_in_fwr(vdev); 190 if (status != QDF_STATUS_SUCCESS) 191 hdd_debug("Failed to enable gtk offload"); 192 } 193 194 #ifdef WLAN_FEATURE_IGMP_OFFLOAD 195 /** 196 * hdd_send_igmp_offload_params() - enable igmp offload 197 * @adapter: pointer to the adapter 198 * @vdev: VDEV ojbmgr pointer 199 * @enable: enable/disable 200 * 201 * Return: nothing 202 */ 203 static QDF_STATUS hdd_send_igmp_offload_params(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,bool enable)204 hdd_send_igmp_offload_params(struct hdd_adapter *adapter, 205 struct wlan_objmgr_vdev *vdev, bool enable) 206 { 207 struct in_device *in_dev = adapter->dev->ip_ptr; 208 struct ip_mc_list *ip_list; 209 struct pmo_igmp_offload_req *igmp_req = NULL; 210 int count = 0; 211 QDF_STATUS status; 212 213 if (!in_dev) { 214 hdd_err("in_dev is NULL"); 215 return QDF_STATUS_E_FAILURE; 216 } 217 218 ip_list = in_dev->mc_list; 219 if (!ip_list) { 220 hdd_debug("ip list empty"); 221 return QDF_STATUS_E_FAILURE; 222 } 223 224 igmp_req = qdf_mem_malloc(sizeof(*igmp_req)); 225 if (!igmp_req) 226 return QDF_STATUS_E_FAILURE; 227 228 while (ip_list && ip_list->multiaddr && enable && 229 count < MAX_MC_IP_ADDR) { 230 if (IGMP_QUERY_ADDRESS != ip_list->multiaddr) { 231 igmp_req->grp_ip_address[count] = ip_list->multiaddr; 232 count++; 233 } 234 235 ip_list = ip_list->next; 236 } 237 igmp_req->enable = enable; 238 igmp_req->num_grp_ip_address = count; 239 240 status = ucfg_pmo_enable_igmp_offload(vdev, igmp_req); 241 if (status != QDF_STATUS_SUCCESS) 242 hdd_debug("Failed to configure igmp offload"); 243 244 qdf_mem_free(igmp_req); 245 return status; 246 } 247 248 /** 249 * hdd_enable_igmp_offload() - enable GTK offload 250 * @adapter: pointer to the adapter 251 * @vdev: VDEV objmgr pointer 252 * 253 * Enable IGMP offload in suspended case to save power 254 * 255 * Return: nothing 256 */ hdd_enable_igmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)257 static void hdd_enable_igmp_offload(struct hdd_adapter *adapter, 258 struct wlan_objmgr_vdev *vdev) 259 { 260 QDF_STATUS status; 261 262 status = hdd_send_igmp_offload_params(adapter, vdev, true); 263 if (status != QDF_STATUS_SUCCESS) 264 hdd_debug("Failed to enable igmp offload"); 265 } 266 267 /** 268 * hdd_disable_igmp_offload() - disable GTK offload 269 * @adapter: pointer to the adapter 270 * @vdev: VDEV objmgr pointer 271 * 272 * Enable IGMP offload in suspended case to save power 273 * 274 * Return: nothing 275 */ hdd_disable_igmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)276 static void hdd_disable_igmp_offload(struct hdd_adapter *adapter, 277 struct wlan_objmgr_vdev *vdev) 278 { 279 QDF_STATUS status; 280 281 status = hdd_send_igmp_offload_params(adapter, vdev, false); 282 if (status != QDF_STATUS_SUCCESS) 283 hdd_debug("Failed to disable igmp offload"); 284 } 285 #else hdd_enable_igmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)286 static inline void hdd_enable_igmp_offload(struct hdd_adapter *adapter, 287 struct wlan_objmgr_vdev *vdev) 288 {} 289 290 static inline QDF_STATUS hdd_send_igmp_offload_params(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,bool enable)291 hdd_send_igmp_offload_params(struct hdd_adapter *adapter, 292 struct wlan_objmgr_vdev *vdev, bool enable) 293 { 294 return QDF_STATUS_SUCCESS; 295 } 296 hdd_disable_igmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)297 static inline void hdd_disable_igmp_offload(struct hdd_adapter *adapter, 298 struct wlan_objmgr_vdev *vdev) 299 {} 300 #endif 301 302 /** 303 * hdd_disable_gtk_offload() - disable GTK offload 304 * @adapter: pointer to the adapter 305 * @vdev: VDEV objmgr pointer 306 * 307 * Central function to disable GTK offload. 308 * 309 * Return: nothing 310 */ hdd_disable_gtk_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)311 static void hdd_disable_gtk_offload(struct hdd_adapter *adapter, 312 struct wlan_objmgr_vdev *vdev) 313 { 314 struct pmo_gtk_rsp_req gtk_rsp_request; 315 QDF_STATUS status; 316 317 /* ensure to get gtk rsp first before disable it*/ 318 gtk_rsp_request.callback = wlan_hdd_cfg80211_update_replay_counter_cb; 319 320 /* Passing as void* as PMO does not know legacy HDD adapter type */ 321 gtk_rsp_request.callback_context = (void *)adapter; 322 323 status = ucfg_pmo_get_gtk_rsp(vdev, >k_rsp_request); 324 if (status != QDF_STATUS_SUCCESS) { 325 hdd_err("Failed to send get gtk rsp status:%d", status); 326 return; 327 } 328 329 hdd_debug("send get_gtk_rsp successful"); 330 status = ucfg_pmo_disable_gtk_offload_in_fwr(vdev); 331 if (status != QDF_STATUS_SUCCESS) 332 hdd_info("Failed to disable gtk offload"); 333 } 334 335 #ifdef WLAN_NS_OFFLOAD 336 /** 337 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function 338 * @net_dev: net_device whose IP address changed 339 * @event: event from kernel, NETDEV_UP or NETDEV_DOWN 340 * 341 * This is a callback function that is registered with the kernel via 342 * register_inet6addr_notifier() which allows the driver to be 343 * notified when there is an IPv6 address change. 344 * 345 * Return: None 346 */ __wlan_hdd_ipv6_changed(struct net_device * net_dev,unsigned long event)347 static void __wlan_hdd_ipv6_changed(struct net_device *net_dev, 348 unsigned long event) 349 { 350 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); 351 struct hdd_context *hdd_ctx; 352 int errno; 353 354 hdd_enter_dev(net_dev); 355 356 errno = hdd_validate_adapter(adapter); 357 if (errno || adapter->dev != net_dev) 358 goto exit; 359 360 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 361 errno = wlan_hdd_validate_context(hdd_ctx); 362 if (errno) 363 goto exit; 364 365 /* Only need to be notified for ipv6_add_addr 366 * No need for ipv6_del_addr or addrconf_ifdown 367 */ 368 if (event == NETDEV_UP && 369 (adapter->device_mode == QDF_STA_MODE || 370 adapter->device_mode == QDF_P2P_CLIENT_MODE)) { 371 hdd_debug("invoking sme_dhcp_done_ind"); 372 sme_dhcp_done_ind(hdd_ctx->mac_handle, 373 adapter->deflink->vdev_id); 374 schedule_work(&adapter->ipv6_notifier_work); 375 } 376 377 exit: 378 hdd_exit(); 379 } 380 wlan_hdd_ipv6_changed(struct notifier_block * nb,unsigned long data,void * context)381 int wlan_hdd_ipv6_changed(struct notifier_block *nb, 382 unsigned long data, void *context) 383 { 384 struct inet6_ifaddr *ifa = context; 385 struct net_device *net_dev = ifa->idev->dev; 386 struct osif_vdev_sync *vdev_sync; 387 388 if (osif_vdev_sync_op_start(net_dev, &vdev_sync)) 389 return NOTIFY_DONE; 390 391 __wlan_hdd_ipv6_changed(net_dev, data); 392 393 osif_vdev_sync_op_stop(vdev_sync); 394 395 return NOTIFY_DONE; 396 } 397 398 /** 399 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses 400 * @idev: pointer to net device 401 * @ipv6_uc_addr: destination array to fill IPv6 addresses 402 * @ipv6addr_type: IPv6 Address type 403 * @scope_array: scope of ipv6 addr 404 * @count: number of IPv6 addresses 405 * 406 * This is the IPv6 utility function to populate unicast addresses. 407 * 408 * Return: 0 on success, error number otherwise. 409 */ hdd_fill_ipv6_uc_addr(struct inet6_dev * idev,uint8_t ipv6_uc_addr[][QDF_IPV6_ADDR_SIZE],uint8_t * ipv6addr_type,enum pmo_ns_addr_scope * scope_array,uint32_t * count)410 static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev, 411 uint8_t ipv6_uc_addr[][QDF_IPV6_ADDR_SIZE], 412 uint8_t *ipv6addr_type, 413 enum pmo_ns_addr_scope *scope_array, 414 uint32_t *count) 415 { 416 struct inet6_ifaddr *ifa; 417 struct list_head *p; 418 uint32_t scope; 419 420 read_lock_bh(&idev->lock); 421 list_for_each(p, &idev->addr_list) { 422 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) { 423 read_unlock_bh(&idev->lock); 424 return -EINVAL; 425 } 426 ifa = list_entry(p, struct inet6_ifaddr, if_list); 427 if (ifa->flags & IFA_F_DADFAILED) 428 continue; 429 scope = ipv6_addr_src_scope(&ifa->addr); 430 switch (scope) { 431 case IPV6_ADDR_SCOPE_GLOBAL: 432 case IPV6_ADDR_SCOPE_LINKLOCAL: 433 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr, 434 sizeof(ifa->addr.s6_addr)); 435 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE; 436 scope_array[*count] = ucfg_pmo_ns_addr_scope(scope); 437 hdd_debug("Index %d scope = %s UC-Address: %pI6", 438 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ? 439 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]); 440 *count += 1; 441 break; 442 default: 443 hdd_warn("The Scope %d is not supported", scope); 444 } 445 } 446 447 read_unlock_bh(&idev->lock); 448 return 0; 449 } 450 451 /** 452 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses 453 * @idev: pointer to net device 454 * @ipv6_ac_addr: destination array to fill IPv6 addresses 455 * @ipv6addr_type: IPv6 Address type 456 * @scope_array: scope of ipv6 addr 457 * @count: number of IPv6 addresses 458 * 459 * This is the IPv6 utility function to populate anycast addresses. 460 * 461 * Return: 0 on success, error number otherwise. 462 */ hdd_fill_ipv6_ac_addr(struct inet6_dev * idev,uint8_t ipv6_ac_addr[][QDF_IPV6_ADDR_SIZE],uint8_t * ipv6addr_type,enum pmo_ns_addr_scope * scope_array,uint32_t * count)463 static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev, 464 uint8_t ipv6_ac_addr[][QDF_IPV6_ADDR_SIZE], 465 uint8_t *ipv6addr_type, 466 enum pmo_ns_addr_scope *scope_array, 467 uint32_t *count) 468 { 469 struct ifacaddr6 *ifaca; 470 uint32_t scope; 471 472 read_lock_bh(&idev->lock); 473 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) { 474 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) { 475 read_unlock_bh(&idev->lock); 476 return -EINVAL; 477 } 478 /* For anycast addr no DAD */ 479 scope = ipv6_addr_src_scope(&ifaca->aca_addr); 480 switch (scope) { 481 case IPV6_ADDR_SCOPE_GLOBAL: 482 case IPV6_ADDR_SCOPE_LINKLOCAL: 483 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr, 484 sizeof(ifaca->aca_addr)); 485 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE; 486 scope_array[*count] = ucfg_pmo_ns_addr_scope(scope); 487 hdd_debug("Index %d scope = %s AC-Address: %pI6", 488 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ? 489 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]); 490 *count += 1; 491 break; 492 default: 493 hdd_warn("The Scope %d is not supported", scope); 494 } 495 } 496 497 read_unlock_bh(&idev->lock); 498 return 0; 499 } 500 hdd_enable_ns_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)501 void hdd_enable_ns_offload(struct hdd_adapter *adapter, 502 struct wlan_objmgr_vdev *vdev, 503 enum pmo_offload_trigger trigger) 504 { 505 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 506 struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; 507 struct inet6_dev *in6_dev; 508 struct pmo_ns_req *ns_req; 509 QDF_STATUS status; 510 int errno; 511 uint8_t vdev_id; 512 513 hdd_enter(); 514 515 if (!psoc) { 516 hdd_err("psoc is NULL"); 517 goto out; 518 } 519 520 in6_dev = __in6_dev_get(adapter->dev); 521 if (!in6_dev) { 522 hdd_err("IPv6 dev does not exist. Failed to request NSOffload"); 523 goto out; 524 } 525 526 ns_req = qdf_mem_malloc(sizeof(*ns_req)); 527 if (!ns_req) 528 goto out; 529 530 vdev_id = wlan_vdev_get_id(vdev); 531 532 ns_req->psoc = psoc; 533 ns_req->vdev_id = vdev_id; 534 ns_req->trigger = trigger; 535 ns_req->count = 0; 536 537 /* check if offload cache and send is required or not */ 538 status = ucfg_pmo_ns_offload_check(psoc, trigger, vdev_id); 539 if (QDF_IS_STATUS_ERROR(status)) { 540 hdd_debug("NS offload is not required"); 541 goto free_req; 542 } 543 544 if (ucfg_pmo_get_arp_ns_offload_dynamic_disable(vdev)) { 545 hdd_debug("Dynamic arp ns offload disabled"); 546 ucfg_pmo_flush_ns_offload_req(vdev); 547 goto skip_cache_ns; 548 } 549 550 /* Unicast Addresses */ 551 errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr, 552 ns_req->ipv6_addr_type, ns_req->scope, 553 &ns_req->count); 554 if (errno) { 555 hdd_disable_ns_offload(adapter, vdev, trigger); 556 hdd_debug("Max supported addresses: disabling NS offload"); 557 goto free_req; 558 } 559 560 /* Anycast Addresses */ 561 errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr, 562 ns_req->ipv6_addr_type, ns_req->scope, 563 &ns_req->count); 564 if (errno) { 565 hdd_disable_ns_offload(adapter, vdev, trigger); 566 hdd_debug("Max supported addresses: disabling NS offload"); 567 goto free_req; 568 } 569 570 /* cache ns request */ 571 status = ucfg_pmo_cache_ns_offload_req(ns_req); 572 if (QDF_IS_STATUS_ERROR(status)) { 573 hdd_debug("Failed to cache ns request; status:%d", status); 574 goto free_req; 575 } 576 577 skip_cache_ns: 578 /* enable ns request */ 579 status = ucfg_pmo_enable_ns_offload_in_fwr(vdev, trigger); 580 if (QDF_IS_STATUS_ERROR(status)) { 581 hdd_debug("Failed to enable ns offload; status:%d", status); 582 goto free_req; 583 } 584 585 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE); 586 free_req: 587 qdf_mem_free(ns_req); 588 589 out: 590 hdd_exit(); 591 } 592 hdd_disable_ns_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)593 void hdd_disable_ns_offload(struct hdd_adapter *adapter, 594 struct wlan_objmgr_vdev *vdev, 595 enum pmo_offload_trigger trigger) 596 { 597 QDF_STATUS status; 598 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 599 600 hdd_enter(); 601 602 status = ucfg_pmo_ns_offload_check(hdd_ctx->psoc, trigger, 603 wlan_vdev_get_id(vdev)); 604 if (status != QDF_STATUS_SUCCESS) { 605 hdd_debug("Flushing of NS offload not required"); 606 goto out; 607 } 608 609 status = ucfg_pmo_flush_ns_offload_req(vdev); 610 if (status != QDF_STATUS_SUCCESS) { 611 hdd_err("Failed to flush NS Offload"); 612 goto out; 613 } 614 615 status = ucfg_pmo_disable_ns_offload_in_fwr(vdev, trigger); 616 if (status != QDF_STATUS_SUCCESS) 617 hdd_err("Failed to disable NS Offload"); 618 else 619 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, 620 SIR_OFFLOAD_DISABLE); 621 out: 622 hdd_exit(); 623 624 } 625 626 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) 627 #ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV hdd_send_mlo_ps_to_fw(struct hdd_adapter * adapter)628 static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter) 629 { 630 struct wlan_hdd_link_info *link_info; 631 mac_handle_t mac_handle; 632 633 if (!adapter) { 634 hdd_err_rl("null hdd_adapter pointer"); 635 return; 636 } 637 638 mac_handle = hdd_adapter_get_mac_handle(adapter); 639 640 if (!mac_handle) { 641 hdd_err_rl("null mac_handle pointer"); 642 return; 643 } 644 645 hdd_adapter_for_each_active_link_info(adapter, link_info) 646 sme_ps_update(mac_handle, link_info->vdev_id); 647 } 648 #else hdd_send_mlo_ps_to_fw(struct hdd_adapter * adapter)649 static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter) 650 { 651 int i; 652 struct hdd_adapter *link_adapter; 653 struct hdd_mlo_adapter_info *mlo_adapter_info; 654 mac_handle_t mac_handle; 655 656 if (!adapter) { 657 hdd_err_rl("null hdd_adapter pointer"); 658 return; 659 } 660 661 mac_handle = hdd_adapter_get_mac_handle(adapter); 662 663 if (!mac_handle) { 664 hdd_err_rl("null mac_handle pointer"); 665 return; 666 } 667 668 mlo_adapter_info = &adapter->mlo_adapter_info; 669 for (i = 0; i < WLAN_MAX_MLD; i++) { 670 link_adapter = mlo_adapter_info->link_adapter[i]; 671 if (!link_adapter) 672 continue; 673 sme_ps_update(mac_handle, link_adapter->deflink->vdev_id); 674 } 675 } 676 #endif 677 #else hdd_send_mlo_ps_to_fw(struct hdd_adapter * adapter)678 static inline void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter) 679 {} 680 #endif 681 hdd_send_ps_config_to_fw(struct hdd_adapter * adapter)682 void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter) 683 { 684 struct hdd_context *hdd_ctx; 685 bool is_mlo_vdev; 686 687 if (hdd_validate_adapter(adapter)) 688 return; 689 690 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 691 692 is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(adapter->deflink->vdev); 693 694 if (!is_mlo_vdev) { 695 sme_ps_update(hdd_ctx->mac_handle, adapter->deflink->vdev_id); 696 return; 697 } 698 699 hdd_send_mlo_ps_to_fw(adapter); 700 } 701 702 /** 703 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function 704 * @adapter: adapter whose IP address changed 705 * 706 * This function performs the work initially triggered by a callback 707 * from the IPv6 netdev notifier. Since this means there has been a 708 * change in IPv6 state for the interface, the NS offload is 709 * reconfigured. 710 * 711 * Return: None 712 */ __hdd_ipv6_notifier_work_queue(struct hdd_adapter * adapter)713 static void __hdd_ipv6_notifier_work_queue(struct hdd_adapter *adapter) 714 { 715 struct hdd_context *hdd_ctx; 716 int errno; 717 struct wlan_objmgr_vdev *vdev; 718 719 hdd_enter(); 720 721 errno = hdd_validate_adapter(adapter); 722 if (errno) 723 goto exit; 724 725 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 726 errno = wlan_hdd_validate_context(hdd_ctx); 727 if (errno) 728 goto exit; 729 730 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); 731 if (!vdev) 732 goto exit; 733 734 hdd_enable_ns_offload(adapter, vdev, pmo_ipv6_change_notify); 735 hdd_enable_icmp_offload(adapter, vdev, pmo_ipv6_change_notify); 736 hdd_send_ps_config_to_fw(adapter); 737 738 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); 739 exit: 740 hdd_exit(); 741 } 742 hdd_ipv6_notifier_work_queue(struct work_struct * work)743 void hdd_ipv6_notifier_work_queue(struct work_struct *work) 744 { 745 struct hdd_adapter *adapter = container_of(work, struct hdd_adapter, 746 ipv6_notifier_work); 747 struct osif_vdev_sync *vdev_sync; 748 749 if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync)) 750 return; 751 752 __hdd_ipv6_notifier_work_queue(adapter); 753 754 osif_vdev_sync_op_stop(vdev_sync); 755 } 756 #endif /* WLAN_NS_OFFLOAD */ 757 hdd_enable_hw_filter(struct wlan_objmgr_vdev * vdev)758 static void hdd_enable_hw_filter(struct wlan_objmgr_vdev *vdev) 759 { 760 QDF_STATUS status; 761 762 hdd_enter(); 763 764 status = ucfg_pmo_enable_hw_filter_in_fwr(vdev); 765 if (status != QDF_STATUS_SUCCESS) 766 hdd_info("Failed to enable hardware filter"); 767 768 hdd_exit(); 769 } 770 hdd_disable_hw_filter(struct wlan_objmgr_vdev * vdev)771 static void hdd_disable_hw_filter(struct wlan_objmgr_vdev *vdev) 772 { 773 QDF_STATUS status; 774 775 hdd_enter(); 776 777 status = ucfg_pmo_disable_hw_filter_in_fwr(vdev); 778 if (status != QDF_STATUS_SUCCESS) 779 hdd_info("Failed to disable hardware filter"); 780 781 hdd_exit(); 782 } 783 hdd_enable_action_frame_patterns(struct wlan_objmgr_vdev * vdev)784 static void hdd_enable_action_frame_patterns(struct wlan_objmgr_vdev *vdev) 785 { 786 QDF_STATUS status; 787 788 hdd_enter(); 789 790 status = ucfg_pmo_enable_action_frame_patterns(vdev, 791 QDF_SYSTEM_SUSPEND); 792 if (QDF_IS_STATUS_ERROR(status)) 793 hdd_info("Failed to enable action frame patterns"); 794 795 hdd_exit(); 796 } 797 hdd_disable_action_frame_patterns(struct wlan_objmgr_vdev * vdev)798 static void hdd_disable_action_frame_patterns(struct wlan_objmgr_vdev *vdev) 799 { 800 QDF_STATUS status; 801 802 hdd_enter(); 803 804 status = ucfg_pmo_disable_action_frame_patterns(vdev); 805 if (QDF_IS_STATUS_ERROR(status)) 806 hdd_info("Failed to disable action frame patterns"); 807 808 hdd_exit(); 809 } 810 hdd_enable_host_offloads(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)811 void hdd_enable_host_offloads(struct hdd_adapter *adapter, 812 enum pmo_offload_trigger trigger) 813 { 814 struct wlan_objmgr_vdev *vdev; 815 816 hdd_enter(); 817 818 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, 819 WLAN_OSIF_POWER_ID); 820 if (!vdev) { 821 hdd_err("vdev is NULL"); 822 goto out; 823 } 824 825 if (!ucfg_pmo_is_vdev_supports_offload(vdev)) { 826 hdd_debug("offload is not supported on vdev opmode %d", 827 adapter->device_mode); 828 goto put_vdev; 829 } 830 831 if (!ucfg_pmo_is_vdev_connected(vdev)) { 832 hdd_debug("offload is not supported on disconnected vdevs"); 833 goto put_vdev; 834 } 835 836 hdd_debug("enable offloads"); 837 hdd_enable_gtk_offload(vdev); 838 hdd_enable_arp_offload(adapter, vdev, trigger); 839 hdd_enable_ns_offload(adapter, vdev, trigger); 840 hdd_enable_mc_addr_filtering(adapter, trigger); 841 if (adapter->device_mode == QDF_STA_MODE) 842 hdd_enable_igmp_offload(adapter, vdev); 843 844 if (adapter->device_mode != QDF_NDI_MODE) 845 hdd_enable_hw_filter(vdev); 846 hdd_enable_action_frame_patterns(vdev); 847 put_vdev: 848 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); 849 out: 850 hdd_exit(); 851 852 } 853 hdd_disable_host_offloads(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)854 void hdd_disable_host_offloads(struct hdd_adapter *adapter, 855 enum pmo_offload_trigger trigger) 856 { 857 struct wlan_objmgr_vdev *vdev; 858 859 hdd_enter(); 860 861 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, 862 WLAN_OSIF_POWER_ID); 863 if (!vdev) { 864 hdd_err("vdev is NULL"); 865 goto out; 866 } 867 868 if (!ucfg_pmo_is_vdev_supports_offload(vdev)) { 869 hdd_info("offload is not supported on this vdev opmode: %d", 870 adapter->device_mode); 871 goto put_vdev; 872 } 873 874 if (!ucfg_pmo_is_vdev_connected(vdev)) { 875 hdd_info("vdev is not connected"); 876 goto put_vdev; 877 } 878 879 hdd_debug("disable offloads"); 880 hdd_disable_gtk_offload(adapter, vdev); 881 hdd_disable_arp_offload(adapter, vdev, trigger); 882 hdd_disable_ns_offload(adapter, vdev, trigger); 883 hdd_disable_mc_addr_filtering(adapter, trigger); 884 if (adapter->device_mode == QDF_STA_MODE) 885 hdd_disable_igmp_offload(adapter, vdev); 886 if (adapter->device_mode != QDF_NDI_MODE) 887 hdd_disable_hw_filter(vdev); 888 hdd_disable_action_frame_patterns(vdev); 889 890 put_vdev: 891 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); 892 out: 893 hdd_exit(); 894 895 } 896 897 /** 898 * hdd_lookup_ifaddr() - Lookup interface address data by name 899 * @adapter: the adapter whose name should be searched for 900 * 901 * return in_ifaddr pointer on success, NULL for failure 902 */ hdd_lookup_ifaddr(struct hdd_adapter * adapter)903 static struct in_ifaddr *hdd_lookup_ifaddr(struct hdd_adapter *adapter) 904 { 905 struct in_ifaddr *ifa; 906 struct in_device *in_dev; 907 908 if (!adapter) { 909 hdd_err("adapter is null"); 910 return NULL; 911 } 912 913 in_dev = __in_dev_get_rtnl(adapter->dev); 914 if (!in_dev) { 915 hdd_err("Failed to get in_device"); 916 return NULL; 917 } 918 919 /* lookup address data by interface name */ 920 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { 921 if (!strcmp(adapter->dev->name, ifa->ifa_label)) 922 return ifa; 923 } 924 925 return NULL; 926 } 927 928 /** 929 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address 930 * @adapter: the adapter whose IPv4 address is desired 931 * @ipv4_addr: the address of the array to copy the IPv4 address into 932 * 933 * return: zero for success; non-zero for failure 934 */ hdd_populate_ipv4_addr(struct hdd_adapter * adapter,uint8_t * ipv4_addr)935 static int hdd_populate_ipv4_addr(struct hdd_adapter *adapter, 936 uint8_t *ipv4_addr) 937 { 938 struct in_ifaddr *ifa; 939 int i; 940 941 if (!adapter) { 942 hdd_err("adapter is null"); 943 return -EINVAL; 944 } 945 946 if (!ipv4_addr) { 947 hdd_err("ipv4_addr is null"); 948 return -EINVAL; 949 } 950 951 ifa = hdd_lookup_ifaddr(adapter); 952 if (!ifa || !ifa->ifa_local) { 953 hdd_err("ipv4 address not found"); 954 return -EINVAL; 955 } 956 957 /* convert u32 to byte array */ 958 for (i = 0; i < 4; i++) 959 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff; 960 961 return 0; 962 } 963 hdd_set_grat_arp_keepalive(struct hdd_adapter * adapter)964 int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter) 965 { 966 QDF_STATUS status; 967 int exit_code; 968 struct hdd_context *hdd_ctx; 969 struct hdd_station_ctx *sta_ctx; 970 struct keep_alive_req req = { 971 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP, 972 .dest_macaddr = QDF_MAC_ADDR_BCAST_INIT, 973 }; 974 975 if (!adapter) { 976 hdd_err("adapter is null"); 977 return -EINVAL; 978 } 979 980 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 981 if (!hdd_ctx) { 982 hdd_err("hdd_ctx is null"); 983 return -EINVAL; 984 } 985 986 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); 987 if (!sta_ctx) { 988 hdd_err("sta_ctx is null"); 989 return -EINVAL; 990 } 991 992 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr); 993 if (exit_code) { 994 hdd_err("Failed to populate ipv4 address"); 995 return exit_code; 996 } 997 998 /* according to RFC5227, sender/target ip address should be the same */ 999 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr, 1000 sizeof(req.destIpv4Addr)); 1001 1002 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssid); 1003 ucfg_mlme_get_sta_keep_alive_period(hdd_ctx->psoc, &req.timePeriod); 1004 req.sessionId = adapter->deflink->vdev_id; 1005 1006 hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u", 1007 req.hostIpv4Addr[0], req.hostIpv4Addr[1], 1008 req.hostIpv4Addr[2], req.hostIpv4Addr[3]); 1009 1010 status = sme_set_keep_alive(hdd_ctx->mac_handle, req.sessionId, &req); 1011 if (QDF_IS_STATUS_ERROR(status)) { 1012 hdd_err("Failed to set keepalive"); 1013 return qdf_status_to_os_return(status); 1014 } 1015 1016 return 0; 1017 } 1018 1019 /** 1020 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function 1021 * @adapter: adapter whose IP address changed 1022 * 1023 * This function performs the work initially triggered by a callback 1024 * from the IPv4 netdev notifier. Since this means there has been a 1025 * change in IPv4 state for the interface, the ARP offload is 1026 * reconfigured. Also, Updates the HLP IE info with IP address info 1027 * to fw if LFR3 is enabled 1028 * 1029 * Return: None 1030 */ __hdd_ipv4_notifier_work_queue(struct hdd_adapter * adapter)1031 static void __hdd_ipv4_notifier_work_queue(struct hdd_adapter *adapter) 1032 { 1033 struct hdd_context *hdd_ctx; 1034 int errno; 1035 struct in_ifaddr *ifa; 1036 enum station_keepalive_method val; 1037 QDF_STATUS status; 1038 struct wlan_objmgr_vdev *vdev; 1039 1040 hdd_enter(); 1041 1042 errno = hdd_validate_adapter(adapter); 1043 if (errno) 1044 goto exit; 1045 1046 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1047 errno = wlan_hdd_validate_context(hdd_ctx); 1048 if (errno) 1049 goto exit; 1050 1051 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); 1052 if (!vdev) 1053 goto exit; 1054 1055 hdd_enable_arp_offload(adapter, vdev, pmo_ipv4_change_notify); 1056 hdd_enable_icmp_offload(adapter, vdev, pmo_ipv4_change_notify); 1057 1058 status = ucfg_mlme_get_sta_keepalive_method(hdd_ctx->psoc, &val); 1059 if (QDF_IS_STATUS_ERROR(status)) 1060 goto vdev_ref; 1061 1062 if (val == MLME_STA_KEEPALIVE_GRAT_ARP) 1063 hdd_set_grat_arp_keepalive(adapter); 1064 1065 hdd_debug("FILS Roaming support: %d", 1066 hdd_ctx->is_fils_roaming_supported); 1067 1068 ifa = hdd_lookup_ifaddr(adapter); 1069 if (ifa && hdd_ctx->is_fils_roaming_supported) 1070 sme_send_hlp_ie_info(hdd_ctx->mac_handle, 1071 wlan_vdev_get_id(vdev), 1072 ifa->ifa_local); 1073 hdd_send_ps_config_to_fw(adapter); 1074 1075 vdev_ref: 1076 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); 1077 exit: 1078 hdd_exit(); 1079 } 1080 hdd_ipv4_notifier_work_queue(struct work_struct * work)1081 void hdd_ipv4_notifier_work_queue(struct work_struct *work) 1082 { 1083 struct hdd_adapter *adapter = container_of(work, struct hdd_adapter, 1084 ipv4_notifier_work); 1085 struct osif_vdev_sync *vdev_sync; 1086 1087 if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync)) 1088 return; 1089 1090 __hdd_ipv4_notifier_work_queue(adapter); 1091 1092 osif_vdev_sync_op_stop(vdev_sync); 1093 } 1094 1095 /** 1096 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function 1097 * @net_dev: the net_device whose IP address changed 1098 * 1099 * This is a callback function that is registered with the kernel via 1100 * register_inetaddr_notifier() which allows the driver to be 1101 * notified when there is an IPv4 address change. 1102 * 1103 * Return: None 1104 */ __wlan_hdd_ipv4_changed(struct net_device * net_dev)1105 static void __wlan_hdd_ipv4_changed(struct net_device *net_dev) 1106 { 1107 struct in_ifaddr *ifa; 1108 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); 1109 struct hdd_context *hdd_ctx; 1110 int errno; 1111 1112 hdd_enter_dev(net_dev); 1113 1114 errno = hdd_validate_adapter(adapter); 1115 if (errno || adapter->dev != net_dev) 1116 goto exit; 1117 1118 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1119 errno = wlan_hdd_validate_context(hdd_ctx); 1120 if (errno) 1121 goto exit; 1122 1123 if (adapter->device_mode == QDF_STA_MODE || 1124 adapter->device_mode == QDF_P2P_CLIENT_MODE) { 1125 hdd_debug("invoking sme_dhcp_done_ind"); 1126 sme_dhcp_done_ind(hdd_ctx->mac_handle, 1127 adapter->deflink->vdev_id); 1128 1129 if (!ucfg_pmo_is_arp_offload_enabled(hdd_ctx->psoc)) { 1130 hdd_debug("Offload not enabled"); 1131 goto exit; 1132 } 1133 1134 ifa = hdd_lookup_ifaddr(adapter); 1135 if (ifa && ifa->ifa_local) 1136 schedule_work(&adapter->ipv4_notifier_work); 1137 } 1138 1139 exit: 1140 hdd_exit(); 1141 } 1142 wlan_hdd_ipv4_changed(struct notifier_block * nb,unsigned long data,void * context)1143 int wlan_hdd_ipv4_changed(struct notifier_block *nb, 1144 unsigned long data, void *context) 1145 { 1146 struct in_ifaddr *ifa = context; 1147 struct net_device *net_dev = ifa->ifa_dev->dev; 1148 struct osif_vdev_sync *vdev_sync; 1149 1150 if (osif_vdev_sync_op_start(net_dev, &vdev_sync)) 1151 return NOTIFY_DONE; 1152 1153 __wlan_hdd_ipv4_changed(net_dev); 1154 1155 osif_vdev_sync_op_stop(vdev_sync); 1156 1157 return NOTIFY_DONE; 1158 } 1159 1160 #ifdef FEATURE_RUNTIME_PM 1161 /* For CPU, the enter & exit latency of the deepest LPM mode(CXPC) 1162 * is about ~10ms. so long as required QoS latency is longer than 10ms, 1163 * CPU can enter CXPC mode. 1164 * The vote value is in microseconds. 1165 */ wlan_hdd_is_cpu_cxpc_allowed(struct hdd_context * hdd_ctx,unsigned long vote)1166 static bool wlan_hdd_is_cpu_cxpc_allowed(struct hdd_context *hdd_ctx, 1167 unsigned long vote) 1168 { 1169 if (vote >= hdd_ctx->config->cpu_cxpc_threshold) 1170 return true; 1171 else 1172 return false; 1173 } 1174 wlan_hdd_pm_qos_notify(struct notifier_block * nb,unsigned long curr_val,void * context)1175 int wlan_hdd_pm_qos_notify(struct notifier_block *nb, unsigned long curr_val, 1176 void *context) 1177 { 1178 struct hdd_context *hdd_ctx = container_of(nb, struct hdd_context, 1179 pm_qos_notifier); 1180 void *hif_ctx; 1181 bool is_any_sta_connected = false; 1182 1183 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { 1184 hdd_debug_rl("Driver Module closed; skipping pm qos notify"); 1185 return 0; 1186 } 1187 1188 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); 1189 if (!hif_ctx) 1190 return -EINVAL; 1191 1192 is_any_sta_connected = hdd_is_any_sta_connected(hdd_ctx); 1193 1194 hdd_debug("PM QOS update: runtime_pm_prevented %d Current value: %ld, is_any_sta_connected %d", 1195 hdd_ctx->runtime_pm_prevented, curr_val, 1196 is_any_sta_connected); 1197 qdf_spin_lock_irqsave(&hdd_ctx->pm_qos_lock); 1198 1199 if (!hdd_ctx->runtime_pm_prevented && 1200 is_any_sta_connected && 1201 !wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val)) { 1202 hif_rtpm_get(HIF_RTPM_GET_NORESUME, HIF_RTPM_ID_PM_QOS_NOTIFY); 1203 hdd_ctx->runtime_pm_prevented = true; 1204 } else if (hdd_ctx->runtime_pm_prevented && 1205 wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val)) { 1206 hif_rtpm_put(HIF_RTPM_PUT_NOIDLE, HIF_RTPM_ID_PM_QOS_NOTIFY); 1207 hdd_ctx->runtime_pm_prevented = false; 1208 } 1209 1210 qdf_spin_unlock_irqrestore(&hdd_ctx->pm_qos_lock); 1211 1212 return NOTIFY_DONE; 1213 } 1214 1215 /** cpuidle_governor_latency_req() is not exported by upstream kernel **/ 1216 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) && \ 1217 defined(__ANDROID_COMMON_KERNEL__)) wlan_hdd_is_cpu_pm_qos_in_progress(struct hdd_context * hdd_ctx)1218 bool wlan_hdd_is_cpu_pm_qos_in_progress(struct hdd_context *hdd_ctx) 1219 { 1220 long long curr_val_ns; 1221 long long curr_val_us; 1222 int max_cpu_num; 1223 1224 if (!hdd_is_any_sta_connected(hdd_ctx)) { 1225 hdd_debug("No active wifi connections. Ignore PM QOS vote"); 1226 return false; 1227 } 1228 1229 max_cpu_num = nr_cpu_ids - 1; 1230 1231 /* Get PM QoS vote from last cpu, as no device votes on that cpu 1232 * so by default we get global PM QoS vote from last cpu. 1233 */ 1234 curr_val_ns = cpuidle_governor_latency_req(max_cpu_num); 1235 curr_val_us = curr_val_ns / NSEC_PER_USEC; 1236 hdd_debug("PM QoS current value: %lld", curr_val_us); 1237 if (!wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val_us)) 1238 return true; 1239 else 1240 return false; 1241 } 1242 #endif 1243 #endif 1244 1245 /** 1246 * hdd_get_ipv4_local_interface() - get ipv4 local interface from iface list 1247 * @adapter: Adapter context for which ARP offload is to be configured 1248 * 1249 * Return: 1250 * ifa - on successful operation, 1251 * NULL - on failure of operation 1252 */ hdd_get_ipv4_local_interface(struct hdd_adapter * adapter)1253 static struct in_ifaddr *hdd_get_ipv4_local_interface( 1254 struct hdd_adapter *adapter) 1255 { 1256 struct in_ifaddr **ifap = NULL; 1257 struct in_ifaddr *ifa = NULL; 1258 struct in_device *in_dev; 1259 1260 in_dev = __in_dev_get_rtnl(adapter->dev); 1261 if (in_dev) { 1262 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; 1263 ifap = &ifa->ifa_next) { 1264 if (!strcmp(adapter->dev->name, ifa->ifa_label)) { 1265 /* if match break */ 1266 return ifa; 1267 } 1268 } 1269 } 1270 ifa = NULL; 1271 1272 return ifa; 1273 } 1274 hdd_enable_arp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)1275 void hdd_enable_arp_offload(struct hdd_adapter *adapter, 1276 struct wlan_objmgr_vdev *vdev, 1277 enum pmo_offload_trigger trigger) 1278 { 1279 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1280 struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; 1281 QDF_STATUS status; 1282 struct pmo_arp_req *arp_req; 1283 struct in_ifaddr *ifa; 1284 uint8_t vdev_id; 1285 1286 hdd_enter(); 1287 1288 arp_req = qdf_mem_malloc(sizeof(*arp_req)); 1289 if (!arp_req) 1290 return; 1291 1292 vdev_id = wlan_vdev_get_id(vdev); 1293 1294 arp_req->psoc = psoc; 1295 arp_req->vdev_id = vdev_id; 1296 arp_req->trigger = trigger; 1297 1298 status = ucfg_pmo_check_arp_offload(psoc, trigger, vdev_id); 1299 if (QDF_IS_STATUS_ERROR(status)) { 1300 hdd_debug("ARP offload not required"); 1301 goto free_req; 1302 } 1303 1304 if (ucfg_pmo_get_arp_ns_offload_dynamic_disable(vdev)) { 1305 hdd_debug("Dynamic arp ns offload disabled"); 1306 ucfg_pmo_flush_arp_offload_req(vdev); 1307 goto skip_cache_arp; 1308 } 1309 1310 ifa = hdd_get_ipv4_local_interface(adapter); 1311 if (!ifa || !ifa->ifa_local) { 1312 hdd_info("IP Address is not assigned"); 1313 status = QDF_STATUS_NOT_INITIALIZED; 1314 goto free_req; 1315 } 1316 1317 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local; 1318 1319 status = ucfg_pmo_cache_arp_offload_req(arp_req); 1320 if (QDF_IS_STATUS_ERROR(status)) { 1321 hdd_err("failed to cache arp offload req; status:%d", status); 1322 goto free_req; 1323 } 1324 1325 skip_cache_arp: 1326 status = ucfg_pmo_enable_arp_offload_in_fwr(vdev, trigger); 1327 if (QDF_IS_STATUS_ERROR(status)) { 1328 hdd_err("failed arp offload config in fw; status:%d", status); 1329 goto free_req; 1330 } 1331 1332 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD, PMO_OFFLOAD_ENABLE); 1333 1334 free_req: 1335 qdf_mem_free(arp_req); 1336 } 1337 1338 #ifdef WLAN_FEATURE_ICMP_OFFLOAD 1339 /** 1340 * hdd_fill_ipv4_addr() - fill IPv4 addresses 1341 * @adapter: Adapter context for which ICMP offload is to be configured 1342 * @pmo_icmp_req: pointer to ICMP offload request params 1343 * 1344 * This is the IPv4 utility function to populate address. 1345 * 1346 * Return: 0 on success, error number otherwise. 1347 */ hdd_fill_ipv4_addr(struct hdd_adapter * adapter,struct pmo_icmp_offload * pmo_icmp_req)1348 static int hdd_fill_ipv4_addr(struct hdd_adapter *adapter, 1349 struct pmo_icmp_offload *pmo_icmp_req) 1350 { 1351 struct in_ifaddr *ifa; 1352 uint8_t ipv4_addr_array[QDF_IPV4_ADDR_SIZE]; 1353 int i; 1354 1355 ifa = hdd_get_ipv4_local_interface(adapter); 1356 if (!ifa || !ifa->ifa_local) { 1357 hdd_debug("IP Address is not assigned"); 1358 return -EINVAL; 1359 } 1360 1361 /* converting u32 to IPv4 address */ 1362 for (i = 0; i < QDF_IPV4_ADDR_SIZE; i++) 1363 ipv4_addr_array[i] = (ifa->ifa_local >> i * 8) & 0xff; 1364 1365 qdf_mem_copy(pmo_icmp_req->ipv4_addr, &ipv4_addr_array, 1366 QDF_IPV4_ADDR_SIZE); 1367 1368 return 0; 1369 } 1370 1371 /** 1372 * hdd_fill_ipv6_addr() - fill IPv6 addresses 1373 * @adapter: Adapter context for which ICMP offload is to be configured 1374 * @pmo_icmp_req: pointer to ICMP offload request params 1375 * 1376 * This is the IPv6 utility function to populate addresses. 1377 * 1378 * Return: 0 on success, error number otherwise. 1379 */ hdd_fill_ipv6_addr(struct hdd_adapter * adapter,struct pmo_icmp_offload * pmo_icmp_req)1380 static int hdd_fill_ipv6_addr(struct hdd_adapter *adapter, 1381 struct pmo_icmp_offload *pmo_icmp_req) 1382 { 1383 struct inet6_dev *in6_dev; 1384 struct pmo_ns_req *ns_req; 1385 int i, errno; 1386 1387 in6_dev = __in6_dev_get(adapter->dev); 1388 if (!in6_dev) { 1389 hdd_err_rl("IPv6 dev does not exist"); 1390 return -EINVAL; 1391 } 1392 1393 ns_req = qdf_mem_malloc(sizeof(*ns_req)); 1394 if (!ns_req) 1395 return -ENOMEM; 1396 1397 ns_req->count = 0; 1398 /* Unicast Addresses */ 1399 errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr, 1400 ns_req->ipv6_addr_type, ns_req->scope, 1401 &ns_req->count); 1402 if (errno) { 1403 hdd_debug("Reached Max IPv6 supported address %d", 1404 ns_req->count); 1405 goto free_req; 1406 } 1407 /* Anycast Addresses */ 1408 errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr, 1409 ns_req->ipv6_addr_type, ns_req->scope, 1410 &ns_req->count); 1411 if (errno) { 1412 hdd_debug("Reached Max IPv6 supported address %d", 1413 ns_req->count); 1414 goto free_req; 1415 } 1416 1417 pmo_icmp_req->ipv6_count = ns_req->count; 1418 for (i = 0; i < pmo_icmp_req->ipv6_count; i++) { 1419 qdf_mem_copy(&pmo_icmp_req->ipv6_addr[i], &ns_req->ipv6_addr[i], 1420 QDF_IPV6_ADDR_SIZE); 1421 } 1422 1423 free_req: 1424 qdf_mem_free(ns_req); 1425 return errno; 1426 } 1427 hdd_enable_icmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)1428 void hdd_enable_icmp_offload(struct hdd_adapter *adapter, 1429 struct wlan_objmgr_vdev *vdev, 1430 enum pmo_offload_trigger trigger) 1431 { 1432 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1433 struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; 1434 struct pmo_icmp_offload *pmo_icmp_req; 1435 bool is_icmp_enable; 1436 QDF_STATUS status; 1437 uint8_t vdev_id; 1438 1439 is_icmp_enable = ucfg_pmo_is_icmp_offload_enabled(psoc); 1440 if (!is_icmp_enable) { 1441 hdd_debug("ICMP Offload not enabled"); 1442 return; 1443 } 1444 1445 pmo_icmp_req = qdf_mem_malloc(sizeof(*pmo_icmp_req)); 1446 if (!pmo_icmp_req) 1447 return; 1448 1449 vdev_id = wlan_vdev_get_id(vdev); 1450 status = ucfg_pmo_check_icmp_offload(psoc, vdev_id); 1451 if (QDF_IS_STATUS_ERROR(status)) 1452 goto free_req; 1453 1454 pmo_icmp_req->vdev_id = vdev_id; 1455 pmo_icmp_req->enable = is_icmp_enable; 1456 pmo_icmp_req->trigger = trigger; 1457 1458 switch (trigger) { 1459 case pmo_ipv4_change_notify: 1460 if (hdd_fill_ipv4_addr(adapter, pmo_icmp_req)) { 1461 hdd_debug("Unable to populate IPv4 Address"); 1462 goto free_req; 1463 } 1464 break; 1465 case pmo_ipv6_change_notify: 1466 if (hdd_fill_ipv6_addr(adapter, pmo_icmp_req)) { 1467 hdd_debug("Unable to populate IPv6 Address"); 1468 goto free_req; 1469 } 1470 break; 1471 default: 1472 QDF_DEBUG_PANIC("The trigger %d is not supported", trigger); 1473 goto free_req; 1474 } 1475 1476 status = ucfg_pmo_config_icmp_offload(psoc, pmo_icmp_req); 1477 if (QDF_IS_STATUS_ERROR(status)) 1478 hdd_err_rl("icmp offload config in fw failed: %d", status); 1479 1480 free_req: 1481 qdf_mem_free(pmo_icmp_req); 1482 } 1483 #endif 1484 hdd_disable_arp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)1485 void hdd_disable_arp_offload(struct hdd_adapter *adapter, 1486 struct wlan_objmgr_vdev *vdev, 1487 enum pmo_offload_trigger trigger) 1488 { 1489 QDF_STATUS status; 1490 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1491 1492 hdd_enter(); 1493 1494 status = ucfg_pmo_check_arp_offload(hdd_ctx->psoc, trigger, 1495 wlan_vdev_get_id(vdev)); 1496 if (status != QDF_STATUS_SUCCESS) { 1497 hdd_debug("Flushing of ARP offload not required"); 1498 return; 1499 } 1500 1501 status = ucfg_pmo_flush_arp_offload_req(vdev); 1502 if (status != QDF_STATUS_SUCCESS) { 1503 hdd_err("Failed to flush arp Offload"); 1504 return; 1505 } 1506 1507 status = ucfg_pmo_disable_arp_offload_in_fwr(vdev, trigger); 1508 if (status == QDF_STATUS_SUCCESS) 1509 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD, 1510 PMO_OFFLOAD_DISABLE); 1511 else 1512 hdd_info("fail to disable arp offload"); 1513 } 1514 hdd_enable_mc_addr_filtering(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)1515 void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter, 1516 enum pmo_offload_trigger trigger) 1517 { 1518 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1519 QDF_STATUS status; 1520 1521 if (wlan_hdd_validate_context(hdd_ctx)) 1522 return; 1523 1524 if (!hdd_cm_is_vdev_associated(adapter->deflink)) 1525 return; 1526 1527 status = ucfg_pmo_enable_mc_addr_filtering_in_fwr( 1528 hdd_ctx->psoc, 1529 adapter->deflink->vdev_id, 1530 trigger); 1531 if (QDF_IS_STATUS_ERROR(status)) 1532 hdd_debug("failed to enable mc list; status:%d", status); 1533 1534 } 1535 hdd_disable_mc_addr_filtering(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)1536 void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter, 1537 enum pmo_offload_trigger trigger) 1538 { 1539 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1540 QDF_STATUS status; 1541 1542 if (wlan_hdd_validate_context(hdd_ctx)) 1543 return; 1544 1545 status = ucfg_pmo_disable_mc_addr_filtering_in_fwr( 1546 hdd_ctx->psoc, 1547 adapter->deflink->vdev_id, 1548 trigger); 1549 if (QDF_IS_STATUS_ERROR(status)) 1550 hdd_err("failed to disable mc list; status:%d", status); 1551 } 1552 hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params * mc_list_config)1553 int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config) 1554 { 1555 QDF_STATUS status; 1556 1557 status = ucfg_pmo_cache_mc_addr_list(mc_list_config); 1558 1559 return qdf_status_to_os_return(status); 1560 } 1561 hdd_disable_and_flush_mc_addr_list(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)1562 void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter, 1563 enum pmo_offload_trigger trigger) 1564 { 1565 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1566 QDF_STATUS status; 1567 1568 /* disable mc list first because the mc list is cached in PMO */ 1569 status = ucfg_pmo_disable_mc_addr_filtering_in_fwr( 1570 hdd_ctx->psoc, 1571 adapter->deflink->vdev_id, 1572 trigger); 1573 if (QDF_IS_STATUS_ERROR(status)) 1574 hdd_debug("failed to disable mc list; status:%d", status); 1575 1576 status = ucfg_pmo_flush_mc_addr_list(hdd_ctx->psoc, 1577 adapter->deflink->vdev_id); 1578 if (QDF_IS_STATUS_ERROR(status)) 1579 hdd_debug("failed to flush mc list; status:%d", status); 1580 } 1581 1582 /** 1583 * hdd_update_conn_state_mask() - record info needed by wma_suspend_req 1584 * @adapter: adapter to get info from 1585 * @conn_state_mask: mask of connection info 1586 * 1587 * currently only need to send connection info. 1588 */ hdd_update_conn_state_mask(struct hdd_adapter * adapter,uint32_t * conn_state_mask)1589 static void hdd_update_conn_state_mask(struct hdd_adapter *adapter, 1590 uint32_t *conn_state_mask) 1591 { 1592 if (hdd_cm_is_vdev_associated(adapter->deflink)) 1593 *conn_state_mask |= (1 << adapter->deflink->vdev_id); 1594 } 1595 1596 /** 1597 * hdd_suspend_wlan() - Driver suspend function 1598 * 1599 * Return: 0 on success else error code. 1600 */ 1601 static int hdd_suspend_wlan(void)1602 hdd_suspend_wlan(void) 1603 { 1604 struct hdd_context *hdd_ctx; 1605 QDF_STATUS status; 1606 struct hdd_adapter *adapter = NULL, *next_adapter = NULL; 1607 uint32_t conn_state_mask = 0; 1608 struct wlan_hdd_link_info *link_info; 1609 1610 hdd_info("WLAN being suspended by OS"); 1611 1612 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 1613 if (!hdd_ctx) 1614 return -EINVAL; 1615 1616 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { 1617 hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!", 1618 cds_get_driver_state()); 1619 return -EINVAL; 1620 } 1621 1622 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 1623 NET_DEV_HOLD_SUSPEND_WLAN) { 1624 hdd_adapter_for_each_active_link_info(adapter, link_info) { 1625 if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) 1626 continue; 1627 1628 if (adapter->device_mode == QDF_STA_MODE) 1629 status = hdd_enable_default_pkt_filters( 1630 hdd_ctx, link_info->vdev_id); 1631 1632 /* Configure supported OffLoads */ 1633 hdd_enable_host_offloads(adapter, pmo_apps_suspend); 1634 hdd_update_conn_state_mask(adapter, &conn_state_mask); 1635 } 1636 hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_SUSPEND_WLAN); 1637 } 1638 1639 status = ucfg_pmo_psoc_user_space_suspend_req(hdd_ctx->psoc, 1640 QDF_SYSTEM_SUSPEND); 1641 if (status != QDF_STATUS_SUCCESS) 1642 return -EAGAIN; 1643 1644 hdd_ctx->hdd_wlan_suspended = true; 1645 1646 ucfg_dp_suspend_wlan(hdd_ctx->psoc); 1647 1648 hdd_configure_sar_sleep_index(hdd_ctx); 1649 1650 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND); 1651 1652 return 0; 1653 } 1654 1655 /** 1656 * hdd_resume_wlan() - Driver resume function 1657 * 1658 * Return: 0 on success else error code. 1659 */ hdd_resume_wlan(void)1660 static int hdd_resume_wlan(void) 1661 { 1662 struct hdd_context *hdd_ctx; 1663 struct hdd_adapter *adapter, *next_adapter = NULL; 1664 QDF_STATUS status; 1665 struct wlan_hdd_link_info *link_info; 1666 1667 hdd_info("WLAN being resumed by OS"); 1668 1669 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 1670 if (!hdd_ctx) 1671 return -EINVAL; 1672 1673 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { 1674 hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!", 1675 cds_get_driver_state()); 1676 return -EINVAL; 1677 } 1678 1679 hdd_ctx->hdd_wlan_suspended = false; 1680 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME); 1681 1682 /*loop through all adapters. Concurrency */ 1683 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 1684 NET_DEV_HOLD_RESUME_WLAN) { 1685 hdd_adapter_for_each_active_link_info(adapter, link_info) { 1686 if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) 1687 continue; 1688 1689 /* Disable supported OffLoads */ 1690 hdd_disable_host_offloads(adapter, pmo_apps_resume); 1691 1692 if (adapter->device_mode == QDF_STA_MODE) 1693 status = hdd_disable_default_pkt_filters( 1694 hdd_ctx, link_info->vdev_id); 1695 1696 hdd_restart_tsf_sync_post_wlan_resume(adapter); 1697 } 1698 hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_RESUME_WLAN); 1699 } 1700 1701 ucfg_ipa_resume(hdd_ctx->pdev); 1702 ucfg_dp_resume_wlan(hdd_ctx->psoc); 1703 status = ucfg_pmo_psoc_user_space_resume_req(hdd_ctx->psoc, 1704 QDF_SYSTEM_SUSPEND); 1705 if (QDF_IS_STATUS_ERROR(status)) 1706 return qdf_status_to_os_return(status); 1707 1708 hdd_configure_sar_resume_index(hdd_ctx); 1709 1710 return 0; 1711 } 1712 1713 /** 1714 * hdd_pause_ns() - Network stack pause function 1715 * @hdd_ctx: hdd context 1716 * 1717 * Return: 0 on success else error code. 1718 */ hdd_pause_ns(struct hdd_context * hdd_ctx)1719 static int hdd_pause_ns(struct hdd_context *hdd_ctx) 1720 { 1721 struct hdd_adapter *adapter = NULL, *next_adapter = NULL; 1722 1723 hdd_debug("Pause NS"); 1724 1725 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { 1726 hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!", 1727 cds_get_driver_state()); 1728 return -EINVAL; 1729 } 1730 1731 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 1732 NET_DEV_HOLD_SUSPEND_WLAN) { 1733 if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) { 1734 hdd_adapter_dev_put_debug(adapter, 1735 NET_DEV_HOLD_SUSPEND_WLAN); 1736 continue; 1737 } 1738 1739 /* stop all TX queues before suspend */ 1740 hdd_debug("Disabling queues for dev mode %s", 1741 qdf_opmode_str(adapter->device_mode)); 1742 wlan_hdd_netif_queue_control(adapter, 1743 WLAN_STOP_ALL_NETIF_QUEUE, 1744 WLAN_CONTROL_PATH); 1745 1746 hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_SUSPEND_WLAN); 1747 } 1748 1749 return 0; 1750 } 1751 1752 /** 1753 * hdd_unpause_ns() - Network stack unpause function 1754 * @hdd_ctx: hdd context 1755 * 1756 * Return: 0 on success else error code. 1757 */ hdd_unpause_ns(struct hdd_context * hdd_ctx)1758 static int hdd_unpause_ns(struct hdd_context *hdd_ctx) 1759 { 1760 struct hdd_adapter *adapter, *next_adapter = NULL; 1761 1762 hdd_debug("Unpause NS"); 1763 1764 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { 1765 hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!", 1766 cds_get_driver_state()); 1767 return -EINVAL; 1768 } 1769 1770 /*loop through all adapters. Concurrency */ 1771 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 1772 NET_DEV_HOLD_RESUME_WLAN) { 1773 if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) { 1774 hdd_adapter_dev_put_debug(adapter, 1775 NET_DEV_HOLD_RESUME_WLAN); 1776 continue; 1777 } 1778 1779 /* wake the tx queues */ 1780 hdd_debug("Enabling queues for dev mode %s", 1781 qdf_opmode_str(adapter->device_mode)); 1782 wlan_hdd_netif_queue_control(adapter, 1783 WLAN_WAKE_ALL_NETIF_QUEUE, 1784 WLAN_CONTROL_PATH); 1785 1786 hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_RESUME_WLAN); 1787 } 1788 1789 return 0; 1790 } hdd_svc_fw_shutdown_ind(struct device * dev)1791 void hdd_svc_fw_shutdown_ind(struct device *dev) 1792 { 1793 struct hdd_context *hdd_ctx; 1794 1795 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 1796 1797 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, 1798 WLAN_SVC_FW_SHUTDOWN_IND, 1799 NULL, 0) : 0; 1800 } 1801 1802 /** 1803 * wlan_hdd_set_twt_responder() - wrapper to configure twt responder 1804 * in sap_config 1805 * @hdd_ctx: Pointer to hdd context 1806 * @adapter: Pointer to hostapd hdd adapter 1807 * 1808 * Return: none 1809 */ 1810 #if defined(WLAN_SUPPORT_TWT) && \ 1811 ((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) || \ 1812 defined(CFG80211_TWT_RESPONDER_SUPPORT)) wlan_hdd_set_twt_responder(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)1813 static void wlan_hdd_set_twt_responder(struct hdd_context *hdd_ctx, 1814 struct hdd_adapter *adapter) 1815 { 1816 bool twt_responder; 1817 1818 twt_responder = 1819 adapter->deflink->session.ap.sap_config.cfg80211_twt_responder; 1820 wlan_hdd_configure_twt_responder(hdd_ctx, twt_responder); 1821 } 1822 #else wlan_hdd_set_twt_responder(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)1823 static inline void wlan_hdd_set_twt_responder(struct hdd_context *hdd_ctx, 1824 struct hdd_adapter *adapter) 1825 { 1826 } 1827 #endif 1828 1829 /** 1830 * hdd_ssr_restart_sap() - restart sap on SSR 1831 * @hdd_ctx: hdd context 1832 * 1833 * Return: nothing 1834 */ hdd_ssr_restart_sap(struct hdd_context * hdd_ctx)1835 static void hdd_ssr_restart_sap(struct hdd_context *hdd_ctx) 1836 { 1837 struct hdd_adapter *adapter, *next_adapter = NULL; 1838 1839 hdd_enter(); 1840 1841 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 1842 NET_DEV_HOLD_SSR_RESTART_SAP) { 1843 if (adapter->device_mode != QDF_SAP_MODE) 1844 goto next_adapter; 1845 1846 if (test_bit(SOFTAP_INIT_DONE, &adapter->deflink->link_flags)) { 1847 hdd_debug("Restart prev SAP session, event_flags 0x%lx, link_flags 0x%lx(%s)", 1848 adapter->event_flags, 1849 adapter->deflink->link_flags, 1850 adapter->dev->name); 1851 wlan_hdd_set_twt_responder(hdd_ctx, adapter); 1852 wlan_hdd_start_sap(adapter->deflink, true); 1853 } 1854 next_adapter: 1855 hdd_adapter_dev_put_debug(adapter, 1856 NET_DEV_HOLD_SSR_RESTART_SAP); 1857 } 1858 1859 hdd_exit(); 1860 } 1861 hdd_wlan_shutdown(void)1862 QDF_STATUS hdd_wlan_shutdown(void) 1863 { 1864 struct hdd_context *hdd_ctx; 1865 struct hdd_adapter *adapter; 1866 struct wlan_objmgr_vdev *vdev; 1867 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 1868 1869 hdd_info("WLAN driver shutting down!"); 1870 1871 /* Get the HDD context. */ 1872 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 1873 if (!hdd_ctx) 1874 return QDF_STATUS_E_FAILURE; 1875 1876 if (ucfg_ipa_is_enabled()) { 1877 ucfg_ipa_uc_force_pipe_shutdown(hdd_ctx->pdev); 1878 1879 if (pld_is_fw_rejuvenate(hdd_ctx->parent_dev) || 1880 pld_is_pdr(hdd_ctx->parent_dev)) 1881 ucfg_ipa_fw_rejuvenate_send_msg(hdd_ctx->pdev); 1882 } 1883 1884 hdd_set_connection_in_progress(false); 1885 1886 hdd_debug("Invoking packetdump deregistration API"); 1887 wlan_deregister_txrx_packetdump(OL_TXRX_PDEV_ID); 1888 1889 /* resume wlan threads before adapter reset which does vdev destroy */ 1890 if (hdd_ctx->is_scheduler_suspended) { 1891 scheduler_resume(); 1892 hdd_ctx->is_scheduler_suspended = false; 1893 hdd_ctx->is_wiphy_suspended = false; 1894 hdd_ctx->hdd_wlan_suspended = false; 1895 ucfg_pmo_resume_all_components(hdd_ctx->psoc, 1896 QDF_SYSTEM_SUSPEND); 1897 } 1898 1899 wlan_hdd_rx_thread_resume(hdd_ctx); 1900 1901 if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != 1902 PACKET_CAPTURE_MODE_DISABLE) { 1903 adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); 1904 if (adapter) { 1905 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, 1906 WLAN_OSIF_POWER_ID); 1907 if (vdev) { 1908 ucfg_pkt_capture_resume_mon_thread(vdev); 1909 hdd_objmgr_put_vdev_by_user( 1910 vdev, WLAN_OSIF_POWER_ID); 1911 } else { 1912 hdd_err("vdev is NULL"); 1913 } 1914 } 1915 } 1916 1917 hdd_reset_all_adapters(hdd_ctx); 1918 1919 ucfg_ipa_uc_ssr_cleanup(hdd_ctx->pdev); 1920 1921 /* Flush cached rx frame queue */ 1922 if (soc) 1923 cdp_flush_cache_rx_queue(soc); 1924 1925 /* De-register the HDD callbacks */ 1926 hdd_deregister_cb(hdd_ctx); 1927 1928 hdd_wlan_stop_modules(hdd_ctx, false); 1929 1930 hdd_lpass_notify_stop(hdd_ctx); 1931 1932 qdf_set_smmu_fault_state(false); 1933 hdd_info("WLAN driver shutdown complete"); 1934 1935 return QDF_STATUS_SUCCESS; 1936 } 1937 1938 #ifdef FEATURE_WLAN_DIAG_SUPPORT 1939 /** 1940 * hdd_wlan_ssr_reinit_event() - send ssr reinit state 1941 * 1942 * This Function send send ssr reinit state diag event 1943 * 1944 * Return: void. 1945 */ hdd_wlan_ssr_reinit_event(void)1946 static void hdd_wlan_ssr_reinit_event(void) 1947 { 1948 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit); 1949 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit)); 1950 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT; 1951 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit, 1952 EVENT_WLAN_SSR_REINIT_SUBSYSTEM); 1953 } 1954 #else hdd_wlan_ssr_reinit_event(void)1955 static inline void hdd_wlan_ssr_reinit_event(void) 1956 { 1957 1958 } 1959 #endif 1960 1961 #ifdef WLAN_FEATURE_DBAM_CONFIG 1962 /** 1963 * hdd_restore_dbam_config() - restore and send dbam config to fw 1964 * @hdd_ctx: HDD context 1965 * 1966 * This function is used to send store dbam config to fw 1967 * in case of wlan re-init 1968 * 1969 * Return: void 1970 */ hdd_restore_dbam_config(struct hdd_context * hdd_ctx)1971 static void hdd_restore_dbam_config(struct hdd_context *hdd_ctx) 1972 { 1973 struct hdd_adapter *adapter, *next_adapter = NULL; 1974 wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER; 1975 1976 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 1977 dbgid) { 1978 if (hdd_is_interface_up(adapter) && 1979 adapter->is_dbam_configured) 1980 hdd_send_dbam_config(adapter, hdd_ctx->dbam_mode); 1981 hdd_adapter_dev_put_debug(adapter, dbgid); 1982 } 1983 } 1984 #else hdd_restore_dbam_config(struct hdd_context * hdd_ctx)1985 static inline void hdd_restore_dbam_config(struct hdd_context *hdd_ctx) 1986 { 1987 } 1988 #endif 1989 1990 /** 1991 * hdd_restore_dual_sta_config() - Restore dual sta configuration 1992 * @hdd_ctx: pointer to struct hdd_context 1993 * 1994 * Return: None 1995 */ hdd_restore_dual_sta_config(struct hdd_context * hdd_ctx)1996 static void hdd_restore_dual_sta_config(struct hdd_context *hdd_ctx) 1997 { 1998 QDF_STATUS status; 1999 struct hdd_dual_sta_policy *sta_policy; 2000 2001 sta_policy = &hdd_ctx->dual_sta_policy; 2002 2003 hdd_debug("Restore dual sta config: Primary vdev_id:%d, sta policy:%d", 2004 sta_policy->primary_vdev_id, 2005 sta_policy->dual_sta_policy); 2006 2007 status = 2008 ucfg_mlme_set_primary_interface(hdd_ctx->psoc, 2009 sta_policy->primary_vdev_id); 2010 if (QDF_IS_STATUS_ERROR(status)) 2011 hdd_err("could not set primary interface, %d", status); 2012 2013 status = 2014 ucfg_mlme_set_dual_sta_policy(hdd_ctx->psoc, 2015 sta_policy->dual_sta_policy); 2016 if (QDF_IS_STATUS_ERROR(status)) 2017 hdd_err("failed to set mlme dual sta config"); 2018 } 2019 2020 /** 2021 * hdd_send_default_scan_ies() - send default scan ies to fw 2022 * @hdd_ctx: HDD context 2023 * 2024 * This function is used to send default scan ies to fw 2025 * in case of wlan re-init 2026 * 2027 * Return: void 2028 */ hdd_send_default_scan_ies(struct hdd_context * hdd_ctx)2029 static void hdd_send_default_scan_ies(struct hdd_context *hdd_ctx) 2030 { 2031 struct hdd_adapter *adapter, *next_adapter = NULL; 2032 2033 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 2034 NET_DEV_HOLD_SEND_DEFAULT_SCAN_IES) { 2035 if (hdd_is_interface_up(adapter) && 2036 (adapter->device_mode == QDF_STA_MODE || 2037 adapter->device_mode == QDF_P2P_DEVICE_MODE) && 2038 adapter->scan_info.default_scan_ies) { 2039 sme_set_default_scan_ie(hdd_ctx->mac_handle, 2040 adapter->deflink->vdev_id, 2041 adapter->scan_info.default_scan_ies, 2042 adapter->scan_info.default_scan_ies_len); 2043 } 2044 hdd_adapter_dev_put_debug(adapter, 2045 NET_DEV_HOLD_SEND_DEFAULT_SCAN_IES); 2046 } 2047 } 2048 2049 /** 2050 * hdd_restore_sar_config() - Restore the saved SAR config after SSR 2051 * @hdd_ctx: HDD context 2052 * 2053 * Restore the SAR config that was lost during SSR. 2054 * 2055 * Return: None 2056 */ hdd_restore_sar_config(struct hdd_context * hdd_ctx)2057 static void hdd_restore_sar_config(struct hdd_context *hdd_ctx) 2058 { 2059 QDF_STATUS status; 2060 2061 if (!hdd_ctx->sar_cmd_params) 2062 return; 2063 2064 status = sme_set_sar_power_limits(hdd_ctx->mac_handle, 2065 hdd_ctx->sar_cmd_params); 2066 if (QDF_IS_STATUS_ERROR(status)) 2067 hdd_err("Unable to configured SAR after SSR"); 2068 } 2069 hdd_handle_cached_commands(void)2070 void hdd_handle_cached_commands(void) 2071 { 2072 struct net_device *net_dev; 2073 struct hdd_adapter *adapter = NULL; 2074 struct hdd_context *hdd_ctx; 2075 struct osif_vdev_sync *vdev_sync_arr = osif_get_vdev_sync_arr(); 2076 struct osif_vdev_sync *vdev_sync; 2077 int i; 2078 uint8_t cmd_id; 2079 2080 /* Get the HDD context */ 2081 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 2082 if (!hdd_ctx) 2083 return; 2084 2085 for (i = 0; i < WLAN_MAX_VDEVS; i++) { 2086 vdev_sync = vdev_sync_arr + i; 2087 if (!vdev_sync || !vdev_sync->in_use) 2088 continue; 2089 2090 cmd_id = osif_vdev_get_cached_cmd(vdev_sync); 2091 net_dev = vdev_sync->net_dev; 2092 if (net_dev) { 2093 adapter = WLAN_HDD_GET_PRIV_PTR( 2094 (struct net_device *)net_dev); 2095 if (!adapter) 2096 continue; 2097 } else { 2098 continue; 2099 } 2100 2101 switch (cmd_id) { 2102 case NO_COMMAND: 2103 break; 2104 case INTERFACE_DOWN: 2105 hdd_debug("Handling cached interface down command for %s", 2106 adapter->dev->name); 2107 2108 if (adapter->device_mode == QDF_SAP_MODE || 2109 adapter->device_mode == QDF_P2P_GO_MODE) 2110 hdd_hostapd_stop_no_trans(net_dev); 2111 else 2112 hdd_stop_no_trans(net_dev); 2113 2114 osif_vdev_cache_command(vdev_sync, NO_COMMAND); 2115 break; 2116 default: 2117 break; 2118 } 2119 } 2120 } 2121 hdd_wlan_re_init(void)2122 QDF_STATUS hdd_wlan_re_init(void) 2123 { 2124 struct hdd_context *hdd_ctx = NULL; 2125 struct hdd_adapter *adapter; 2126 int ret; 2127 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT; 2128 bool value; 2129 2130 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); 2131 2132 /* Get the HDD context */ 2133 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 2134 if (!hdd_ctx) 2135 goto err_ctx_null; 2136 2137 bug_on_reinit_failure = hdd_ctx->config->bug_on_reinit_failure; 2138 2139 adapter = hdd_get_first_valid_adapter(hdd_ctx); 2140 if (!adapter) 2141 hdd_err("Failed to get adapter"); 2142 2143 ret = hdd_wlan_start_modules(hdd_ctx, true); 2144 if (ret) { 2145 hdd_err("Failed to start wlan after error"); 2146 goto err_re_init; 2147 } 2148 2149 hdd_update_hw_sw_info(hdd_ctx); 2150 2151 wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, 2152 WLAN_SVC_FW_CRASHED_IND, NULL, 0); 2153 2154 /* Restart all adapters */ 2155 hdd_start_all_adapters(hdd_ctx, false); 2156 2157 hdd_init_scan_reject_params(hdd_ctx); 2158 hdd_ctx->bt_coex_mode_set = false; 2159 2160 /* Allow the phone to go to sleep */ 2161 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); 2162 /* set chip power save failure detected callback */ 2163 sme_set_chip_pwr_save_fail_cb(hdd_ctx->mac_handle, 2164 hdd_chip_pwr_save_fail_detected_cb); 2165 2166 hdd_restore_thermal_mitigation_config(hdd_ctx); 2167 hdd_restore_sar_config(hdd_ctx); 2168 2169 hdd_send_default_scan_ies(hdd_ctx); 2170 hdd_restore_dual_sta_config(hdd_ctx); 2171 hdd_restore_dbam_config(hdd_ctx); 2172 hdd_info("WLAN host driver reinitiation completed!"); 2173 2174 ucfg_mlme_get_sap_internal_restart(hdd_ctx->psoc, &value); 2175 if (value) 2176 hdd_ssr_restart_sap(hdd_ctx); 2177 hdd_wlan_ssr_reinit_event(); 2178 2179 if (hdd_ctx->is_wiphy_suspended) 2180 hdd_ctx->is_wiphy_suspended = false; 2181 2182 if (hdd_ctx->hdd_wlan_suspended) 2183 hdd_ctx->hdd_wlan_suspended = false; 2184 2185 return QDF_STATUS_SUCCESS; 2186 2187 err_re_init: 2188 qdf_dp_trace_deinit(); 2189 2190 err_ctx_null: 2191 /* Allow the phone to go to sleep */ 2192 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); 2193 if (bug_on_reinit_failure) 2194 QDF_BUG(0); 2195 return -EPERM; 2196 } 2197 wlan_hdd_set_powersave(struct wlan_hdd_link_info * link_info,bool allow_power_save,uint32_t timeout)2198 int wlan_hdd_set_powersave(struct wlan_hdd_link_info *link_info, 2199 bool allow_power_save, uint32_t timeout) 2200 { 2201 struct hdd_adapter *adapter = link_info->adapter; 2202 struct hdd_context *hdd_ctx; 2203 QDF_STATUS status; 2204 struct hdd_station_ctx *sta_ctx; 2205 2206 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 2207 if (!hdd_ctx) { 2208 hdd_err("hdd context is NULL"); 2209 return -EINVAL; 2210 } 2211 2212 if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) 2213 return -EINVAL; 2214 2215 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); 2216 2217 status = sme_ps_set_powersave( 2218 hdd_ctx->mac_handle, link_info->vdev_id, 2219 allow_power_save, timeout, 2220 sta_ctx->ap_supports_immediate_power_save); 2221 if (!allow_power_save && adapter->device_mode == QDF_STA_MODE) 2222 hdd_twt_del_dialog_in_ps_disable(hdd_ctx, 2223 &sta_ctx->conn_info.bssid, 2224 link_info->vdev_id); 2225 2226 return qdf_status_to_os_return(status); 2227 } 2228 wlan_hdd_print_suspend_fail_stats(struct hdd_context * hdd_ctx)2229 static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx) 2230 { 2231 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats; 2232 2233 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d", 2234 stats->suspend_fail[SUSPEND_FAIL_IPA], 2235 stats->suspend_fail[SUSPEND_FAIL_RADAR], 2236 stats->suspend_fail[SUSPEND_FAIL_ROAM], 2237 stats->suspend_fail[SUSPEND_FAIL_SCAN], 2238 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]); 2239 } 2240 wlan_hdd_inc_suspend_stats(struct hdd_context * hdd_ctx,enum suspend_fail_reason reason)2241 void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx, 2242 enum suspend_fail_reason reason) 2243 { 2244 wlan_hdd_print_suspend_fail_stats(hdd_ctx); 2245 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++; 2246 wlan_hdd_print_suspend_fail_stats(hdd_ctx); 2247 } 2248 2249 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) 2250 static inline void hdd_sched_scan_results(struct wiphy * wiphy,uint64_t reqid)2251 hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid) 2252 { 2253 cfg80211_sched_scan_results(wiphy); 2254 } 2255 #else 2256 static inline void hdd_sched_scan_results(struct wiphy * wiphy,uint64_t reqid)2257 hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid) 2258 { 2259 cfg80211_sched_scan_results(wiphy, reqid); 2260 } 2261 #endif 2262 2263 /** 2264 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback 2265 * @wiphy: Pointer to wiphy 2266 * 2267 * This API is called when cfg80211 driver resumes driver updates 2268 * latest sched_scan scan result(if any) to cfg80211 database 2269 * 2270 * Return: integer status 2271 */ __wlan_hdd_cfg80211_resume_wlan(struct wiphy * wiphy)2272 static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) 2273 { 2274 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2275 QDF_STATUS status = QDF_STATUS_SUCCESS; 2276 struct hdd_adapter *adapter; 2277 struct wlan_objmgr_vdev *vdev; 2278 int exit_code; 2279 2280 hdd_enter(); 2281 2282 if (cds_is_driver_recovering()) { 2283 hdd_debug("Driver is recovering; Skipping resume"); 2284 exit_code = 0; 2285 goto exit_with_code; 2286 } 2287 2288 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() || 2289 QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) { 2290 hdd_err("Command not allowed in mode %d", 2291 hdd_get_conparam()); 2292 exit_code = -EINVAL; 2293 goto exit_with_code; 2294 } 2295 2296 if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) == PMO_SUSPEND_NONE) { 2297 hdd_info_rl("Suspend is not supported"); 2298 return -EINVAL; 2299 } 2300 2301 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { 2302 hdd_debug("Driver is not enabled; Skipping resume"); 2303 exit_code = 0; 2304 goto exit_with_code; 2305 } 2306 2307 status = hdd_resume_wlan(); 2308 if (status != QDF_STATUS_SUCCESS) { 2309 exit_code = 0; 2310 goto exit_with_code; 2311 } 2312 /* Resume control path scheduler */ 2313 if (hdd_ctx->is_scheduler_suspended) { 2314 scheduler_resume(); 2315 hdd_ctx->is_scheduler_suspended = false; 2316 } 2317 /* Resume all components registered to pmo */ 2318 status = ucfg_pmo_resume_all_components(hdd_ctx->psoc, 2319 QDF_SYSTEM_SUSPEND); 2320 2321 /* Unpause NS no matter of the return value of pmo_resume */ 2322 hdd_unpause_ns(hdd_ctx); 2323 2324 if (status != QDF_STATUS_SUCCESS) { 2325 exit_code = 0; 2326 goto exit_with_code; 2327 } 2328 /* Resume tlshim Rx thread */ 2329 if (ucfg_dp_is_rx_common_thread_enabled(hdd_ctx->psoc)) 2330 wlan_hdd_rx_thread_resume(hdd_ctx); 2331 2332 if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != 2333 PACKET_CAPTURE_MODE_DISABLE) { 2334 adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); 2335 if (adapter) { 2336 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, 2337 WLAN_OSIF_POWER_ID); 2338 if (vdev) { 2339 ucfg_pkt_capture_resume_mon_thread(vdev); 2340 hdd_objmgr_put_vdev_by_user( 2341 vdev, WLAN_OSIF_POWER_ID); 2342 } else { 2343 hdd_err("vdev is NULL"); 2344 } 2345 } 2346 } 2347 2348 ucfg_pmo_notify_system_resume(hdd_ctx->psoc); 2349 wlan_hdd_resume_pmo_twt(hdd_ctx); 2350 2351 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, 2352 TRACE_CODE_HDD_CFG80211_RESUME_WLAN, 2353 NO_SESSION, hdd_ctx->is_wiphy_suspended); 2354 2355 hdd_ctx->is_wiphy_suspended = false; 2356 2357 hdd_ctx->suspend_resume_stats.resumes++; 2358 exit_code = 0; 2359 2360 exit_with_code: 2361 hdd_exit(); 2362 return exit_code; 2363 } 2364 _wlan_hdd_cfg80211_resume_wlan(struct wiphy * wiphy)2365 static int _wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) 2366 { 2367 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2368 qdf_runtime_lock_t *suspend_lock; 2369 int errno; 2370 2371 if (!hdd_ctx) { 2372 hdd_err_rl("hdd context is null"); 2373 return -ENODEV; 2374 } 2375 2376 /* If Wifi is off, return success for system resume */ 2377 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { 2378 hdd_debug("Driver Modules not Enabled "); 2379 return 0; 2380 } 2381 2382 /* 2383 * Return success if recovery is in progress, otherwise, linux kernel 2384 * will shutdown all interfaces in wiphy_resume. 2385 */ 2386 if (cds_is_driver_recovering()) { 2387 hdd_debug("Recovery in progress"); 2388 return 0; 2389 } 2390 2391 errno = wlan_hdd_validate_context(hdd_ctx); 2392 if (errno) 2393 return errno; 2394 2395 suspend_lock = &hdd_ctx->runtime_context.system_suspend; 2396 errno = qdf_runtime_pm_allow_suspend(suspend_lock); 2397 if (errno) 2398 return errno; 2399 2400 errno = __wlan_hdd_cfg80211_resume_wlan(wiphy); 2401 2402 /* It may happen during cfg80211 suspend this timer is stopped. 2403 * This means that if 2404 * 1) work was queued in the workqueue, it was removed from the 2405 * workqueue and suspend proceeded. 2406 * 2) The work was scheduled and cfg80211 suspend waited for this 2407 * work to complete and then suspend proceeded. 2408 * So here in cfg80211 resume, check if no interface is up and 2409 * the module state is enabled then trigger idle timer start. 2410 */ 2411 if (!hdd_is_any_interface_open(hdd_ctx) && 2412 hdd_ctx->driver_status == DRIVER_MODULES_ENABLED) 2413 hdd_psoc_idle_timer_start(hdd_ctx); 2414 2415 return errno; 2416 } 2417 wlan_hdd_cfg80211_resume_wlan(struct wiphy * wiphy)2418 int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) 2419 { 2420 struct osif_psoc_sync *psoc_sync; 2421 int errno; 2422 2423 errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); 2424 if (errno) 2425 return errno; 2426 2427 errno = _wlan_hdd_cfg80211_resume_wlan(wiphy); 2428 2429 osif_psoc_sync_op_stop(psoc_sync); 2430 2431 return errno; 2432 } 2433 hdd_suspend_cb(void)2434 static void hdd_suspend_cb(void) 2435 { 2436 struct hdd_context *hdd_ctx; 2437 2438 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 2439 if (!hdd_ctx) 2440 return; 2441 2442 complete(&hdd_ctx->mc_sus_event_var); 2443 } 2444 2445 /** 2446 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback 2447 * @wiphy: Pointer to wiphy 2448 * @wow: Pointer to wow 2449 * 2450 * This API is called when cfg80211 driver suspends 2451 * 2452 * Return: integer status 2453 */ __wlan_hdd_cfg80211_suspend_wlan(struct wiphy * wiphy,struct cfg80211_wowlan * wow)2454 static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, 2455 struct cfg80211_wowlan *wow) 2456 { 2457 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2458 struct hdd_adapter *adapter, *next_adapter = NULL; 2459 mac_handle_t mac_handle; 2460 struct wlan_objmgr_vdev *vdev; 2461 enum pmo_suspend_mode mode; 2462 int rc; 2463 wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_CFG80211_SUSPEND_WLAN; 2464 struct hdd_ap_ctx *ap_ctx; 2465 struct hdd_hostapd_state *hapd_state; 2466 struct csr_del_sta_params params = { 2467 .peerMacAddr = QDF_MAC_ADDR_BCAST_INIT, 2468 .reason_code = REASON_DEAUTH_NETWORK_LEAVING, 2469 .subtype = SIR_MAC_MGMT_DEAUTH, 2470 }; 2471 struct wlan_hdd_link_info *link_info; 2472 2473 hdd_enter(); 2474 2475 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() || 2476 QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) { 2477 hdd_err_rl("Command not allowed in mode %d", 2478 hdd_get_conparam()); 2479 return -EINVAL; 2480 } 2481 2482 rc = wlan_hdd_validate_context(hdd_ctx); 2483 if (0 != rc) { 2484 if (pld_is_low_power_mode(hdd_ctx->parent_dev)) 2485 hdd_debug("low power mode (Deep Sleep/Hibernate)"); 2486 else 2487 return rc; 2488 } 2489 2490 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { 2491 hdd_debug("Driver Modules not Enabled "); 2492 return 0; 2493 } 2494 2495 mode = ucfg_pmo_get_suspend_mode(hdd_ctx->psoc); 2496 if (mode == PMO_SUSPEND_NONE) { 2497 hdd_info_rl("Suspend is not supported"); 2498 return -EINVAL; 2499 } else if (mode == PMO_SUSPEND_SHUTDOWN) { 2500 hdd_info_rl("shutdown suspend should complete in prepare"); 2501 return -EINVAL; 2502 } 2503 2504 mac_handle = hdd_ctx->mac_handle; 2505 2506 /* If RADAR detection is in progress (HDD), prevent suspend. The flag 2507 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true 2508 * until CAC is done for a SoftAP which is in started state. 2509 */ 2510 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 2511 dbgid) { 2512 hdd_adapter_for_each_active_link_info(adapter, link_info) { 2513 if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) 2514 continue; 2515 2516 if (QDF_SAP_MODE == adapter->device_mode) { 2517 hapd_state = 2518 WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); 2519 ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); 2520 if (BSS_START == hapd_state->bss_state && 2521 true == ap_ctx->dfs_cac_block_tx) { 2522 hdd_err("RADAR detection in progress, do not allow suspend"); 2523 wlan_hdd_inc_suspend_stats(hdd_ctx, 2524 SUSPEND_FAIL_RADAR); 2525 hdd_adapter_dev_put_debug(adapter, 2526 dbgid); 2527 if (next_adapter) 2528 hdd_adapter_dev_put_debug( 2529 next_adapter, 2530 dbgid); 2531 return -EAGAIN; 2532 } else if (!ucfg_pmo_get_enable_sap_suspend( 2533 hdd_ctx->psoc)) { 2534 /* return -EOPNOTSUPP if SAP 2535 * does not support suspend 2536 */ 2537 hdd_err("SAP does not support suspend!!"); 2538 hdd_adapter_dev_put_debug(adapter, 2539 dbgid); 2540 if (next_adapter) 2541 hdd_adapter_dev_put_debug( 2542 next_adapter, 2543 dbgid); 2544 return -EOPNOTSUPP; 2545 } else if (ucfg_pmo_get_disconnect_sap_tdls_in_wow( 2546 hdd_ctx->psoc)) { 2547 hdd_softap_deauth_all_sta(adapter, 2548 hapd_state, 2549 ¶ms); 2550 } 2551 } else if (QDF_P2P_GO_MODE == adapter->device_mode) { 2552 hapd_state = 2553 WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); 2554 if (!ucfg_pmo_get_enable_sap_suspend( 2555 hdd_ctx->psoc)) { 2556 /* return -EOPNOTSUPP if GO 2557 * does not support suspend 2558 */ 2559 hdd_err("GO does not support suspend!!"); 2560 hdd_adapter_dev_put_debug(adapter, 2561 dbgid); 2562 if (next_adapter) 2563 hdd_adapter_dev_put_debug( 2564 next_adapter, 2565 dbgid); 2566 return -EOPNOTSUPP; 2567 } else if (ucfg_pmo_get_disconnect_sap_tdls_in_wow( 2568 hdd_ctx->psoc)) { 2569 hdd_softap_deauth_all_sta(adapter, 2570 hapd_state, 2571 ¶ms); 2572 } 2573 } else if (QDF_TDLS_MODE == adapter->device_mode && 2574 ucfg_pmo_get_disconnect_sap_tdls_in_wow( 2575 hdd_ctx->psoc)) { 2576 vdev = hdd_objmgr_get_vdev_by_user(link_info, 2577 WLAN_TDLS_NB_ID); 2578 if (vdev) { 2579 ucfg_tdls_teardown_links_sync(hdd_ctx->psoc, 2580 vdev); 2581 hdd_objmgr_put_vdev_by_user(vdev, 2582 WLAN_TDLS_NB_ID); 2583 } 2584 } 2585 } 2586 hdd_adapter_dev_put_debug(adapter, dbgid); 2587 } 2588 /* p2p cleanup task based on scheduler */ 2589 ucfg_p2p_cleanup_tx_by_psoc(hdd_ctx->psoc); 2590 ucfg_p2p_cleanup_roc_by_psoc(hdd_ctx->psoc); 2591 2592 if (hdd_is_connection_in_progress(NULL, NULL)) { 2593 hdd_err_rl("Connection is in progress, rejecting suspend"); 2594 return -EINVAL; 2595 } 2596 2597 /* flush any pending powersave timers */ 2598 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, 2599 dbgid) { 2600 hdd_adapter_for_each_active_link_info(adapter, link_info) { 2601 if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) 2602 continue; 2603 2604 sme_ps_timer_flush_sync(mac_handle, link_info->vdev_id); 2605 } 2606 hdd_adapter_dev_put_debug(adapter, dbgid); 2607 } 2608 2609 hdd_pause_ns(hdd_ctx); 2610 2611 /* 2612 * Suspend all components registered to pmo, abort ongoing scan and 2613 * don't allow new scan any more before scheduler thread suspended. 2614 */ 2615 if (ucfg_pmo_suspend_all_components(hdd_ctx->psoc, 2616 QDF_SYSTEM_SUSPEND)) { 2617 hdd_err("Some components not ready to suspend!"); 2618 return -EAGAIN; 2619 } 2620 2621 wlan_hdd_suspend_pmo_twt(hdd_ctx); 2622 2623 /* 2624 * Suspend IPA early before proceeding to suspend other entities like 2625 * firmware to avoid any race conditions. 2626 */ 2627 if (ucfg_ipa_suspend(hdd_ctx->pdev)) { 2628 hdd_err("IPA not ready to suspend!"); 2629 wlan_hdd_inc_suspend_stats(hdd_ctx, SUSPEND_FAIL_IPA); 2630 goto resume_all_components; 2631 } 2632 2633 /* Suspend control path scheduler */ 2634 scheduler_register_hdd_suspend_callback(hdd_suspend_cb); 2635 scheduler_set_event_mask(MC_SUSPEND_EVENT); 2636 scheduler_wake_up_controller_thread(); 2637 2638 /* Wait for suspend confirmation from scheduler */ 2639 rc = wait_for_completion_timeout(&hdd_ctx->mc_sus_event_var, 2640 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND)); 2641 if (!rc) { 2642 scheduler_clear_event_mask(MC_SUSPEND_EVENT); 2643 hdd_err("Failed to stop mc thread"); 2644 goto resume_tx; 2645 } 2646 hdd_ctx->is_scheduler_suspended = true; 2647 2648 if (ucfg_dp_is_rx_common_thread_enabled(hdd_ctx->psoc)) { 2649 if (wlan_hdd_rx_thread_suspend(hdd_ctx)) 2650 goto resume_ol_rx; 2651 } 2652 2653 if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != 2654 PACKET_CAPTURE_MODE_DISABLE) { 2655 adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); 2656 if (adapter) { 2657 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, 2658 WLAN_OSIF_POWER_ID); 2659 if (!vdev) { 2660 hdd_err("vdev is NULL"); 2661 goto resume_dp_thread; 2662 } 2663 if (ucfg_pkt_capture_suspend_mon_thread(vdev)) { 2664 hdd_objmgr_put_vdev_by_user( 2665 vdev, WLAN_OSIF_POWER_ID); 2666 goto resume_dp_thread; 2667 } 2668 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); 2669 } 2670 } 2671 2672 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, 2673 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN, 2674 NO_SESSION, hdd_ctx->is_wiphy_suspended); 2675 2676 if (hdd_suspend_wlan() < 0) { 2677 hdd_err("Failed to suspend WLAN"); 2678 goto resume_dp_thread; 2679 } 2680 2681 hdd_ctx->is_wiphy_suspended = true; 2682 2683 hdd_exit(); 2684 return 0; 2685 2686 resume_dp_thread: 2687 /* Resume packet capture MON thread */ 2688 if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != 2689 PACKET_CAPTURE_MODE_DISABLE) { 2690 adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); 2691 if (adapter) { 2692 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, 2693 WLAN_OSIF_POWER_ID); 2694 if (vdev) { 2695 ucfg_pkt_capture_resume_mon_thread(vdev); 2696 hdd_objmgr_put_vdev_by_user( 2697 vdev, WLAN_OSIF_POWER_ID); 2698 } else { 2699 hdd_err("vdev is NULL"); 2700 } 2701 } 2702 } 2703 2704 resume_ol_rx: 2705 /* Resume tlshim Rx thread */ 2706 wlan_hdd_rx_thread_resume(hdd_ctx); 2707 scheduler_resume(); 2708 hdd_ctx->is_scheduler_suspended = false; 2709 resume_tx: 2710 hdd_resume_wlan(); 2711 resume_all_components: 2712 ucfg_pmo_resume_all_components(hdd_ctx->psoc, QDF_SYSTEM_SUSPEND); 2713 hdd_unpause_ns(hdd_ctx); 2714 2715 return -ETIME; 2716 2717 } 2718 _wlan_hdd_cfg80211_suspend_wlan(struct wiphy * wiphy,struct cfg80211_wowlan * wow)2719 static int _wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, 2720 struct cfg80211_wowlan *wow) 2721 { 2722 void *hif_ctx; 2723 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2724 qdf_runtime_lock_t *suspend_lock; 2725 int errno; 2726 2727 if (!hdd_ctx) { 2728 hdd_err_rl("hdd context is null"); 2729 return -ENODEV; 2730 } 2731 2732 /* If Wifi is off, return success for system suspend */ 2733 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { 2734 hdd_debug("Driver Modules not Enabled "); 2735 return 0; 2736 } 2737 2738 errno = wlan_hdd_validate_context(hdd_ctx); 2739 if (0 != errno) { 2740 if (pld_is_low_power_mode(hdd_ctx->parent_dev)) 2741 hdd_debug("low power mode (Deep Sleep/Hibernate)"); 2742 else 2743 return errno; 2744 } 2745 2746 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); 2747 if (!hif_ctx) 2748 return -EINVAL; 2749 2750 suspend_lock = &hdd_ctx->runtime_context.system_suspend; 2751 errno = qdf_runtime_pm_prevent_suspend_sync(suspend_lock); 2752 if (errno) 2753 return errno; 2754 2755 errno = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow); 2756 if (errno) { 2757 qdf_runtime_pm_allow_suspend(suspend_lock); 2758 return errno; 2759 } 2760 2761 return errno; 2762 } 2763 wlan_hdd_cfg80211_suspend_wlan(struct wiphy * wiphy,struct cfg80211_wowlan * wow)2764 int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, 2765 struct cfg80211_wowlan *wow) 2766 { 2767 struct osif_psoc_sync *psoc_sync; 2768 int errno; 2769 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2770 2771 errno = wlan_hdd_validate_context(hdd_ctx); 2772 if (0 != errno) { 2773 if (pld_is_low_power_mode(hdd_ctx->parent_dev)) 2774 hdd_debug("low power mode (Deep Sleep/Hibernate)"); 2775 else 2776 return errno; 2777 } 2778 2779 /* 2780 * Flush the idle shutdown before ops start.This is done here to avoid 2781 * the deadlock as idle shutdown waits for the dsc ops 2782 * to complete. 2783 */ 2784 hdd_psoc_idle_timer_stop(hdd_ctx); 2785 2786 errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); 2787 if (errno) 2788 return errno; 2789 2790 errno = _wlan_hdd_cfg80211_suspend_wlan(wiphy, wow); 2791 2792 osif_psoc_sync_op_stop(psoc_sync); 2793 2794 return errno; 2795 } 2796 2797 /** 2798 * hdd_stop_dhcp_ind() - API to stop DHCP sequence 2799 * @link_info: Link info pointer in HDD adapter 2800 * @mac: mac address 2801 * 2802 * Release the wakelock held for DHCP process and allow 2803 * the runtime pm to continue 2804 * 2805 * Return: None 2806 */ hdd_stop_dhcp_ind(struct wlan_hdd_link_info * link_info,uint8_t * mac)2807 static void hdd_stop_dhcp_ind(struct wlan_hdd_link_info *link_info, 2808 uint8_t *mac) 2809 { 2810 struct hdd_adapter *adapter = link_info->adapter; 2811 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 2812 2813 hdd_debug("DHCP stop indicated through power save"); 2814 sme_dhcp_stop_ind(hdd_ctx->mac_handle, adapter->device_mode, 2815 mac, link_info->vdev_id); 2816 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP); 2817 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect); 2818 } 2819 2820 /** 2821 * hdd_start_dhcp_ind() - API to start DHCP sequence 2822 * @link_info: Link info pointer in HDD adapter 2823 * @mac: mac address 2824 * 2825 * Prevent APPS suspend and the runtime suspend during 2826 * DHCP sequence 2827 * 2828 * Return: None 2829 */ 2830 static void hdd_start_dhcp_ind(struct wlan_hdd_link_info * link_info,uint8_t * mac)2831 hdd_start_dhcp_ind(struct wlan_hdd_link_info *link_info, uint8_t *mac) 2832 { 2833 struct hdd_adapter *adapter = link_info->adapter; 2834 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 2835 2836 hdd_debug("DHCP start indicated through power save"); 2837 qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.connect); 2838 hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT, 2839 WIFI_POWER_EVENT_WAKELOCK_DHCP); 2840 sme_dhcp_start_ind(hdd_ctx->mac_handle, adapter->device_mode, 2841 mac, link_info->vdev_id); 2842 } 2843 wlan_hdd_set_ps(struct wlan_hdd_link_info * link_info,uint8_t * mac,bool allow_power_save,int timeout)2844 static int wlan_hdd_set_ps(struct wlan_hdd_link_info *link_info, 2845 uint8_t *mac, bool allow_power_save, int timeout) 2846 { 2847 int status; 2848 struct hdd_adapter *adapter = link_info->adapter; 2849 2850 status = wlan_hdd_set_powersave(link_info, allow_power_save, timeout); 2851 2852 if (!hdd_cm_is_vdev_associated(link_info)) { 2853 hdd_debug("vdev[%d] mode %d disconnected ignore dhcp protection", 2854 link_info->vdev_id, adapter->device_mode); 2855 return status; 2856 } 2857 2858 hdd_debug("vdev[%d] mode %d enable dhcp protection", 2859 link_info->vdev_id, adapter->device_mode); 2860 allow_power_save ? hdd_stop_dhcp_ind(link_info, mac) : 2861 hdd_start_dhcp_ind(link_info, mac); 2862 2863 return status; 2864 } 2865 2866 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) 2867 #ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV wlan_hdd_set_mlo_ps(struct hdd_adapter * adapter,bool allow_power_save,int timeout,int link_id)2868 int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter, 2869 bool allow_power_save, int timeout, 2870 int link_id) 2871 { 2872 struct wlan_hdd_link_info *link_info; 2873 int status = -EINVAL; 2874 2875 hdd_adapter_for_each_active_link_info(adapter, link_info) { 2876 if (link_id >= 0 && 2877 wlan_vdev_get_link_id(link_info->vdev) != link_id) 2878 continue; 2879 2880 status = wlan_hdd_set_ps(link_info, 2881 link_info->link_addr.bytes, 2882 allow_power_save, timeout); 2883 if (status) 2884 break; 2885 } 2886 2887 return status; 2888 } 2889 #else wlan_hdd_set_mlo_ps(struct hdd_adapter * adapter,bool allow_power_save,int timeout,int link_id)2890 int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter, 2891 bool allow_power_save, int timeout, 2892 int link_id) 2893 { 2894 struct hdd_adapter *link_adapter; 2895 struct hdd_mlo_adapter_info *mlo_adapter_info; 2896 int i, status = -EINVAL; 2897 2898 mlo_adapter_info = &adapter->mlo_adapter_info; 2899 for (i = 0; i < WLAN_MAX_MLD; i++) { 2900 link_adapter = mlo_adapter_info->link_adapter[i]; 2901 if (!link_adapter) 2902 continue; 2903 2904 if (link_id >= 0 && 2905 wlan_vdev_get_link_id(link_adapter->deflink->vdev) != 2906 link_id) 2907 continue; 2908 2909 status = wlan_hdd_set_ps(link_adapter->deflink, 2910 link_adapter->mac_addr.bytes, 2911 allow_power_save, timeout); 2912 if (status) 2913 break; 2914 } 2915 2916 if (i == WLAN_MAX_MLD && link_id >= 0) 2917 hdd_err("No link adapter found for link id: %d", link_id); 2918 2919 return status; 2920 } 2921 #endif 2922 #endif 2923 2924 /** 2925 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config 2926 * @wiphy: Pointer to wiphy 2927 * @dev: Pointer to network device 2928 * @allow_power_save: is wlan allowed to go into power save mode 2929 * @timeout: Timeout value in ms 2930 * 2931 * Return: 0 for success, non-zero for failure 2932 */ __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool allow_power_save,int timeout)2933 static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, 2934 struct net_device *dev, 2935 bool allow_power_save, 2936 int timeout) 2937 { 2938 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 2939 struct hdd_context *hdd_ctx; 2940 int status; 2941 struct wlan_hdd_link_info *link_info = adapter->deflink; 2942 2943 hdd_enter(); 2944 2945 if (timeout < 0) { 2946 hdd_debug("User space timeout: %d; Enter full power or power save: %d", 2947 timeout, allow_power_save); 2948 timeout = 0; 2949 } 2950 2951 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 2952 hdd_err("Command not allowed in FTM mode"); 2953 return -EINVAL; 2954 } 2955 2956 if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) 2957 return -EINVAL; 2958 2959 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, 2960 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT, 2961 link_info->vdev_id, timeout); 2962 2963 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 2964 status = wlan_hdd_validate_context(hdd_ctx); 2965 2966 if (0 != status) 2967 return status; 2968 2969 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { 2970 hdd_debug("Driver Module not enabled return success"); 2971 return 0; 2972 } 2973 2974 /* Flush any scheduled inet change notifier work 2975 * This is to make sure set power save request 2976 * sent to FW are serialized to avoid race condition 2977 */ 2978 flush_work(&adapter->ipv4_notifier_work); 2979 hdd_adapter_flush_ipv6_notifier_work(adapter); 2980 2981 if (hdd_adapter_is_ml_adapter(adapter)) { 2982 status = wlan_hdd_set_mlo_ps(adapter, allow_power_save, 2983 timeout, -1); 2984 goto exit; 2985 } 2986 2987 status = wlan_hdd_set_ps(link_info, adapter->mac_addr.bytes, 2988 allow_power_save, timeout); 2989 2990 exit: 2991 /* Cache the powersave state for success case */ 2992 if (!status) 2993 adapter->allow_power_save = allow_power_save; 2994 2995 hdd_exit(); 2996 return status; 2997 } 2998 wlan_hdd_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool allow_power_save,int timeout)2999 int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, 3000 struct net_device *dev, 3001 bool allow_power_save, 3002 int timeout) 3003 { 3004 int errno; 3005 struct osif_vdev_sync *vdev_sync; 3006 3007 errno = osif_vdev_sync_op_start(dev, &vdev_sync); 3008 if (errno) 3009 return errno; 3010 3011 errno = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev, allow_power_save, 3012 timeout); 3013 3014 osif_vdev_sync_op_stop(vdev_sync); 3015 3016 return errno; 3017 } 3018 3019 /** 3020 * __wlan_hdd_cfg80211_set_txpower() - set TX power 3021 * @wiphy: Pointer to wiphy 3022 * @wdev: Pointer to network device 3023 * @type: TX power setting type 3024 * @mbm: TX power in mBm 3025 * 3026 * Return: 0 for success, non-zero for failure 3027 */ __wlan_hdd_cfg80211_set_txpower(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,int mbm)3028 static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, 3029 struct wireless_dev *wdev, 3030 enum nl80211_tx_power_setting type, 3031 int mbm) 3032 { 3033 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy); 3034 mac_handle_t mac_handle; 3035 struct hdd_adapter *adapter; 3036 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT; 3037 struct qdf_mac_addr selfmac; 3038 QDF_STATUS status; 3039 int errno; 3040 int dbm; 3041 3042 hdd_enter(); 3043 3044 if (!wdev) { 3045 hdd_err("wdev is null, set tx power failed"); 3046 return -EIO; 3047 } 3048 3049 adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); 3050 3051 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 3052 hdd_err("Command not allowed in FTM mode"); 3053 return -EINVAL; 3054 } 3055 3056 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, 3057 TRACE_CODE_HDD_CFG80211_SET_TXPOWER, 3058 NO_SESSION, type); 3059 3060 errno = wlan_hdd_validate_context(hdd_ctx); 3061 if (errno) 3062 return errno; 3063 3064 if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) 3065 return -EINVAL; 3066 3067 if (adapter->device_mode == QDF_SAP_MODE || 3068 adapter->device_mode == QDF_P2P_GO_MODE) { 3069 qdf_copy_macaddr(&bssid, &adapter->mac_addr); 3070 } else { 3071 struct hdd_station_ctx *sta_ctx = 3072 WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); 3073 3074 if (hdd_cm_is_vdev_associated(adapter->deflink)) 3075 qdf_copy_macaddr(&bssid, &sta_ctx->conn_info.bssid); 3076 } 3077 3078 qdf_copy_macaddr(&selfmac, &adapter->mac_addr); 3079 3080 mac_handle = hdd_ctx->mac_handle; 3081 3082 dbm = MBM_TO_DBM(mbm); 3083 3084 /* 3085 * the original implementation of this function expected power 3086 * values in dBm instead of mBm. If the conversion from mBm to 3087 * dBm is zero, then assume dBm was passed. 3088 */ 3089 if (!dbm) 3090 dbm = mbm; 3091 3092 status = ucfg_mlme_set_current_tx_power_level(hdd_ctx->psoc, dbm); 3093 if (QDF_IS_STATUS_ERROR(status)) { 3094 hdd_err("sme_cfg_set_int failed for tx power %d, %d", 3095 dbm, status); 3096 return -EIO; 3097 } 3098 3099 hdd_debug("Set tx power level %d dbm", dbm); 3100 3101 switch (type) { 3102 /* Automatically determine transmit power */ 3103 case NL80211_TX_POWER_AUTOMATIC: 3104 case NL80211_TX_POWER_LIMITED: 3105 /* Limit TX power by the mBm parameter */ 3106 status = sme_set_max_tx_power(mac_handle, bssid, selfmac, dbm); 3107 if (QDF_IS_STATUS_ERROR(status)) { 3108 hdd_err("Setting maximum tx power failed, %d", status); 3109 return -EIO; 3110 } 3111 break; 3112 3113 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */ 3114 status = sme_set_tx_power(mac_handle, adapter->deflink->vdev_id, 3115 bssid, adapter->device_mode, dbm); 3116 if (QDF_IS_STATUS_ERROR(status)) { 3117 hdd_err("Setting tx power failed, %d", status); 3118 return -EIO; 3119 } 3120 break; 3121 default: 3122 hdd_err("Invalid power setting type %d", type); 3123 return -EIO; 3124 } 3125 3126 hdd_exit(); 3127 return 0; 3128 } 3129 wlan_hdd_cfg80211_set_txpower(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,int mbm)3130 int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, 3131 struct wireless_dev *wdev, 3132 enum nl80211_tx_power_setting type, 3133 int mbm) 3134 { 3135 struct osif_psoc_sync *psoc_sync; 3136 int errno; 3137 3138 errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); 3139 if (errno) 3140 return errno; 3141 3142 errno = __wlan_hdd_cfg80211_set_txpower(wiphy, wdev, type, mbm); 3143 3144 osif_psoc_sync_op_stop(psoc_sync); 3145 3146 return errno; 3147 } 3148 3149 #define WLAN_HDD_TX_POWER_CACHE_EXPIRY_TIME 350 3150 3151 static QDF_STATUS wlan_hdd_tx_power_request_needed(struct hdd_adapter * adapter)3152 wlan_hdd_tx_power_request_needed(struct hdd_adapter *adapter) 3153 { 3154 uint32_t tx_pwr_cached_duration; 3155 3156 tx_pwr_cached_duration = 3157 qdf_system_ticks_to_msecs(qdf_system_ticks()) - 3158 adapter->tx_power.tx_pwr_cached_timestamp; 3159 3160 if (tx_pwr_cached_duration <= WLAN_HDD_TX_POWER_CACHE_EXPIRY_TIME) 3161 return QDF_STATUS_E_ALREADY; 3162 3163 return QDF_STATUS_SUCCESS; 3164 } 3165 wlan_hdd_get_tx_power(struct hdd_adapter * adapter,int * dbm)3166 static int wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm) 3167 { 3168 struct wlan_objmgr_vdev *vdev; 3169 int ret; 3170 3171 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, 3172 WLAN_OSIF_POWER_ID); 3173 if (!vdev) { 3174 hdd_info("vdev is NULL"); 3175 return -EINVAL; 3176 } 3177 3178 ret = wlan_cfg80211_mc_cp_stats_get_tx_power(vdev, dbm); 3179 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); 3180 hdd_debug("power: %d", *dbm); 3181 return ret; 3182 } 3183 3184 #ifdef FEATURE_ANI_LEVEL_REQUEST hdd_get_ani_level_cb(struct wmi_host_ani_level_event * ani,uint8_t num,void * context)3185 static void hdd_get_ani_level_cb(struct wmi_host_ani_level_event *ani, 3186 uint8_t num, void *context) 3187 { 3188 struct osif_request *request; 3189 struct ani_priv *priv; 3190 uint8_t min_recv_freqs = QDF_MIN(num, MAX_NUM_FREQS_FOR_ANI_LEVEL); 3191 3192 request = osif_request_get(context); 3193 if (!request) { 3194 hdd_err("Obsolete request"); 3195 return; 3196 } 3197 3198 /* propagate response back to requesting thread */ 3199 priv = osif_request_priv(request); 3200 priv->ani = qdf_mem_malloc(min_recv_freqs * 3201 sizeof(struct wmi_host_ani_level_event)); 3202 if (!priv->ani) 3203 goto complete; 3204 3205 priv->num_freq = min_recv_freqs; 3206 qdf_mem_copy(priv->ani, ani, 3207 min_recv_freqs * sizeof(struct wmi_host_ani_level_event)); 3208 3209 complete: 3210 osif_request_complete(request); 3211 osif_request_put(request); 3212 } 3213 3214 /** 3215 * wlan_hdd_get_ani_level_dealloc() - Dealloc mem allocated in priv data 3216 * @priv: the priv data 3217 * 3218 * Return: None 3219 */ wlan_hdd_get_ani_level_dealloc(void * priv)3220 static void wlan_hdd_get_ani_level_dealloc(void *priv) 3221 { 3222 struct ani_priv *ani = priv; 3223 3224 if (ani->ani) 3225 qdf_mem_free(ani->ani); 3226 } 3227 wlan_hdd_get_ani_level(struct hdd_adapter * adapter,struct wmi_host_ani_level_event * ani,uint32_t * parsed_freqs,uint8_t num_freqs)3228 QDF_STATUS wlan_hdd_get_ani_level(struct hdd_adapter *adapter, 3229 struct wmi_host_ani_level_event *ani, 3230 uint32_t *parsed_freqs, 3231 uint8_t num_freqs) 3232 { 3233 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 3234 int ret; 3235 QDF_STATUS status; 3236 void *cookie; 3237 struct osif_request *request; 3238 struct ani_priv *priv; 3239 static const struct osif_request_params params = { 3240 .priv_size = sizeof(*priv), 3241 .timeout_ms = 1000, 3242 .dealloc = wlan_hdd_get_ani_level_dealloc, 3243 }; 3244 3245 if (!hdd_ctx) { 3246 hdd_err("Invalid HDD context"); 3247 return QDF_STATUS_E_INVAL; 3248 } 3249 3250 request = osif_request_alloc(¶ms); 3251 if (!request) { 3252 hdd_err("Request allocation failure"); 3253 return QDF_STATUS_E_NOMEM; 3254 } 3255 cookie = osif_request_cookie(request); 3256 3257 status = sme_get_ani_level(hdd_ctx->mac_handle, parsed_freqs, 3258 num_freqs, hdd_get_ani_level_cb, cookie); 3259 3260 if (QDF_IS_STATUS_ERROR(status)) { 3261 hdd_err("Unable to retrieve ani level"); 3262 goto complete; 3263 } else { 3264 /* request was sent -- wait for the response */ 3265 ret = osif_request_wait_for_response(request); 3266 if (ret) { 3267 hdd_err("SME timed out while retrieving ANI level"); 3268 status = QDF_STATUS_E_TIMEOUT; 3269 goto complete; 3270 } 3271 } 3272 3273 priv = osif_request_priv(request); 3274 3275 qdf_mem_copy(ani, priv->ani, sizeof(struct wmi_host_ani_level_event) * 3276 priv->num_freq); 3277 3278 complete: 3279 /* 3280 * either we never sent a request, we sent a request and 3281 * received a response or we sent a request and timed out. 3282 * regardless we are done with the request. 3283 */ 3284 osif_request_put(request); 3285 3286 hdd_exit(); 3287 return status; 3288 } 3289 #endif 3290 3291 /** 3292 * __wlan_hdd_cfg80211_get_txpower() - get TX power 3293 * @wiphy: Pointer to wiphy 3294 * @wdev: Pointer to network device 3295 * @dbm: Pointer to TX power in dbm 3296 * 3297 * Return: 0 for success, non-zero for failure 3298 */ __wlan_hdd_cfg80211_get_txpower(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)3299 static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, 3300 struct wireless_dev *wdev, 3301 int *dbm) 3302 { 3303 3304 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy); 3305 struct net_device *ndev = wdev->netdev; 3306 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); 3307 QDF_STATUS status; 3308 int ret; 3309 static bool is_rate_limited; 3310 struct wlan_objmgr_vdev *vdev; 3311 3312 hdd_enter_dev(ndev); 3313 3314 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 3315 hdd_err("Command not allowed in FTM mode"); 3316 return -EINVAL; 3317 } 3318 3319 *dbm = 0; 3320 3321 ret = wlan_hdd_validate_context(hdd_ctx); 3322 if (ret) 3323 return ret; 3324 3325 /* Validate adapter sessionId */ 3326 ret = wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id); 3327 if (ret) 3328 return ret; 3329 switch (adapter->device_mode) { 3330 case QDF_STA_MODE: 3331 case QDF_P2P_CLIENT_MODE: 3332 if (hdd_cm_is_vdev_roaming(adapter->deflink)) { 3333 hdd_debug("Roaming is in progress, rej this req"); 3334 return -EINVAL; 3335 } 3336 if (!hdd_cm_is_vdev_associated(adapter->deflink)) { 3337 hdd_debug("Not associated"); 3338 return 0; 3339 } 3340 break; 3341 case QDF_SAP_MODE: 3342 case QDF_P2P_GO_MODE: 3343 if (!test_bit(SOFTAP_BSS_STARTED, 3344 &adapter->deflink->link_flags)) { 3345 hdd_debug("SAP is not started yet"); 3346 return 0; 3347 } 3348 break; 3349 default: 3350 hdd_debug_rl("Current interface is not supported for get tx_power"); 3351 return 0; 3352 } 3353 3354 HDD_IS_RATE_LIMIT_REQ(is_rate_limited, 3355 hdd_ctx->config->nb_commands_interval); 3356 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED || 3357 is_rate_limited) { 3358 /* Send cached data to upperlayer*/ 3359 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, 3360 WLAN_OSIF_POWER_ID); 3361 if (!vdev) { 3362 hdd_err("vdev is NULL"); 3363 return -EINVAL; 3364 } 3365 ucfg_mc_cp_stats_get_tx_power(vdev, dbm); 3366 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); 3367 hdd_debug("Modules not enabled/rate limited, cached tx power = %d", 3368 *dbm); 3369 return 0; 3370 } 3371 3372 status = wlan_hdd_tx_power_request_needed(adapter); 3373 if (status == QDF_STATUS_E_ALREADY) { 3374 /* TX_POWER is sent by STATION_STATS by firmware and 3375 * is copied into the adapter. So, return cached value. 3376 */ 3377 *dbm = adapter->tx_power.tx_pwr; 3378 hdd_nofl_debug("cached tx_power: %d", *dbm); 3379 return 0; 3380 } 3381 3382 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, 3383 TRACE_CODE_HDD_CFG80211_GET_TXPOWER, 3384 adapter->deflink->vdev_id, adapter->device_mode); 3385 3386 return wlan_hdd_get_tx_power(adapter, dbm); 3387 } 3388 wlan_hdd_cfg80211_get_txpower(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)3389 int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, 3390 struct wireless_dev *wdev, 3391 int *dbm) 3392 { 3393 struct osif_psoc_sync *psoc_sync; 3394 int errno; 3395 3396 errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); 3397 if (errno) 3398 return errno; 3399 3400 errno = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm); 3401 3402 osif_psoc_sync_op_stop(psoc_sync); 3403 3404 return errno; 3405 } 3406 3407 /** 3408 * hdd_convert_opm_mode() - convert opm with equivalent wma opm 3409 * @opm_mode: Optimized power management mode 3410 * 3411 * Return: enum wma_sta_ps_scheme_cfg 3412 */ 3413 static enum wma_sta_ps_scheme_cfg hdd_convert_opm_mode(enum qca_wlan_vendor_opm_mode opm_mode)3414 hdd_convert_opm_mode(enum qca_wlan_vendor_opm_mode opm_mode) 3415 { 3416 switch (opm_mode) { 3417 case QCA_WLAN_VENDOR_OPM_MODE_DISABLE: 3418 return WMA_STA_PS_OPM_CONSERVATIVE; 3419 case QCA_WLAN_VENDOR_OPM_MODE_ENABLE: 3420 return WMA_STA_PS_OPM_AGGRESSIVE; 3421 case QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED: 3422 return WMA_STA_PS_USER_DEF; 3423 default: 3424 hdd_err("Invalid opm_mode: %d", opm_mode); 3425 return WMA_STA_PS_OPM_CONSERVATIVE; 3426 } 3427 } 3428 hdd_set_power_config(struct hdd_context * hddctx,struct hdd_adapter * adapter,enum qca_wlan_vendor_opm_mode * opm_mode)3429 int hdd_set_power_config(struct hdd_context *hddctx, 3430 struct hdd_adapter *adapter, 3431 enum qca_wlan_vendor_opm_mode *opm_mode) 3432 { 3433 QDF_STATUS status; 3434 3435 if (adapter->device_mode != QDF_STA_MODE && 3436 adapter->device_mode != QDF_P2P_CLIENT_MODE) { 3437 hdd_info("Advanced power save only allowed in STA/P2P-Client modes:%d", 3438 adapter->device_mode); 3439 return -EINVAL; 3440 } 3441 3442 if (*opm_mode > QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED || 3443 *opm_mode < QCA_WLAN_VENDOR_OPM_MODE_DISABLE) { 3444 hdd_err("invalid power value: %d", *opm_mode); 3445 return -EINVAL; 3446 } 3447 3448 if (ucfg_pmo_get_max_ps_poll(hddctx->psoc)) { 3449 hdd_info("Disable advanced power save since max ps poll is enabled"); 3450 *opm_mode = QCA_WLAN_VENDOR_OPM_MODE_DISABLE; 3451 } 3452 3453 status = wma_set_power_config(adapter->deflink->vdev_id, 3454 hdd_convert_opm_mode(*opm_mode)); 3455 if (status != QDF_STATUS_SUCCESS) { 3456 hdd_err("failed to configure power: %d", status); 3457 return -EINVAL; 3458 } 3459 3460 return 0; 3461 } 3462 hdd_set_power_config_params(struct hdd_context * hddctx,struct hdd_adapter * adapter,uint16_t ps_ito,uint16_t spec_wake)3463 int hdd_set_power_config_params(struct hdd_context *hddctx, 3464 struct hdd_adapter *adapter, 3465 uint16_t ps_ito, uint16_t spec_wake) 3466 { 3467 QDF_STATUS status; 3468 3469 status = wma_set_power_config_ito(adapter->deflink->vdev_id, ps_ito); 3470 if (status != QDF_STATUS_SUCCESS) { 3471 hdd_err("failed to configure power ito: %d", status); 3472 return -EINVAL; 3473 } 3474 3475 status = wma_set_power_config_spec_wake(adapter->deflink->vdev_id, 3476 spec_wake); 3477 if (status != QDF_STATUS_SUCCESS) { 3478 hdd_err("failed to configure power spec wake: %d", status); 3479 return -EINVAL; 3480 } 3481 3482 return 0; 3483 } 3484 3485 #ifdef WLAN_SUSPEND_RESUME_TEST 3486 static struct net_device *g_dev; 3487 static struct wiphy *g_wiphy; 3488 static enum wow_resume_trigger g_resume_trigger; 3489 3490 #define HDD_FA_SUSPENDED_BIT (0) 3491 static unsigned long fake_apps_state; 3492 3493 /** 3494 * __hdd_wlan_fake_apps_resume() - The core logic for 3495 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(), 3496 * which is only need for non-irq resume 3497 * @wiphy: the kernel wiphy struct for the device being resumed 3498 * @dev: the kernel net_device struct for the device being resumed 3499 * 3500 * Return: none, calls QDF_BUG() on failure 3501 */ __hdd_wlan_fake_apps_resume(struct wiphy * wiphy,struct net_device * dev)3502 static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy, 3503 struct net_device *dev) 3504 { 3505 struct hif_opaque_softc *hif_ctx; 3506 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 3507 qdf_device_t qdf_dev; 3508 3509 if (wlan_hdd_validate_context(hdd_ctx)) 3510 return; 3511 3512 if (!hdd_ctx->config->is_unit_test_framework_enabled) { 3513 hdd_warn_rl("UT framework is disabled"); 3514 return; 3515 } 3516 3517 hdd_info("Unit-test resume WLAN"); 3518 3519 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); 3520 if (!qdf_dev) { 3521 QDF_BUG(0); 3522 return; 3523 } 3524 3525 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); 3526 if (!hif_ctx) 3527 return; 3528 3529 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) { 3530 hdd_alert("Not unit-test suspended; Nothing to do"); 3531 return; 3532 } 3533 3534 /* simulate kernel disable irqs */ 3535 QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx)); 3536 3537 QDF_BUG(!wlan_hdd_bus_resume_noirq()); 3538 3539 /* simulate kernel enable irqs */ 3540 QDF_BUG(!hif_apps_irqs_enable(hif_ctx)); 3541 3542 QDF_BUG(!wlan_hdd_bus_resume(QDF_UNIT_TEST_WOW_SUSPEND)); 3543 3544 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy)); 3545 3546 if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP) 3547 hif_vote_link_down(hif_ctx); 3548 3549 dev->watchdog_timeo = HDD_TX_TIMEOUT; 3550 3551 hdd_alert("Unit-test resume succeeded"); 3552 3553 hdd_info("allow rtpm wow for wow unit test"); 3554 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.wow_unit_test); 3555 } 3556 3557 /** 3558 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming 3559 * from unit-test initiated suspend from irq wakeup signal 3560 * 3561 * Resume wlan after getting very 1st CE interrupt from target 3562 * 3563 * Return: none 3564 */ hdd_wlan_fake_apps_resume_irq_callback(void)3565 static void hdd_wlan_fake_apps_resume_irq_callback(void) 3566 { 3567 hdd_info("Trigger unit-test resume WLAN"); 3568 3569 QDF_BUG(g_wiphy); 3570 QDF_BUG(g_dev); 3571 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev); 3572 g_wiphy = NULL; 3573 g_dev = NULL; 3574 } 3575 hdd_wlan_fake_apps_suspend(struct wiphy * wiphy,struct net_device * dev,enum wow_interface_pause pause_setting,enum wow_resume_trigger resume_setting)3576 int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev, 3577 enum wow_interface_pause pause_setting, 3578 enum wow_resume_trigger resume_setting) 3579 { 3580 int errno; 3581 qdf_device_t qdf_dev; 3582 struct hif_opaque_softc *hif_ctx; 3583 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 3584 struct wow_enable_params wow_params = { 3585 .is_unit_test = true, 3586 .interface_pause = pause_setting, 3587 .resume_trigger = resume_setting 3588 }; 3589 3590 if (wlan_hdd_validate_context(hdd_ctx)) 3591 return -EINVAL; 3592 3593 if (!hdd_ctx->config->is_unit_test_framework_enabled) { 3594 hdd_warn_rl("UT framework is disabled"); 3595 return -EINVAL; 3596 } 3597 3598 hdd_info("Unit-test suspend WLAN"); 3599 3600 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT || 3601 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) { 3602 hdd_err_rl("Invalid interface pause %d (expected range [0, 2])", 3603 pause_setting); 3604 return -EINVAL; 3605 } 3606 3607 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT || 3608 resume_setting >= WOW_RESUME_TRIGGER_COUNT) { 3609 hdd_err_rl("Invalid resume trigger %d (expected range [0, 2])", 3610 resume_setting); 3611 return -EINVAL; 3612 } 3613 3614 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); 3615 if (!qdf_dev) 3616 return -EINVAL; 3617 3618 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); 3619 if (!hif_ctx) 3620 return -EINVAL; 3621 3622 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) { 3623 hdd_alert("Already unit-test suspended; Nothing to do"); 3624 return 0; 3625 } 3626 3627 hdd_info("prevent rtpm wow for wow unit test"); 3628 qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.wow_unit_test); 3629 3630 /* pci link is needed to wakeup from HTC wakeup trigger */ 3631 if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP) 3632 hif_vote_link_up(hif_ctx); 3633 3634 errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL); 3635 if (errno) 3636 goto link_down; 3637 3638 errno = wlan_hdd_unit_test_bus_suspend(wow_params); 3639 if (errno) 3640 goto cfg80211_resume; 3641 3642 /* simulate kernel disabling irqs */ 3643 errno = hif_apps_irqs_disable(hif_ctx); 3644 if (errno) 3645 goto bus_resume; 3646 3647 errno = wlan_hdd_bus_suspend_noirq(); 3648 if (errno) 3649 goto enable_irqs; 3650 3651 /* pass wiphy/dev to callback via global variables */ 3652 g_wiphy = wiphy; 3653 g_dev = dev; 3654 g_resume_trigger = resume_setting; 3655 hif_ut_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback); 3656 3657 /* re-enable wake irq */ 3658 errno = hif_apps_wake_irq_enable(hif_ctx); 3659 if (errno) 3660 goto fake_apps_resume; 3661 3662 /* 3663 * Tell the kernel not to worry if TX queues aren't moving. This is 3664 * expected since we are suspending the wifi hardware, but not APPS 3665 */ 3666 dev->watchdog_timeo = INT_MAX; 3667 3668 hdd_alert("Unit-test suspend succeeded"); 3669 3670 return 0; 3671 3672 fake_apps_resume: 3673 hif_ut_apps_resume(hif_ctx); 3674 3675 enable_irqs: 3676 QDF_BUG(!hif_apps_irqs_enable(hif_ctx)); 3677 3678 bus_resume: 3679 QDF_BUG(!wlan_hdd_bus_resume(QDF_UNIT_TEST_WOW_SUSPEND)); 3680 3681 cfg80211_resume: 3682 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy)); 3683 3684 link_down: 3685 if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP) 3686 hif_vote_link_down(hif_ctx); 3687 3688 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state); 3689 hdd_err("Unit-test suspend failed: %d", errno); 3690 3691 hdd_info("allow rtpm wow for wow unit test"); 3692 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.wow_unit_test); 3693 3694 return errno; 3695 } 3696 hdd_wlan_fake_apps_resume(struct wiphy * wiphy,struct net_device * dev)3697 int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev) 3698 { 3699 struct hif_opaque_softc *hif_ctx; 3700 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); 3701 3702 if (wlan_hdd_validate_context(hdd_ctx)) 3703 return -EINVAL; 3704 3705 if (!hdd_ctx->config->is_unit_test_framework_enabled) { 3706 hdd_warn_rl("UT framework is disabled"); 3707 return -EINVAL; 3708 } 3709 3710 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); 3711 if (!hif_ctx) 3712 return -EINVAL; 3713 3714 hif_ut_apps_resume(hif_ctx); 3715 __hdd_wlan_fake_apps_resume(wiphy, dev); 3716 3717 return 0; 3718 } 3719 #endif 3720