blob: 3ed004c183691c54e9006a032d4d636f971fa8fb [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Yuanyuan Liu057fc4c2018-01-08 10:50:28 -08002 * Copyright (c) 2015-2018 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#include <linux/platform_device.h>
29#include <linux/pci.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080030#include "cds_api.h"
Anurag Chouhance0dc992016-02-16 18:18:03 +053031#include "qdf_status.h"
Anurag Chouhana37b5b72016-02-21 14:53:42 +053032#include "qdf_lock.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080033#include "cds_sched.h"
34#include "osdep.h"
35#include "hif.h"
Houston Hoffmane8937082015-11-10 16:49:12 -080036#include "htc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080037#include "epping_main.h"
38#include "wlan_hdd_main.h"
39#include "wlan_hdd_power.h"
40#include "wlan_logging_sock_svc.h"
41#include "wma_api.h"
42#include "wlan_hdd_napi.h"
Tushnim Bhattacharyya9028cc72017-03-09 13:10:49 -080043#include "wlan_policy_mgr_api.h"
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080044#include "qwlan_version.h"
Komal Seelamd9106492016-02-15 10:31:44 +053045#include "bmi.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080046#include "cdp_txrx_bus.h"
Sarada Prasanna Garnayake1722632017-01-05 15:27:15 +053047#include "cdp_txrx_misc.h"
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -070048#include "pld_common.h"
Jeff Johnson7782cb92016-10-05 14:22:40 -070049#include "wlan_hdd_driver_ops.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080050
51#ifdef MODULE
52#define WLAN_MODULE_NAME module_name(THIS_MODULE)
53#else
54#define WLAN_MODULE_NAME "wlan"
55#endif
56
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -070057#define DISABLE_KRAIT_IDLE_PS_VAL 1
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080058
Srinivas Girigowdabafb8b72017-10-11 17:52:32 -070059#define SSR_MAX_FAIL_CNT 3
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +053060static uint8_t re_init_fail_cnt, probe_fail_cnt;
61
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080062/*
63 * In BMI Phase we are only sending small chunk (256 bytes) of the FW image at
64 * a time, and wait for the completion interrupt to start the next transfer.
65 * During this phase, the KRAIT is entering IDLE/StandAlone(SA) Power Save(PS).
66 * The delay incurred for resuming from IDLE/SA PS is huge during driver load.
67 * So prevent APPS IDLE/SA PS durint driver load for reducing interrupt latency.
68 */
Yuanyuan Liu13738502016-04-06 17:41:37 -070069
70static inline void hdd_request_pm_qos(struct device *dev, int val)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080071{
Yuanyuan Liu13738502016-04-06 17:41:37 -070072 pld_request_pm_qos(dev, val);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080073}
74
Yuanyuan Liu13738502016-04-06 17:41:37 -070075static inline void hdd_remove_pm_qos(struct device *dev)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080076{
Yuanyuan Liu13738502016-04-06 17:41:37 -070077 pld_remove_pm_qos(dev);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080078}
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080079
80/**
Komal Seelamad5a90d2016-02-16 13:50:03 +053081 * hdd_set_recovery_in_progress() - API to set recovery in progress
82 * @data: Context
83 * @val: Value to set
84 *
85 * Return: None
86 */
87static void hdd_set_recovery_in_progress(void *data, uint8_t val)
88{
89 cds_set_recovery_in_progress(val);
90}
91
92/**
93 * hdd_is_driver_unloading() - API to query if driver is unloading
94 * @data: Private Data
95 *
96 * Return: True/False
97 */
98static bool hdd_is_driver_unloading(void *data)
99{
100 return cds_is_driver_unloading();
101}
102
103/**
104 * hdd_is_load_or_unload_in_progress() - API to query if driver is
105 * loading/unloading
106 * @data: Private Data
107 *
108 * Return: bool
109 */
110static bool hdd_is_load_or_unload_in_progress(void *data)
111{
112 return cds_is_load_or_unload_in_progress();
113}
114
115/**
Komal Seelam1aac1982016-03-02 15:57:26 +0530116 * hdd_is_recovery_in_progress() - API to query if recovery in progress
Komal Seelamad5a90d2016-02-16 13:50:03 +0530117 * @data: Private Data
118 *
119 * Return: bool
120 */
Komal Seelam1aac1982016-03-02 15:57:26 +0530121static bool hdd_is_recovery_in_progress(void *data)
Komal Seelamad5a90d2016-02-16 13:50:03 +0530122{
123 return cds_is_driver_recovering();
124}
125
126/**
Govind Singha1f6dac2017-06-13 11:45:07 +0530127 * hdd_is_target_ready() - API to query if target is in ready state
128 * @data: Private Data
129 *
130 * Return: bool
131 */
132static bool hdd_is_target_ready(void *data)
133{
134 return cds_is_target_ready();
135}
136
137/**
Komal Seelam1aac1982016-03-02 15:57:26 +0530138 * hdd_hif_init_driver_state_callbacks() - API to initialize HIF callbacks
Komal Seelamad5a90d2016-02-16 13:50:03 +0530139 * @data: Private Data
Komal Seelam1aac1982016-03-02 15:57:26 +0530140 * @cbk: HIF Driver State callbacks
Komal Seelamad5a90d2016-02-16 13:50:03 +0530141 *
142 * HIF should be independent of CDS calls. Pass CDS Callbacks to HIF, HIF will
143 * call the callbacks.
144 *
145 * Return: void
146 */
Komal Seelam1aac1982016-03-02 15:57:26 +0530147static void hdd_hif_init_driver_state_callbacks(void *data,
148 struct hif_driver_state_callbacks *cbk)
Komal Seelamad5a90d2016-02-16 13:50:03 +0530149{
150 cbk->context = data;
151 cbk->set_recovery_in_progress = hdd_set_recovery_in_progress;
Komal Seelam1aac1982016-03-02 15:57:26 +0530152 cbk->is_recovery_in_progress = hdd_is_recovery_in_progress;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530153 cbk->is_load_unload_in_progress = hdd_is_load_or_unload_in_progress;
154 cbk->is_driver_unloading = hdd_is_driver_unloading;
Govind Singha1f6dac2017-06-13 11:45:07 +0530155 cbk->is_target_ready = hdd_is_target_ready;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530156}
157
158/**
159 * hdd_init_cds_hif_context() - API to set CDS HIF Context
160 * @hif: HIF Context
161 *
162 * Return: success/failure
163 */
164static int hdd_init_cds_hif_context(void *hif)
165{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530166 QDF_STATUS status;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530167
Anurag Chouhan6d760662016-02-20 16:05:43 +0530168 status = cds_set_context(QDF_MODULE_ID_HIF, hif);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530169
170 if (status)
171 return -ENOENT;
172
173 return 0;
174}
175
176/**
177 * hdd_deinit_cds_hif_context() - API to clear CDS HIF COntext
178 *
179 * Return: None
180 */
181static void hdd_deinit_cds_hif_context(void)
182{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530183 QDF_STATUS status;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530184
Anurag Chouhan6d760662016-02-20 16:05:43 +0530185 status = cds_set_context(QDF_MODULE_ID_HIF, NULL);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530186
187 if (status)
188 hdd_err("Failed to reset CDS HIF Context");
Komal Seelamad5a90d2016-02-16 13:50:03 +0530189}
190
191/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -0700192 * to_bus_type() - Map PLD bus type to low level bus type
193 * @bus_type: PLD bus type
194 *
195 * Map PLD bus type to low level bus type.
196 *
197 * Return: low level bus type.
198 */
199static enum qdf_bus_type to_bus_type(enum pld_bus_type bus_type)
200{
201 switch (bus_type) {
202 case PLD_BUS_TYPE_PCIE:
203 return QDF_BUS_TYPE_PCI;
204 case PLD_BUS_TYPE_SNOC:
205 return QDF_BUS_TYPE_SNOC;
Poddar, Siddarth3e9fa5c2016-05-13 14:25:05 +0530206 case PLD_BUS_TYPE_SDIO:
207 return QDF_BUS_TYPE_SDIO;
Mohit Khannafa99aea2016-05-12 21:43:13 -0700208 case PLD_BUS_TYPE_USB:
209 return QDF_BUS_TYPE_USB;
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -0700210 default:
211 return QDF_BUS_TYPE_NONE;
212 }
213}
214
Manikandan Mohan617a5162017-04-10 13:14:40 -0700215int hdd_hif_open(struct device *dev, void *bdev, const struct hif_bus_id *bid,
Anurag Chouhan2ed1fce2016-02-22 15:07:01 +0530216 enum qdf_bus_type bus_type, bool reinit)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800217{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530218 QDF_STATUS status;
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800219 int ret = 0;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530220 struct hif_opaque_softc *hif_ctx;
Anurag Chouhandf2b2682016-02-29 14:15:27 +0530221 qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
Komal Seelam1aac1982016-03-02 15:57:26 +0530222 struct hif_driver_state_callbacks cbk;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530223 uint32_t mode = cds_get_conparam();
Jeff Johnson6bc79d82017-08-28 12:02:36 -0700224 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Govind Singh068c4b02016-08-17 16:37:13 +0530225
226 if (!hdd_ctx) {
227 hdd_err("hdd_ctx error");
228 return -EFAULT;
229 }
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800230
Komal Seelam1aac1982016-03-02 15:57:26 +0530231 hdd_hif_init_driver_state_callbacks(dev, &cbk);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530232
Anurag Chouhandf2b2682016-02-29 14:15:27 +0530233 hif_ctx = hif_open(qdf_ctx, mode, bus_type, &cbk);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530234 if (!hif_ctx) {
235 hdd_err("hif_open error");
236 return -ENOMEM;
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800237 }
238
Komal Seelamad5a90d2016-02-16 13:50:03 +0530239 ret = hdd_init_cds_hif_context(hif_ctx);
240 if (ret) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800241 hdd_err("Failed to set global HIF CDS Context err: %d", ret);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530242 goto err_hif_close;
243 }
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800244
Houston Hoffmanc1f962e2016-04-13 16:35:44 -0700245 status = hif_enable(hif_ctx, dev, bdev, bid, bus_type,
246 (reinit == true) ? HIF_ENABLE_TYPE_REINIT :
247 HIF_ENABLE_TYPE_PROBE);
248 if (!QDF_IS_STATUS_SUCCESS(status)) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800249 hdd_err("hif_enable failed status: %d, reinit: %d",
Houston Hoffmanc1f962e2016-04-13 16:35:44 -0700250 status, reinit);
Nachiket Kukade8003d252017-03-30 15:55:58 +0530251
Houston Hoffmanc1f962e2016-04-13 16:35:44 -0700252 ret = qdf_status_to_os_return(status);
253 goto err_hif_close;
254 } else {
Yuanyuan Liu057fc4c2018-01-08 10:50:28 -0800255 cds_set_target_ready(true);
Houston Hoffmanc1f962e2016-04-13 16:35:44 -0700256 ret = hdd_napi_create();
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800257 hdd_debug("hdd_napi_create returned: %d", ret);
Manjunathappa Prakash9dd19132016-04-21 16:27:04 -0700258 if (ret == 0)
259 hdd_warn("NAPI: no instances are created");
260 else if (ret < 0) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800261 hdd_err("NAPI creation error, rc: 0x%x, reinit: %d",
Komal Seelamad5a90d2016-02-16 13:50:03 +0530262 ret, reinit);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800263 ret = -EFAULT;
264 goto err_hif_close;
Govind Singh068c4b02016-08-17 16:37:13 +0530265 } else {
266 hdd_napi_event(NAPI_EVT_INI_FILE,
267 (void *)hdd_ctx->napi_enable);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800268 }
269 }
270
Sravan Kumar Kairam27296782017-04-21 22:04:18 +0530271 pmo_ucfg_psoc_set_hif_handle(hdd_ctx->hdd_psoc, hif_ctx);
272
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800273 return 0;
274
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800275err_hif_close:
Komal Seelamad5a90d2016-02-16 13:50:03 +0530276 hdd_deinit_cds_hif_context();
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800277 hif_close(hif_ctx);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800278 return ret;
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800279}
280
Jeff Johnson6bc79d82017-08-28 12:02:36 -0700281void hdd_hif_close(struct hdd_context *hdd_ctx, void *hif_ctx)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800282{
Sravan Kumar Kairam27296782017-04-21 22:04:18 +0530283 if (!hdd_ctx) {
284 hdd_err("hdd_ctx error");
285 return;
286 }
287
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800288 if (hif_ctx == NULL)
289 return;
290
291 hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE);
292
293 hdd_napi_destroy(true);
294
Komal Seelamad5a90d2016-02-16 13:50:03 +0530295 hdd_deinit_cds_hif_context();
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800296 hif_close(hif_ctx);
Sravan Kumar Kairam27296782017-04-21 22:04:18 +0530297
298 pmo_ucfg_psoc_set_hif_handle(hdd_ctx->hdd_psoc, NULL);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800299}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800300
301/**
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530302 * hdd_init_qdf_ctx() - API to initialize global QDF Device structure
Komal Seelam48152e12016-02-09 17:50:33 +0530303 * @dev: Device Pointer
304 * @bdev: Bus Device pointer
Arun Khandavallifae92942016-08-01 13:31:08 +0530305 * @bus_type: Underlying bus type
306 * @bid: Bus id passed by platform driver
Komal Seelam48152e12016-02-09 17:50:33 +0530307 *
308 * Return: void
309 */
Jeff Johnson7782cb92016-10-05 14:22:40 -0700310static void hdd_init_qdf_ctx(struct device *dev, void *bdev,
311 enum qdf_bus_type bus_type,
312 const struct hif_bus_id *bid)
Komal Seelam48152e12016-02-09 17:50:33 +0530313{
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530314 qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
Komal Seelam48152e12016-02-09 17:50:33 +0530315
Jeff Johnson615d4bb2016-07-20 11:03:04 -0700316 if (!qdf_dev) {
317 hdd_err("Invalid QDF device");
318 return;
319 }
320
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530321 qdf_dev->dev = dev;
322 qdf_dev->drv_hdl = bdev;
Govind Singh9db91ba2016-04-29 14:15:47 +0530323 qdf_dev->bus_type = bus_type;
Arun Khandavallifae92942016-08-01 13:31:08 +0530324 qdf_dev->bid = bid;
Komal Seelam48152e12016-02-09 17:50:33 +0530325}
326
327/**
Yuanyuan Liu5583b2c2017-10-09 17:30:13 -0700328 * check_for_probe_defer() - API to check return value
329 * @ret: Return Value
330 *
331 * Return: return -EPROBE_DEFER to platform driver if return value
332 * is -ENOMEM. Platform driver will try to re-probe.
333 */
334#ifdef MODULE
335static int check_for_probe_defer(int ret)
336{
337 return ret;
338}
339#else
340static int check_for_probe_defer(int ret)
341{
342 if (ret == -ENOMEM)
343 return -EPROBE_DEFER;
344 return ret;
345}
346#endif
347
348/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800349 * wlan_hdd_probe() - handles probe request
350 *
351 * This function is called to probe the wlan driver
352 *
353 * @dev: wlan device structure
354 * @bdev: bus device structure
355 * @bid: bus identifier for shared busses
356 * @bus_type: underlying bus type
357 * @reinit: true if we are reinitiallizing the driver after a subsystem restart
358 *
359 * Return: 0 on successfull probe
360 */
Manikandan Mohan617a5162017-04-10 13:14:40 -0700361static int wlan_hdd_probe(struct device *dev, void *bdev,
362 const struct hif_bus_id *bid,
363 enum qdf_bus_type bus_type, bool reinit)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364{
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800365 int ret = 0;
366
367 pr_info("%s: %sprobing driver v%s\n", WLAN_MODULE_NAME,
368 reinit ? "re-" : "", QWLAN_VERSIONSTR);
369
Arunk Khandavalli16d84252017-06-21 15:26:29 +0530370 mutex_lock(&hdd_init_deinit_lock);
Rakesh Pillai0a54fa92017-11-23 17:13:38 +0530371 cds_set_driver_in_bad_state(false);
Nachiket Kukadebe8850b2017-09-18 15:37:00 +0530372 if (!reinit)
373 hdd_start_driver_ops_timer(eHDD_DRV_OP_PROBE);
374 else
375 hdd_start_driver_ops_timer(eHDD_DRV_OP_REINIT);
376
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800377 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
378
379 /*
Jeff Johnson0a9da592017-01-12 09:48:36 -0800380 * The Krait is going to Idle/Stand Alone Power Save more
381 * aggressively which is resulting in the longer driver load
382 * time. The Fix is to not allow Krait to enter Idle Power
383 * Save during driver load.
384 */
Yuanyuan Liu13738502016-04-06 17:41:37 -0700385 hdd_request_pm_qos(dev, DISABLE_KRAIT_IDLE_PS_VAL);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800386
Arunk Khandavalli2dc0c962016-10-20 12:37:26 +0530387 if (reinit)
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800388 cds_set_recovery_in_progress(true);
Arunk Khandavalli2dc0c962016-10-20 12:37:26 +0530389 else
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800390 cds_set_load_in_progress(true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800391
Arun Khandavallifae92942016-08-01 13:31:08 +0530392 hdd_init_qdf_ctx(dev, bdev, bus_type, (const struct hif_bus_id *)bid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800393
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530394 if (reinit) {
Arun Khandavallifae92942016-08-01 13:31:08 +0530395 ret = hdd_wlan_re_init();
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530396 if (ret)
397 re_init_fail_cnt++;
398 } else {
Arun Khandavallifae92942016-08-01 13:31:08 +0530399 ret = hdd_wlan_startup(dev);
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530400 if (ret)
401 probe_fail_cnt++;
402 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800403
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800404 if (ret)
Arun Khandavallifae92942016-08-01 13:31:08 +0530405 goto err_hdd_deinit;
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800406
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800407
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800408 if (reinit) {
409 cds_set_recovery_in_progress(false);
410 } else {
411 cds_set_load_in_progress(false);
412 cds_set_driver_loaded(true);
413 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800414
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800415 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
Yuanyuan Liu13738502016-04-06 17:41:37 -0700416 hdd_remove_pm_qos(dev);
Nachiket Kukade8003d252017-03-30 15:55:58 +0530417 cds_set_fw_down(false);
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530418 probe_fail_cnt = 0;
419 re_init_fail_cnt = 0;
Nachiket Kukadebe8850b2017-09-18 15:37:00 +0530420 hdd_stop_driver_ops_timer();
Arunk Khandavalli16d84252017-06-21 15:26:29 +0530421 mutex_unlock(&hdd_init_deinit_lock);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800422 return 0;
423
Arun Khandavallifae92942016-08-01 13:31:08 +0530424
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800425err_hdd_deinit:
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530426 pr_err("probe/reinit failure counts %hhu/%hhu",
427 probe_fail_cnt, re_init_fail_cnt);
428 if (probe_fail_cnt >= SSR_MAX_FAIL_CNT ||
429 re_init_fail_cnt >= SSR_MAX_FAIL_CNT)
430 QDF_BUG(0);
431
432 if (reinit) {
433 cds_set_driver_in_bad_state(true);
Arun Khandavallifae92942016-08-01 13:31:08 +0530434 cds_set_recovery_in_progress(false);
Srinivas Girigowda576b2352017-08-25 14:44:26 -0700435 } else
Arun Khandavallifae92942016-08-01 13:31:08 +0530436 cds_set_load_in_progress(false);
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530437
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800438 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
Yuanyuan Liu13738502016-04-06 17:41:37 -0700439 hdd_remove_pm_qos(dev);
Nachiket Kukade8003d252017-03-30 15:55:58 +0530440
441 cds_set_fw_down(false);
Nachiket Kukadebe8850b2017-09-18 15:37:00 +0530442 hdd_stop_driver_ops_timer();
Arunk Khandavalli16d84252017-06-21 15:26:29 +0530443 mutex_unlock(&hdd_init_deinit_lock);
Yuanyuan Liu5583b2c2017-10-09 17:30:13 -0700444 return check_for_probe_defer(ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800445}
446
447/**
448 * wlan_hdd_remove() - wlan_hdd_remove
449 *
450 * This function is called by the platform driver to remove the
451 * driver
452 *
453 * Return: void
454 */
Yuanyuan Liu13738502016-04-06 17:41:37 -0700455static void wlan_hdd_remove(struct device *dev)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800456{
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800457 pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME,
458 QWLAN_VERSIONSTR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800459
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800460 cds_set_driver_loaded(false);
461 cds_set_unload_in_progress(true);
462
Rajeev Kumardbc886e2016-01-19 12:56:04 -0800463 if (!cds_wait_for_external_threads_completion(__func__))
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800464 hdd_warn("External threads are still active attempting driver unload anyway");
Rajeev Kumardbc886e2016-01-19 12:56:04 -0800465
Houston Hoffman371d4a92016-04-14 17:02:37 -0700466 if (QDF_IS_EPPING_ENABLED(cds_get_conparam())) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800467 epping_disable();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800468 epping_close();
469 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800470 __hdd_wlan_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800471 }
472
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530473 cds_set_driver_in_bad_state(false);
Hanumanth Reddy Pothulafc70ea32017-01-18 18:19:08 +0530474 cds_set_unload_in_progress(false);
475
Mohit Khannafa99aea2016-05-12 21:43:13 -0700476 pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477}
478
Sen, Devendra154b3c42017-02-13 20:44:15 +0530479#ifdef FEATURE_WLAN_DIAG_SUPPORT
480/**
481 * hdd_wlan_ssr_shutdown_event()- send ssr shutdown state
482 *
483 * This Function send send ssr shutdown state diag event
484 *
485 * Return: void.
486 */
487static void hdd_wlan_ssr_shutdown_event(void)
488{
489 WLAN_HOST_DIAG_EVENT_DEF(ssr_shutdown,
490 struct host_event_wlan_ssr_shutdown);
491 qdf_mem_zero(&ssr_shutdown, sizeof(ssr_shutdown));
492 ssr_shutdown.status = SSR_SUB_SYSTEM_SHUTDOWN;
493 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_shutdown,
494 EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM);
495}
496#else
497static inline void hdd_wlan_ssr_shutdown_event(void)
498{
499
500};
501#endif
502
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800503/**
Anurag Chouhan4085ff72017-10-05 18:09:56 +0530504 * hdd_send_hang_reason() - Send hang reason to the userspace
505 *
506 * Return: None
507 */
508static void hdd_send_hang_reason(void)
509{
Mahesh Kumar Kalikot Veetil9111a572017-10-10 16:11:11 -0700510 enum qdf_hang_reason reason = QDF_REASON_UNSPECIFIED;
Anurag Chouhan4085ff72017-10-05 18:09:56 +0530511 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
512
513 if (wlan_hdd_validate_context(hdd_ctx))
514 return;
515
516 cds_get_recovery_reason(&reason);
517 cds_reset_recovery_reason();
518 wlan_hdd_send_hang_reason_event(hdd_ctx, reason);
519}
520
521/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800522 * wlan_hdd_shutdown() - wlan_hdd_shutdown
523 *
524 * This is routine is called by platform driver to shutdown the
525 * driver
526 *
527 * Return: void
528 */
529static void wlan_hdd_shutdown(void)
530{
Anurag Chouhan6d760662016-02-20 16:05:43 +0530531 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532
Dustin Browncd601322017-03-28 14:18:46 -0700533 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
534 hdd_err("Crash recovery is not allowed in FTM mode");
535 QDF_BUG(0);
536 return;
537 }
538
bings5f0ae142017-07-14 17:52:45 +0800539 if (!hif_ctx) {
540 hdd_err("Failed to get HIF context, ignore SSR shutdown");
541 return;
542 }
543 /* mask the host controller interrupts */
544 hif_mask_interrupt_call(hif_ctx);
545
Rajeev Kumarfec3dbe2016-01-19 15:23:52 -0800546 if (cds_is_load_or_unload_in_progress()) {
Jeff Johnsonbd561a92016-01-07 18:31:35 -0800547 hdd_err("Load/unload in progress, ignore SSR shutdown");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800548 return;
549 }
Yuanyuan Liu13738502016-04-06 17:41:37 -0700550 /* this is for cases, where shutdown invoked from platform */
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800551 cds_set_recovery_in_progress(true);
Sen, Devendra154b3c42017-02-13 20:44:15 +0530552 hdd_wlan_ssr_shutdown_event();
Anurag Chouhan4085ff72017-10-05 18:09:56 +0530553 hdd_send_hang_reason();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800554
Rajeev Kumardbc886e2016-01-19 12:56:04 -0800555 if (!cds_wait_for_external_threads_completion(__func__))
Jeff Johnsonbd561a92016-01-07 18:31:35 -0800556 hdd_err("Host is not ready for SSR, attempting anyway");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800557
Houston Hoffman371d4a92016-04-14 17:02:37 -0700558 if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) {
bings5f0ae142017-07-14 17:52:45 +0800559 hif_disable_isr(hif_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800560 hdd_wlan_shutdown();
Yue Macd961442015-10-20 16:15:31 -0700561 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800562}
563
564/**
565 * wlan_hdd_crash_shutdown() - wlan_hdd_crash_shutdown
566 *
567 * HDD crash shutdown funtion: This function is called by
568 * platfrom driver's crash shutdown routine
569 *
570 * Return: void
571 */
Jeff Johnson7782cb92016-10-05 14:22:40 -0700572static void wlan_hdd_crash_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800573{
Yu Wang46082dc2017-09-19 12:25:38 +0800574 QDF_STATUS ret;
575 WMA_HANDLE wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
576
577 if (!wma_handle) {
578 hdd_err("wma_handle is null");
579 return;
580 }
581
582 /*
583 * When kernel panic happen, if WiFi FW is still active
584 * it may cause NOC errors/memory corruption, to avoid
585 * this, inject a fw crash first.
586 * send crash_inject to FW directly, because we are now
587 * in an atomic context, and preempt has been disabled,
588 * MCThread won't be scheduled at the moment, at the same
589 * time, TargetFailure event wont't be received after inject
590 * crash due to the same reason.
591 */
592 ret = wma_crash_inject(wma_handle, RECOVERY_SIM_ASSERT, 0);
593 if (QDF_IS_STATUS_ERROR(ret)) {
594 hdd_err("Failed to send crash inject:%d", ret);
595 return;
596 }
597
Anurag Chouhan6d760662016-02-20 16:05:43 +0530598 hif_crash_shutdown(cds_get_context(QDF_MODULE_ID_HIF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800599}
600
601/**
602 * wlan_hdd_notify_handler() - wlan_hdd_notify_handler
603 *
604 * This function is called by the platform driver to notify the
605 * COEX
606 *
607 * @state: state
608 *
609 * Return: void
610 */
Jeff Johnson7782cb92016-10-05 14:22:40 -0700611static void wlan_hdd_notify_handler(int state)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800612{
Houston Hoffman371d4a92016-04-14 17:02:37 -0700613 if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) {
Jeff Johnson10251bc2017-03-24 15:30:52 -0700614 int ret;
615
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616 ret = hdd_wlan_notify_modem_power_state(state);
617 if (ret < 0)
Jeff Johnsonbd561a92016-01-07 18:31:35 -0800618 hdd_err("Fail to send notify");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800619 }
620}
621
Dustin Brown9ef609b2017-03-15 12:19:37 -0700622static int hdd_to_pmo_interface_pause(enum wow_interface_pause hdd_pause,
623 enum pmo_wow_interface_pause *pmo_pause)
624{
625 switch (hdd_pause) {
626 case WOW_INTERFACE_PAUSE_DEFAULT:
627 *pmo_pause = PMO_WOW_INTERFACE_PAUSE_DEFAULT;
628 break;
629 case WOW_INTERFACE_PAUSE_ENABLE:
630 *pmo_pause = PMO_WOW_INTERFACE_PAUSE_ENABLE;
631 break;
632 case WOW_INTERFACE_PAUSE_DISABLE:
633 *pmo_pause = PMO_WOW_INTERFACE_PAUSE_DISABLE;
634 break;
635 default:
636 hdd_err("Invalid interface pause: %d", hdd_pause);
637 return -EINVAL;
638 }
639
640 return 0;
641}
642
643static int hdd_to_pmo_resume_trigger(enum wow_resume_trigger hdd_trigger,
644 enum pmo_wow_resume_trigger *pmo_trigger)
645{
646 switch (hdd_trigger) {
647 case WOW_RESUME_TRIGGER_DEFAULT:
648 *pmo_trigger = PMO_WOW_RESUME_TRIGGER_DEFAULT;
649 break;
650 case WOW_RESUME_TRIGGER_HTC_WAKEUP:
651 *pmo_trigger = PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP;
652 break;
653 case WOW_RESUME_TRIGGER_GPIO:
654 *pmo_trigger = PMO_WOW_RESUME_TRIGGER_GPIO;
655 break;
656 default:
657 hdd_err("Invalid resume trigger: %d", hdd_trigger);
658 return -EINVAL;
659 }
660
661 return 0;
662}
663
664static int
665hdd_to_pmo_wow_enable_params(struct wow_enable_params *in_params,
666 struct pmo_wow_enable_params *out_params)
667{
668 int err;
669
670 /* unit-test suspend */
671 out_params->is_unit_test = in_params->is_unit_test;
672
673 /* interface pause */
674 err = hdd_to_pmo_interface_pause(in_params->interface_pause,
675 &out_params->interface_pause);
676 if (err)
677 return err;
678
679 /* resume trigger */
680 err = hdd_to_pmo_resume_trigger(in_params->resume_trigger,
681 &out_params->resume_trigger);
682 if (err)
683 return err;
684
685 return 0;
686}
687
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800688/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800689 * __wlan_hdd_bus_suspend() - handles platform supsend
Dustin Brown54096432017-02-23 13:00:44 -0800690 * @wow_params: collection of wow enable override parameters
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800691 *
692 * Does precondtion validation. Ensures that a subsystem restart isn't in
Dustin Brown9ef609b2017-03-15 12:19:37 -0700693 * progress. Ensures that no load or unload is in progress. Does:
694 * data path suspend
695 * component (pmo) suspend
696 * hif (bus) suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800697 *
698 * Return: 0 for success, -EFAULT for null pointers,
699 * -EBUSY or -EAGAIN if another opperation is in progress and
700 * wlan will not be ready to suspend in time.
701 */
Dustin Brown9ef609b2017-03-15 12:19:37 -0700702static int __wlan_hdd_bus_suspend(struct wow_enable_params wow_params)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800703{
Dustin Brown562b9672016-12-22 15:25:33 -0800704 int err;
Dustin Brown9ef609b2017-03-15 12:19:37 -0700705 QDF_STATUS status;
Jeff Johnson6bc79d82017-08-28 12:02:36 -0700706 struct hdd_context *hdd_ctx;
Dustin Brown9ef609b2017-03-15 12:19:37 -0700707 void *hif_ctx;
Dustin Brown7ff24dd2017-05-10 15:49:59 -0700708 void *dp_soc;
709 void *dp_pdev;
Dustin Brown9ef609b2017-03-15 12:19:37 -0700710 struct pmo_wow_enable_params pmo_params;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800711
Rajeev Kumarb0ef9822017-12-15 18:14:43 -0800712 hdd_info("starting bus suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800713
Dustin Brown9ef609b2017-03-15 12:19:37 -0700714 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Dustin Brown562b9672016-12-22 15:25:33 -0800715 err = wlan_hdd_validate_context(hdd_ctx);
716 if (err) {
Dustin Brown9ef609b2017-03-15 12:19:37 -0700717 hdd_err("Invalid hdd context: %d", err);
718 return err;
Dustin Brown562b9672016-12-22 15:25:33 -0800719 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800720
Rajeev Kumar99805a72016-08-29 13:53:52 -0700721 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800722 hdd_debug("Driver Module closed; skipping suspend");
Rajeev Kumar99805a72016-08-29 13:53:52 -0700723 return 0;
724 }
725
SaidiReddy Yenugad8323662016-07-20 15:45:34 +0530726 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Dustin Brown9ef609b2017-03-15 12:19:37 -0700727 if (!hif_ctx) {
Dustin Brown562b9672016-12-22 15:25:33 -0800728 hdd_err("Failed to get hif context");
Dustin Brown9ef609b2017-03-15 12:19:37 -0700729 return -EINVAL;
SaidiReddy Yenugad8323662016-07-20 15:45:34 +0530730 }
Arun Khandavallifae92942016-08-01 13:31:08 +0530731
Dustin Brown9ef609b2017-03-15 12:19:37 -0700732 err = hdd_to_pmo_wow_enable_params(&wow_params, &pmo_params);
733 if (err) {
734 hdd_err("Invalid WoW enable parameters: %d", err);
735 return err;
736 }
737
Dustin Brown7ff24dd2017-05-10 15:49:59 -0700738 dp_soc = cds_get_context(QDF_MODULE_ID_SOC);
739 dp_pdev = cds_get_context(QDF_MODULE_ID_TXRX);
740 err = qdf_status_to_os_return(cdp_bus_suspend(dp_soc, dp_pdev));
Dustin Brown562b9672016-12-22 15:25:33 -0800741 if (err) {
Dustin Brown9ef609b2017-03-15 12:19:37 -0700742 hdd_err("Failed cdp bus suspend: %d", err);
743 return err;
Dustin Brown562b9672016-12-22 15:25:33 -0800744 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745
Houston Hoffmane5cd52c2017-02-08 17:48:57 -0800746 err = hif_bus_early_suspend(hif_ctx);
747 if (err) {
748 hdd_err("Failed hif bus early suspend");
749 goto resume_cdp;
750 }
751
Dustin Brown9ef609b2017-03-15 12:19:37 -0700752 status = pmo_ucfg_psoc_bus_suspend_req(hdd_ctx->hdd_psoc,
753 QDF_SYSTEM_SUSPEND,
754 &pmo_params);
755 err = qdf_status_to_os_return(status);
Dustin Brown562b9672016-12-22 15:25:33 -0800756 if (err) {
Dustin Brown9ef609b2017-03-15 12:19:37 -0700757 hdd_err("Failed pmo bus suspend: %d", status);
Houston Hoffmane5cd52c2017-02-08 17:48:57 -0800758 goto late_hif_resume;
Dustin Brown562b9672016-12-22 15:25:33 -0800759 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800760
Komal Seelamc12e6752016-02-02 18:17:13 +0530761 err = hif_bus_suspend(hif_ctx);
Dustin Brown562b9672016-12-22 15:25:33 -0800762 if (err) {
Dustin Brown9ef609b2017-03-15 12:19:37 -0700763 hdd_err("Failed hif bus suspend: %d", err);
764 goto resume_pmo;
Dustin Brown562b9672016-12-22 15:25:33 -0800765 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800766
Rajeev Kumarb0ef9822017-12-15 18:14:43 -0800767 hdd_info("bus suspend succeeded");
Dustin Brown2d228232016-09-22 15:06:19 -0700768 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800769
Dustin Brown9ef609b2017-03-15 12:19:37 -0700770resume_pmo:
771 status = pmo_ucfg_psoc_bus_resume_req(hdd_ctx->hdd_psoc,
772 QDF_SYSTEM_SUSPEND);
773 QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
774
Houston Hoffmane5cd52c2017-02-08 17:48:57 -0800775late_hif_resume:
776 status = hif_bus_late_resume(hif_ctx);
777 QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
778
Dustin Brown9ef609b2017-03-15 12:19:37 -0700779resume_cdp:
Dustin Brown7ff24dd2017-05-10 15:49:59 -0700780 status = cdp_bus_resume(dp_soc, dp_pdev);
Dustin Brown9ef609b2017-03-15 12:19:37 -0700781 QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
782
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800783 return err;
784}
785
Dustin Brown9ef609b2017-03-15 12:19:37 -0700786int wlan_hdd_bus_suspend(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787{
788 int ret;
Dustin Brown54096432017-02-23 13:00:44 -0800789 struct wow_enable_params default_params = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800790
791 cds_ssr_protect(__func__);
Dustin Brown9ef609b2017-03-15 12:19:37 -0700792 ret = __wlan_hdd_bus_suspend(default_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 cds_ssr_unprotect(__func__);
794
795 return ret;
796}
797
Dustin Browne70fd972016-11-10 11:17:40 -0800798#ifdef WLAN_SUSPEND_RESUME_TEST
Dustin Brown9ef609b2017-03-15 12:19:37 -0700799int wlan_hdd_unit_test_bus_suspend(struct wow_enable_params wow_params)
Dustin Browne70fd972016-11-10 11:17:40 -0800800{
801 int ret;
802
803 cds_ssr_protect(__func__);
Dustin Brown9ef609b2017-03-15 12:19:37 -0700804 ret = __wlan_hdd_bus_suspend(wow_params);
Dustin Browne70fd972016-11-10 11:17:40 -0800805 cds_ssr_unprotect(__func__);
806
807 return ret;
808}
809#endif
810
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811/**
Rajeev Kumar99805a72016-08-29 13:53:52 -0700812 * __wlan_hdd_bus_suspend_noirq() - handle .suspend_noirq callback
813 *
814 * This function is called by the platform driver to complete the
815 * bus suspend callback when device interrupts are disabled by kernel.
816 * Call HIF and WMA suspend_noirq callbacks to make sure there is no
817 * wake up pending from FW before allowing suspend.
818 *
819 * Return: 0 for success and -EBUSY if FW is requesting wake up
820 */
Jeff Johnson7782cb92016-10-05 14:22:40 -0700821static int __wlan_hdd_bus_suspend_noirq(void)
Rajeev Kumar99805a72016-08-29 13:53:52 -0700822{
Jeff Johnson6bc79d82017-08-28 12:02:36 -0700823 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Rajeev Kumar99805a72016-08-29 13:53:52 -0700824 void *hif_ctx;
Dustin Brown05557182017-10-12 14:44:49 -0700825 int errno;
826 uint32_t pending_events;
Rajeev Kumar99805a72016-08-29 13:53:52 -0700827
Rajeev Kumarb0ef9822017-12-15 18:14:43 -0800828 hdd_info("start bus_suspend_noirq");
Dustin Brown05557182017-10-12 14:44:49 -0700829 errno = wlan_hdd_validate_context(hdd_ctx);
830 if (errno) {
831 hdd_err("Invalid HDD context: errno %d", errno);
832 return errno;
Rajeev Kumar99805a72016-08-29 13:53:52 -0700833 }
834
835 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
Dustin Brown05557182017-10-12 14:44:49 -0700836 hdd_debug("Driver module closed; skip bus-noirq suspend");
Rajeev Kumar99805a72016-08-29 13:53:52 -0700837 return 0;
838 }
839
840 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Dustin Brown05557182017-10-12 14:44:49 -0700841 if (!hif_ctx) {
842 hdd_err("hif_ctx is null");
843 return -EINVAL;
Rajeev Kumar99805a72016-08-29 13:53:52 -0700844 }
845
Dustin Brown05557182017-10-12 14:44:49 -0700846 errno = hif_bus_suspend_noirq(hif_ctx);
847 if (errno)
Rajeev Kumar99805a72016-08-29 13:53:52 -0700848 goto done;
849
Dustin Brown05557182017-10-12 14:44:49 -0700850 errno = pmo_ucfg_psoc_is_target_wake_up_received(hdd_ctx->hdd_psoc);
851 if (errno == -EAGAIN) {
852 hdd_err("Firmware attempting wakeup, try again");
853 wlan_hdd_inc_suspend_stats(hdd_ctx,
854 SUSPEND_FAIL_INITIAL_WAKEUP);
855 }
856 if (errno)
Rajeev Kumar99805a72016-08-29 13:53:52 -0700857 goto resume_hif_noirq;
858
Dustin Brown05557182017-10-12 14:44:49 -0700859 pending_events = wma_critical_events_in_flight();
860 if (pending_events) {
861 hdd_err("%d critical event(s) in flight; try again",
862 pending_events);
863 errno = -EAGAIN;
864 goto resume_hif_noirq;
865 }
866
Dustin Brownd9322482017-01-09 12:46:03 -0800867 hdd_ctx->suspend_resume_stats.suspends++;
868
Rajeev Kumarb0ef9822017-12-15 18:14:43 -0800869 hdd_info("bus_suspend_noirq done");
Dustin Brown2d228232016-09-22 15:06:19 -0700870 return 0;
Rajeev Kumar99805a72016-08-29 13:53:52 -0700871
872resume_hif_noirq:
Dustin Brown05557182017-10-12 14:44:49 -0700873 QDF_BUG(!hif_bus_resume_noirq(hif_ctx));
Dustin Brown105d7902016-10-03 16:27:59 -0700874
Dustin Brown05557182017-10-12 14:44:49 -0700875done:
876 hdd_err("suspend_noirq failed, status: %d", errno);
877
878 return errno;
Rajeev Kumar99805a72016-08-29 13:53:52 -0700879}
880
Rajeev Kumar99805a72016-08-29 13:53:52 -0700881int wlan_hdd_bus_suspend_noirq(void)
882{
883 int ret;
884
885 cds_ssr_protect(__func__);
886 ret = __wlan_hdd_bus_suspend_noirq();
887 cds_ssr_unprotect(__func__);
888
889 return ret;
890}
891
892/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800893 * __wlan_hdd_bus_resume() - handles platform resume
894 *
895 * Does precondtion validation. Ensures that a subsystem restart isn't in
896 * progress. Ensures that no load or unload is in progress. Ensures that
897 * it has valid pointers for the required contexts.
898 * Calls into hif to resume the bus opperation.
899 * Calls into wma to handshake with firmware and notify it that the bus is up.
900 * Calls into ol_txrx for symetry.
901 * Failures are treated as catastrophic.
902 *
903 * return: error code or 0 for success
904 */
905static int __wlan_hdd_bus_resume(void)
906{
Jeff Johnson6bc79d82017-08-28 12:02:36 -0700907 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
SaidiReddy Yenugad8323662016-07-20 15:45:34 +0530908 void *hif_ctx;
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700909 int status;
910 QDF_STATUS qdf_status;
Dustin Brown7ff24dd2017-05-10 15:49:59 -0700911 void *dp_soc;
912 void *dp_pdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800913
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700914 if (cds_is_driver_recovering())
915 return 0;
916
Rajeev Kumarb0ef9822017-12-15 18:14:43 -0800917 hdd_info("starting bus resume");
Dustin Brown562b9672016-12-22 15:25:33 -0800918
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700919 status = wlan_hdd_validate_context(hdd_ctx);
Dustin Brown562b9672016-12-22 15:25:33 -0800920 if (status) {
921 hdd_err("Invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922 return status;
Dustin Brown562b9672016-12-22 15:25:33 -0800923 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924
Arun Khandavallifae92942016-08-01 13:31:08 +0530925 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800926 hdd_debug("Driver Module closed; return success");
Arun Khandavallifae92942016-08-01 13:31:08 +0530927 return 0;
928 }
929
SaidiReddy Yenugad8323662016-07-20 15:45:34 +0530930 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Dustin Brown562b9672016-12-22 15:25:33 -0800931 if (NULL == hif_ctx) {
932 hdd_err("Failed to get hif context");
SaidiReddy Yenugad8323662016-07-20 15:45:34 +0530933 return -EINVAL;
Dustin Brown562b9672016-12-22 15:25:33 -0800934 }
SaidiReddy Yenugad8323662016-07-20 15:45:34 +0530935
Komal Seelamc12e6752016-02-02 18:17:13 +0530936 status = hif_bus_resume(hif_ctx);
Dustin Brown562b9672016-12-22 15:25:33 -0800937 if (status) {
938 hdd_err("Failed hif bus resume");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700939 goto out;
Dustin Brown562b9672016-12-22 15:25:33 -0800940 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941
Mukul Sharma4c60a7e2017-03-06 19:42:18 +0530942 qdf_status = pmo_ucfg_psoc_bus_resume_req(hdd_ctx->hdd_psoc,
943 QDF_SYSTEM_SUSPEND);
944 status = qdf_status_to_os_return(qdf_status);
Dustin Brown562b9672016-12-22 15:25:33 -0800945 if (status) {
Dustin Brown05557182017-10-12 14:44:49 -0700946 hdd_err("Failed pmo bus resume");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700947 goto out;
Dustin Brown562b9672016-12-22 15:25:33 -0800948 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949
Houston Hoffmane5cd52c2017-02-08 17:48:57 -0800950 status = hif_bus_late_resume(hif_ctx);
951 if (status) {
952 hdd_err("Failed hif bus late resume");
953 goto out;
954 }
955
Dustin Brown7ff24dd2017-05-10 15:49:59 -0700956 dp_soc = cds_get_context(QDF_MODULE_ID_SOC);
957 dp_pdev = cds_get_context(QDF_MODULE_ID_TXRX);
958 qdf_status = cdp_bus_resume(dp_soc, dp_pdev);
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700959 status = qdf_status_to_os_return(qdf_status);
Dustin Brown562b9672016-12-22 15:25:33 -0800960 if (status) {
961 hdd_err("Failed cdp bus resume");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700962 goto out;
Dustin Brown562b9672016-12-22 15:25:33 -0800963 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964
Rajeev Kumarb0ef9822017-12-15 18:14:43 -0800965 hdd_info("bus resume succeeded");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700966 return 0;
967
968out:
Rajeev Kumar10466012018-01-24 14:12:20 -0800969 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() ||
970 cds_is_fw_down())
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -0700971 return 0;
972
973 QDF_BUG(false);
974
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800975 return status;
976}
977
Rajeev Kumara78a0a42016-07-13 19:28:20 -0700978int wlan_hdd_bus_resume(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979{
980 int ret;
981
982 cds_ssr_protect(__func__);
983 ret = __wlan_hdd_bus_resume();
984 cds_ssr_unprotect(__func__);
985
986 return ret;
987}
988
Mohit Khannafa99aea2016-05-12 21:43:13 -0700989/**
Rajeev Kumar99805a72016-08-29 13:53:52 -0700990 * __wlan_hdd_bus_resume_noirq(): handle bus resume no irq
991 *
992 * This function is called by the platform driver to do bus
993 * resume no IRQ before calling resume callback. Call WMA and HIF
994 * layers to complete the resume_noirq.
995 *
996 * Return: 0 for success and negative error code for failure
997 */
Jeff Johnson7782cb92016-10-05 14:22:40 -0700998static int __wlan_hdd_bus_resume_noirq(void)
Rajeev Kumar99805a72016-08-29 13:53:52 -0700999{
Jeff Johnson6bc79d82017-08-28 12:02:36 -07001000 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Rajeev Kumar99805a72016-08-29 13:53:52 -07001001 void *hif_ctx;
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001002 int status;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301003 QDF_STATUS qdf_status;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001004
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001005 hdd_info("starting bus_resume_noirq");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001006 if (cds_is_driver_recovering())
1007 return 0;
1008
1009 status = wlan_hdd_validate_context(hdd_ctx);
Rajeev Kumar99805a72016-08-29 13:53:52 -07001010 if (status) {
1011 hdd_err("Invalid HDD context: %d", status);
1012 return status;
1013 }
1014
1015 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -08001016 hdd_debug("Driver Module closed return success");
Rajeev Kumar99805a72016-08-29 13:53:52 -07001017 return 0;
1018 }
1019
1020 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
1021 if (NULL == hif_ctx)
1022 return -EINVAL;
1023
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301024 qdf_status = pmo_ucfg_psoc_clear_target_wake_up(hdd_ctx->hdd_psoc);
1025 QDF_BUG(!qdf_status);
Rajeev Kumar99805a72016-08-29 13:53:52 -07001026
1027 status = hif_bus_resume_noirq(hif_ctx);
1028 QDF_BUG(!status);
1029
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001030 hdd_info("bus_resume_noirq done");
Rajeev Kumar99805a72016-08-29 13:53:52 -07001031 return status;
1032}
1033
Rajeev Kumar99805a72016-08-29 13:53:52 -07001034int wlan_hdd_bus_resume_noirq(void)
1035{
1036 int ret;
1037
1038 cds_ssr_protect(__func__);
1039 ret = __wlan_hdd_bus_resume_noirq();
1040 cds_ssr_unprotect(__func__);
1041
1042 return ret;
1043}
1044
1045/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07001046 * wlan_hdd_bus_reset_resume() - resume wlan bus after reset
1047 *
1048 * This function is called to tell the driver that the device has been resumed
1049 * and it has also been reset. The driver should redo any necessary
1050 * initialization. It is mainly used by the USB bus
1051 *
1052 * Return: int 0 for success, non zero for failure
1053 */
1054static int wlan_hdd_bus_reset_resume(void)
1055{
1056 int ret;
Anurag Chouhance6a4052016-09-14 18:20:42 +05301057 struct hif_opaque_softc *scn = NULL;
1058
1059 scn = cds_get_context(QDF_MODULE_ID_HIF);
1060 if (!scn) {
1061 hdd_err("Failed to get HIF context");
1062 return -EFAULT;
1063 }
Mohit Khannafa99aea2016-05-12 21:43:13 -07001064
1065 cds_ssr_protect(__func__);
Anurag Chouhance6a4052016-09-14 18:20:42 +05301066 ret = hif_bus_reset_resume(scn);
Mohit Khannafa99aea2016-05-12 21:43:13 -07001067 cds_ssr_unprotect(__func__);
1068 return ret;
1069}
1070
Houston Hoffmane8937082015-11-10 16:49:12 -08001071#ifdef FEATURE_RUNTIME_PM
Houston Hoffmane8937082015-11-10 16:49:12 -08001072/**
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301073 * hdd_pld_runtime_suspend_cb() - Runtime suspend callback from PMO
1074 *
1075 * Return: 0 on success or error value otherwise
1076 */
1077static int hdd_pld_runtime_suspend_cb(void)
1078{
1079 qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
1080
1081 if (!qdf_dev) {
1082 hdd_err("Invalid context");
1083 return -EINVAL;
1084 }
1085
1086 return pld_auto_suspend(qdf_dev->dev);
1087}
1088
1089/**
Houston Hoffmane8937082015-11-10 16:49:12 -08001090 * __wlan_hdd_runtime_suspend() - suspend the wlan bus without apps suspend
1091 *
1092 * Each layer is responsible for its own suspend actions. wma_runtime_suspend
1093 * takes care of the parts of the 802.11 suspend that we want to do for runtime
1094 * suspend.
1095 *
1096 * Return: 0 or errno
1097 */
Yuanyuan Liu13738502016-04-06 17:41:37 -07001098static int __wlan_hdd_runtime_suspend(struct device *dev)
Houston Hoffmane8937082015-11-10 16:49:12 -08001099{
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301100 int err;
1101 QDF_STATUS status;
Jeff Johnson6bc79d82017-08-28 12:02:36 -07001102 struct hdd_context *hdd_ctx;
Houston Hoffmane8937082015-11-10 16:49:12 -08001103
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301104 hdd_debug("Starting runtime suspend");
Houston Hoffmane8937082015-11-10 16:49:12 -08001105
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301106 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1107 err = wlan_hdd_validate_context(hdd_ctx);
1108 if (err)
1109 return err;
Houston Hoffmane8937082015-11-10 16:49:12 -08001110
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301111 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1112 hdd_debug("Driver module closed skipping runtime suspend");
1113 return 0;
1114 }
Houston Hoffmane8937082015-11-10 16:49:12 -08001115
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301116 if (ucfg_scan_get_pdev_status(hdd_ctx->hdd_pdev) !=
1117 SCAN_NOT_IN_PROGRESS) {
1118 hdd_debug("Scan in progress, ignore runtime suspend");
1119 return -EBUSY;
1120 }
Yue Ma1e11d792016-02-26 18:58:44 -08001121
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301122 status = pmo_ucfg_psoc_bus_runtime_suspend(hdd_ctx->hdd_psoc,
1123 hdd_pld_runtime_suspend_cb);
1124 err = qdf_status_to_os_return(status);
Houston Hoffmane8937082015-11-10 16:49:12 -08001125
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301126 hdd_debug("Runtime suspend done result: %d", err);
Houston Hoffmane8937082015-11-10 16:49:12 -08001127
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301128 return err;
Houston Hoffmane8937082015-11-10 16:49:12 -08001129}
1130
Houston Hoffmane8937082015-11-10 16:49:12 -08001131/**
1132 * wlan_hdd_runtime_suspend() - suspend the wlan bus without apps suspend
1133 *
1134 * This function is called by the platform driver to suspend the
1135 * wlan bus separately from system suspend
1136 *
1137 * Return: 0 or errno
1138 */
Yuanyuan Liu13738502016-04-06 17:41:37 -07001139static int wlan_hdd_runtime_suspend(struct device *dev)
Houston Hoffmane8937082015-11-10 16:49:12 -08001140{
1141 int ret;
1142
1143 cds_ssr_protect(__func__);
Yuanyuan Liu13738502016-04-06 17:41:37 -07001144 ret = __wlan_hdd_runtime_suspend(dev);
Houston Hoffmane8937082015-11-10 16:49:12 -08001145 cds_ssr_unprotect(__func__);
1146
1147 return ret;
1148}
1149
1150/**
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301151 * hdd_pld_runtime_resume_cb() - Runtime resume callback from PMO
1152 *
1153 * Return: 0 on success or error value otherwise
1154 */
1155static int hdd_pld_runtime_resume_cb(void)
1156{
1157 qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
1158
1159 if (!qdf_dev) {
1160 hdd_err("Invalid context");
1161 return -EINVAL;
1162 }
1163
1164 return pld_auto_resume(qdf_dev->dev);
1165}
1166
1167/**
Houston Hoffmane8937082015-11-10 16:49:12 -08001168 * __wlan_hdd_runtime_resume() - resume the wlan bus from runtime suspend
1169 *
1170 * Sets the runtime pm state and coordinates resume between hif wma and
1171 * ol_txrx.
1172 *
1173 * Return: success since failure is a bug
1174 */
Yuanyuan Liu13738502016-04-06 17:41:37 -07001175static int __wlan_hdd_runtime_resume(struct device *dev)
Houston Hoffmane8937082015-11-10 16:49:12 -08001176{
Jeff Johnson6bc79d82017-08-28 12:02:36 -07001177 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301178 QDF_STATUS status;
Komal Seelamc12e6752016-02-02 18:17:13 +05301179
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301180 hdd_debug("Starting runtime resume");
1181
1182 if (wlan_hdd_validate_context(hdd_ctx))
1183 return 0;
1184
1185 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1186 hdd_debug("Driver module closed skipping runtime resume");
1187 return 0;
1188 }
1189
1190 status = pmo_ucfg_psoc_bus_runtime_resume(hdd_ctx->hdd_psoc,
1191 hdd_pld_runtime_resume_cb);
1192 if (status != QDF_STATUS_SUCCESS)
1193 hdd_err("PMO Runtime resume failed: %d", status);
1194
1195 hdd_debug("Runtime resume done");
1196
Houston Hoffmane8937082015-11-10 16:49:12 -08001197 return 0;
1198}
1199
1200/**
1201 * wlan_hdd_runtime_resume() - resume the wlan bus from runtime suspend
1202 *
1203 * This function is called by the platform driver to resume the
1204 * wlan bus separately from system suspend
1205 *
1206 * Return: success since failure is a bug
1207 */
Yuanyuan Liu13738502016-04-06 17:41:37 -07001208static int wlan_hdd_runtime_resume(struct device *dev)
Houston Hoffmane8937082015-11-10 16:49:12 -08001209{
1210 int ret;
1211
1212 cds_ssr_protect(__func__);
Yuanyuan Liu13738502016-04-06 17:41:37 -07001213 ret = __wlan_hdd_runtime_resume(dev);
Houston Hoffmane8937082015-11-10 16:49:12 -08001214 cds_ssr_unprotect(__func__);
1215
1216 return ret;
1217}
1218#endif
1219
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001220/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001221 * wlan_hdd_pld_probe() - probe function registered to PLD
1222 * @dev: device
1223 * @pld_bus_type: PLD bus type
1224 * @bdev: bus device structure
1225 * @id: bus identifier for shared busses
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001226 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001227 * Return: 0 on success
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001228 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001229static int wlan_hdd_pld_probe(struct device *dev,
1230 enum pld_bus_type pld_bus_type,
1231 void *bdev, void *id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232{
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001233 enum qdf_bus_type bus_type;
1234
1235 bus_type = to_bus_type(pld_bus_type);
1236 if (bus_type == QDF_BUS_TYPE_NONE) {
1237 hdd_err("Invalid bus type %d->%d",
1238 pld_bus_type, bus_type);
1239 return -EINVAL;
1240 }
1241
1242 return wlan_hdd_probe(dev, bdev, id, bus_type, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001243}
1244
1245/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001246 * wlan_hdd_pld_remove() - remove function registered to PLD
1247 * @dev: device
1248 * @pld_bus_type: PLD bus type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249 *
1250 * Return: void
1251 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001252static void wlan_hdd_pld_remove(struct device *dev,
1253 enum pld_bus_type bus_type)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254{
Arunk Khandavalli16d84252017-06-21 15:26:29 +05301255 ENTER();
1256 mutex_lock(&hdd_init_deinit_lock);
Nachiket Kukadebe8850b2017-09-18 15:37:00 +05301257 hdd_start_driver_ops_timer(eHDD_DRV_OP_REMOVE);
1258
Yuanyuan Liu13738502016-04-06 17:41:37 -07001259 wlan_hdd_remove(dev);
Nachiket Kukadebe8850b2017-09-18 15:37:00 +05301260
1261 hdd_stop_driver_ops_timer();
Arunk Khandavalli16d84252017-06-21 15:26:29 +05301262 mutex_unlock(&hdd_init_deinit_lock);
1263 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001264}
1265
1266/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001267 * wlan_hdd_pld_shutdown() - shutdown function registered to PLD
1268 * @dev: device
1269 * @pld_bus_type: PLD bus type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001270 *
1271 * Return: void
1272 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001273static void wlan_hdd_pld_shutdown(struct device *dev,
1274 enum pld_bus_type bus_type)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001275{
Arunk Khandavalli16d84252017-06-21 15:26:29 +05301276 ENTER();
1277 mutex_lock(&hdd_init_deinit_lock);
Nachiket Kukadebe8850b2017-09-18 15:37:00 +05301278 hdd_start_driver_ops_timer(eHDD_DRV_OP_SHUTDOWN);
1279
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001280 wlan_hdd_shutdown();
Nachiket Kukadebe8850b2017-09-18 15:37:00 +05301281
1282 hdd_stop_driver_ops_timer();
Arunk Khandavalli16d84252017-06-21 15:26:29 +05301283 mutex_unlock(&hdd_init_deinit_lock);
1284 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285}
1286
1287/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001288 * wlan_hdd_pld_reinit() - reinit function registered to PLD
1289 * @dev: device
1290 * @pld_bus_type: PLD bus type
1291 * @bdev: bus device structure
1292 * @id: bus identifier for shared busses
1293 *
1294 * Return: 0 on success
1295 */
1296static int wlan_hdd_pld_reinit(struct device *dev,
1297 enum pld_bus_type pld_bus_type,
1298 void *bdev, void *id)
1299{
1300 enum qdf_bus_type bus_type;
1301
1302 bus_type = to_bus_type(pld_bus_type);
1303 if (bus_type == QDF_BUS_TYPE_NONE) {
1304 hdd_err("Invalid bus type %d->%d",
1305 pld_bus_type, bus_type);
1306 return -EINVAL;
1307 }
1308
1309 return wlan_hdd_probe(dev, bdev, id, bus_type, true);
1310}
1311
1312/**
1313 * wlan_hdd_pld_crash_shutdown() - crash_shutdown function registered to PLD
1314 * @dev: device
1315 * @pld_bus_type: PLD bus type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001316 *
1317 * Return: void
1318 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001319static void wlan_hdd_pld_crash_shutdown(struct device *dev,
1320 enum pld_bus_type bus_type)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001321{
1322 wlan_hdd_crash_shutdown();
1323}
1324
1325/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001326 * wlan_hdd_pld_suspend() - suspend function registered to PLD
1327 * @dev: device
1328 * @pld_bus_type: PLD bus type
1329 * @state: PM state
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001330 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001331 * Return: 0 on success
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001333static int wlan_hdd_pld_suspend(struct device *dev,
Dustin Brown9ef609b2017-03-15 12:19:37 -07001334 enum pld_bus_type bus_type,
1335 pm_message_t state)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001336
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001337{
Dustin Brown9ef609b2017-03-15 12:19:37 -07001338 return wlan_hdd_bus_suspend();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001339}
1340
1341/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001342 * wlan_hdd_pld_resume() - resume function registered to PLD
1343 * @dev: device
1344 * @pld_bus_type: PLD bus type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001345 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001346 * Return: 0 on success
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001347 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001348static int wlan_hdd_pld_resume(struct device *dev,
1349 enum pld_bus_type bus_type)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001350{
1351 return wlan_hdd_bus_resume();
1352}
Houston Hoffmane8937082015-11-10 16:49:12 -08001353
Rajeev Kumar99805a72016-08-29 13:53:52 -07001354
1355/**
1356 * wlan_hdd_pld_suspend_noirq() - handle suspend no irq
1357 * @dev: device
1358 * @pld_bus_type: PLD bus type
1359 *
1360 * Complete the actions started by suspend(). Carry out any
1361 * additional operations required for suspending the device that might be
1362 * racing with its driver's interrupt handler, which is guaranteed not to
1363 * run while suspend_noirq() is being executed. Make sure to resume device
1364 * if FW has sent initial wake up message and expecting APPS to wake up.
1365 *
1366 * Return: 0 on success
1367 */
1368static int wlan_hdd_pld_suspend_noirq(struct device *dev,
1369 enum pld_bus_type bus_type)
1370{
1371 return wlan_hdd_bus_suspend_noirq();
1372}
1373
1374/**
1375 * wlan_hdd_pld_resume_noirq() - handle resume no irq
1376 * @dev: device
1377 * @pld_bus_type: PLD bus type
1378 *
1379 * Prepare for the execution of resume() by carrying out any
1380 * operations required for resuming the device that might be racing with
1381 * its driver's interrupt handler, which is guaranteed not to run while
1382 * resume_noirq() is being executed. Make sure to clear target initial
1383 * wake up request such that next suspend can happen cleanly.
1384 *
1385 * Return: 0 on success
1386 */
1387static int wlan_hdd_pld_resume_noirq(struct device *dev,
1388 enum pld_bus_type bus_type)
1389{
1390 return wlan_hdd_bus_resume_noirq();
1391}
1392
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001393/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07001394 * wlan_hdd_pld_reset_resume() - reset resume function registered to PLD
1395 * @dev: device
1396 * @pld_bus_type: PLD bus type
1397 *
1398 * Return: 0 on success
1399 */
1400static int wlan_hdd_pld_reset_resume(struct device *dev,
1401 enum pld_bus_type bus_type)
1402{
1403 return wlan_hdd_bus_reset_resume();
1404}
1405
1406/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001407 * wlan_hdd_pld_notify_handler() - notify_handler function registered to PLD
1408 * @dev: device
1409 * @pld_bus_type: PLD bus type
1410 * @state: Modem power state
1411 *
1412 * Return: void
1413 */
1414static void wlan_hdd_pld_notify_handler(struct device *dev,
1415 enum pld_bus_type bus_type,
1416 int state)
1417{
1418 wlan_hdd_notify_handler(state);
1419}
1420
Arunk Khandavalli932a9e12017-10-04 12:41:27 +05301421static void wlan_hdd_purge_notifier(void)
1422{
1423 struct hdd_context *hdd_ctx;
1424
1425 ENTER();
1426
1427 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1428 if (!hdd_ctx) {
1429 hdd_err("hdd context is NULL return!!");
1430 return;
1431 }
1432
Dustin Brown6f427922017-09-19 12:19:00 -07001433 qdf_cancel_delayed_work(&hdd_ctx->iface_idle_work);
Dustin Brown1fe30a82017-10-03 16:13:36 -07001434
1435 mutex_lock(&hdd_ctx->iface_change_lock);
Arunk Khandavalli932a9e12017-10-04 12:41:27 +05301436 cds_shutdown_notifier_call();
1437 cds_shutdown_notifier_purge();
1438 mutex_unlock(&hdd_ctx->iface_change_lock);
1439 EXIT();
1440}
1441
Yuanyuan Liu06a342f2017-01-12 16:48:19 -08001442/**
Kabilan Kannand48b0162017-11-22 14:00:44 -08001443 * wlan_hdd_set_the_pld_uevent() - set the pld event
1444 * @uevent: uevent status
1445 *
1446 * Return: void
1447 */
1448static void wlan_hdd_set_the_pld_uevent(struct pld_uevent_data *uevent)
1449{
1450 switch (uevent->uevent) {
1451 case PLD_RECOVERY:
1452 cds_set_recovery_in_progress(true);
1453 break;
1454 case PLD_FW_DOWN:
1455 cds_set_fw_state(CDS_FW_STATE_DOWN);
1456 break;
Kabilan Kannand48b0162017-11-22 14:00:44 -08001457 }
1458}
1459
1460/**
1461 * wlan_hdd_handle_the_pld_uevent() - handle the pld event
1462 * @uevent: uevent status
1463 *
1464 * Return: void
1465 */
1466static void wlan_hdd_handle_the_pld_uevent(struct pld_uevent_data *uevent)
1467{
1468 enum cds_driver_state driver_state;
Arunk Khandavallif0c0d762017-12-07 10:18:50 +05301469 struct hdd_context *hdd_ctx;
Kabilan Kannand48b0162017-11-22 14:00:44 -08001470
1471 driver_state = cds_get_driver_state();
1472
1473 if (driver_state == CDS_DRIVER_STATE_UNINITIALIZED)
1474 return;
1475
1476 if (cds_is_driver_loading())
1477 return;
1478
1479 switch (uevent->uevent) {
1480 case PLD_RECOVERY:
1481 hdd_pld_ipa_uc_shutdown_pipes();
1482 break;
1483 case PLD_FW_DOWN:
1484 qdf_complete_wait_events();
1485 cds_set_target_ready(false);
Arunk Khandavallif0c0d762017-12-07 10:18:50 +05301486 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1487 if (hdd_ctx != NULL)
1488 wlan_cfg80211_cleanup_scan_queue(
1489 hdd_ctx->hdd_pdev);
Kabilan Kannand48b0162017-11-22 14:00:44 -08001490 break;
Kabilan Kannand48b0162017-11-22 14:00:44 -08001491 default:
1492 break;
1493 }
1494}
1495
1496/**
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +05301497 * wlan_hdd_pld_uevent() - update driver status
Yuanyuan Liu06a342f2017-01-12 16:48:19 -08001498 * @dev: device
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +05301499 * @uevent: uevent status
Yuanyuan Liu06a342f2017-01-12 16:48:19 -08001500 *
1501 * Return: void
1502 */
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +05301503static void wlan_hdd_pld_uevent(struct device *dev,
1504 struct pld_uevent_data *uevent)
Yuanyuan Liu06a342f2017-01-12 16:48:19 -08001505{
Kabilan Kannand48b0162017-11-22 14:00:44 -08001506 ENTER();
Sandeep Puligilla5ac6bd22017-10-17 12:33:56 -07001507 hdd_info("pld event %d", uevent->uevent);
Kabilan Kannand48b0162017-11-22 14:00:44 -08001508
1509 mutex_lock(&hdd_init_deinit_lock);
1510 wlan_hdd_set_the_pld_uevent(uevent);
1511 wlan_hdd_handle_the_pld_uevent(uevent);
1512 mutex_unlock(&hdd_init_deinit_lock);
Arunk Khandavalli932a9e12017-10-04 12:41:27 +05301513
1514 wlan_hdd_purge_notifier();
Kabilan Kannand48b0162017-11-22 14:00:44 -08001515 EXIT();
Yuanyuan Liu06a342f2017-01-12 16:48:19 -08001516}
1517
Houston Hoffmane8937082015-11-10 16:49:12 -08001518#ifdef FEATURE_RUNTIME_PM
1519/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001520 * wlan_hdd_pld_runtime_suspend() - runtime suspend function registered to PLD
1521 * @dev: device
1522 * @pld_bus_type: PLD bus type
Houston Hoffmane8937082015-11-10 16:49:12 -08001523 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001524 * Return: 0 on success
Houston Hoffmane8937082015-11-10 16:49:12 -08001525 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001526static int wlan_hdd_pld_runtime_suspend(struct device *dev,
1527 enum pld_bus_type bus_type)
Houston Hoffmane8937082015-11-10 16:49:12 -08001528{
Yuanyuan Liu13738502016-04-06 17:41:37 -07001529 return wlan_hdd_runtime_suspend(dev);
Houston Hoffmane8937082015-11-10 16:49:12 -08001530}
1531
1532/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001533 * wlan_hdd_pld_runtime_resume() - runtime resume function registered to PLD
1534 * @dev: device
1535 * @pld_bus_type: PLD bus type
Houston Hoffmane8937082015-11-10 16:49:12 -08001536 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001537 * Return: 0 on success
Houston Hoffmane8937082015-11-10 16:49:12 -08001538 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001539static int wlan_hdd_pld_runtime_resume(struct device *dev,
1540 enum pld_bus_type bus_type)
Houston Hoffmane8937082015-11-10 16:49:12 -08001541{
Yuanyuan Liu13738502016-04-06 17:41:37 -07001542 return wlan_hdd_runtime_resume(dev);
Houston Hoffmane8937082015-11-10 16:49:12 -08001543}
1544#endif
1545
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001546struct pld_driver_ops wlan_drv_ops = {
1547 .probe = wlan_hdd_pld_probe,
1548 .remove = wlan_hdd_pld_remove,
1549 .shutdown = wlan_hdd_pld_shutdown,
1550 .reinit = wlan_hdd_pld_reinit,
1551 .crash_shutdown = wlan_hdd_pld_crash_shutdown,
1552 .suspend = wlan_hdd_pld_suspend,
1553 .resume = wlan_hdd_pld_resume,
Rajeev Kumar99805a72016-08-29 13:53:52 -07001554 .suspend_noirq = wlan_hdd_pld_suspend_noirq,
1555 .resume_noirq = wlan_hdd_pld_resume_noirq,
Mohit Khannafa99aea2016-05-12 21:43:13 -07001556 .reset_resume = wlan_hdd_pld_reset_resume,
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001557 .modem_status = wlan_hdd_pld_notify_handler,
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +05301558 .uevent = wlan_hdd_pld_uevent,
Houston Hoffmane8937082015-11-10 16:49:12 -08001559#ifdef FEATURE_RUNTIME_PM
Jeff Johnson330292a2016-05-16 16:09:49 -07001560 .runtime_suspend = wlan_hdd_pld_runtime_suspend,
1561 .runtime_resume = wlan_hdd_pld_runtime_resume,
Houston Hoffmane8937082015-11-10 16:49:12 -08001562#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001563};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001564
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565int wlan_hdd_register_driver(void)
1566{
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001567 return pld_register_driver(&wlan_drv_ops);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001568}
1569
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001570void wlan_hdd_unregister_driver(void)
1571{
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001572 pld_unregister_driver();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001573}