blob: 262d07f7377d0fd3323dc6d1621227f5375491bb [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Poddar, Siddartha78cac32016-12-29 20:08:34 +05302 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_power.c
30 *
31 * WLAN power management functions
32 *
33 */
34
35/* Include files */
36
37#include <linux/pm.h>
38#include <linux/wait.h>
39#include <linux/cpu.h>
40#include <wlan_hdd_includes.h>
41#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK)
42#include <linux/wakelock.h>
43#endif
Anurag Chouhan6d760662016-02-20 16:05:43 +053044#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045#include "sme_api.h"
46#include <cds_api.h>
47#include <cds_sched.h>
48#include <mac_init_api.h>
49#include <wlan_qct_sys.h>
50#include <wlan_hdd_main.h>
51#include <wlan_hdd_assoc.h>
52#include <wlan_nlink_srv.h>
53#include <wlan_hdd_misc.h>
54#include <wlan_hdd_power.h>
Jeff Johnsonc8d0c252016-10-05 16:19:50 -070055#include <wlan_hdd_host_offload.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056#include <dbglog_host.h>
57#include <wlan_hdd_trace.h>
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +053058#include <wlan_hdd_p2p.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
60#include <linux/semaphore.h>
61#include <wlan_hdd_hostapd.h>
62#include "cfg_api.h"
63
64#include <linux/inetdevice.h>
65#include <wlan_hdd_cfg.h>
Sandeep Puligillae390be52016-02-08 17:07:05 -080066#include <wlan_hdd_scan.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067#include <wlan_hdd_cfg80211.h>
68#include <net/addrconf.h>
69#include <wlan_hdd_ipa.h>
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070070#include <wlan_hdd_lpass.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071
72#include <wma_types.h>
Poddar, Siddartha78cac32016-12-29 20:08:34 +053073#include <ol_txrx_osif_api.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074#include "hif.h"
75#include "sme_power_save_api.h"
Chandrasekaran, Manishekar0d814c72015-11-05 10:42:48 +053076#include "cds_concurrency.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080077#include "cdp_txrx_flow_ctrl_v2.h"
Yuanyuan Liu13738502016-04-06 17:41:37 -070078#include "pld_common.h"
Rajeev Kumar9bb2e852016-09-24 12:29:25 -070079#include "wlan_hdd_driver_ops.h"
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +053080#include <wlan_logging_sock_svc.h>
Krunal Sonid32c6bc2016-10-18 18:00:21 -070081#include "scheduler_api.h"
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +053082#include "cds_utils.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080083
84/* Preprocessor definitions and constants */
Yue Ma4ea4f052015-10-27 12:25:27 -070085#define HDD_SSR_BRING_UP_TIME 30000
Sreelakshmi Konamki22528532016-09-06 16:34:50 +053086#define HDD_WAKE_LOCK_RESUME_DURATION 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080087
88/* Type declarations */
89
Abhishek Singhbaea27d2016-04-27 13:29:30 +053090#ifdef FEATURE_WLAN_DIAG_SUPPORT
91/**
92 * hdd_wlan_suspend_resume_event()- send suspend/resume state
93 * @state: suspend/resume state
94 *
95 * This Function send send suspend resume state diag event
96 *
97 * Return: void.
98 */
99void hdd_wlan_suspend_resume_event(uint8_t state)
100{
101 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
102 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
103
104 suspend_state.state = state;
105 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
106}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530107
108/**
109 * hdd_wlan_offload_event()- send offloads event
110 * @type: offload type
111 * @state: enabled or disabled
112 *
113 * This Function send offloads enable/disable diag event
114 *
115 * Return: void.
116 */
117
118void hdd_wlan_offload_event(uint8_t type, uint8_t state)
119{
120 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
121 qdf_mem_zero(&host_offload, sizeof(host_offload));
122
123 host_offload.offload_type = type;
124 host_offload.state = state;
125
126 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
127}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530128#endif
129
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800130/* Function and variables declarations */
131
132extern struct notifier_block hdd_netdev_notifier;
133
134static struct timer_list ssr_timer;
135static bool ssr_timer_started;
Mukul Sharma3d36c392017-01-18 18:39:12 +0530136
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800137/**
Mukul Sharma3d36c392017-01-18 18:39:12 +0530138 * hdd_enable_gtk_offload() - enable GTK offload
139 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 *
Mukul Sharma3d36c392017-01-18 18:39:12 +0530141 * Central function to enable GTK offload.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800142 *
143 * Return: nothing
144 */
Mukul Sharma3d36c392017-01-18 18:39:12 +0530145static void hdd_enable_gtk_offload(hdd_adapter_t *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146{
Mukul Sharma3d36c392017-01-18 18:39:12 +0530147 QDF_STATUS status;
148 status = pmo_ucfg_enable_gtk_offload_in_fwr(adapter->hdd_vdev);
149 if (status != QDF_STATUS_SUCCESS)
150 hdd_info("Failed to enable gtk offload");
151}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800152
Mukul Sharma3d36c392017-01-18 18:39:12 +0530153/**
154 * hdd_disable_gtk_offload() - disable GTK offload
155 * @pAdapter: pointer to the adapter
156 *
157 * Central function to disable GTK offload.
158 *
159 * Return: nothing
160 */
161static void hdd_disable_gtk_offload(hdd_adapter_t *adapter)
162{
163 struct pmo_gtk_rsp_req gtk_rsp_request;
164 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165
Mukul Sharma3d36c392017-01-18 18:39:12 +0530166 /* ensure to get gtk rsp first before disable it*/
167 gtk_rsp_request.callback =
168 wlan_hdd_cfg80211_update_replay_counter_callback;
169 /* Passing as void* as PMO does not know legacy HDD adapter type */
170 gtk_rsp_request.callback_context =
171 (void *)adapter;
172 status = pmo_ucfg_get_gtk_rsp(adapter->hdd_vdev,
173 &gtk_rsp_request);
174 if (status != QDF_STATUS_SUCCESS) {
175 hdd_err("Failed to send get gtk rsp status:%d", status);
176 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177 }
Mukul Sharma3d36c392017-01-18 18:39:12 +0530178 hdd_notice("send get_gtk_rsp successful");
179 status = pmo_ucfg_disable_gtk_offload_in_fwr(adapter->hdd_vdev);
180 if (status != QDF_STATUS_SUCCESS)
181 hdd_info("Failed to disable gtk offload");
182
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800183}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186/**
187 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
188 * @nb: notifier block that was registered with the kernel
189 * @data: (unused) generic data that was registered with the kernel
190 * @arg: (unused) generic argument that was registered with the kernel
191 *
192 * This is a callback function that is registered with the kernel via
193 * register_inet6addr_notifier() which allows the driver to be
194 * notified when there is an IPv6 address change.
195 *
196 * Return: NOTIFY_DONE to indicate we don't care what happens with
197 * other callbacks
198 */
199static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
200 unsigned long data, void *arg)
201{
202 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
203 struct net_device *ndev = ifa->idev->dev;
204 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
205 hdd_context_t *pHddCtx;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700206 hdd_station_ctx_t *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 int status;
208
Jeff Johnson158c8d02016-10-31 13:11:48 -0700209 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530210
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700212 hdd_err("Adapter context is invalid %p", pAdapter);
Jeff Johnson158c8d02016-10-31 13:11:48 -0700213 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800214 }
215
216 if ((pAdapter->dev == ndev) &&
Jeff Johnson158c8d02016-10-31 13:11:48 -0700217 (pAdapter->device_mode == QDF_STA_MODE ||
218 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
219 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
221 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530222 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 return NOTIFY_DONE;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700224 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530225 hdd_debug("invoking sme_dhcp_done_ind");
226 sme_dhcp_done_ind(pHddCtx->hHal,
Jeff Johnson158c8d02016-10-31 13:11:48 -0700227 pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800228 schedule_work(&pAdapter->ipv6NotifierWorkQueue);
229 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530230 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800231 return NOTIFY_DONE;
232}
233
234/**
235 * wlan_hdd_ipv6_changed() - IPv6 change notifier callback
236 * @nb: pointer to notifier block
237 * @data: data
238 * @arg: arg
239 *
240 * This is the IPv6 notifier callback function gets invoked
241 * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed
242 * to reconfigure the offload parameters.
243 *
244 * Return: 0 on success, error number otherwise.
245 */
246int wlan_hdd_ipv6_changed(struct notifier_block *nb,
247 unsigned long data, void *arg)
248{
249 int ret;
250
251 cds_ssr_protect(__func__);
252 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
253 cds_ssr_unprotect(__func__);
254
255 return ret;
256}
257
258/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530259 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
260 * @idev: pointer to net device
261 * @ipv6addr: destination array to fill IPv6 addresses
262 * @ipv6addr_type: IPv6 Address type
263 * @count: number of IPv6 addresses
264 *
265 * This is the IPv6 utility function to populate unicast addresses.
266 *
267 * Return: 0 on success, error number otherwise.
268 */
269static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
270 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
271 uint8_t *ipv6addr_type, uint32_t *count)
272{
273 struct inet6_ifaddr *ifa;
274 struct list_head *p;
275 uint32_t scope;
276
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700277 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530278 list_for_each(p, &idev->addr_list) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530279 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700280 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530281 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700282 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530283 ifa = list_entry(p, struct inet6_ifaddr, if_list);
284 if (ifa->flags & IFA_F_DADFAILED)
285 continue;
286 scope = ipv6_addr_src_scope(&ifa->addr);
287 switch (scope) {
288 case IPV6_ADDR_SCOPE_GLOBAL:
289 case IPV6_ADDR_SCOPE_LINKLOCAL:
290 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
291 sizeof(ifa->addr.s6_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530292 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530293 hdd_info("Index %d scope = %s UC-Address: %pI6",
294 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
295 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
296 *count += 1;
297 break;
298 default:
299 hdd_err("The Scope %d is not supported", scope);
300 }
301 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700302
303 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530304 return 0;
305}
306
307/**
308 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
309 * @idev: pointer to net device
310 * @ipv6addr: destination array to fill IPv6 addresses
311 * @ipv6addr_type: IPv6 Address type
312 * @count: number of IPv6 addresses
313 *
314 * This is the IPv6 utility function to populate anycast addresses.
315 *
316 * Return: 0 on success, error number otherwise.
317 */
318static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
319 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
320 uint8_t *ipv6addr_type, uint32_t *count)
321{
322 struct ifacaddr6 *ifaca;
323 uint32_t scope;
324
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700325 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530326 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530327 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700328 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530329 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700330 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530331 /* For anycast addr no DAD */
332 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
333 switch (scope) {
334 case IPV6_ADDR_SCOPE_GLOBAL:
335 case IPV6_ADDR_SCOPE_LINKLOCAL:
336 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
337 sizeof(ifaca->aca_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530338 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530339 hdd_info("Index %d scope = %s AC-Address: %pI6",
340 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
341 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
342 *count += 1;
343 break;
344 default:
345 hdd_err("The Scope %d is not supported", scope);
346 }
347 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700348
349 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530350 return 0;
351}
352
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530353void hdd_enable_ns_offload(hdd_adapter_t *adapter,
354 enum pmo_offload_trigger trigger)
Dustin Brown2444ee62016-09-06 17:20:36 -0700355{
356 struct inet6_dev *in6_dev;
Dustin Brown2444ee62016-09-06 17:20:36 -0700357 QDF_STATUS status;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530358 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
359 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
360 struct pmo_ns_req *ns_req = NULL;
361 int err;
362
363 ENTER();
364 if (!psoc) {
365 hdd_err("psoc is NULL");
366 goto out;
367 }
Dustin Brown2444ee62016-09-06 17:20:36 -0700368
369 in6_dev = __in6_dev_get(adapter->dev);
370 if (NULL == in6_dev) {
371 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530372 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700373 }
374
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530375 ns_req = qdf_mem_malloc(sizeof(*ns_req));
376 if (!ns_req) {
377 hdd_err("fail to allocate ns_req");
378 goto out;
379 }
380
381 ns_req->psoc = psoc;
382 ns_req->vdev_id = adapter->sessionId;
383 ns_req->trigger = trigger;
384 ns_req->count = 0;
385
Dustin Brown2444ee62016-09-06 17:20:36 -0700386 /* Unicast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530387 err = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
388 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700389 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530390 hdd_disable_ns_offload(adapter, trigger);
Dustin Brown2444ee62016-09-06 17:20:36 -0700391 hdd_notice("Reached max supported addresses and not enabling "
392 "NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530393 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700394 }
395
396 /* Anycast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530397 err = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
398 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700399 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530400 hdd_disable_ns_offload(adapter, trigger);
Dustin Brown2444ee62016-09-06 17:20:36 -0700401 hdd_notice("Reached max supported addresses and not enabling "
402 "NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530403 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700404 }
405
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530406 /* cache ns request */
407 status = pmo_ucfg_cache_ns_offload_req(ns_req);
408 if (status != QDF_STATUS_SUCCESS) {
409 hdd_err("Failed to cache ns request status: %d", status);
410 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700411 }
412
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530413 /* enable ns request */
414 status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
415 if (status != QDF_STATUS_SUCCESS)
Dustin Brown2444ee62016-09-06 17:20:36 -0700416 hdd_err("Failed to enable HostOffload feature with status: %d",
417 status);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530418 else
419 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
420out:
421 if (ns_req)
422 qdf_mem_free(ns_req);
423 EXIT();
424
Dustin Brown2444ee62016-09-06 17:20:36 -0700425}
426
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530427void hdd_disable_ns_offload(hdd_adapter_t *adapter,
428 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800429{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530430 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431
432 ENTER();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530433 status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
434 if (status != QDF_STATUS_SUCCESS) {
435 hdd_err("Failed to flush NS Offload");
436 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800437 }
438
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530439 status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
440 if (status != QDF_STATUS_SUCCESS)
441 hdd_err("Failed to disable NS Offload");
Dustin Brown2444ee62016-09-06 17:20:36 -0700442 else
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530443 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
444 SIR_OFFLOAD_DISABLE);
445out:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800446 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530447
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800448}
449
450/**
451 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
452 * @work: registered work item
453 *
454 * This function performs the work initially trigged by a callback
455 * from the IPv6 netdev notifier. Since this means there has been a
456 * change in IPv6 state for the interface, the NS offload is
457 * reconfigured.
458 *
459 * Return: None
460 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700461static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800462{
463 hdd_adapter_t *pAdapter =
464 container_of(work, hdd_adapter_t, ipv6NotifierWorkQueue);
465 hdd_context_t *pHddCtx;
466 int status;
467
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530468 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800469
470 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
471 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530472 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800473 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530475 hdd_enable_ns_offload(pAdapter, pmo_ipv6_change_notify);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530476 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477}
478
479/**
480 * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler
481 * @work: Pointer to work context
482 *
483 * Return: none
484 */
485void hdd_ipv6_notifier_work_queue(struct work_struct *work)
486{
487 cds_ssr_protect(__func__);
488 __hdd_ipv6_notifier_work_queue(work);
489 cds_ssr_unprotect(__func__);
490}
491
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530492void hdd_enable_host_offloads(hdd_adapter_t *adapter,
493 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800494{
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530495 ENTER();
496
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530497 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
498 hdd_info("offload is not supported on this vdev opmode: %d",
499 adapter->device_mode);
500 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501 }
502
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530503 if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
504 hdd_info("vdev is not connected");
505 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800506 }
507
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530508 hdd_info("enable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530509 hdd_enable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530510 hdd_enable_arp_offload(adapter, trigger);
511 hdd_enable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530512 hdd_enable_mc_addr_filtering(adapter, trigger);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530513out:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530514 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530515
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800516}
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530517
518void hdd_disable_host_offloads(hdd_adapter_t *adapter,
519 enum pmo_offload_trigger trigger)
520{
521 ENTER();
522
523 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
524 hdd_info("offload is not supported on this vdev opmode: %d",
525 adapter->device_mode);
526 goto out;
527 }
528
529 if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
530 hdd_info("vdev is not connected");
531 goto out;
532 }
533
534 hdd_info("disable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530535 hdd_disable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530536 hdd_disable_arp_offload(adapter, trigger);
537 hdd_disable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530538 hdd_disable_mc_addr_filtering(adapter, trigger);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530539out:
540 EXIT();
541
542}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800543
544/**
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800545 * hdd_lookup_ifaddr() - Lookup interface address data by name
546 * @adapter: the adapter whose name should be searched for
547 *
548 * return in_ifaddr pointer on success, NULL for failure
549 */
550static struct in_ifaddr *hdd_lookup_ifaddr(hdd_adapter_t *adapter)
551{
552 struct in_ifaddr *ifa;
553 struct in_device *in_dev;
554
555 if (!adapter) {
556 hdd_err("adapter is null");
557 return NULL;
558 }
559
560 in_dev = __in_dev_get_rtnl(adapter->dev);
561 if (!in_dev) {
562 hdd_err("Failed to get in_device");
563 return NULL;
564 }
565
566 /* lookup address data by interface name */
567 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
568 if (!strcmp(adapter->dev->name, ifa->ifa_label))
569 return ifa;
570 }
571
572 return NULL;
573}
574
575/**
576 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
577 * @adapter: the adapter whose IPv4 address is desired
578 * @ipv4_addr: the address of the array to copy the IPv4 address into
579 *
580 * return: zero for success; non-zero for failure
581 */
582static int hdd_populate_ipv4_addr(hdd_adapter_t *adapter, uint8_t *ipv4_addr)
583{
584 struct in_ifaddr *ifa;
585 int i;
586
587 if (!adapter) {
588 hdd_err("adapter is null");
589 return -EINVAL;
590 }
591
592 if (!ipv4_addr) {
593 hdd_err("ipv4_addr is null");
594 return -EINVAL;
595 }
596
597 ifa = hdd_lookup_ifaddr(adapter);
598 if (!ifa || !ifa->ifa_local) {
599 hdd_err("ipv4 address not found");
600 return -EINVAL;
601 }
602
603 /* convert u32 to byte array */
604 for (i = 0; i < 4; i++)
605 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
606
607 return 0;
608}
609
610/**
611 * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive
612 * @adapter: the HDD adapter to configure
613 *
614 * This configures gratuitous APR keepalive based on the adapter's current
615 * connection information, specifically IPv4 address and BSSID
616 *
617 * return: zero for success, non-zero for failure
618 */
619static int hdd_set_grat_arp_keepalive(hdd_adapter_t *adapter)
620{
621 QDF_STATUS status;
622 int exit_code;
623 hdd_context_t *hdd_ctx;
624 hdd_station_ctx_t *sta_ctx;
625 tSirKeepAliveReq req = {
626 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800627 .dest_macaddr = QDF_MAC_ADDR_BROADCAST_INITIALIZER,
628 };
629
630 if (!adapter) {
631 hdd_err("adapter is null");
632 return -EINVAL;
633 }
634
635 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
636 if (!hdd_ctx) {
637 hdd_err("hdd_ctx is null");
638 return -EINVAL;
639 }
640
641 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
642 if (!sta_ctx) {
643 hdd_err("sta_ctx is null");
644 return -EINVAL;
645 }
646
647 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
648 if (exit_code) {
649 hdd_err("Failed to populate ipv4 address");
650 return exit_code;
651 }
652
Dustin Brown6b4643d2017-02-09 12:19:28 -0800653 /* according to RFC5227, sender/target ip address should be the same */
654 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
655 sizeof(req.destIpv4Addr));
656
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800657 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId);
658 req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod;
659 req.sessionId = adapter->sessionId;
660
661 hdd_info("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
662 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
663 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
664
665 status = sme_set_keep_alive(hdd_ctx->hHal, req.sessionId, &req);
666 if (QDF_IS_STATUS_ERROR(status)) {
667 hdd_err("Failed to set keepalive");
668 return qdf_status_to_os_return(status);
669 }
670
671 return 0;
672}
673
674/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800675 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
676 * @work: registered work item
677 *
678 * This function performs the work initially trigged by a callback
679 * from the IPv4 netdev notifier. Since this means there has been a
680 * change in IPv4 state for the interface, the ARP offload is
681 * reconfigured.
682 *
683 * Return: None
684 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700685static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800686{
Dustin Brownb6b0f182017-03-08 13:08:27 -0800687 hdd_adapter_t *adapter;
688 hdd_context_t *hdd_ctx;
689
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530690 ENTER();
Dustin Brownb6b0f182017-03-08 13:08:27 -0800691
692 adapter = container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue);
693 hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify);
694
695 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
696 if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP)
697 hdd_set_grat_arp_keepalive(adapter);
698
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530699 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800700}
701
702/**
703 * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler
704 * @work: Pointer to work context
705 *
706 * Return: none
707 */
708void hdd_ipv4_notifier_work_queue(struct work_struct *work)
709{
710 cds_ssr_protect(__func__);
711 __hdd_ipv4_notifier_work_queue(work);
712 cds_ssr_unprotect(__func__);
713}
714
715/**
716 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
717 * @nb: notifier block that was registered with the kernel
718 * @data: (unused) generic data that was registered with the kernel
719 * @arg: (unused) generic argument that was registered with the kernel
720 *
721 * This is a callback function that is registered with the kernel via
722 * register_inetaddr_notifier() which allows the driver to be
723 * notified when there is an IPv4 address change.
724 *
725 * Return: NOTIFY_DONE to indicate we don't care what happens with
726 * other callbacks
727 */
728static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
729 unsigned long data, void *arg)
730{
731 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 struct net_device *ndev = ifa->ifa_dev->dev;
733 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
734 hdd_context_t *pHddCtx;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700735 hdd_station_ctx_t *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800736 int status;
737
Jeff Johnson158c8d02016-10-31 13:11:48 -0700738 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530739
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800740 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700741 hdd_err("Adapter context is invalid %p", pAdapter);
Jeff Johnson158c8d02016-10-31 13:11:48 -0700742 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800743 }
744
Jeff Johnson158c8d02016-10-31 13:11:48 -0700745 if ((pAdapter->dev == ndev) &&
746 (pAdapter->device_mode == QDF_STA_MODE ||
747 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
748 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800749
750 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
751 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530752 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800753 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800754
Jeff Johnson158c8d02016-10-31 13:11:48 -0700755 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530756 hdd_debug("invoking sme_dhcp_done_ind");
757 sme_dhcp_done_ind(pHddCtx->hHal,
Jeff Johnson158c8d02016-10-31 13:11:48 -0700758 pAdapter->sessionId);
Abhishek Singhca408032016-09-13 15:26:12 +0530759
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800760 if (!pHddCtx->config->fhostArpOffload) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700761 hdd_notice("Offload not enabled ARPOffload=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800762 pHddCtx->config->fhostArpOffload);
763 return NOTIFY_DONE;
764 }
765
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800766 ifa = hdd_lookup_ifaddr(pAdapter);
767 if (ifa && ifa->ifa_local)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800768 schedule_work(&pAdapter->ipv4NotifierWorkQueue);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800769 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530770 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800771 return NOTIFY_DONE;
772}
773
774/**
775 * wlan_hdd_ipv4_changed() - IPv4 change notifier callback
776 * @nb: pointer to notifier block
777 * @data: data
778 * @arg: arg
779 *
780 * This is the IPv4 notifier callback function gets invoked
781 * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed
782 * to reconfigure the offload parameters.
783 *
784 * Return: 0 on success, error number otherwise.
785 */
786int wlan_hdd_ipv4_changed(struct notifier_block *nb,
787 unsigned long data, void *arg)
788{
789 int ret;
790
791 cds_ssr_protect(__func__);
792 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
793 cds_ssr_unprotect(__func__);
794
795 return ret;
796}
797
798/**
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530799 * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800 * @pAdapter: Adapter context for which ARP offload is to be configured
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800801 *
802 * Return:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530803 * ifa - on successful operation,
804 * NULL - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800805 */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530806static struct in_ifaddr *hdd_get_ipv4_local_interface(
807 hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800808{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530809 struct in_ifaddr **ifap = NULL;
810 struct in_ifaddr *ifa = NULL;
811 struct in_device *in_dev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800812
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530813 in_dev = __in_dev_get_rtnl(pAdapter->dev);
814 if (in_dev) {
815 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
816 ifap = &ifa->ifa_next) {
817 if (!strcmp(pAdapter->dev->name, ifa->ifa_label)) {
818 /* if match break */
819 return ifa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800821 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530822 }
823 ifa = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800824
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530825 return ifa;
826}
827
828void hdd_enable_arp_offload(hdd_adapter_t *adapter,
829 enum pmo_offload_trigger trigger)
830{
831 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
832 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
833 QDF_STATUS status;
834 struct pmo_arp_req *arp_req = NULL;
835 struct in_ifaddr *ifa = NULL;
836
837 ENTER();
838 arp_req = qdf_mem_malloc(sizeof(*arp_req));
839 if (!arp_req) {
840 hdd_err("cannot allocate arp_req");
841 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800842 }
Jeff Johnson68755312017-02-10 11:46:55 -0800843
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530844 arp_req->psoc = psoc;
845 arp_req->vdev_id = adapter->sessionId;
846 arp_req->trigger = trigger;
Jeff Johnson68755312017-02-10 11:46:55 -0800847
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530848 ifa = hdd_get_ipv4_local_interface(adapter);
849 if (ifa && ifa->ifa_local) {
850 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
851 status = pmo_ucfg_cache_arp_offload_req(arp_req);
852 if (status == QDF_STATUS_SUCCESS) {
853 status = pmo_ucfg_enable_arp_offload_in_fwr(
854 adapter->hdd_vdev, trigger);
855 if (status == QDF_STATUS_SUCCESS)
856 hdd_wlan_offload_event(
857 PMO_IPV4_ARP_REPLY_OFFLOAD,
858 PMO_OFFLOAD_ENABLE);
859 else
860 hdd_info("fail to enable arp offload in fwr");
861 } else
862 hdd_info("fail to cache arp offload request");
863 } else {
864 hdd_notice("IP Address is not assigned");
865 status = QDF_STATUS_NOT_INITIALIZED;
866 }
867out:
868 if (arp_req)
869 qdf_mem_free(arp_req);
870 EXIT();
871
872}
873
874void hdd_disable_arp_offload(hdd_adapter_t *adapter,
875 enum pmo_offload_trigger trigger)
876{
877 QDF_STATUS status;
878
879 ENTER();
880 status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
881 if (status != QDF_STATUS_SUCCESS) {
882 hdd_err("Failed to flush arp Offload");
883 goto out;
Jeff Johnson68755312017-02-10 11:46:55 -0800884 }
885
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530886 status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev, trigger);
887 if (status == QDF_STATUS_SUCCESS)
888 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
889 PMO_OFFLOAD_DISABLE);
890 else
891 hdd_info("fail to disable arp offload");
892out:
893 EXIT();
894
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800895}
896
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530897void hdd_enable_mc_addr_filtering(hdd_adapter_t *adapter,
898 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899{
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530900 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
901 QDF_STATUS status;
902 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800903
Ravi Joshi24477b72016-07-19 15:45:09 -0700904 ENTER();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530905 if (wlan_hdd_validate_context(hdd_ctx))
906 goto out;
Ravi Joshi24477b72016-07-19 15:45:09 -0700907
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530908 status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(psoc,
909 adapter->sessionId, trigger);
910 if (status != QDF_STATUS_SUCCESS)
911 hdd_info("failed to enable mc list status %d", status);
912out:
Ravi Joshi24477b72016-07-19 15:45:09 -0700913 EXIT();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530914
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800915}
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530916
917void hdd_disable_mc_addr_filtering(hdd_adapter_t *adapter,
918 enum pmo_offload_trigger trigger)
919{
920 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
921 QDF_STATUS status = QDF_STATUS_SUCCESS;
922 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
923
924 ENTER();
925 if (wlan_hdd_validate_context(hdd_ctx))
926 goto out;
927
928 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
929 adapter->sessionId, trigger);
930 if (status != QDF_STATUS_SUCCESS)
931 hdd_info("failed to disable mc list status %d", status);
932out:
933 EXIT();
934
935}
936
937int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
938{
939 QDF_STATUS status;
940 int ret = 0;
941
942 ENTER();
943 /* cache mc addr list */
944 status = pmo_ucfg_cache_mc_addr_list(mc_list_config);
945 if (status != QDF_STATUS_SUCCESS) {
946 hdd_info("fail to cache mc list status %d", status);
947 ret = -EINVAL;
948 }
949 EXIT();
950
951 return ret;
952}
953
954void hdd_disable_and_flush_mc_addr_list(hdd_adapter_t *adapter,
955 enum pmo_offload_trigger trigger)
956{
957 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
958 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
959 QDF_STATUS status = QDF_STATUS_SUCCESS;
960
961 ENTER();
962 /* disable mc list first */
963 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
964 adapter->sessionId, trigger);
965 if (status != QDF_STATUS_SUCCESS)
966 hdd_info("fail to disable mc list");
967
968 /* flush mc list */
969 status = pmo_ucfg_flush_mc_addr_list(psoc, adapter->sessionId);
970 if (status != QDF_STATUS_SUCCESS)
971 hdd_info("fail to flush mc list status %d", status);
972 EXIT();
973
974 return;
975
976}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977
978/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700979 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
980 * @adapter: adapter to get info from
981 * @conn_state_mask: mask of connection info
982 *
983 * currently only need to send connection info.
984 */
985static void
986hdd_update_conn_state_mask(hdd_adapter_t *adapter, uint32_t *conn_state_mask)
987{
988
989 eConnectionState connState;
990 hdd_station_ctx_t *sta_ctx;
991 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
992 connState = sta_ctx->conn_info.connState;
993
994 if (connState == eConnectionState_Associated ||
995 connState == eConnectionState_IbssConnected)
996 *conn_state_mask |= (1 << adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800997}
998
999/**
1000 * hdd_suspend_wlan() - Driver suspend function
1001 * @callback: Callback function to invoke when driver is ready to suspend
1002 * @callbackContext: Context to pass back to @callback function
1003 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301004 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001005 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301006static int
1007hdd_suspend_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008{
1009 hdd_context_t *pHddCtx;
1010
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301011 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001012 hdd_adapter_t *pAdapter = NULL;
1013 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001014 uint32_t conn_state_mask = 0;
Jeff Johnsonc3273322016-07-06 15:28:17 -07001015 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001016
Anurag Chouhan6d760662016-02-20 16:05:43 +05301017 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001018 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001019 hdd_alert("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301020 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001021 }
1022
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001023 if (cds_is_driver_recovering()) {
1024 hdd_err("Recovery in Progress. State: 0x%x Ignore suspend!!!",
1025 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301026 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 }
1028
1029 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301030 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031 pAdapter = pAdapterNode->pAdapter;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301032 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1033 hdd_err("invalid session id: %d", pAdapter->sessionId);
1034 goto next_adapter;
1035 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001036
1037 /* stop all TX queues before suspend */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001038 hdd_notice("Disabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE,
1040 WLAN_CONTROL_PATH);
1041
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001042 /* Configure supported OffLoads */
Mukul Sharma3ba26b82017-01-12 21:59:41 +05301043 hdd_enable_host_offloads(pAdapter, pmo_apps_suspend);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001044 hdd_update_conn_state_mask(pAdapter, &conn_state_mask);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301045next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1047 pAdapterNode = pNext;
1048 }
1049
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301050 status = pmo_ucfg_psoc_user_space_suspend_req(pHddCtx->hdd_psoc,
1051 QDF_SYSTEM_SUSPEND);
1052 if (status != QDF_STATUS_SUCCESS)
1053 return -EAGAIN;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001054
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055 pHddCtx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301056 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301058 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001059}
1060
1061/**
1062 * hdd_resume_wlan() - Driver resume function
1063 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301064 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301066static int hdd_resume_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001067{
1068 hdd_context_t *pHddCtx;
1069 hdd_adapter_t *pAdapter = NULL;
1070 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301071 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072
Dustin Brown2d228232016-09-22 15:06:19 -07001073 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001074
Anurag Chouhan6d760662016-02-20 16:05:43 +05301075 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076 if (!pHddCtx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001077 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301078 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079 }
1080
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001081 if (cds_is_driver_recovering()) {
Dustin Brown2d228232016-09-22 15:06:19 -07001082 hdd_err("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001083 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301084 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085 }
1086
1087 pHddCtx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301088 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001089
1090 /*loop through all adapters. Concurrency */
1091 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
1092
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301093 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001094 pAdapter = pAdapterNode->pAdapter;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301095 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1096 hdd_err("invalid session id: %d", pAdapter->sessionId);
1097 goto next_adapter;
1098 }
1099 /* Disable supported OffLoads */
1100 hdd_disable_host_offloads(pAdapter, pmo_apps_resume);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001101
1102 /* wake the tx queues */
Dustin Brown2d228232016-09-22 15:06:19 -07001103 hdd_info("Enabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001104 wlan_hdd_netif_queue_control(pAdapter,
1105 WLAN_WAKE_ALL_NETIF_QUEUE,
1106 WLAN_CONTROL_PATH);
1107
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301108next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1110 pAdapterNode = pNext;
1111 }
1112 hdd_ipa_resume(pHddCtx);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301113 status = pmo_ucfg_psoc_user_space_resume_req(pHddCtx->hdd_psoc,
1114 QDF_SYSTEM_SUSPEND);
1115 if (status != QDF_STATUS_SUCCESS)
1116 return -EAGAIN;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301118 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001119}
1120
1121/**
1122 * DOC: SSR Timer
1123 *
1124 * When SSR is initiated, an SSR timer is started. Under normal
1125 * circumstances SSR should complete amd the timer should be deleted
1126 * before it fires. If the SSR timer does fire, it indicates SSR has
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301127 * taken too long, and our only recourse is to invoke the QDF_BUG()
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 * API which can allow a crashdump to be captured.
1129 */
1130
1131/**
1132 * hdd_ssr_timer_init() - Initialize SSR Timer
1133 *
1134 * Return: None.
1135 */
1136static void hdd_ssr_timer_init(void)
1137{
1138 init_timer(&ssr_timer);
1139}
1140
1141/**
1142 * hdd_ssr_timer_del() - Delete SSR Timer
1143 *
1144 * Return: None.
1145 */
1146static void hdd_ssr_timer_del(void)
1147{
1148 del_timer(&ssr_timer);
1149 ssr_timer_started = false;
1150}
1151
1152/**
1153 * hdd_ssr_timer_cb() - SSR Timer callback function
1154 * @data: opaque data registered with timer infrastructure
1155 *
1156 * Return: None.
1157 */
1158static void hdd_ssr_timer_cb(unsigned long data)
1159{
Jeff Johnsonc3273322016-07-06 15:28:17 -07001160 hdd_alert("HDD SSR timer expired!");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301161 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162}
1163
1164/**
1165 * hdd_ssr_timer_start() - Start SSR Timer
1166 * @msec: Timer timeout value in milliseconds
1167 *
1168 * Return: None.
1169 */
1170static void hdd_ssr_timer_start(int msec)
1171{
1172 if (ssr_timer_started) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001173 hdd_alert("Trying to start SSR timer when " "it's running!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001174 }
1175 ssr_timer.expires = jiffies + msecs_to_jiffies(msec);
1176 ssr_timer.function = hdd_ssr_timer_cb;
1177 add_timer(&ssr_timer);
1178 ssr_timer_started = true;
1179}
1180
1181/**
Komal Seelam78ff65a2016-08-18 15:25:24 +05301182 * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace
1183 *
1184 * @dev: Device Pointer
1185 *
1186 * Return: None
1187 */
1188void hdd_svc_fw_shutdown_ind(struct device *dev)
1189{
1190 hdd_context_t *hdd_ctx;
1191 v_CONTEXT_t g_context;
1192
1193 g_context = cds_get_global_context();
1194
1195 if (!g_context)
1196 return;
1197
1198 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1199
1200 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1201 WLAN_SVC_FW_SHUTDOWN_IND,
1202 NULL, 0) : 0;
1203}
1204
1205/**
Arun Khandavallicc544b32017-01-30 19:52:16 +05301206 * hdd_ssr_restart_sap() - restart sap on SSR
1207 * @hdd_ctx: hdd context
1208 *
1209 * Return: nothing
1210 */
1211static void hdd_ssr_restart_sap(hdd_context_t *hdd_ctx)
1212{
1213 QDF_STATUS status;
1214 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
1215 hdd_adapter_t *adapter;
1216
1217 ENTER();
1218
1219 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
1220 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
1221 adapter = adapter_node->pAdapter;
1222 if (adapter && adapter->device_mode == QDF_SAP_MODE) {
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001223 if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
1224 hdd_notice("Restart prev SAP session");
1225 wlan_hdd_start_sap(adapter, true);
1226 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301227 }
1228 status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next);
1229 adapter_node = next;
1230 }
1231
1232 EXIT();
1233}
1234
1235/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 * hdd_wlan_shutdown() - HDD SSR shutdown function
1237 *
1238 * This function is called by the HIF to shutdown the driver during SSR.
1239 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301240 * Return: QDF_STATUS_SUCCESS if the driver was shut down,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001241 * or an error status otherwise
1242 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301243QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001245 v_CONTEXT_t p_cds_context = NULL;
1246 hdd_context_t *pHddCtx;
1247 p_cds_sched_context cds_sched_context = NULL;
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001248 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249
Jeff Johnsonc3273322016-07-06 15:28:17 -07001250 hdd_alert("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001251
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001252 /* If SSR never completes, then do kernel panic. */
1253 hdd_ssr_timer_init();
1254 hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME);
1255
1256 /* Get the global CDS context. */
1257 p_cds_context = cds_get_global_context();
1258 if (!p_cds_context) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001259 hdd_alert("Global CDS context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301260 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001261 }
1262
1263 /* Get the HDD context. */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301264 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001266 hdd_alert("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301267 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001268 }
1269
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001270 cds_clear_concurrent_session_count();
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301271
1272 hdd_info("Invoking packetdump deregistration API");
1273 wlan_deregister_txrx_packetdump();
Sandeep Puligillad0004212017-02-26 18:34:56 -08001274#ifndef NAPIER_SCAN
Sandeep Puligillae390be52016-02-08 17:07:05 -08001275 hdd_cleanup_scan_queue(pHddCtx);
Sandeep Puligillad0004212017-02-26 18:34:56 -08001276#else
1277 wlan_cfg80211_abort_scan(pHddCtx->hdd_pdev);
1278#endif
Govind Singh9c58eba2016-09-02 16:23:06 +05301279 hdd_ipa_uc_ssr_deinit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001280 hdd_reset_all_adapters(pHddCtx);
1281
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301282 /* Flush cached rx frame queue */
Poddar, Siddartha78cac32016-12-29 20:08:34 +05301283 ol_txrx_flush_cache_rx_queue();
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301284
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301285 /* De-register the HDD callbacks */
1286 hdd_deregister_cb(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001287
1288 cds_sched_context = get_cds_sched_ctxt();
1289
Rajeev Kumareada0d02016-12-08 17:44:17 -08001290 if (pHddCtx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001291 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001292 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001293 }
1294#ifdef QCA_CONFIG_SMP
1295 if (true == pHddCtx->is_ol_rx_thread_suspended) {
1296 complete(&cds_sched_context->ol_resume_rx_event);
1297 pHddCtx->is_ol_rx_thread_suspended = false;
1298 }
1299#endif
1300
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001301 qdf_status = cds_sched_close(p_cds_context);
1302 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1303 hdd_err("Failed to close CDS Scheduler");
1304 QDF_ASSERT(false);
1305 }
1306
Nitesh Shah61c10d92016-10-19 19:29:15 +05301307 qdf_mc_timer_stop(&pHddCtx->tdls_source_timer);
1308
Prashanth Bhattaab004382016-10-11 16:08:11 -07001309 hdd_bus_bandwidth_destroy(pHddCtx);
1310
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001311 hdd_wlan_stop_modules(pHddCtx);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301312
Jeff Johnsonf7f66f02016-09-23 14:50:11 -07001313 hdd_lpass_notify_stop(pHddCtx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001314
Jeff Johnsonc3273322016-07-06 15:28:17 -07001315 hdd_alert("WLAN driver shutdown complete");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301316 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317}
1318
Sen, Devendra154b3c42017-02-13 20:44:15 +05301319#ifdef FEATURE_WLAN_DIAG_SUPPORT
1320/**
1321* hdd_wlan_ssr_reinit_event()- send ssr reinit state
1322*
1323* This Function send send ssr reinit state diag event
1324*
1325* Return: void.
1326*/
1327static void hdd_wlan_ssr_reinit_event(void)
1328{
1329 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1330 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1331 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1332 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1333 EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1334}
1335#else
1336static inline void hdd_wlan_ssr_reinit_event(void)
1337{
1338
1339}
1340#endif
1341
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342/**
1343 * hdd_wlan_re_init() - HDD SSR re-init function
1344 *
1345 * This function is called by the HIF to re-initialize the driver after SSR.
1346 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301347 * Return: QDF_STATUS_SUCCESS if the driver was re-initialized,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348 * or an error status otherwise
1349 */
Arun Khandavallifae92942016-08-01 13:31:08 +05301350QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001351{
Arun Khandavallifae92942016-08-01 13:31:08 +05301352
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001353 v_CONTEXT_t p_cds_context = NULL;
1354 hdd_context_t *pHddCtx = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001355 hdd_adapter_t *pAdapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301356 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301357 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001358
1359 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1360
1361 /* Get the CDS context */
1362 p_cds_context = cds_get_global_context();
1363 if (p_cds_context == NULL) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001364 hdd_alert("Failed cds_get_global_context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001365 goto err_re_init;
1366 }
1367
1368 /* Get the HDD context */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301369 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001370 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001371 hdd_alert("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001372 goto err_re_init;
1373 }
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301374 bug_on_reinit_failure = pHddCtx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001375
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001376 /* The driver should always be initialized in STA mode after SSR */
1377 hdd_set_conparam(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001378 /* Try to get an adapter from mode ID */
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001379 pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001380 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001381 pAdapter = hdd_get_adapter(pHddCtx, QDF_SAP_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001382 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001383 pAdapter = hdd_get_adapter(pHddCtx, QDF_IBSS_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001384 if (!pAdapter) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001385 hdd_alert("Failed to get Adapter!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001386 }
1387 }
1388 }
1389
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301390 if (pHddCtx->config->enable_dp_trace)
1391 qdf_dp_trace_init();
1392
Prashanth Bhattaab004382016-10-11 16:08:11 -07001393 hdd_bus_bandwidth_init(pHddCtx);
1394
Arun Khandavallicc544b32017-01-30 19:52:16 +05301395
Arun Khandavallifae92942016-08-01 13:31:08 +05301396 ret = hdd_wlan_start_modules(pHddCtx, pAdapter, true);
1397 if (ret) {
1398 hdd_err("Failed to start wlan after error");
1399 goto err_wiphy_unregister;
1400 }
1401
Arun Khandavallia96c2c02016-05-17 19:15:34 +05301402 hdd_wlan_get_version(pHddCtx, NULL, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001403
Wu Gao36717432016-11-21 15:09:48 +08001404 wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index,
1405 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
1406
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001407 /* Restart all adapters */
1408 hdd_start_all_adapters(pHddCtx);
1409
Sreelakshmi Konamkib53c6292017-03-01 13:13:23 +05301410 pHddCtx->last_scan_reject_session_id = 0xFF;
1411 pHddCtx->last_scan_reject_reason = 0;
1412 pHddCtx->last_scan_reject_timestamp = 0;
1413
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001414 pHddCtx->btCoexModeSet = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001416 /* Allow the phone to go to sleep */
1417 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1418
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301419 ret = hdd_register_cb(pHddCtx);
1420 if (ret) {
1421 hdd_err("Failed to register HDD callbacks!");
Chandrasekaran Manishekarcde33d72016-04-14 19:03:39 +05301422 goto err_cds_disable;
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301423 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001424
Jeff Johnson9afc5012016-09-23 13:56:27 -07001425 hdd_lpass_notify_start(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426
Jeff Johnsonc3273322016-07-06 15:28:17 -07001427 hdd_err("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001428 goto success;
1429
1430err_cds_disable:
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001431 hdd_wlan_stop_modules(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432
Arun Khandavallifae92942016-08-01 13:31:08 +05301433err_wiphy_unregister:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001434 if (pHddCtx) {
1435 /* Unregister the Net Device Notifier */
1436 unregister_netdevice_notifier(&hdd_netdev_notifier);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001437 ptt_sock_deactivate_svc();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438 nl_srv_exit();
1439
1440 /* Free up dynamically allocated members inside HDD Adapter */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07001441 qdf_mem_free(pHddCtx->config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001442 pHddCtx->config = NULL;
Nirav Shahed34b212016-04-25 10:59:16 +05301443 wlan_hdd_deinit_tx_rx_histogram(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444 wiphy_unregister(pHddCtx->wiphy);
1445 wiphy_free(pHddCtx->wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446 }
1447
1448err_re_init:
1449 /* Allow the phone to go to sleep */
1450 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301451 if (bug_on_reinit_failure)
1452 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 return -EPERM;
1454
1455success:
Arun Khandavallicc544b32017-01-30 19:52:16 +05301456 if (pHddCtx->config->sap_internal_restart)
1457 hdd_ssr_restart_sap(pHddCtx);
Srinivas Girigowda02c084d2016-10-18 15:27:21 -07001458 hdd_ssr_timer_del();
Sen, Devendra154b3c42017-02-13 20:44:15 +05301459 hdd_wlan_ssr_reinit_event();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301460 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001461}
1462
1463/**
1464 * wlan_hdd_set_powersave() - Set powersave mode
1465 * @adapter: adapter upon which the request was received
Dustin Brownf660fb42016-09-09 12:04:00 -07001466 * @allow_power_save: is wlan allowed to go into power save mode
1467 * @timeout: timeout period in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468 *
1469 * Return: 0 on success, non-zero on any error
1470 */
Dustin Brownf660fb42016-09-09 12:04:00 -07001471static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
1472 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001473{
1474 tHalHandle hal;
1475 hdd_context_t *hdd_ctx;
1476
1477 if (NULL == adapter) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001478 hdd_alert("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001479 return -ENODEV;
1480 }
1481
1482 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1483 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001484 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001485 return -EINVAL;
1486 }
1487
Dustin Brownf660fb42016-09-09 12:04:00 -07001488 hdd_info("Allow power save: %d", allow_power_save);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489 hal = WLAN_HDD_GET_HAL_CTX(adapter);
1490
Dustin Brownf660fb42016-09-09 12:04:00 -07001491 if (allow_power_save) {
1492 if (QDF_STA_MODE == adapter->device_mode ||
1493 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001494 hdd_notice("Disabling Auto Power save timer");
Dustin Brownf660fb42016-09-09 12:04:00 -07001495 sme_ps_disable_auto_ps_timer(
1496 WLAN_HDD_GET_HAL_CTX(adapter),
1497 adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001499
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001500 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001501 hdd_notice("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001502
1503 /*
1504 * Enter Power Save command received from GUI
1505 * this means DHCP is completed
1506 */
1507 sme_ps_enable_disable(hal, adapter->sessionId,
1508 SME_PS_ENABLE);
1509 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001510 hdd_info("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001511 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001512 } else {
1513 hdd_info("Wlan driver Entering Full Power");
1514
1515 /*
1516 * Enter Full power command received from GUI
1517 * this means we are disconnected
1518 */
1519 sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1520 adapter->sessionId);
1521 sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE);
1522 sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1523 adapter->sessionId, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001524 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001525
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001526 return 0;
1527}
1528
Dustin Brown105d7902016-10-03 16:27:59 -07001529static void wlan_hdd_print_suspend_fail_stats(hdd_context_t *hdd_ctx)
1530{
Dustin Brownd9322482017-01-09 12:46:03 -08001531 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
Dustin Brown105d7902016-10-03 16:27:59 -07001532 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
Dustin Brownd9322482017-01-09 12:46:03 -08001533 stats->suspend_fail[SUSPEND_FAIL_IPA],
1534 stats->suspend_fail[SUSPEND_FAIL_RADAR],
1535 stats->suspend_fail[SUSPEND_FAIL_ROAM],
1536 stats->suspend_fail[SUSPEND_FAIL_SCAN],
1537 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
Dustin Brown105d7902016-10-03 16:27:59 -07001538}
1539
1540void wlan_hdd_inc_suspend_stats(hdd_context_t *hdd_ctx,
1541 enum suspend_fail_reason reason)
1542{
1543 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001544 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
Dustin Brown105d7902016-10-03 16:27:59 -07001545 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1546}
1547
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001548/**
1549 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1550 * @wiphy: Pointer to wiphy
1551 *
1552 * This API is called when cfg80211 driver resumes driver updates
1553 * latest sched_scan scan result(if any) to cfg80211 database
1554 *
1555 * Return: integer status
1556 */
1557static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1558{
1559 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1560 hdd_adapter_t *pAdapter;
1561 hdd_adapter_list_node_t *pAdapterNode, *pNext;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301562 QDF_STATUS status = QDF_STATUS_SUCCESS;
Dustin Brownd9322482017-01-09 12:46:03 -08001563 int exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001564 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1565
1566 ENTER();
1567
Dustin Brownd9322482017-01-09 12:46:03 -08001568 if (cds_is_driver_recovering()) {
1569 hdd_info("Driver is recovering; Skipping resume");
1570 exit_code = 0;
1571 goto exit_with_code;
1572 }
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001573
Anurag Chouhan6d760662016-02-20 16:05:43 +05301574 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001575 hdd_err("Command not allowed in FTM mode");
Dustin Brownd9322482017-01-09 12:46:03 -08001576 exit_code = -EINVAL;
1577 goto exit_with_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001578 }
1579
Dustin Brownd9322482017-01-09 12:46:03 -08001580 exit_code = wlan_hdd_validate_context(pHddCtx);
1581 if (exit_code) {
1582 hdd_err("Invalid HDD context");
1583 goto exit_with_code;
1584 }
Arun Khandavallifae92942016-08-01 13:31:08 +05301585
1586 mutex_lock(&pHddCtx->iface_change_lock);
1587 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1588 mutex_unlock(&pHddCtx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001589 hdd_info("Driver is not enabled; Skipping resume");
1590 exit_code = 0;
1591 goto exit_with_code;
Arun Khandavallifae92942016-08-01 13:31:08 +05301592 }
1593 mutex_unlock(&pHddCtx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001594
Yuanyuan Liu13738502016-04-06 17:41:37 -07001595 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001596
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301597 status = hdd_resume_wlan();
1598 if (status != QDF_STATUS_SUCCESS) {
1599 exit_code = 0;
1600 goto exit_with_code;
1601 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001602 /* Resume control path scheduler */
1603 if (pHddCtx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001604 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001605 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001606 }
1607#ifdef QCA_CONFIG_SMP
1608 /* Resume tlshim Rx thread */
1609 if (pHddCtx->is_ol_rx_thread_suspended) {
1610 complete(&cds_sched_context->ol_resume_rx_event);
1611 pHddCtx->is_ol_rx_thread_suspended = false;
1612 }
1613#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301615 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301616 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
1617 NO_SESSION, pHddCtx->isWiphySuspended));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301618 qdf_spin_lock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619 pHddCtx->isWiphySuspended = false;
1620 if (true != pHddCtx->isSchedScanUpdatePending) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301621 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Dustin Brown2d228232016-09-22 15:06:19 -07001622 hdd_info("Return resume is not due to PNO indication");
Dustin Brownd9322482017-01-09 12:46:03 -08001623 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001624 }
1625 /* Reset flag to avoid updatating cfg80211 data old results again */
1626 pHddCtx->isSchedScanUpdatePending = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301627 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628
1629 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301630 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001631 pAdapter = pAdapterNode->pAdapter;
1632 if ((NULL != pAdapter) &&
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001633 (QDF_STA_MODE == pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634 if (0 !=
1635 wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy,
1636 pAdapter, 0)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001637 hdd_warn("NO SCAN result");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638 } else {
1639 /* Acquire wakelock to handle the case where
1640 * APP's tries to suspend immediately after
1641 * updating the scan results. Whis results in
1642 * app's is in suspended state and not able to
1643 * process the connect request to AP
1644 */
Sreelakshmi Konamki22528532016-09-06 16:34:50 +05301645 hdd_prevent_suspend_timeout(
1646 HDD_WAKE_LOCK_RESUME_DURATION,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647 WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN);
1648 cfg80211_sched_scan_results(pHddCtx->wiphy);
1649 }
1650
Dustin Brown2d228232016-09-22 15:06:19 -07001651 hdd_info("cfg80211 scan result database updated");
Dustin Brownd9322482017-01-09 12:46:03 -08001652 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001653 }
1654 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1655 pAdapterNode = pNext;
1656 }
1657
Dustin Brownd9322482017-01-09 12:46:03 -08001658exit_with_success:
1659 pHddCtx->suspend_resume_stats.resumes++;
1660 exit_code = 0;
1661
1662exit_with_code:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301663 EXIT();
Dustin Brownd9322482017-01-09 12:46:03 -08001664 return exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665}
1666
1667/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668 * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1669 * @wiphy: Pointer to wiphy
1670 *
1671 * This API is called when cfg80211 driver resumes driver updates
1672 * latest sched_scan scan result(if any) to cfg80211 database
1673 *
1674 * Return: integer status
1675 */
1676int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1677{
1678 int ret;
1679
1680 cds_ssr_protect(__func__);
1681 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1682 cds_ssr_unprotect(__func__);
1683
1684 return ret;
1685}
1686
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001687static void hdd_suspend_cb(void)
1688{
1689 hdd_context_t *hdd_ctx;
1690
1691 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1692 if (!hdd_ctx) {
1693 cds_err("HDD context is NULL");
1694 return;
1695 }
1696
1697 complete(&hdd_ctx->mc_sus_event_var);
1698}
1699
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700/**
1701 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1702 * @wiphy: Pointer to wiphy
1703 * @wow: Pointer to wow
1704 *
1705 * This API is called when cfg80211 driver suspends
1706 *
1707 * Return: integer status
1708 */
1709static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1710 struct cfg80211_wowlan *wow)
1711{
1712#ifdef QCA_CONFIG_SMP
1713#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1714#endif
1715 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1716 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1717 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
1718 hdd_adapter_t *pAdapter;
1719 hdd_scaninfo_t *pScanInfo;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301720 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721 int rc;
1722
1723 ENTER();
1724
Anurag Chouhan6d760662016-02-20 16:05:43 +05301725 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001726 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001727 return -EINVAL;
1728 }
1729
1730 rc = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301731 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733
Arun Khandavallifae92942016-08-01 13:31:08 +05301734 mutex_lock(&pHddCtx->iface_change_lock);
1735 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1736 mutex_unlock(&pHddCtx->iface_change_lock);
1737 hdd_info("Driver Modules not Enabled ");
1738 return 0;
1739 }
1740 mutex_unlock(&pHddCtx->iface_change_lock);
1741
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1743 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1744 * until CAC is done for a SoftAP which is in started state.
1745 */
1746 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301747 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748 pAdapter = pAdapterNode->pAdapter;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301749
1750 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1751 hdd_err("invalid session id: %d", pAdapter->sessionId);
1752 goto next_adapter;
1753 }
1754
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001755 if (QDF_SAP_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001756 if (BSS_START ==
1757 WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter)->bssState &&
1758 true ==
1759 WLAN_HDD_GET_AP_CTX_PTR(pAdapter)->
1760 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001761 hdd_err("RADAR detection in progress, do not allow suspend");
Dustin Brown105d7902016-10-03 16:27:59 -07001762 wlan_hdd_inc_suspend_stats(pHddCtx,
1763 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764 return -EAGAIN;
1765 } else if (!pHddCtx->config->enableSapSuspend) {
1766 /* return -EOPNOTSUPP if SAP does not support
1767 * suspend
1768 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001769 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770 return -EOPNOTSUPP;
1771 }
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001772 } else if (QDF_P2P_GO_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001773 if (!pHddCtx->config->enableSapSuspend) {
1774 /* return -EOPNOTSUPP if GO does not support
1775 * suspend
1776 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001777 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001778 return -EOPNOTSUPP;
1779 }
1780 }
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +05301781 if (pAdapter->is_roc_inprogress)
1782 wlan_hdd_cleanup_remain_on_channel_ctx(pAdapter);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301783next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1785 pAdapterNode = pNext;
1786 }
1787
1788 /* Stop ongoing scan on each interface */
1789 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301790 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001791 pAdapter = pAdapterNode->pAdapter;
1792 pScanInfo = &pAdapter->scan_info;
1793
Sandeep Puligillaf8527122016-11-16 18:35:16 -08001794 if (sme_neighbor_middle_of_roaming
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001795 (pHddCtx->hHal, pAdapter->sessionId)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001796 hdd_err("Roaming in progress, do not allow suspend");
Dustin Brown105d7902016-10-03 16:27:59 -07001797 wlan_hdd_inc_suspend_stats(pHddCtx,
1798 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799 return -EAGAIN;
1800 }
1801
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802 if (pScanInfo->mScanPending) {
1803 INIT_COMPLETION(pScanInfo->abortscan_event_var);
1804 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +05301805 INVALID_SCAN_ID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806 eCSR_SCAN_ABORT_DEFAULT);
1807
1808 status =
1809 wait_for_completion_timeout(&pScanInfo->
1810 abortscan_event_var,
1811 msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN));
1812 if (!status) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001813 hdd_err("Timeout occurred while waiting for abort scan");
Dustin Brown105d7902016-10-03 16:27:59 -07001814 wlan_hdd_inc_suspend_stats(pHddCtx,
1815 SUSPEND_FAIL_SCAN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816 return -ETIME;
1817 }
1818 }
1819 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1820 pAdapterNode = pNext;
1821 }
1822
1823 /*
1824 * Suspend IPA early before proceeding to suspend other entities like
1825 * firmware to avoid any race conditions.
1826 */
1827 if (hdd_ipa_suspend(pHddCtx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001828 hdd_err("IPA not ready to suspend!");
Dustin Brown105d7902016-10-03 16:27:59 -07001829 wlan_hdd_inc_suspend_stats(pHddCtx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830 return -EAGAIN;
1831 }
1832
Rajeev Kumareada0d02016-12-08 17:44:17 -08001833 /* Suspend control path scheduler */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001834 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
1835 scheduler_set_event_mask(MC_SUSPEND_EVENT_MASK);
1836 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001837
Rajeev Kumareada0d02016-12-08 17:44:17 -08001838 /* Wait for suspend confirmation from scheduler */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839 rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var,
1840 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1841 if (!rc) {
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001842 scheduler_clear_event_mask(MC_SUSPEND_EVENT_MASK);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001843 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001844 goto resume_tx;
1845 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001846 pHddCtx->is_scheduler_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001847
1848#ifdef QCA_CONFIG_SMP
1849 /* Suspend tlshim rx thread */
1850 set_bit(RX_SUSPEND_EVENT_MASK, &cds_sched_context->ol_rx_event_flag);
1851 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1852 rc = wait_for_completion_timeout(&cds_sched_context->
1853 ol_suspend_rx_event,
1854 msecs_to_jiffies
1855 (RX_TLSHIM_SUSPEND_TIMEOUT));
1856 if (!rc) {
1857 clear_bit(RX_SUSPEND_EVENT_MASK,
1858 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001859 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 goto resume_all;
1861 }
1862 pHddCtx->is_ol_rx_thread_suspended = true;
1863#endif
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301864 if (hdd_suspend_wlan() < 0)
1865 goto resume_all;
1866
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301867 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301868 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
1869 NO_SESSION, pHddCtx->isWiphySuspended));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870 pHddCtx->isWiphySuspended = true;
1871
Yuanyuan Liu13738502016-04-06 17:41:37 -07001872 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001873
1874 EXIT();
1875 return 0;
1876
1877#ifdef QCA_CONFIG_SMP
1878resume_all:
1879
Rajeev Kumar0b732952016-12-08 17:51:39 -08001880 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001881 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001882#endif
1883
1884resume_tx:
1885
1886 hdd_resume_wlan();
1887 return -ETIME;
1888
1889}
1890
1891/**
1892 * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1893 * @wiphy: Pointer to wiphy
1894 * @wow: Pointer to wow
1895 *
1896 * This API is called when cfg80211 driver suspends
1897 *
1898 * Return: integer status
1899 */
1900int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1901 struct cfg80211_wowlan *wow)
1902{
1903 int ret;
1904
1905 cds_ssr_protect(__func__);
1906 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1907 cds_ssr_unprotect(__func__);
1908
1909 return ret;
1910}
1911
1912/**
Komal Seelama89be8d2016-09-29 11:09:26 +05301913 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
1914 * @adapter: Adapter on which DHCP needs to be stopped
1915 *
1916 * Release the wakelock held for DHCP process and allow
1917 * the runtime pm to continue
1918 *
1919 * Return: None
1920 */
1921static void hdd_stop_dhcp_ind(hdd_adapter_t *adapter)
1922{
1923 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1924
1925 hdd_warn("DHCP stop indicated through power save");
1926 sme_dhcp_stop_ind(hdd_ctx->hHal, adapter->device_mode,
1927 adapter->macAddressCurrent.bytes,
1928 adapter->sessionId);
1929 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
1930 qdf_runtime_pm_allow_suspend(adapter->connect_rpm_ctx.connect);
1931}
1932
1933/**
1934 * hdd_start_dhcp_ind() - API to start DHCP sequence
1935 * @adapter: Adapter on which DHCP needs to be stopped
1936 *
1937 * Prevent APPS suspend and the runtime suspend during
1938 * DHCP sequence
1939 *
1940 * Return: None
1941 */
1942static void hdd_start_dhcp_ind(hdd_adapter_t *adapter)
1943{
1944 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1945
1946 hdd_err("DHCP start indicated through power save");
1947 qdf_runtime_pm_prevent_suspend(adapter->connect_rpm_ctx.connect);
1948 hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_DHCP);
1949 sme_dhcp_start_ind(hdd_ctx->hHal, adapter->device_mode,
1950 adapter->macAddressCurrent.bytes,
1951 adapter->sessionId);
1952}
1953
1954/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001955 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1956 * @wiphy: Pointer to wiphy
1957 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001958 * @allow_power_save: is wlan allowed to go into power save mode
1959 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001960 *
1961 * Return: 0 for success, non-zero for failure
1962 */
1963static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001964 struct net_device *dev,
1965 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966 int timeout)
1967{
1968 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1969 hdd_context_t *pHddCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 int status;
1971
Dustin Brownecfce632016-09-13 10:41:45 -07001972 ENTER();
1973
Dustin Brownf660fb42016-09-09 12:04:00 -07001974 if (timeout < 0) {
1975 hdd_notice("User space timeout: %d; Using default instead: %d",
1976 timeout, AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE);
1977 timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE;
1978 }
1979
Anurag Chouhan6d760662016-02-20 16:05:43 +05301980 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001981 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001982 return -EINVAL;
1983 }
1984
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301985 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1986 hdd_err("invalid session id: %d", pAdapter->sessionId);
1987 return -EINVAL;
1988 }
1989
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301990 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
1992 pAdapter->sessionId, timeout));
1993
1994 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1995 status = wlan_hdd_validate_context(pHddCtx);
1996
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301997 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999
Arun Khandavalli99286452016-08-22 12:13:41 +05302000 mutex_lock(&pHddCtx->iface_change_lock);
2001 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2002 mutex_unlock(&pHddCtx->iface_change_lock);
2003 hdd_info("Driver Module not enabled return success");
2004 return 0;
2005 }
2006 mutex_unlock(&pHddCtx->iface_change_lock);
2007
Dustin Brownf660fb42016-09-09 12:04:00 -07002008 status = wlan_hdd_set_powersave(pAdapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002009
Komal Seelama89be8d2016-09-29 11:09:26 +05302010 allow_power_save ? hdd_stop_dhcp_ind(pAdapter) :
2011 hdd_start_dhcp_ind(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012
2013 EXIT();
2014 return status;
2015}
2016
2017/**
2018 * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2019 * @wiphy: Pointer to wiphy
2020 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07002021 * @allow_power_save: is wlan allowed to go into power save mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002022 * @timeout: Timeout value
2023 *
2024 * Return: 0 for success, non-zero for failure
2025 */
2026int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002027 struct net_device *dev,
2028 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029 int timeout)
2030{
2031 int ret;
2032
2033 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07002034 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
2035 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002036 cds_ssr_unprotect(__func__);
2037
2038 return ret;
2039}
2040
2041/**
2042 * __wlan_hdd_cfg80211_set_txpower() - set TX power
2043 * @wiphy: Pointer to wiphy
2044 * @wdev: Pointer to network device
2045 * @type: TX power setting type
2046 * @dbm: TX power in dbm
2047 *
2048 * Return: 0 for success, non-zero for failure
2049 */
2050static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052 enum nl80211_tx_power_setting type,
2053 int dbm)
2054{
2055 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
2056 tHalHandle hHal = NULL;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302057 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
2058 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002059 int status;
2060
2061 ENTER();
2062
Anurag Chouhan6d760662016-02-20 16:05:43 +05302063 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002064 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065 return -EINVAL;
2066 }
2067
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302068 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002069 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
2070 NO_SESSION, type));
2071
2072 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302073 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002074 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002075
2076 hHal = pHddCtx->hHal;
2077
2078 if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002079 hdd_err("sme_cfg_set_int failed for tx power %hu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002080 dbm);
2081 return -EIO;
2082 }
2083
Jeff Johnsonc3273322016-07-06 15:28:17 -07002084 hdd_info("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085
2086 switch (type) {
2087 /* Automatically determine transmit power */
2088 case NL80211_TX_POWER_AUTOMATIC:
2089 /* Fall through */
2090 case NL80211_TX_POWER_LIMITED: /* Limit TX power by the mBm parameter */
2091 if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302092 QDF_STATUS_SUCCESS) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002093 hdd_err("Setting maximum tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002094 return -EIO;
2095 }
2096 break;
2097
2098 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07002099 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100 return -EOPNOTSUPP;
2101 break;
2102
2103 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07002104 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105 return -EIO;
2106 }
2107
2108 EXIT();
2109 return 0;
2110}
2111
2112/**
2113 * wlan_hdd_cfg80211_set_txpower() - set TX power
2114 * @wiphy: Pointer to wiphy
2115 * @wdev: Pointer to network device
2116 * @type: TX power setting type
2117 * @dbm: TX power in dbm
2118 *
2119 * Return: 0 for success, non-zero for failure
2120 */
2121int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002123 enum nl80211_tx_power_setting type,
2124 int dbm)
2125{
2126 int ret;
2127 cds_ssr_protect(__func__);
2128 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002129 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002130 type, dbm);
2131 cds_ssr_unprotect(__func__);
2132
2133 return ret;
2134}
2135
2136/**
2137 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2138 * @wiphy: Pointer to wiphy
2139 * @wdev: Pointer to network device
2140 * @dbm: Pointer to TX power in dbm
2141 *
2142 * Return: 0 for success, non-zero for failure
2143 */
2144static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146 int *dbm)
2147{
2148
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002149 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
Arun Khandavalli99286452016-08-22 12:13:41 +05302150 struct net_device *ndev = wdev->netdev;
2151 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152 int status;
2153
2154 ENTER();
2155
Anurag Chouhan6d760662016-02-20 16:05:43 +05302156 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002157 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002158 return -EINVAL;
2159 }
2160
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302161 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2162 hdd_err("invalid session id: %d", adapter->sessionId);
2163 return -EINVAL;
2164 }
2165
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 status = wlan_hdd_validate_context(pHddCtx);
2167 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002168 *dbm = 0;
2169 return status;
2170 }
2171
Arun Khandavalli99286452016-08-22 12:13:41 +05302172 /* Validate adapter sessionId */
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302173 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2174 hdd_err("invalid session id: %d", adapter->sessionId);
Arun Khandavalli99286452016-08-22 12:13:41 +05302175 return -ENOTSUPP;
2176 }
2177
2178 mutex_lock(&pHddCtx->iface_change_lock);
2179 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2180 mutex_unlock(&pHddCtx->iface_change_lock);
2181 hdd_info("Driver Module not enabled return success");
2182 /* Send cached data to upperlayer*/
2183 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
2184 return 0;
2185 }
2186 mutex_unlock(&pHddCtx->iface_change_lock);
2187
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302188 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302189 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Arun Khandavalli99286452016-08-22 12:13:41 +05302190 adapter->sessionId, adapter->device_mode));
2191 wlan_hdd_get_class_astats(adapter);
2192 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193
2194 EXIT();
2195 return 0;
2196}
2197
2198/**
2199 * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function
2200 * @wiphy: Pointer to wiphy structure.
2201 * @wdev: Pointer to wireless_dev structure.
2202 * @dbm: dbm
2203 *
2204 * This is the cfg80211 get txpower handler function which invokes
2205 * the internal function @__wlan_hdd_cfg80211_get_txpower with
2206 * SSR protection.
2207 *
2208 * Return: 0 for success, error number on failure.
2209 */
2210int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002212 int *dbm)
2213{
2214 int ret;
2215
2216 cds_ssr_protect(__func__);
2217 ret = __wlan_hdd_cfg80211_get_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002218 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002219 dbm);
2220 cds_ssr_unprotect(__func__);
2221
2222 return ret;
2223}
Kapil Gupta6213c012016-09-02 19:39:09 +05302224
2225/**
2226 * hdd_set_qpower_config() - set qpower config to firmware
2227 * @adapter: HDD adapter
2228 * @qpower: new qpower config value
2229 *
2230 * Return: 0 on success; Errno on failure
2231 */
2232int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002233 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302234{
Dustin Brown10a7b712016-10-07 10:31:16 -07002235 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302236
2237 if (!hddctx->config->enablePowersaveOffload) {
2238 hdd_err("qpower is disabled in configuration");
2239 return -EINVAL;
2240 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002241
Kapil Gupta6213c012016-09-02 19:39:09 +05302242 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2243 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002244 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302245 return -EINVAL;
2246 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302247
Kiran Kumar Lokere7006e0a2017-03-07 19:28:36 -08002248 if (hddctx->config->nMaxPsPoll) {
2249 if ((qpower == PS_QPOWER_NODEEPSLEEP) ||
2250 (qpower == PS_LEGACY_NODEEPSLEEP))
2251 qpower = PS_LEGACY_NODEEPSLEEP;
2252 else
2253 qpower = PS_LEGACY_DEEPSLEEP;
2254 hdd_info("Qpower disabled, %d", qpower);
2255 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002256 status = wma_set_qpower_config(adapter->sessionId, qpower);
2257 if (status != QDF_STATUS_SUCCESS) {
2258 hdd_err("failed to configure qpower: %d", status);
2259 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302260 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002261
Kapil Gupta6213c012016-09-02 19:39:09 +05302262 return 0;
2263}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002264
Dustin Brown54096432017-02-23 13:00:44 -08002265
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002266#ifdef WLAN_SUSPEND_RESUME_TEST
2267/*
Dustin Brownd53d1a82016-10-03 12:57:33 -07002268 * On iHelium there are 12 CE irqs and #2 is the wake irq. This may not be
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002269 * a valid assumption on future platforms.
2270 */
2271#define CE_IRQ_COUNT 12
2272#define CE_WAKE_IRQ 2
Dustin Brownbc81a472016-10-26 16:56:59 -07002273static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002274static struct wiphy *g_wiphy;
2275
2276#define HDD_FA_SUSPENDED_BIT (0)
2277static unsigned long fake_apps_state;
2278
Dustin Brownd53d1a82016-10-03 12:57:33 -07002279/**
2280 * __hdd_wlan_fake_apps_resume() - The core logic for
2281 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2282 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002283 * @wiphy: the kernel wiphy struct for the device being resumed
2284 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002285 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002286 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002287 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002288static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2289 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002290{
Dustin Brownddb59702017-01-12 16:20:31 -08002291 qdf_device_t qdf_dev;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002292 int i, resume_err;
2293
2294 hdd_info("Unit-test resume WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002295
2296 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2297 if (!qdf_dev) {
2298 hdd_err("Failed to get QDF device context");
2299 QDF_BUG(0);
2300 return;
2301 }
2302
Dustin Brownd53d1a82016-10-03 12:57:33 -07002303 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
2304 hdd_info("Not unit-test suspended; Nothing to do");
2305 return;
2306 }
2307
2308 /* disable wake irq */
2309 pld_disable_irq(qdf_dev->dev, CE_WAKE_IRQ);
2310
2311 resume_err = wlan_hdd_bus_resume_noirq();
2312 QDF_BUG(resume_err == 0);
2313
2314 /* simulate kernel enable irqs */
2315 for (i = 0; i < CE_IRQ_COUNT; i++)
2316 pld_enable_irq(qdf_dev->dev, i);
2317
2318 resume_err = wlan_hdd_bus_resume();
2319 QDF_BUG(resume_err == 0);
2320
2321 resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy);
2322 QDF_BUG(resume_err == 0);
Dustin Brownbc81a472016-10-26 16:56:59 -07002323
2324 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brown562b9672016-12-22 15:25:33 -08002325
2326 hdd_info("Unit-test resume succeeded");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002327}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002328
2329/**
2330 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2331 * from unit-test initiated suspend from irq wakeup signal
2332 * @val: interrupt val
2333 *
2334 * Resume wlan after getting very 1st CE interrupt from target
2335 *
2336 * Return: none
2337 */
2338static void hdd_wlan_fake_apps_resume_irq_callback(uint32_t val)
2339{
2340 hdd_info("Trigger unit-test resume WLAN; val: 0x%x", val);
2341
2342 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002343 QDF_BUG(g_dev);
2344 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002345 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002346 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002347}
2348
Dustin Brown54096432017-02-23 13:00:44 -08002349int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
2350 enum wow_interface_pause pause_setting,
2351 enum wow_resume_trigger resume_setting)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002352{
Dustin Brownddb59702017-01-12 16:20:31 -08002353 qdf_device_t qdf_dev;
2354 struct hif_opaque_softc *hif_ctx;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002355 int i, resume_err, suspend_err;
Dustin Brown54096432017-02-23 13:00:44 -08002356 struct wow_enable_params wow_params = {
2357 .is_unit_test = true,
2358 .interface_pause = pause_setting,
2359 .resume_trigger = resume_setting
2360 };
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002361
2362 hdd_info("Unit-test suspend WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002363
Dustin Brown54096432017-02-23 13:00:44 -08002364 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
2365 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
2366 hdd_err("Invalid interface pause %d (expected range [0, 2])",
2367 pause_setting);
2368 return -EINVAL;
2369 }
2370
2371 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
2372 resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
2373 hdd_err("Invalid resume trigger %d (expected range [0, 2])",
2374 resume_setting);
2375 return -EINVAL;
2376 }
2377
Dustin Brownddb59702017-01-12 16:20:31 -08002378 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2379 if (!qdf_dev) {
2380 hdd_err("Failed to get QDF device context");
2381 return -EINVAL;
2382 }
2383
2384 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2385 if (!hif_ctx) {
2386 hdd_err("Failed to get HIF context");
2387 return -EINVAL;
2388 }
2389
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002390 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
2391 hdd_info("Already unit-test suspended; Nothing to do");
2392 return 0;
2393 }
2394
2395 suspend_err = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2396 if (suspend_err)
2397 goto resume_done;
2398
Dustin Brown9ef609b2017-03-15 12:19:37 -07002399 suspend_err = wlan_hdd_unit_test_bus_suspend(wow_params);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002400 if (suspend_err)
2401 goto cfg80211_resume;
2402
2403 /* simulate kernel disabling irqs */
2404 for (i = 0; i < CE_IRQ_COUNT; i++)
2405 pld_disable_irq(qdf_dev->dev, i);
2406
2407 suspend_err = wlan_hdd_bus_suspend_noirq();
2408 if (suspend_err)
2409 goto enable_irqs_and_bus_resume;
2410
2411 /* re-enable wake irq */
2412 pld_enable_irq(qdf_dev->dev, CE_WAKE_IRQ);
2413
Dustin Brownbc81a472016-10-26 16:56:59 -07002414 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002415 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002416 g_dev = dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002417 hif_fake_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
2418
Dustin Brownbc81a472016-10-26 16:56:59 -07002419 /*
2420 * Tell the kernel not to worry if TX queues aren't moving. This is
2421 * expected since we are suspending the wifi hardware, but not APPS
2422 */
2423 dev->watchdog_timeo = INT_MAX;
2424
Dustin Brown562b9672016-12-22 15:25:33 -08002425 hdd_info("Unit-test suspend succeeded");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002426 return 0;
2427
2428enable_irqs_and_bus_resume:
2429 /* re-enable irqs */
2430 for (i = 0; i < CE_IRQ_COUNT; i++)
2431 pld_enable_irq(qdf_dev->dev, i);
2432
2433 resume_err = wlan_hdd_bus_resume();
2434 QDF_BUG(resume_err == 0);
2435
2436cfg80211_resume:
2437 resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy);
2438 QDF_BUG(resume_err == 0);
2439
2440resume_done:
2441 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
2442 hdd_err("Unit-test suspend failed: %d", suspend_err);
2443 return suspend_err;
2444}
2445
Dustin Brownbc81a472016-10-26 16:56:59 -07002446int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002447{
Dustin Brownddb59702017-01-12 16:20:31 -08002448 struct hif_opaque_softc *hif_ctx;
2449
2450 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2451 if (!hif_ctx) {
2452 hdd_err("Failed to get HIF context");
2453 return -EINVAL;
2454 }
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002455
2456 hif_fake_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002457 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002458
2459 return 0;
2460}
2461#endif