blob: c2d33947d39bbd13ce787e3fbfa62cbb952cf6b6 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002 * Copyright (c) 2012-2016 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>
55#include <dbglog_host.h>
56#include <wlan_hdd_trace.h>
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +053057#include <wlan_hdd_p2p.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080058
59#include <linux/semaphore.h>
60#include <wlan_hdd_hostapd.h>
61#include "cfg_api.h"
62
63#include <linux/inetdevice.h>
64#include <wlan_hdd_cfg.h>
Sandeep Puligillae390be52016-02-08 17:07:05 -080065#include <wlan_hdd_scan.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080066#include <wlan_hdd_cfg80211.h>
67#include <net/addrconf.h>
68#include <wlan_hdd_ipa.h>
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070069#include <wlan_hdd_lpass.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080070
71#include <wma_types.h>
72#include "hif.h"
73#include "sme_power_save_api.h"
Chandrasekaran, Manishekar0d814c72015-11-05 10:42:48 +053074#include "cds_concurrency.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080075#include "cdp_txrx_flow_ctrl_v2.h"
Yuanyuan Liu13738502016-04-06 17:41:37 -070076#include "pld_common.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080077
78/* Preprocessor definitions and constants */
Yue Ma4ea4f052015-10-27 12:25:27 -070079#define HDD_SSR_BRING_UP_TIME 30000
Sreelakshmi Konamki22528532016-09-06 16:34:50 +053080#define HDD_WAKE_LOCK_RESUME_DURATION 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080081
82/* Type declarations */
83
Abhishek Singhbaea27d2016-04-27 13:29:30 +053084#ifdef FEATURE_WLAN_DIAG_SUPPORT
85/**
86 * hdd_wlan_suspend_resume_event()- send suspend/resume state
87 * @state: suspend/resume state
88 *
89 * This Function send send suspend resume state diag event
90 *
91 * Return: void.
92 */
93void hdd_wlan_suspend_resume_event(uint8_t state)
94{
95 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
96 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
97
98 suspend_state.state = state;
99 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
100}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530101
102/**
103 * hdd_wlan_offload_event()- send offloads event
104 * @type: offload type
105 * @state: enabled or disabled
106 *
107 * This Function send offloads enable/disable diag event
108 *
109 * Return: void.
110 */
111
112void hdd_wlan_offload_event(uint8_t type, uint8_t state)
113{
114 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
115 qdf_mem_zero(&host_offload, sizeof(host_offload));
116
117 host_offload.offload_type = type;
118 host_offload.state = state;
119
120 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
121}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530122#endif
123
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800124/* Function and variables declarations */
125
126extern struct notifier_block hdd_netdev_notifier;
127
128static struct timer_list ssr_timer;
129static bool ssr_timer_started;
130/**
131 * hdd_conf_gtk_offload() - Configure GTK offload
132 * @pAdapter: pointer to the adapter
133 * @fenable: flag set to enable (1) or disable (0) GTK offload
134 *
135 * Central function to enable or disable GTK offload.
136 *
137 * Return: nothing
138 */
139#ifdef WLAN_FEATURE_GTK_OFFLOAD
140static void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, bool fenable)
141{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530142 QDF_STATUS ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143 tSirGtkOffloadParams hddGtkOffloadReqParams;
144 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
145
146 if (fenable) {
147 if ((eConnectionState_Associated ==
148 pHddStaCtx->conn_info.connState)
149 && (GTK_OFFLOAD_ENABLE ==
150 pHddStaCtx->gtkOffloadReqParams.ulFlags)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530151 qdf_mem_copy(&hddGtkOffloadReqParams,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800152 &pHddStaCtx->gtkOffloadReqParams,
153 sizeof(tSirGtkOffloadParams));
154
155 ret = sme_set_gtk_offload(WLAN_HDD_GET_HAL_CTX(pAdapter),
156 &hddGtkOffloadReqParams,
157 pAdapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530158 if (QDF_STATUS_SUCCESS != ret) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700159 hdd_err("sme_set_gtk_offload failed, returned %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800160 return;
161 }
162
Jeff Johnsonc3273322016-07-06 15:28:17 -0700163 hdd_notice("sme_set_gtk_offload successfull");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164 }
165
166 } else {
167 if ((eConnectionState_Associated ==
168 pHddStaCtx->conn_info.connState)
Anurag Chouhanc5548422016-02-24 18:33:27 +0530169 && (qdf_is_macaddr_equal(&pHddStaCtx->gtkOffloadReqParams.bssid,
Srinivas Girigowda2213b1d2015-11-20 17:10:11 -0800170 &pHddStaCtx->conn_info.bssId))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800171 && (GTK_OFFLOAD_ENABLE ==
172 pHddStaCtx->gtkOffloadReqParams.ulFlags)) {
173
174 /* Host driver has previously offloaded GTK rekey */
175 ret = sme_get_gtk_offload
176 (WLAN_HDD_GET_HAL_CTX(pAdapter),
177 wlan_hdd_cfg80211_update_replay_counter_callback,
178 pAdapter, pAdapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530179 if (QDF_STATUS_SUCCESS != ret) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700180 hdd_err("sme_get_gtk_offload failed, returned %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800181 return;
182 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700183 hdd_notice("sme_get_gtk_offload successful");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184
185 /* Sending GTK offload dissable */
186 memcpy(&hddGtkOffloadReqParams,
187 &pHddStaCtx->gtkOffloadReqParams,
188 sizeof(tSirGtkOffloadParams));
189 hddGtkOffloadReqParams.ulFlags =
190 GTK_OFFLOAD_DISABLE;
191 ret =
192 sme_set_gtk_offload(WLAN_HDD_GET_HAL_CTX
193 (pAdapter),
194 &hddGtkOffloadReqParams,
195 pAdapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530196 if (QDF_STATUS_SUCCESS != ret) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700197 hdd_err("failed to dissable GTK offload, returned %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800198 return;
199 }
Jeff Johnsonc3273322016-07-06 15:28:17 -0700200 hdd_notice("successfully dissabled GTK offload request to HAL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800201 }
202 }
203 }
204 return;
205}
206#else /* WLAN_FEATURE_GTK_OFFLOAD */
207static void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, bool fenable)
208{
209}
210#endif /*WLAN_FEATURE_GTK_OFFLOAD */
211
212#ifdef WLAN_NS_OFFLOAD
213/**
214 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
215 * @nb: notifier block that was registered with the kernel
216 * @data: (unused) generic data that was registered with the kernel
217 * @arg: (unused) generic argument that was registered with the kernel
218 *
219 * This is a callback function that is registered with the kernel via
220 * register_inet6addr_notifier() which allows the driver to be
221 * notified when there is an IPv6 address change.
222 *
223 * Return: NOTIFY_DONE to indicate we don't care what happens with
224 * other callbacks
225 */
226static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
227 unsigned long data, void *arg)
228{
229 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
230 struct net_device *ndev = ifa->idev->dev;
231 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
232 hdd_context_t *pHddCtx;
233 int status;
234
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530235 ENTER();
236
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800237 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700238 hdd_err("Adapter context is invalid %p", pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800239 return -EINVAL;
240 }
241
242 if ((pAdapter->dev == ndev) &&
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800243 (pAdapter->device_mode == QDF_STA_MODE ||
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700244 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
245 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800246 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
247 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530248 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800249 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800250
251 schedule_work(&pAdapter->ipv6NotifierWorkQueue);
252 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530253 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800254 return NOTIFY_DONE;
255}
256
257/**
258 * wlan_hdd_ipv6_changed() - IPv6 change notifier callback
259 * @nb: pointer to notifier block
260 * @data: data
261 * @arg: arg
262 *
263 * This is the IPv6 notifier callback function gets invoked
264 * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed
265 * to reconfigure the offload parameters.
266 *
267 * Return: 0 on success, error number otherwise.
268 */
269int wlan_hdd_ipv6_changed(struct notifier_block *nb,
270 unsigned long data, void *arg)
271{
272 int ret;
273
274 cds_ssr_protect(__func__);
275 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
276 cds_ssr_unprotect(__func__);
277
278 return ret;
279}
280
281/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530282 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
283 * @idev: pointer to net device
284 * @ipv6addr: destination array to fill IPv6 addresses
285 * @ipv6addr_type: IPv6 Address type
286 * @count: number of IPv6 addresses
287 *
288 * This is the IPv6 utility function to populate unicast addresses.
289 *
290 * Return: 0 on success, error number otherwise.
291 */
292static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
293 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
294 uint8_t *ipv6addr_type, uint32_t *count)
295{
296 struct inet6_ifaddr *ifa;
297 struct list_head *p;
298 uint32_t scope;
299
300 list_for_each(p, &idev->addr_list) {
301 if (*count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA)
302 return -EINVAL;
303 ifa = list_entry(p, struct inet6_ifaddr, if_list);
304 if (ifa->flags & IFA_F_DADFAILED)
305 continue;
306 scope = ipv6_addr_src_scope(&ifa->addr);
307 switch (scope) {
308 case IPV6_ADDR_SCOPE_GLOBAL:
309 case IPV6_ADDR_SCOPE_LINKLOCAL:
310 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
311 sizeof(ifa->addr.s6_addr));
312 ipv6addr_type[*count] = SIR_IPV6_ADDR_UC_TYPE;
313 hdd_info("Index %d scope = %s UC-Address: %pI6",
314 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
315 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
316 *count += 1;
317 break;
318 default:
319 hdd_err("The Scope %d is not supported", scope);
320 }
321 }
322 return 0;
323}
324
325/**
326 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
327 * @idev: pointer to net device
328 * @ipv6addr: destination array to fill IPv6 addresses
329 * @ipv6addr_type: IPv6 Address type
330 * @count: number of IPv6 addresses
331 *
332 * This is the IPv6 utility function to populate anycast addresses.
333 *
334 * Return: 0 on success, error number otherwise.
335 */
336static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
337 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
338 uint8_t *ipv6addr_type, uint32_t *count)
339{
340 struct ifacaddr6 *ifaca;
341 uint32_t scope;
342
343 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
344 if (*count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA)
345 return -EINVAL;
346 /* For anycast addr no DAD */
347 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
348 switch (scope) {
349 case IPV6_ADDR_SCOPE_GLOBAL:
350 case IPV6_ADDR_SCOPE_LINKLOCAL:
351 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
352 sizeof(ifaca->aca_addr));
353 ipv6addr_type[*count] = SIR_IPV6_ADDR_AC_TYPE;
354 hdd_info("Index %d scope = %s AC-Address: %pI6",
355 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
356 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
357 *count += 1;
358 break;
359 default:
360 hdd_err("The Scope %d is not supported", scope);
361 }
362 }
363 return 0;
364}
365
366/**
Dustin Brown2444ee62016-09-06 17:20:36 -0700367 * hdd_disable_ns_offload() - Disables IPv6 NS offload
368 * @adapter: ponter to the adapter
369 *
370 * Return: nothing
371 */
372static void hdd_disable_ns_offload(hdd_adapter_t *adapter)
373{
374 tSirHostOffloadReq offloadReq;
375 QDF_STATUS status;
376
377 qdf_mem_zero((void *)&offloadReq, sizeof(tSirHostOffloadReq));
378 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_DISABLE);
379 offloadReq.enableOrDisable = SIR_OFFLOAD_DISABLE;
380 offloadReq.offloadType = SIR_IPV6_NS_OFFLOAD;
381 status = sme_set_host_offload(
382 WLAN_HDD_GET_HAL_CTX(adapter),
383 adapter->sessionId, &offloadReq);
384
385 if (QDF_STATUS_SUCCESS != status)
386 hdd_err("Failed to disable NS Offload");
387}
388
389/**
390 * hdd_enable_ns_offload() - Enables IPv6 NS offload
391 * @adapter: ponter to the adapter
392 *
393 * Return: nothing
394 */
395static void hdd_enable_ns_offload(hdd_adapter_t *adapter)
396{
397 struct inet6_dev *in6_dev;
398 uint8_t ipv6_addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]
399 [SIR_MAC_IPV6_ADDR_LEN] = { {0,} };
400 uint8_t ipv6_addr_type[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] = { 0 };
401 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
402 tSirHostOffloadReq offloadReq;
403 QDF_STATUS status;
404 uint32_t count = 0;
405 int err, i;
406
407 in6_dev = __in6_dev_get(adapter->dev);
408 if (NULL == in6_dev) {
409 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
410 return;
411 }
412
413 /* Unicast Addresses */
414 err = hdd_fill_ipv6_uc_addr(in6_dev, ipv6_addr, ipv6_addr_type, &count);
415 if (err) {
416 hdd_disable_ns_offload(adapter);
417 hdd_notice("Reached max supported addresses and not enabling "
418 "NS offload");
419 return;
420 }
421
422 /* Anycast Addresses */
423 err = hdd_fill_ipv6_ac_addr(in6_dev, ipv6_addr, ipv6_addr_type, &count);
424 if (err) {
425 hdd_disable_ns_offload(adapter);
426 hdd_notice("Reached max supported addresses and not enabling "
427 "NS offload");
428 return;
429 }
430
431 qdf_mem_zero(&offloadReq, sizeof(offloadReq));
432 for (i = 0; i < count; i++) {
433 /* Filling up the request structure
434 * Filling the selfIPv6Addr with solicited address
435 * A Solicited-Node multicast address is created by
436 * taking the last 24 bits of a unicast or anycast
437 * address and appending them to the prefix
438 *
439 * FF02:0000:0000:0000:0000:0001:FFXX:XXXX
440 *
441 * here XX is the unicast/anycast bits
442 */
443 offloadReq.nsOffloadInfo.selfIPv6Addr[i][0] = 0xFF;
444 offloadReq.nsOffloadInfo.selfIPv6Addr[i][1] = 0x02;
445 offloadReq.nsOffloadInfo.selfIPv6Addr[i][11] = 0x01;
446 offloadReq.nsOffloadInfo.selfIPv6Addr[i][12] = 0xFF;
447 offloadReq.nsOffloadInfo.selfIPv6Addr[i][13] =
448 ipv6_addr[i][13];
449 offloadReq.nsOffloadInfo.selfIPv6Addr[i][14] =
450 ipv6_addr[i][14];
451 offloadReq.nsOffloadInfo.selfIPv6Addr[i][15] =
452 ipv6_addr[i][15];
453 offloadReq.nsOffloadInfo.slotIdx = i;
454 qdf_mem_copy(&offloadReq.nsOffloadInfo.targetIPv6Addr[i],
455 &ipv6_addr[i][0], SIR_MAC_IPV6_ADDR_LEN);
456
457 offloadReq.nsOffloadInfo.targetIPv6AddrValid[i] =
458 SIR_IPV6_ADDR_VALID;
459 offloadReq.nsOffloadInfo.target_ipv6_addr_ac_type[i] =
460 ipv6_addr_type[i];
461
462 qdf_mem_copy(&offloadReq.params.hostIpv6Addr,
463 &offloadReq.nsOffloadInfo.targetIPv6Addr[i],
464 SIR_MAC_IPV6_ADDR_LEN);
465
466 hdd_info("Setting NSOffload with solicitedIp: "
467 "%pI6, targetIp: %pI6, Index %d",
468 &offloadReq.nsOffloadInfo.selfIPv6Addr[i],
469 &offloadReq.nsOffloadInfo.targetIPv6Addr[i], i);
470 }
471
472 hdd_info("configuredMcastBcastFilter: %d",
473 hdd_ctx->configuredMcastBcastFilter);
474 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
475 offloadReq.offloadType = SIR_IPV6_NS_OFFLOAD;
476 offloadReq.enableOrDisable = SIR_OFFLOAD_ENABLE;
477 qdf_copy_macaddr(&offloadReq.nsOffloadInfo.self_macaddr,
478 &adapter->macAddressCurrent);
479
480 /* set number of ns offload address count */
481 offloadReq.num_ns_offload_count = count;
482
483 /* Configure the Firmware with this */
484 status = sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(adapter),
485 adapter->sessionId, &offloadReq);
486 if (QDF_STATUS_SUCCESS != status) {
487 hdd_err("Failed to enable HostOffload feature with status: %d",
488 status);
489 }
490}
491
492/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800493 * hdd_conf_ns_offload() - Configure NS offload
Dustin Brown2444ee62016-09-06 17:20:36 -0700494 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800495 * @fenable: flag to enable or disable
496 * 0 - disable
497 * 1 - enable
498 *
499 * Return: nothing
500 */
Dustin Brownd8279d22016-09-07 14:52:57 -0700501void hdd_conf_ns_offload(hdd_adapter_t *adapter, bool fenable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502{
Dustin Brown2444ee62016-09-06 17:20:36 -0700503 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800504
505 ENTER();
Jeff Johnsonc3273322016-07-06 15:28:17 -0700506 hdd_notice(" fenable = %d", fenable);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507
Dustin Brown2444ee62016-09-06 17:20:36 -0700508 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800509
510 /* In SAP/P2PGo mode, ARP/NS offload feature capability
511 * is controlled by one bit.
512 */
513
Dustin Brown2444ee62016-09-06 17:20:36 -0700514 if ((QDF_SAP_MODE == adapter->device_mode ||
515 QDF_P2P_GO_MODE == adapter->device_mode) &&
516 !hdd_ctx->ap_arpns_support) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700517 hdd_notice("NS Offload is not supported in SAP/P2PGO mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800518 return;
519 }
520
Dustin Brown2444ee62016-09-06 17:20:36 -0700521 if (fenable)
522 hdd_enable_ns_offload(adapter);
523 else
524 hdd_disable_ns_offload(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800526 EXIT();
527 return;
528}
529
530/**
531 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
532 * @work: registered work item
533 *
534 * This function performs the work initially trigged by a callback
535 * from the IPv6 netdev notifier. Since this means there has been a
536 * change in IPv6 state for the interface, the NS offload is
537 * reconfigured.
538 *
539 * Return: None
540 */
541void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
542{
543 hdd_adapter_t *pAdapter =
544 container_of(work, hdd_adapter_t, ipv6NotifierWorkQueue);
545 hdd_context_t *pHddCtx;
546 int status;
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700547 bool ndi_connected = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800548
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530549 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550
551 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
552 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530553 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800554 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800555
556 if (!pHddCtx->config->active_mode_offload) {
557 hdd_err("Active mode offload is disabled");
558 return;
559 }
560
561 if (false == pHddCtx->sus_res_mcastbcast_filter_valid) {
562 pHddCtx->sus_res_mcastbcast_filter =
563 pHddCtx->configuredMcastBcastFilter;
564 pHddCtx->sus_res_mcastbcast_filter_valid = true;
565 }
566
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700567 /* check if the device is in NAN data mode */
568 if (WLAN_HDD_IS_NDI(pAdapter))
569 ndi_connected = WLAN_HDD_IS_NDI_CONNECTED(pAdapter);
570
571 if (eConnectionState_Associated ==
572 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState ||
573 ndi_connected)
Sravan Kumar Kairamfece87f2016-07-26 14:58:28 +0530574 if (pHddCtx->config->fhostNSOffload &&
575 pHddCtx->ns_offload_enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800576 hdd_conf_ns_offload(pAdapter, true);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530577 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800578}
579
580/**
581 * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler
582 * @work: Pointer to work context
583 *
584 * Return: none
585 */
586void hdd_ipv6_notifier_work_queue(struct work_struct *work)
587{
588 cds_ssr_protect(__func__);
589 __hdd_ipv6_notifier_work_queue(work);
590 cds_ssr_unprotect(__func__);
591}
592
593/**
594 * hdd_conf_hostoffload() - Central function to configure the supported offloads
595 * @pAdapter: pointer to the adapter
596 * @fenable: flag set to enable (1) or disable (0)
597 *
598 * Central function to configure the supported offloads either
599 * enable or disable them.
600 *
601 * Return: nothing
602 */
603void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, bool fenable)
604{
605 hdd_context_t *pHddCtx;
606
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530607 ENTER();
608
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800609 hdd_info("Configuring offloads with flag: %d", fenable);
610
611 /* Get the HDD context. */
612 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
613
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800614 if (((QDF_STA_MODE != pAdapter->device_mode) &&
615 (QDF_P2P_CLIENT_MODE != pAdapter->device_mode))) {
Rajeev Kumar30cb6762016-07-28 20:01:15 -0700616 hdd_info("Offloads not supported in mode %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800617 pAdapter->device_mode);
618 return;
619 }
620
621 if (eConnectionState_Associated !=
622 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) {
Rajeev Kumar30cb6762016-07-28 20:01:15 -0700623 hdd_info("Offloads not supported in state %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800624 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->
625 conn_info.connState);
626 return;
627 }
628
629 hdd_conf_gtk_offload(pAdapter, fenable);
630
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700631 /* Configure ARP/NS offload during cfg80211 suspend/resume and
632 * Enable MC address filtering during cfg80211 suspend
633 * only if active mode offload is disabled
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800634 */
635 if (!pHddCtx->config->active_mode_offload) {
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700636 hdd_info("configuring unconfigured active mode offloads");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800637 hdd_conf_arp_offload(pAdapter, fenable);
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700638 wlan_hdd_set_mc_addr_list(pAdapter, fenable);
639
Sravan Kumar Kairamfece87f2016-07-26 14:58:28 +0530640 if (pHddCtx->config->fhostNSOffload &&
641 pHddCtx->ns_offload_enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800642 hdd_conf_ns_offload(pAdapter, fenable);
643 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530644 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800645 return;
646}
647#endif
648
649/**
650 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
651 * @work: registered work item
652 *
653 * This function performs the work initially trigged by a callback
654 * from the IPv4 netdev notifier. Since this means there has been a
655 * change in IPv4 state for the interface, the ARP offload is
656 * reconfigured.
657 *
658 * Return: None
659 */
660void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
661{
662 hdd_adapter_t *pAdapter =
663 container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue);
664 hdd_context_t *pHddCtx;
665 int status;
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700666 bool ndi_connected = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800667
668 hdd_info("Configuring ARP Offload");
669 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
670 status = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530671 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800672 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800673
674 if (!pHddCtx->config->active_mode_offload) {
675 hdd_err("Active mode offload is disabled");
676 return;
677 }
678
679 if (false == pHddCtx->sus_res_mcastbcast_filter_valid) {
680 pHddCtx->sus_res_mcastbcast_filter =
681 pHddCtx->configuredMcastBcastFilter;
682 pHddCtx->sus_res_mcastbcast_filter_valid = true;
683 }
684
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700685 /* check if the device is in NAN data mode */
686 if (WLAN_HDD_IS_NDI(pAdapter))
687 ndi_connected = WLAN_HDD_IS_NDI_CONNECTED(pAdapter);
688
689 if (eConnectionState_Associated ==
690 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState ||
691 ndi_connected)
692 /*
693 * This invocation being part of the IPv4 registration callback,
694 * we are passing second parameter as 2 to avoid registration
695 * of IPv4 notifier again.
696 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800697 hdd_conf_arp_offload(pAdapter, true);
698}
699
700/**
701 * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler
702 * @work: Pointer to work context
703 *
704 * Return: none
705 */
706void hdd_ipv4_notifier_work_queue(struct work_struct *work)
707{
708 cds_ssr_protect(__func__);
709 __hdd_ipv4_notifier_work_queue(work);
710 cds_ssr_unprotect(__func__);
711}
712
713/**
714 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
715 * @nb: notifier block that was registered with the kernel
716 * @data: (unused) generic data that was registered with the kernel
717 * @arg: (unused) generic argument that was registered with the kernel
718 *
719 * This is a callback function that is registered with the kernel via
720 * register_inetaddr_notifier() which allows the driver to be
721 * notified when there is an IPv4 address change.
722 *
723 * Return: NOTIFY_DONE to indicate we don't care what happens with
724 * other callbacks
725 */
726static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
727 unsigned long data, void *arg)
728{
729 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
730 struct in_ifaddr **ifap = NULL;
731 struct in_device *in_dev;
732
733 struct net_device *ndev = ifa->ifa_dev->dev;
734 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
735 hdd_context_t *pHddCtx;
736 int status;
737
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530738 ENTER();
739
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);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742 return -EINVAL;
743 }
744
745 if ((pAdapter && pAdapter->dev == ndev) &&
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800746 (pAdapter->device_mode == QDF_STA_MODE ||
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700747 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
755 if (!pHddCtx->config->fhostArpOffload) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700756 hdd_notice("Offload not enabled ARPOffload=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800757 pHddCtx->config->fhostArpOffload);
758 return NOTIFY_DONE;
759 }
760
761 in_dev = __in_dev_get_rtnl(pAdapter->dev);
762 if (in_dev) {
763 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
764 ifap = &ifa->ifa_next) {
765 if (!strcmp(pAdapter->dev->name,
766 ifa->ifa_label)) {
767 break; /* found */
768 }
769 }
770 }
771 if (ifa && ifa->ifa_local) {
772 schedule_work(&pAdapter->ipv4NotifierWorkQueue);
773 }
774 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530775 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800776 return NOTIFY_DONE;
777}
778
779/**
780 * wlan_hdd_ipv4_changed() - IPv4 change notifier callback
781 * @nb: pointer to notifier block
782 * @data: data
783 * @arg: arg
784 *
785 * This is the IPv4 notifier callback function gets invoked
786 * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed
787 * to reconfigure the offload parameters.
788 *
789 * Return: 0 on success, error number otherwise.
790 */
791int wlan_hdd_ipv4_changed(struct notifier_block *nb,
792 unsigned long data, void *arg)
793{
794 int ret;
795
796 cds_ssr_protect(__func__);
797 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
798 cds_ssr_unprotect(__func__);
799
800 return ret;
801}
802
803/**
804 * hdd_conf_arp_offload() - Configure ARP offload
805 * @pAdapter: Adapter context for which ARP offload is to be configured
806 * @fenable: true : enable ARP offload false : disable arp offload
807 *
808 * Return:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530809 * QDF_STATUS_SUCCESS - on successful operation,
810 * QDF_STATUS_E_FAILURE - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530812QDF_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, bool fenable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813{
814 struct in_ifaddr **ifap = NULL;
815 struct in_ifaddr *ifa = NULL;
816 struct in_device *in_dev;
817 int i = 0;
818 tSirHostOffloadReq offLoadRequest;
819 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
820
821 hdd_info("fenable = %d", fenable);
822
823 /* In SAP/P2P Go mode, ARP/NS Offload feature capability
824 * is controlled by one bit.
825 */
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800826 if ((QDF_SAP_MODE == pAdapter->device_mode ||
827 QDF_P2P_GO_MODE == pAdapter->device_mode) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800828 !pHddCtx->ap_arpns_support) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700829 hdd_notice("ARP Offload is not supported in SAP/P2PGO mode");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530830 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831 }
832
833 if (fenable) {
834 in_dev = __in_dev_get_rtnl(pAdapter->dev);
835 if (in_dev) {
836 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
837 ifap = &ifa->ifa_next) {
838 if (!strcmp(pAdapter->dev->name,
839 ifa->ifa_label)) {
840 break; /* found */
841 }
842 }
843 }
844 if (ifa && ifa->ifa_local) {
845 offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD;
846 offLoadRequest.enableOrDisable = SIR_OFFLOAD_ENABLE;
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530847 hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD,
848 SIR_OFFLOAD_ENABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800849
Jeff Johnsonc3273322016-07-06 15:28:17 -0700850 hdd_notice("Enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800851
852 if (((HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST ==
853 pHddCtx->sus_res_mcastbcast_filter) ||
854 (HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST_BROADCAST
855 == pHddCtx->sus_res_mcastbcast_filter))
856 && (true ==
857 pHddCtx->sus_res_mcastbcast_filter_valid)) {
858 offLoadRequest.enableOrDisable =
859 SIR_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE;
Jeff Johnsonc3273322016-07-06 15:28:17 -0700860 hdd_notice("offload: inside arp offload conditional check");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800861 }
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530862 hdd_wlan_offload_event(
863 SIR_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE,
864 SIR_OFFLOAD_ENABLE);
Jeff Johnsonc3273322016-07-06 15:28:17 -0700865 hdd_notice("offload: arp filter programmed = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 offLoadRequest.enableOrDisable);
867
868 /* converting u32 to IPV4 address */
869 for (i = 0; i < 4; i++) {
870 offLoadRequest.params.hostIpv4Addr[i] =
871 (ifa->ifa_local >> (i * 8)) & 0xFF;
872 }
Jeff Johnsonc3273322016-07-06 15:28:17 -0700873 hdd_notice(" Enable SME HostOffload: %d.%d.%d.%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800874 offLoadRequest.params.hostIpv4Addr[0],
875 offLoadRequest.params.hostIpv4Addr[1],
876 offLoadRequest.params.hostIpv4Addr[2],
877 offLoadRequest.params.hostIpv4Addr[3]);
878
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530879 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800880 sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter),
881 pAdapter->sessionId,
882 &offLoadRequest)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700883 hdd_err("Failed to enable HostOffload feature");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530884 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800885 }
886 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700887 hdd_notice("IP Address is not assigned");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 }
889
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530890 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800891 } else {
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530892 hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD,
893 SIR_OFFLOAD_DISABLE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530894 qdf_mem_zero((void *)&offLoadRequest,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800895 sizeof(tSirHostOffloadReq));
896 offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE;
897 offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD;
898
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530899 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800900 sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter),
901 pAdapter->sessionId, &offLoadRequest)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700902 hdd_err("Failure to disable host " "offload feature");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530903 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800904 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530905 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800906 }
907}
908
909/**
910 * hdd_mcbc_filter_modification() - MCBC Filter Modifier
911 * @pHddCtx: Global Hdd Context
912 * @pMcBcFilter: Multicast/Broadcast filter to be modified
913 *
914 * This function is called before setting mcbc filters
915 * to modify filter value considering different offloads
916 *
917 * Return: None.
918 */
919static void hdd_mcbc_filter_modification(hdd_context_t *pHddCtx,
920 uint8_t *pMcBcFilter)
921{
922 if (NULL == pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700923 hdd_err("NULL HDD context passed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 return;
925 }
926
927 *pMcBcFilter = pHddCtx->configuredMcastBcastFilter;
928 if (pHddCtx->config->fhostArpOffload) {
929 /* ARP offload is enabled, do not block bcast packets at RXP
930 * Will be using Bitmasking to reset the filter. As we have
931 * disable Broadcast filtering, Anding with the negation
932 * of Broadcast BIT
933 */
934 *pMcBcFilter &= ~(HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST);
Agrawal Ashish02460a82015-09-16 17:20:30 +0530935 hdd_info("ARP offload is enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800936 }
937#ifdef WLAN_NS_OFFLOAD
938 if (pHddCtx->config->fhostNSOffload) {
939 /* NS offload is enabled, do not block mcast packets at RXP
940 * Will be using Bitmasking to reset the filter. As we have
941 * disable Multicast filtering, Anding with the negation
942 * of Multicast BIT
943 */
Agrawal Ashish02460a82015-09-16 17:20:30 +0530944 hdd_info("NS offload is enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800945 *pMcBcFilter &= ~(HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST);
946 }
947#endif
948
949 pHddCtx->configuredMcastBcastFilter = *pMcBcFilter;
950}
951
952/**
953 * hdd_conf_mcastbcast_filter() - Configure multicast/broadcast filter
954 * @pHddCtx: Global HDD context
955 * @setfilter: true if filter is being set, false if filter is being cleared
956 *
957 * Return: None.
958 */
959void hdd_conf_mcastbcast_filter(hdd_context_t *pHddCtx, bool setfilter)
960{
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530961 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962 tpSirWlanSetRxpFilters wlanRxpFilterParam =
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530963 qdf_mem_malloc(sizeof(tSirWlanSetRxpFilters));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964 if (NULL == wlanRxpFilterParam) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700965 hdd_alert("qdf_mem_malloc failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966 return;
967 }
Jeff Johnsonc3273322016-07-06 15:28:17 -0700968 hdd_notice("Configuring Mcast/Bcast Filter Setting. setfilter %d", setfilter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800969 if (true == setfilter) {
970 hdd_mcbc_filter_modification(pHddCtx,
971 &wlanRxpFilterParam->
972 configuredMcstBcstFilterSetting);
973 } else {
974 /*Use the current configured value to clear */
975 wlanRxpFilterParam->configuredMcstBcstFilterSetting =
976 pHddCtx->configuredMcastBcastFilter;
977 }
978
979 wlanRxpFilterParam->setMcstBcstFilter = setfilter;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530980 qdf_ret_status =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800981 sme_configure_rxp_filter(pHddCtx->hHal, wlanRxpFilterParam);
982
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530983 if (setfilter && (QDF_STATUS_SUCCESS == qdf_ret_status))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800984 pHddCtx->hdd_mcastbcast_filter_set = true;
985
Jeff Johnsonc3273322016-07-06 15:28:17 -0700986 hdd_notice("%s to post set/reset filter to lower mac with status %d configuredMcstBcstFilterSetting = %d setMcstBcstFilter = %d",
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530987 (QDF_STATUS_SUCCESS != qdf_ret_status) ? "Failed" : "Success",
988 qdf_ret_status,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989 wlanRxpFilterParam->configuredMcstBcstFilterSetting,
990 wlanRxpFilterParam->setMcstBcstFilter);
991
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530992 if (QDF_STATUS_SUCCESS != qdf_ret_status)
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530993 qdf_mem_free(wlanRxpFilterParam);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994}
995
996#ifdef WLAN_FEATURE_PACKET_FILTERING
997/**
998 * wlan_hdd_set_mc_addr_list() - set MC address list in FW
999 * @pAdapter: adapter whose MC list is being set
1000 * @set: flag which indicates if addresses are being set or cleared
1001 */
1002void wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set)
1003{
1004 uint8_t i;
1005 tpSirRcvFltMcAddrList pMulticastAddrs = NULL;
1006 tHalHandle hHal = NULL;
1007 hdd_context_t *pHddCtx = (hdd_context_t *) pAdapter->pHddCtx;
Ravi Joshi24477b72016-07-19 15:45:09 -07001008 hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001009
Ravi Joshi24477b72016-07-19 15:45:09 -07001010 ENTER();
1011
1012 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001013 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014
1015 hHal = pHddCtx->hHal;
1016
1017 if (NULL == hHal) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001018 hdd_err("HAL Handle is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019 return;
1020 }
1021
Ravi Joshi24477b72016-07-19 15:45:09 -07001022 if (!sta_ctx) {
1023 hdd_err("sta_ctx is NULL");
1024 return;
1025 }
1026
1027 /* Check if INI is enabled or not, other wise just return */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 if (!pHddCtx->config->fEnableMCAddrList) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001029 hdd_notice("gMCAddrListEnable is not enabled in INI");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001030 return;
1031 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301032 pMulticastAddrs = qdf_mem_malloc(sizeof(tSirRcvFltMcAddrList));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001033 if (NULL == pMulticastAddrs) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001034 hdd_err("Could not allocate Memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035 return;
1036 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301037 qdf_mem_zero(pMulticastAddrs, sizeof(tSirRcvFltMcAddrList));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038 pMulticastAddrs->action = set;
1039
1040 if (set) {
Ravi Joshi24477b72016-07-19 15:45:09 -07001041 /*
1042 * Following pre-conditions should be satisfied before we
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043 * configure the MC address list.
1044 */
Ravi Joshi24477b72016-07-19 15:45:09 -07001045 if (pAdapter->mc_addr_list.mc_cnt &&
1046 (((pAdapter->device_mode == QDF_STA_MODE ||
1047 pAdapter->device_mode == QDF_P2P_CLIENT_MODE) &&
1048 hdd_conn_is_connected(sta_ctx)) ||
1049 (WLAN_HDD_IS_NDI(pAdapter) &&
1050 WLAN_HDD_IS_NDI_CONNECTED(pAdapter)))) {
1051
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052 pMulticastAddrs->ulMulticastAddrCnt =
1053 pAdapter->mc_addr_list.mc_cnt;
Ravi Joshi24477b72016-07-19 15:45:09 -07001054
1055 for (i = 0; i < pAdapter->mc_addr_list.mc_cnt; i++) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08001056 memcpy(pMulticastAddrs->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057 pAdapter->mc_addr_list.addr[i],
Ravi Joshi24477b72016-07-19 15:45:09 -07001058 sizeof(pAdapter->mc_addr_list.addr[i]));
Srinivas Girigowda98530492015-11-20 17:39:24 -08001059 hdd_info("%s multicast filter: addr ="
1060 MAC_ADDRESS_STR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001061 set ? "setting" : "clearing",
1062 MAC_ADDR_ARRAY(pMulticastAddrs->
Srinivas Girigowda98530492015-11-20 17:39:24 -08001063 multicastAddr[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001064 }
1065 /* Set multicast filter */
1066 sme_8023_multicast_list(hHal, pAdapter->sessionId,
1067 pMulticastAddrs);
1068 }
1069 } else {
1070 /* Need to clear only if it was previously configured */
1071 if (pAdapter->mc_addr_list.isFilterApplied) {
1072 pMulticastAddrs->ulMulticastAddrCnt =
1073 pAdapter->mc_addr_list.mc_cnt;
Ravi Joshi24477b72016-07-19 15:45:09 -07001074 for (i = 0; i < pAdapter->mc_addr_list.mc_cnt; i++) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08001075 memcpy(pMulticastAddrs->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076 pAdapter->mc_addr_list.addr[i],
Ravi Joshi24477b72016-07-19 15:45:09 -07001077 sizeof(pAdapter->mc_addr_list.addr[i]));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078 }
1079 sme_8023_multicast_list(hHal, pAdapter->sessionId,
1080 pMulticastAddrs);
1081 }
1082
1083 }
1084 /* MAddrCnt is MulticastAddrCnt */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001085 hdd_notice("smeSessionId:%d; set:%d; MCAdddrCnt :%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001086 pAdapter->sessionId, set,
1087 pMulticastAddrs->ulMulticastAddrCnt);
1088
1089 pAdapter->mc_addr_list.isFilterApplied = set ? true : false;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301090 qdf_mem_free(pMulticastAddrs);
Ravi Joshi24477b72016-07-19 15:45:09 -07001091
1092 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093 return;
1094}
1095#endif
1096
1097/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001098 * hdd_update_mcastbcast_filter(): cache multi and broadcast filter for suspend
1099 * @hdd_ctx: hdd context
1100 *
1101 * Cache the configured filter to be used in suspend resume.
1102 */
1103static void hdd_update_mcastbcast_filter(hdd_context_t *hdd_ctx)
1104{
1105 if (false == hdd_ctx->sus_res_mcastbcast_filter_valid) {
1106 hdd_ctx->sus_res_mcastbcast_filter =
1107 hdd_ctx->configuredMcastBcastFilter;
1108 hdd_ctx->sus_res_mcastbcast_filter_valid = true;
1109 hdd_info("configuredMCastBcastFilter saved = %d",
1110 hdd_ctx->configuredMcastBcastFilter);
1111 }
1112}
1113
1114/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001115 * hdd_conf_suspend_ind() - Send Suspend notification
1116 * @pHddCtx: HDD Global context
1117 * @pAdapter: adapter being suspended
1118 * @callback: callback function to be called upon completion
1119 * @callbackContext: callback context to be passed back to callback function
1120 *
1121 * Return: None.
1122 */
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001123static void hdd_send_suspend_ind(hdd_context_t *pHddCtx,
1124 uint32_t conn_state_mask,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125 void (*callback)(void *callbackContext,
1126 bool suspended),
1127 void *callbackContext)
1128{
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301129 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130
Jeff Johnsonc3273322016-07-06 15:28:17 -07001131 hdd_info("send wlan suspend indication");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001132
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301133 qdf_ret_status =
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001134 sme_configure_suspend_ind(pHddCtx->hHal, conn_state_mask,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135 callback, callbackContext);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001136
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301137 if (QDF_STATUS_SUCCESS == qdf_ret_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001138 pHddCtx->hdd_mcastbcast_filter_set = true;
1139 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001140 hdd_err("sme_configure_suspend_ind returned failure %d",
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301141 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 }
1143}
1144
1145/**
1146 * hdd_conf_suspend_ind() - Send Resume notification
1147 * @pAdapter: adapter being resumed
1148 *
1149 * Return: None.
1150 */
1151static void hdd_conf_resume_ind(hdd_adapter_t *pAdapter)
1152{
1153 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301154 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301156 qdf_ret_status = sme_configure_resume_req(pHddCtx->hHal, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001157
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301158 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001159 hdd_err("sme_configure_resume_req return failure %d", qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001160
1161 }
1162
Jeff Johnsonc3273322016-07-06 15:28:17 -07001163 hdd_notice("send wlan resume indication");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164 /* Disable supported OffLoads */
1165 hdd_conf_hostoffload(pAdapter, false);
1166 pHddCtx->hdd_mcastbcast_filter_set = false;
1167
1168 if (true == pHddCtx->sus_res_mcastbcast_filter_valid) {
1169 pHddCtx->configuredMcastBcastFilter =
1170 pHddCtx->sus_res_mcastbcast_filter;
1171 pHddCtx->sus_res_mcastbcast_filter_valid = false;
1172 }
1173
Jeff Johnsonc3273322016-07-06 15:28:17 -07001174 hdd_notice("offload: in hdd_conf_resume_ind, restoring configuredMcastBcastFilter");
1175 hdd_notice("configuredMcastBcastFilter = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001176 pHddCtx->configuredMcastBcastFilter);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001177}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001178
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001179/**
1180 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
1181 * @adapter: adapter to get info from
1182 * @conn_state_mask: mask of connection info
1183 *
1184 * currently only need to send connection info.
1185 */
1186static void
1187hdd_update_conn_state_mask(hdd_adapter_t *adapter, uint32_t *conn_state_mask)
1188{
1189
1190 eConnectionState connState;
1191 hdd_station_ctx_t *sta_ctx;
1192 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1193 connState = sta_ctx->conn_info.connState;
1194
1195 if (connState == eConnectionState_Associated ||
1196 connState == eConnectionState_IbssConnected)
1197 *conn_state_mask |= (1 << adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001198}
1199
1200/**
1201 * hdd_suspend_wlan() - Driver suspend function
1202 * @callback: Callback function to invoke when driver is ready to suspend
1203 * @callbackContext: Context to pass back to @callback function
1204 *
1205 * Return: None.
1206 */
1207static void
1208hdd_suspend_wlan(void (*callback)(void *callbackContext, bool suspended),
1209 void *callbackContext)
1210{
1211 hdd_context_t *pHddCtx;
1212
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301213 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001214 hdd_adapter_t *pAdapter = NULL;
1215 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001216 uint32_t conn_state_mask = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217
Jeff Johnsonc3273322016-07-06 15:28:17 -07001218 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001219
Anurag Chouhan6d760662016-02-20 16:05:43 +05301220 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001222 hdd_alert("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001223 return;
1224 }
1225
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001226 if (cds_is_driver_recovering()) {
1227 hdd_err("Recovery in Progress. State: 0x%x Ignore suspend!!!",
1228 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 return;
1230 }
1231
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001232 hdd_update_mcastbcast_filter(pHddCtx);
1233
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001234 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301235 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 pAdapter = pAdapterNode->pAdapter;
1237
1238 /* stop all TX queues before suspend */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001239 hdd_notice("Disabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240 wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE,
1241 WLAN_CONTROL_PATH);
1242
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001243 /* Configure supported OffLoads */
1244 hdd_conf_hostoffload(pAdapter, true);
1245
1246 hdd_update_conn_state_mask(pAdapter, &conn_state_mask);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001247
1248 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001249
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250 pAdapterNode = pNext;
1251 }
1252
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001253 hdd_send_suspend_ind(pHddCtx, conn_state_mask, callback,
1254 callbackContext);
1255
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001256 pHddCtx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301257 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258
1259 return;
1260}
1261
1262/**
1263 * hdd_resume_wlan() - Driver resume function
1264 *
1265 * Return: None.
1266 */
1267static void hdd_resume_wlan(void)
1268{
1269 hdd_context_t *pHddCtx;
1270 hdd_adapter_t *pAdapter = NULL;
1271 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301272 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001273
Jeff Johnsonc3273322016-07-06 15:28:17 -07001274 hdd_notice("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001275
Anurag Chouhan6d760662016-02-20 16:05:43 +05301276 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001277 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001278 hdd_alert("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 return;
1280 }
1281
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001282 if (cds_is_driver_recovering()) {
1283 hdd_warn("Recovery in Progress. State: 0x%x Ignore resume!!!",
1284 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285 return;
1286 }
1287
1288 pHddCtx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301289 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290
1291 /*loop through all adapters. Concurrency */
1292 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
1293
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301294 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001295 pAdapter = pAdapterNode->pAdapter;
1296
1297 /* wake the tx queues */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001298 hdd_notice("Enabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001299 wlan_hdd_netif_queue_control(pAdapter,
1300 WLAN_WAKE_ALL_NETIF_QUEUE,
1301 WLAN_CONTROL_PATH);
1302
1303 hdd_conf_resume_ind(pAdapter);
1304
1305 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1306 pAdapterNode = pNext;
1307 }
1308 hdd_ipa_resume(pHddCtx);
1309
1310 return;
1311}
1312
1313/**
1314 * DOC: SSR Timer
1315 *
1316 * When SSR is initiated, an SSR timer is started. Under normal
1317 * circumstances SSR should complete amd the timer should be deleted
1318 * before it fires. If the SSR timer does fire, it indicates SSR has
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301319 * taken too long, and our only recourse is to invoke the QDF_BUG()
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001320 * API which can allow a crashdump to be captured.
1321 */
1322
1323/**
1324 * hdd_ssr_timer_init() - Initialize SSR Timer
1325 *
1326 * Return: None.
1327 */
1328static void hdd_ssr_timer_init(void)
1329{
1330 init_timer(&ssr_timer);
1331}
1332
1333/**
1334 * hdd_ssr_timer_del() - Delete SSR Timer
1335 *
1336 * Return: None.
1337 */
1338static void hdd_ssr_timer_del(void)
1339{
1340 del_timer(&ssr_timer);
1341 ssr_timer_started = false;
1342}
1343
1344/**
1345 * hdd_ssr_timer_cb() - SSR Timer callback function
1346 * @data: opaque data registered with timer infrastructure
1347 *
1348 * Return: None.
1349 */
1350static void hdd_ssr_timer_cb(unsigned long data)
1351{
Jeff Johnsonc3273322016-07-06 15:28:17 -07001352 hdd_alert("HDD SSR timer expired!");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301353 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354}
1355
1356/**
1357 * hdd_ssr_timer_start() - Start SSR Timer
1358 * @msec: Timer timeout value in milliseconds
1359 *
1360 * Return: None.
1361 */
1362static void hdd_ssr_timer_start(int msec)
1363{
1364 if (ssr_timer_started) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001365 hdd_alert("Trying to start SSR timer when " "it's running!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001366 }
1367 ssr_timer.expires = jiffies + msecs_to_jiffies(msec);
1368 ssr_timer.function = hdd_ssr_timer_cb;
1369 add_timer(&ssr_timer);
1370 ssr_timer_started = true;
1371}
1372
1373/**
1374 * hdd_wlan_shutdown() - HDD SSR shutdown function
1375 *
1376 * This function is called by the HIF to shutdown the driver during SSR.
1377 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301378 * Return: QDF_STATUS_SUCCESS if the driver was shut down,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001379 * or an error status otherwise
1380 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301381QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001382{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001383 v_CONTEXT_t p_cds_context = NULL;
1384 hdd_context_t *pHddCtx;
1385 p_cds_sched_context cds_sched_context = NULL;
1386
Jeff Johnsonc3273322016-07-06 15:28:17 -07001387 hdd_alert("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001388
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001389 /* If SSR never completes, then do kernel panic. */
1390 hdd_ssr_timer_init();
1391 hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME);
1392
1393 /* Get the global CDS context. */
1394 p_cds_context = cds_get_global_context();
1395 if (!p_cds_context) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001396 hdd_alert("Global CDS context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301397 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001398 }
1399
1400 /* Get the HDD context. */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301401 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001402 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001403 hdd_alert("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301404 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405 }
1406
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001407 cds_set_recovery_in_progress(true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001408
1409 cds_clear_concurrent_session_count();
Sandeep Puligillae390be52016-02-08 17:07:05 -08001410 hdd_cleanup_scan_queue(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 hdd_reset_all_adapters(pHddCtx);
1412
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301413 /* De-register the HDD callbacks */
1414 hdd_deregister_cb(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415 hdd_ipa_uc_ssr_deinit();
1416
1417 cds_sched_context = get_cds_sched_ctxt();
1418
1419 /* Wakeup all driver threads */
1420 if (true == pHddCtx->isMcThreadSuspended) {
1421 complete(&cds_sched_context->ResumeMcEvent);
1422 pHddCtx->isMcThreadSuspended = false;
1423 }
1424#ifdef QCA_CONFIG_SMP
1425 if (true == pHddCtx->is_ol_rx_thread_suspended) {
1426 complete(&cds_sched_context->ol_resume_rx_event);
1427 pHddCtx->is_ol_rx_thread_suspended = false;
1428 }
1429#endif
1430
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301431 wlansap_global_deinit();
Arun Khandavallifae92942016-08-01 13:31:08 +05301432 hdd_wlan_stop_modules(pHddCtx, true);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301433
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001434 wlan_hdd_send_status_pkg(NULL, NULL, 0, 0);
1435
Jeff Johnsonc3273322016-07-06 15:28:17 -07001436 hdd_alert("WLAN driver shutdown complete");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301437 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438}
1439
1440/**
1441 * hdd_wlan_re_init() - HDD SSR re-init function
1442 *
1443 * This function is called by the HIF to re-initialize the driver after SSR.
1444 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301445 * Return: QDF_STATUS_SUCCESS if the driver was re-initialized,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446 * or an error status otherwise
1447 */
Arun Khandavallifae92942016-08-01 13:31:08 +05301448QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449{
Arun Khandavallifae92942016-08-01 13:31:08 +05301450
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001451 v_CONTEXT_t p_cds_context = NULL;
1452 hdd_context_t *pHddCtx = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 hdd_adapter_t *pAdapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301454 QDF_STATUS qdf_status;
1455 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456
1457 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1458
1459 /* Get the CDS context */
1460 p_cds_context = cds_get_global_context();
1461 if (p_cds_context == NULL) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001462 hdd_alert("Failed cds_get_global_context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001463 goto err_re_init;
1464 }
1465
1466 /* Get the HDD context */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301467 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001469 hdd_alert("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470 goto err_re_init;
1471 }
1472
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001473 /* The driver should always be initialized in STA mode after SSR */
1474 hdd_set_conparam(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001475 /* Try to get an adapter from mode ID */
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001476 pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001477 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001478 pAdapter = hdd_get_adapter(pHddCtx, QDF_SAP_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001479 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001480 pAdapter = hdd_get_adapter(pHddCtx, QDF_IBSS_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001481 if (!pAdapter) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001482 hdd_alert("Failed to get Adapter!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001483 }
1484 }
1485 }
1486
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301487 if (pHddCtx->config->enable_dp_trace)
1488 qdf_dp_trace_init();
1489
Arun Khandavallifae92942016-08-01 13:31:08 +05301490 ret = hdd_wlan_start_modules(pHddCtx, pAdapter, true);
1491 if (ret) {
1492 hdd_err("Failed to start wlan after error");
1493 goto err_wiphy_unregister;
1494 }
1495
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496 if (hdd_ipa_uc_ssr_reinit())
Jeff Johnsonc3273322016-07-06 15:28:17 -07001497 hdd_err("HDD IPA UC reinit failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498
Arun Khandavallia96c2c02016-05-17 19:15:34 +05301499 hdd_wlan_get_version(pHddCtx, NULL, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001501 /* Restart all adapters */
1502 hdd_start_all_adapters(pHddCtx);
1503
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504 pHddCtx->hdd_mcastbcast_filter_set = false;
1505 pHddCtx->btCoexModeSet = false;
1506 hdd_ssr_timer_del();
1507
Kondabattini, Ganesh96ac37b2016-09-02 23:12:15 +05301508 wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index,
1509 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001510
1511 /* Allow the phone to go to sleep */
1512 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1513
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301514 ret = hdd_register_cb(pHddCtx);
1515 if (ret) {
1516 hdd_err("Failed to register HDD callbacks!");
Chandrasekaran Manishekarcde33d72016-04-14 19:03:39 +05301517 goto err_cds_disable;
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301518 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001519
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001520 wlan_hdd_send_all_scan_intf_info(pHddCtx);
1521 wlan_hdd_send_version_pkg(pHddCtx->target_fw_version,
1522 pHddCtx->target_hw_version,
1523 pHddCtx->target_hw_name);
Manishekar Chandrasekaran2e71e932016-06-24 02:31:55 +05301524 qdf_status = wlansap_global_init();
1525 if (QDF_IS_STATUS_ERROR(qdf_status))
1526 goto err_cds_disable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001527
Srinivas Girigowdad9e6f7b2016-02-01 19:37:52 -08001528 if (cds_is_packet_log_enabled())
Srinivas Girigowdac34f11d2016-02-25 16:02:42 -08001529 hdd_pktlog_enable_disable(pHddCtx, true, 0);
Srinivas Girigowdad9e6f7b2016-02-01 19:37:52 -08001530
Jeff Johnsonc3273322016-07-06 15:28:17 -07001531 hdd_err("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001532 goto success;
1533
1534err_cds_disable:
Arun Khandavallifae92942016-08-01 13:31:08 +05301535 hdd_wlan_stop_modules(pHddCtx, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001536
Arun Khandavallifae92942016-08-01 13:31:08 +05301537err_wiphy_unregister:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001538 if (pHddCtx) {
1539 /* Unregister the Net Device Notifier */
1540 unregister_netdevice_notifier(&hdd_netdev_notifier);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541 ptt_sock_deactivate_svc();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001542 nl_srv_exit();
1543
1544 /* Free up dynamically allocated members inside HDD Adapter */
1545 kfree(pHddCtx->config);
1546 pHddCtx->config = NULL;
Nirav Shahed34b212016-04-25 10:59:16 +05301547 wlan_hdd_deinit_tx_rx_histogram(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001548 wiphy_unregister(pHddCtx->wiphy);
1549 wiphy_free(pHddCtx->wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550 }
1551
1552err_re_init:
1553 /* Allow the phone to go to sleep */
1554 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301555 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001556 return -EPERM;
1557
1558success:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301559 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001560}
1561
1562/**
1563 * wlan_hdd_set_powersave() - Set powersave mode
1564 * @adapter: adapter upon which the request was received
Dustin Brownf660fb42016-09-09 12:04:00 -07001565 * @allow_power_save: is wlan allowed to go into power save mode
1566 * @timeout: timeout period in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567 *
1568 * Return: 0 on success, non-zero on any error
1569 */
Dustin Brownf660fb42016-09-09 12:04:00 -07001570static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
1571 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572{
1573 tHalHandle hal;
1574 hdd_context_t *hdd_ctx;
1575
1576 if (NULL == adapter) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001577 hdd_alert("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001578 return -ENODEV;
1579 }
1580
1581 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1582 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001583 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001584 return -EINVAL;
1585 }
1586
Dustin Brownf660fb42016-09-09 12:04:00 -07001587 hdd_info("Allow power save: %d", allow_power_save);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001588 hal = WLAN_HDD_GET_HAL_CTX(adapter);
1589
Dustin Brownf660fb42016-09-09 12:04:00 -07001590 if (allow_power_save) {
1591 if (QDF_STA_MODE == adapter->device_mode ||
1592 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001593 hdd_notice("Disabling Auto Power save timer");
Dustin Brownf660fb42016-09-09 12:04:00 -07001594 sme_ps_disable_auto_ps_timer(
1595 WLAN_HDD_GET_HAL_CTX(adapter),
1596 adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001597 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001598
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001600 hdd_notice("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001601
1602 /*
1603 * Enter Power Save command received from GUI
1604 * this means DHCP is completed
1605 */
1606 sme_ps_enable_disable(hal, adapter->sessionId,
1607 SME_PS_ENABLE);
1608 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001609 hdd_info("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001610 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001611 } else {
1612 hdd_info("Wlan driver Entering Full Power");
1613
1614 /*
1615 * Enter Full power command received from GUI
1616 * this means we are disconnected
1617 */
1618 sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1619 adapter->sessionId);
1620 sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE);
1621 sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1622 adapter->sessionId, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001623 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001624
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625 return 0;
1626}
1627
1628/**
1629 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1630 * @wiphy: Pointer to wiphy
1631 *
1632 * This API is called when cfg80211 driver resumes driver updates
1633 * latest sched_scan scan result(if any) to cfg80211 database
1634 *
1635 * Return: integer status
1636 */
1637static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1638{
1639 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1640 hdd_adapter_t *pAdapter;
1641 hdd_adapter_list_node_t *pAdapterNode, *pNext;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301642 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643 int result;
1644 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1645
1646 ENTER();
1647
Anurag Chouhan6d760662016-02-20 16:05:43 +05301648 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001649 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001650 return -EINVAL;
1651 }
1652
1653 result = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301654 if (0 != result)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001655 return result;
Arun Khandavallifae92942016-08-01 13:31:08 +05301656
1657 mutex_lock(&pHddCtx->iface_change_lock);
1658 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1659 mutex_unlock(&pHddCtx->iface_change_lock);
1660 hdd_info("Driver Module not enabled return success");
1661 return 0;
1662 }
1663 mutex_unlock(&pHddCtx->iface_change_lock);
Yuanyuan Liu13738502016-04-06 17:41:37 -07001664 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665
1666 /* Resume MC thread */
1667 if (pHddCtx->isMcThreadSuspended) {
1668 complete(&cds_sched_context->ResumeMcEvent);
1669 pHddCtx->isMcThreadSuspended = false;
1670 }
1671#ifdef QCA_CONFIG_SMP
1672 /* Resume tlshim Rx thread */
1673 if (pHddCtx->is_ol_rx_thread_suspended) {
1674 complete(&cds_sched_context->ol_resume_rx_event);
1675 pHddCtx->is_ol_rx_thread_suspended = false;
1676 }
1677#endif
1678 hdd_resume_wlan();
1679
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301680 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301681 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
1682 NO_SESSION, pHddCtx->isWiphySuspended));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301683 qdf_spin_lock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684 pHddCtx->isWiphySuspended = false;
1685 if (true != pHddCtx->isSchedScanUpdatePending) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301686 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001687 hdd_notice("Return resume is not due to PNO indication");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 return 0;
1689 }
1690 /* Reset flag to avoid updatating cfg80211 data old results again */
1691 pHddCtx->isSchedScanUpdatePending = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301692 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693
1694 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
1695
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301696 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 pAdapter = pAdapterNode->pAdapter;
1698 if ((NULL != pAdapter) &&
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001699 (QDF_STA_MODE == pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700 if (0 !=
1701 wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy,
1702 pAdapter, 0)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001703 hdd_warn("NO SCAN result");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704 } else {
1705 /* Acquire wakelock to handle the case where
1706 * APP's tries to suspend immediately after
1707 * updating the scan results. Whis results in
1708 * app's is in suspended state and not able to
1709 * process the connect request to AP
1710 */
Sreelakshmi Konamki22528532016-09-06 16:34:50 +05301711 hdd_prevent_suspend_timeout(
1712 HDD_WAKE_LOCK_RESUME_DURATION,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713 WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN);
1714 cfg80211_sched_scan_results(pHddCtx->wiphy);
1715 }
1716
Jeff Johnsonc3273322016-07-06 15:28:17 -07001717 hdd_notice("cfg80211 scan result database updated");
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301718 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001719 return result;
1720 }
1721 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1722 pAdapterNode = pNext;
1723 }
1724
Jeff Johnsonc3273322016-07-06 15:28:17 -07001725 hdd_notice("Failed to find Adapter");
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301726 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001727 return result;
1728}
1729
1730/**
1731 * wlan_hdd_cfg80211_ready_to_suspend() - set cfg80211 ready to suspend event
1732 * @callbackContext: Pointer to callback context
1733 * @suspended: Suspend flag
1734 *
1735 * Return: none
1736 */
1737static void wlan_hdd_cfg80211_ready_to_suspend(void *callbackContext,
1738 bool suspended)
1739{
1740 hdd_context_t *pHddCtx = (hdd_context_t *) callbackContext;
1741 pHddCtx->suspended = suspended;
1742 complete(&pHddCtx->ready_to_suspend);
1743}
1744
1745/**
1746 * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1747 * @wiphy: Pointer to wiphy
1748 *
1749 * This API is called when cfg80211 driver resumes driver updates
1750 * latest sched_scan scan result(if any) to cfg80211 database
1751 *
1752 * Return: integer status
1753 */
1754int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1755{
1756 int ret;
1757
1758 cds_ssr_protect(__func__);
1759 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1760 cds_ssr_unprotect(__func__);
1761
1762 return ret;
1763}
1764
1765/**
1766 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1767 * @wiphy: Pointer to wiphy
1768 * @wow: Pointer to wow
1769 *
1770 * This API is called when cfg80211 driver suspends
1771 *
1772 * Return: integer status
1773 */
1774static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1775 struct cfg80211_wowlan *wow)
1776{
1777#ifdef QCA_CONFIG_SMP
1778#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1779#endif
1780 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1781 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1782 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
1783 hdd_adapter_t *pAdapter;
1784 hdd_scaninfo_t *pScanInfo;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301785 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786 int rc;
1787
1788 ENTER();
1789
Anurag Chouhan6d760662016-02-20 16:05:43 +05301790 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001791 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001792 return -EINVAL;
1793 }
1794
1795 rc = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301796 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001797 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798
Arun Khandavallifae92942016-08-01 13:31:08 +05301799 mutex_lock(&pHddCtx->iface_change_lock);
1800 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1801 mutex_unlock(&pHddCtx->iface_change_lock);
1802 hdd_info("Driver Modules not Enabled ");
1803 return 0;
1804 }
1805 mutex_unlock(&pHddCtx->iface_change_lock);
1806
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1808 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1809 * until CAC is done for a SoftAP which is in started state.
1810 */
1811 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301812 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001813 pAdapter = pAdapterNode->pAdapter;
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001814 if (QDF_SAP_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001815 if (BSS_START ==
1816 WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter)->bssState &&
1817 true ==
1818 WLAN_HDD_GET_AP_CTX_PTR(pAdapter)->
1819 dfs_cac_block_tx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001820 hdd_notice("RADAR detection in progress, do not allow suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821 return -EAGAIN;
1822 } else if (!pHddCtx->config->enableSapSuspend) {
1823 /* return -EOPNOTSUPP if SAP does not support
1824 * suspend
1825 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001826 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001827 return -EOPNOTSUPP;
1828 }
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001829 } else if (QDF_P2P_GO_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830 if (!pHddCtx->config->enableSapSuspend) {
1831 /* return -EOPNOTSUPP if GO does not support
1832 * suspend
1833 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001834 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 return -EOPNOTSUPP;
1836 }
1837 }
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +05301838 if (pAdapter->is_roc_inprogress)
1839 wlan_hdd_cleanup_remain_on_channel_ctx(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001840 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1841 pAdapterNode = pNext;
1842 }
1843
1844 /* Stop ongoing scan on each interface */
1845 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301846 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001847 pAdapter = pAdapterNode->pAdapter;
1848 pScanInfo = &pAdapter->scan_info;
1849
1850 if (sme_sta_in_middle_of_roaming
1851 (pHddCtx->hHal, pAdapter->sessionId)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001852 hdd_notice("Roaming in progress, do not allow suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001853 return -EAGAIN;
1854 }
1855
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001856 if (pScanInfo->mScanPending) {
1857 INIT_COMPLETION(pScanInfo->abortscan_event_var);
1858 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
1859 eCSR_SCAN_ABORT_DEFAULT);
1860
1861 status =
1862 wait_for_completion_timeout(&pScanInfo->
1863 abortscan_event_var,
1864 msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN));
1865 if (!status) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001866 hdd_err("Timeout occurred while waiting for abort scan");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001867 return -ETIME;
1868 }
1869 }
1870 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1871 pAdapterNode = pNext;
1872 }
1873
1874 /*
1875 * Suspend IPA early before proceeding to suspend other entities like
1876 * firmware to avoid any race conditions.
1877 */
1878 if (hdd_ipa_suspend(pHddCtx)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001879 hdd_notice("IPA not ready to suspend!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001880 return -EAGAIN;
1881 }
1882
1883 /* Wait for the target to be ready for suspend */
1884 INIT_COMPLETION(pHddCtx->ready_to_suspend);
1885
1886 hdd_suspend_wlan(&wlan_hdd_cfg80211_ready_to_suspend, pHddCtx);
1887
1888 rc = wait_for_completion_timeout(&pHddCtx->ready_to_suspend,
1889 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_SUSPEND));
1890 if (!rc) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001891 hdd_err("Failed to get ready to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001892 goto resume_tx;
1893 }
1894
1895 if (!pHddCtx->suspended) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001896 hdd_err("Faied as suspend_status is wrong:%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001897 pHddCtx->suspended);
1898 goto resume_tx;
1899 }
1900
1901 /* Suspend MC thread */
1902 set_bit(MC_SUSPEND_EVENT_MASK, &cds_sched_context->mcEventFlag);
1903 wake_up_interruptible(&cds_sched_context->mcWaitQueue);
1904
1905 /* Wait for suspend confirmation from MC thread */
1906 rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var,
1907 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1908 if (!rc) {
1909 clear_bit(MC_SUSPEND_EVENT_MASK,
1910 &cds_sched_context->mcEventFlag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001911 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912 goto resume_tx;
1913 }
1914
1915 pHddCtx->isMcThreadSuspended = true;
1916
1917#ifdef QCA_CONFIG_SMP
1918 /* Suspend tlshim rx thread */
1919 set_bit(RX_SUSPEND_EVENT_MASK, &cds_sched_context->ol_rx_event_flag);
1920 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1921 rc = wait_for_completion_timeout(&cds_sched_context->
1922 ol_suspend_rx_event,
1923 msecs_to_jiffies
1924 (RX_TLSHIM_SUSPEND_TIMEOUT));
1925 if (!rc) {
1926 clear_bit(RX_SUSPEND_EVENT_MASK,
1927 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001928 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001929 goto resume_all;
1930 }
1931 pHddCtx->is_ol_rx_thread_suspended = true;
1932#endif
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301933 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301934 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
1935 NO_SESSION, pHddCtx->isWiphySuspended));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936 pHddCtx->isWiphySuspended = true;
1937
Yuanyuan Liu13738502016-04-06 17:41:37 -07001938 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001939
1940 EXIT();
1941 return 0;
1942
1943#ifdef QCA_CONFIG_SMP
1944resume_all:
1945
1946 complete(&cds_sched_context->ResumeMcEvent);
1947 pHddCtx->isMcThreadSuspended = false;
1948#endif
1949
1950resume_tx:
1951
1952 hdd_resume_wlan();
1953 return -ETIME;
1954
1955}
1956
1957/**
1958 * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1959 * @wiphy: Pointer to wiphy
1960 * @wow: Pointer to wow
1961 *
1962 * This API is called when cfg80211 driver suspends
1963 *
1964 * Return: integer status
1965 */
1966int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1967 struct cfg80211_wowlan *wow)
1968{
1969 int ret;
1970
1971 cds_ssr_protect(__func__);
1972 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1973 cds_ssr_unprotect(__func__);
1974
1975 return ret;
1976}
1977
1978/**
1979 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1980 * @wiphy: Pointer to wiphy
1981 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001982 * @allow_power_save: is wlan allowed to go into power save mode
1983 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984 *
1985 * Return: 0 for success, non-zero for failure
1986 */
1987static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001988 struct net_device *dev,
1989 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990 int timeout)
1991{
1992 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1993 hdd_context_t *pHddCtx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301994 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001995 int status;
1996
Dustin Brownf660fb42016-09-09 12:04:00 -07001997 if (timeout < 0) {
1998 hdd_notice("User space timeout: %d; Using default instead: %d",
1999 timeout, AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE);
2000 timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE;
2001 }
2002
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003 ENTER();
2004
Anurag Chouhan6d760662016-02-20 16:05:43 +05302005 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002006 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007 return -EINVAL;
2008 }
2009
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302010 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
2012 pAdapter->sessionId, timeout));
2013
2014 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2015 status = wlan_hdd_validate_context(pHddCtx);
2016
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302017 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002018 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002019
Arun Khandavalli99286452016-08-22 12:13:41 +05302020 mutex_lock(&pHddCtx->iface_change_lock);
2021 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2022 mutex_unlock(&pHddCtx->iface_change_lock);
2023 hdd_info("Driver Module not enabled return success");
2024 return 0;
2025 }
2026 mutex_unlock(&pHddCtx->iface_change_lock);
2027
Dustin Brownf660fb42016-09-09 12:04:00 -07002028 if (allow_power_save &&
2029 pHddCtx->hdd_wlan_suspended &&
2030 pHddCtx->config->fhostArpOffload &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031 (eConnectionState_Associated ==
2032 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) {
Dustin Brownf660fb42016-09-09 12:04:00 -07002033 hdd_notice("offload: in cfg80211_set_power_mgmt, "
2034 "calling arp offload");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302035 qdf_status = hdd_conf_arp_offload(pAdapter, true);
2036 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002037 hdd_notice("Failed to enable ARPOFFLOAD Feature %d",
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302038 qdf_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039 }
2040 }
2041
Dustin Brownf660fb42016-09-09 12:04:00 -07002042 status = wlan_hdd_set_powersave(pAdapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043
Dustin Brownf660fb42016-09-09 12:04:00 -07002044 if (allow_power_save) {
2045 hdd_warn("DHCP stop indicated through power save");
2046 sme_dhcp_stop_ind(pHddCtx->hHal, pAdapter->device_mode,
2047 pAdapter->macAddressCurrent.bytes,
2048 pAdapter->sessionId);
2049 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
2050 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002051 hdd_err("DHCP start indicated through power save");
Dustin Brown6a609d62016-08-31 14:17:00 -07002052 hdd_prevent_suspend_timeout(1000,
2053 WIFI_POWER_EVENT_WAKELOCK_DHCP);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002054 sme_dhcp_start_ind(pHddCtx->hHal, pAdapter->device_mode,
2055 pAdapter->macAddressCurrent.bytes,
2056 pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002057 }
2058
2059 EXIT();
2060 return status;
2061}
2062
2063/**
2064 * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2065 * @wiphy: Pointer to wiphy
2066 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07002067 * @allow_power_save: is wlan allowed to go into power save mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 * @timeout: Timeout value
2069 *
2070 * Return: 0 for success, non-zero for failure
2071 */
2072int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002073 struct net_device *dev,
2074 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002075 int timeout)
2076{
2077 int ret;
2078
2079 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07002080 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
2081 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002082 cds_ssr_unprotect(__func__);
2083
2084 return ret;
2085}
2086
2087/**
2088 * __wlan_hdd_cfg80211_set_txpower() - set TX power
2089 * @wiphy: Pointer to wiphy
2090 * @wdev: Pointer to network device
2091 * @type: TX power setting type
2092 * @dbm: TX power in dbm
2093 *
2094 * Return: 0 for success, non-zero for failure
2095 */
2096static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002097 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002098 enum nl80211_tx_power_setting type,
2099 int dbm)
2100{
2101 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
2102 tHalHandle hHal = NULL;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302103 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
2104 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105 int status;
2106
2107 ENTER();
2108
Anurag Chouhan6d760662016-02-20 16:05:43 +05302109 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002110 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002111 return -EINVAL;
2112 }
2113
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302114 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
2116 NO_SESSION, type));
2117
2118 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302119 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002120 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002121
2122 hHal = pHddCtx->hHal;
2123
2124 if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002125 hdd_err("sme_cfg_set_int failed for tx power %hu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002126 dbm);
2127 return -EIO;
2128 }
2129
Jeff Johnsonc3273322016-07-06 15:28:17 -07002130 hdd_info("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002131
2132 switch (type) {
2133 /* Automatically determine transmit power */
2134 case NL80211_TX_POWER_AUTOMATIC:
2135 /* Fall through */
2136 case NL80211_TX_POWER_LIMITED: /* Limit TX power by the mBm parameter */
2137 if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302138 QDF_STATUS_SUCCESS) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002139 hdd_err("Setting maximum tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002140 return -EIO;
2141 }
2142 break;
2143
2144 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07002145 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146 return -EOPNOTSUPP;
2147 break;
2148
2149 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07002150 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002151 return -EIO;
2152 }
2153
2154 EXIT();
2155 return 0;
2156}
2157
2158/**
2159 * wlan_hdd_cfg80211_set_txpower() - set TX power
2160 * @wiphy: Pointer to wiphy
2161 * @wdev: Pointer to network device
2162 * @type: TX power setting type
2163 * @dbm: TX power in dbm
2164 *
2165 * Return: 0 for success, non-zero for failure
2166 */
2167int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002168 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002169 enum nl80211_tx_power_setting type,
2170 int dbm)
2171{
2172 int ret;
2173 cds_ssr_protect(__func__);
2174 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002175 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002176 type, dbm);
2177 cds_ssr_unprotect(__func__);
2178
2179 return ret;
2180}
2181
2182/**
2183 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2184 * @wiphy: Pointer to wiphy
2185 * @wdev: Pointer to network device
2186 * @dbm: Pointer to TX power in dbm
2187 *
2188 * Return: 0 for success, non-zero for failure
2189 */
2190static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002192 int *dbm)
2193{
2194
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002195 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
Arun Khandavalli99286452016-08-22 12:13:41 +05302196 struct net_device *ndev = wdev->netdev;
2197 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002198 int status;
2199
2200 ENTER();
2201
Anurag Chouhan6d760662016-02-20 16:05:43 +05302202 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002203 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002204 return -EINVAL;
2205 }
2206
2207 status = wlan_hdd_validate_context(pHddCtx);
2208 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002209 *dbm = 0;
2210 return status;
2211 }
2212
Arun Khandavalli99286452016-08-22 12:13:41 +05302213 if (!adapter) {
2214 hdd_err("adapter is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002215 return -ENOENT;
2216 }
2217
Arun Khandavalli99286452016-08-22 12:13:41 +05302218 /* Validate adapter sessionId */
2219 if (adapter->sessionId == HDD_SESSION_ID_INVALID) {
2220 hdd_err("Adapter Session Invalid!");
2221 return -ENOTSUPP;
2222 }
2223
2224 mutex_lock(&pHddCtx->iface_change_lock);
2225 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2226 mutex_unlock(&pHddCtx->iface_change_lock);
2227 hdd_info("Driver Module not enabled return success");
2228 /* Send cached data to upperlayer*/
2229 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
2230 return 0;
2231 }
2232 mutex_unlock(&pHddCtx->iface_change_lock);
2233
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302234 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302235 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Arun Khandavalli99286452016-08-22 12:13:41 +05302236 adapter->sessionId, adapter->device_mode));
2237 wlan_hdd_get_class_astats(adapter);
2238 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239
2240 EXIT();
2241 return 0;
2242}
2243
2244/**
2245 * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function
2246 * @wiphy: Pointer to wiphy structure.
2247 * @wdev: Pointer to wireless_dev structure.
2248 * @dbm: dbm
2249 *
2250 * This is the cfg80211 get txpower handler function which invokes
2251 * the internal function @__wlan_hdd_cfg80211_get_txpower with
2252 * SSR protection.
2253 *
2254 * Return: 0 for success, error number on failure.
2255 */
2256int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002257 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002258 int *dbm)
2259{
2260 int ret;
2261
2262 cds_ssr_protect(__func__);
2263 ret = __wlan_hdd_cfg80211_get_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002264 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002265 dbm);
2266 cds_ssr_unprotect(__func__);
2267
2268 return ret;
2269}