blob: bf48114754ea657c9c922e1ca6fb8d95fcbf6a0c [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Naman Padhiar07f0c712019-12-09 23:01:12 +05302 * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080019#include <linux/platform_device.h>
20#include <linux/pci.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080021#include "cds_api.h"
Anurag Chouhance0dc992016-02-16 18:18:03 +053022#include "qdf_status.h"
Anurag Chouhana37b5b72016-02-21 14:53:42 +053023#include "qdf_lock.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080024#include "cds_sched.h"
25#include "osdep.h"
26#include "hif.h"
Houston Hoffmane8937082015-11-10 16:49:12 -080027#include "htc.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080028#include "epping_main.h"
Dustin Brown6412d1f2019-02-05 14:52:29 -080029#include "osif_sync.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080030#include "wlan_hdd_main.h"
31#include "wlan_hdd_power.h"
32#include "wlan_logging_sock_svc.h"
33#include "wma_api.h"
34#include "wlan_hdd_napi.h"
Tushnim Bhattacharyya9028cc72017-03-09 13:10:49 -080035#include "wlan_policy_mgr_api.h"
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080036#include "qwlan_version.h"
Komal Seelamd9106492016-02-15 10:31:44 +053037#include "bmi.h"
Rakesh Pillaid2e53852019-09-13 04:20:13 +053038#include <ol_defines.h>
Dhanashri Atreb08959a2016-03-01 17:28:03 -080039#include "cdp_txrx_bus.h"
Sarada Prasanna Garnayake1722632017-01-05 15:27:15 +053040#include "cdp_txrx_misc.h"
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -070041#include "pld_common.h"
Jeff Johnson7782cb92016-10-05 14:22:40 -070042#include "wlan_hdd_driver_ops.h"
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +053043#include "wlan_ipa_ucfg_api.h"
Rajeev Kumar Sirasanagandla197d4172018-02-15 19:03:29 +053044#include "wlan_hdd_debugfs.h"
jitiphil377bcc12018-10-05 19:46:08 +053045#include "cfg_ucfg_api.h"
Alan Chen0f29e972019-09-04 12:04:22 -070046#include <linux/suspend.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080047
48#ifdef MODULE
49#define WLAN_MODULE_NAME module_name(THIS_MODULE)
50#else
51#define WLAN_MODULE_NAME "wlan"
52#endif
53
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -070054#define DISABLE_KRAIT_IDLE_PS_VAL 1
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080055
Srinivas Girigowdabafb8b72017-10-11 17:52:32 -070056#define SSR_MAX_FAIL_CNT 3
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +053057static uint8_t re_init_fail_cnt, probe_fail_cnt;
58
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080059/*
60 * In BMI Phase we are only sending small chunk (256 bytes) of the FW image at
61 * a time, and wait for the completion interrupt to start the next transfer.
62 * During this phase, the KRAIT is entering IDLE/StandAlone(SA) Power Save(PS).
63 * The delay incurred for resuming from IDLE/SA PS is huge during driver load.
64 * So prevent APPS IDLE/SA PS durint driver load for reducing interrupt latency.
65 */
Yuanyuan Liu13738502016-04-06 17:41:37 -070066
67static inline void hdd_request_pm_qos(struct device *dev, int val)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080068{
Yuanyuan Liu13738502016-04-06 17:41:37 -070069 pld_request_pm_qos(dev, val);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080070}
71
Yuanyuan Liu13738502016-04-06 17:41:37 -070072static inline void hdd_remove_pm_qos(struct device *dev)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080073{
Yuanyuan Liu13738502016-04-06 17:41:37 -070074 pld_remove_pm_qos(dev);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080075}
Prashanth Bhatta5da711e2015-11-30 14:28:52 -080076
77/**
Komal Seelamad5a90d2016-02-16 13:50:03 +053078 * hdd_set_recovery_in_progress() - API to set recovery in progress
79 * @data: Context
80 * @val: Value to set
81 *
82 * Return: None
83 */
84static void hdd_set_recovery_in_progress(void *data, uint8_t val)
85{
86 cds_set_recovery_in_progress(val);
87}
88
89/**
90 * hdd_is_driver_unloading() - API to query if driver is unloading
91 * @data: Private Data
92 *
93 * Return: True/False
94 */
95static bool hdd_is_driver_unloading(void *data)
96{
97 return cds_is_driver_unloading();
98}
99
100/**
101 * hdd_is_load_or_unload_in_progress() - API to query if driver is
102 * loading/unloading
103 * @data: Private Data
104 *
105 * Return: bool
106 */
107static bool hdd_is_load_or_unload_in_progress(void *data)
108{
109 return cds_is_load_or_unload_in_progress();
110}
111
112/**
Komal Seelam1aac1982016-03-02 15:57:26 +0530113 * hdd_is_recovery_in_progress() - API to query if recovery in progress
Komal Seelamad5a90d2016-02-16 13:50:03 +0530114 * @data: Private Data
115 *
116 * Return: bool
117 */
Komal Seelam1aac1982016-03-02 15:57:26 +0530118static bool hdd_is_recovery_in_progress(void *data)
Komal Seelamad5a90d2016-02-16 13:50:03 +0530119{
120 return cds_is_driver_recovering();
121}
122
123/**
Govind Singha1f6dac2017-06-13 11:45:07 +0530124 * hdd_is_target_ready() - API to query if target is in ready state
125 * @data: Private Data
126 *
127 * Return: bool
128 */
129static bool hdd_is_target_ready(void *data)
130{
131 return cds_is_target_ready();
132}
133
134/**
Komal Seelam1aac1982016-03-02 15:57:26 +0530135 * hdd_hif_init_driver_state_callbacks() - API to initialize HIF callbacks
Komal Seelamad5a90d2016-02-16 13:50:03 +0530136 * @data: Private Data
Komal Seelam1aac1982016-03-02 15:57:26 +0530137 * @cbk: HIF Driver State callbacks
Komal Seelamad5a90d2016-02-16 13:50:03 +0530138 *
139 * HIF should be independent of CDS calls. Pass CDS Callbacks to HIF, HIF will
140 * call the callbacks.
141 *
142 * Return: void
143 */
Komal Seelam1aac1982016-03-02 15:57:26 +0530144static void hdd_hif_init_driver_state_callbacks(void *data,
145 struct hif_driver_state_callbacks *cbk)
Komal Seelamad5a90d2016-02-16 13:50:03 +0530146{
147 cbk->context = data;
148 cbk->set_recovery_in_progress = hdd_set_recovery_in_progress;
Komal Seelam1aac1982016-03-02 15:57:26 +0530149 cbk->is_recovery_in_progress = hdd_is_recovery_in_progress;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530150 cbk->is_load_unload_in_progress = hdd_is_load_or_unload_in_progress;
151 cbk->is_driver_unloading = hdd_is_driver_unloading;
Govind Singha1f6dac2017-06-13 11:45:07 +0530152 cbk->is_target_ready = hdd_is_target_ready;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530153}
154
Venkata Sharath Chandra Manchala06f1f122019-10-29 13:22:15 -0700155#ifdef FORCE_WAKE
156void hdd_set_hif_init_phase(struct hif_opaque_softc *hif_ctx,
157 bool hal_init_phase)
158{
159 hif_srng_init_phase(hif_ctx, hal_init_phase);
160}
161#endif /* FORCE_WAKE */
162
Komal Seelamad5a90d2016-02-16 13:50:03 +0530163/**
hangtian1c37fb92019-04-10 11:15:20 +0800164 * hdd_hif_set_attribute() - API to set CE attribute if memory is limited
165 * @hif_ctx: hif context
166 *
167 * Return: None
168 */
Hangtian Zhu39e2e212019-09-02 13:34:57 +0800169#ifdef SLUB_MEM_OPTIMIZE
hangtian1c37fb92019-04-10 11:15:20 +0800170static void hdd_hif_set_attribute(struct hif_opaque_softc *hif_ctx)
171{
172 hif_set_attribute(hif_ctx, HIF_LOWDESC_CE_NO_PKTLOG_CFG);
173}
174#else
175static void hdd_hif_set_attribute(struct hif_opaque_softc *hif_ctx)
176{}
177#endif
178
179/**
Komal Seelamad5a90d2016-02-16 13:50:03 +0530180 * hdd_init_cds_hif_context() - API to set CDS HIF Context
181 * @hif: HIF Context
182 *
183 * Return: success/failure
184 */
185static int hdd_init_cds_hif_context(void *hif)
186{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530187 QDF_STATUS status;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530188
Anurag Chouhan6d760662016-02-20 16:05:43 +0530189 status = cds_set_context(QDF_MODULE_ID_HIF, hif);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530190
191 if (status)
192 return -ENOENT;
193
194 return 0;
195}
196
197/**
198 * hdd_deinit_cds_hif_context() - API to clear CDS HIF COntext
199 *
200 * Return: None
201 */
202static void hdd_deinit_cds_hif_context(void)
203{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530204 QDF_STATUS status;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530205
Anurag Chouhan6d760662016-02-20 16:05:43 +0530206 status = cds_set_context(QDF_MODULE_ID_HIF, NULL);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530207
208 if (status)
209 hdd_err("Failed to reset CDS HIF Context");
Komal Seelamad5a90d2016-02-16 13:50:03 +0530210}
211
212/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -0700213 * to_bus_type() - Map PLD bus type to low level bus type
214 * @bus_type: PLD bus type
215 *
216 * Map PLD bus type to low level bus type.
217 *
218 * Return: low level bus type.
219 */
220static enum qdf_bus_type to_bus_type(enum pld_bus_type bus_type)
221{
222 switch (bus_type) {
Naman Padhiarc52e7fd2019-06-23 01:21:42 +0530223 case PLD_BUS_TYPE_PCIE_FW_SIM:
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -0700224 case PLD_BUS_TYPE_PCIE:
225 return QDF_BUS_TYPE_PCI;
Naman Padhiarc52e7fd2019-06-23 01:21:42 +0530226 case PLD_BUS_TYPE_SNOC_FW_SIM:
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -0700227 case PLD_BUS_TYPE_SNOC:
228 return QDF_BUS_TYPE_SNOC;
Poddar, Siddarth3e9fa5c2016-05-13 14:25:05 +0530229 case PLD_BUS_TYPE_SDIO:
230 return QDF_BUS_TYPE_SDIO;
Mohit Khannafa99aea2016-05-12 21:43:13 -0700231 case PLD_BUS_TYPE_USB:
232 return QDF_BUS_TYPE_USB;
Naman Padhiar07f0c712019-12-09 23:01:12 +0530233 case PLD_BUS_TYPE_IPCI:
234 return QDF_BUS_TYPE_IPCI;
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -0700235 default:
236 return QDF_BUS_TYPE_NONE;
237 }
238}
239
Manikandan Mohan617a5162017-04-10 13:14:40 -0700240int hdd_hif_open(struct device *dev, void *bdev, const struct hif_bus_id *bid,
Anurag Chouhan2ed1fce2016-02-22 15:07:01 +0530241 enum qdf_bus_type bus_type, bool reinit)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800242{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530243 QDF_STATUS status;
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800244 int ret = 0;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530245 struct hif_opaque_softc *hif_ctx;
Anurag Chouhandf2b2682016-02-29 14:15:27 +0530246 qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
Komal Seelam1aac1982016-03-02 15:57:26 +0530247 struct hif_driver_state_callbacks cbk;
Komal Seelamad5a90d2016-02-16 13:50:03 +0530248 uint32_t mode = cds_get_conparam();
Jeff Johnson6bc79d82017-08-28 12:02:36 -0700249 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Govind Singh068c4b02016-08-17 16:37:13 +0530250
251 if (!hdd_ctx) {
252 hdd_err("hdd_ctx error");
253 return -EFAULT;
254 }
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800255
Komal Seelam1aac1982016-03-02 15:57:26 +0530256 hdd_hif_init_driver_state_callbacks(dev, &cbk);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530257
Venkata Sharath Chandra Manchala0d0ef552020-01-07 16:37:43 -0800258 hif_ctx = hif_open(qdf_ctx, mode, bus_type, &cbk, hdd_ctx->psoc);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530259 if (!hif_ctx) {
260 hdd_err("hif_open error");
261 return -ENOMEM;
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800262 }
263
Komal Seelamad5a90d2016-02-16 13:50:03 +0530264 ret = hdd_init_cds_hif_context(hif_ctx);
265 if (ret) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800266 hdd_err("Failed to set global HIF CDS Context err: %d", ret);
Komal Seelamad5a90d2016-02-16 13:50:03 +0530267 goto err_hif_close;
268 }
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800269
hangtian1c37fb92019-04-10 11:15:20 +0800270 hdd_hif_set_attribute(hif_ctx);
271
Houston Hoffmanc1f962e2016-04-13 16:35:44 -0700272 status = hif_enable(hif_ctx, dev, bdev, bid, bus_type,
273 (reinit == true) ? HIF_ENABLE_TYPE_REINIT :
274 HIF_ENABLE_TYPE_PROBE);
275 if (!QDF_IS_STATUS_SUCCESS(status)) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800276 hdd_err("hif_enable failed status: %d, reinit: %d",
Houston Hoffmanc1f962e2016-04-13 16:35:44 -0700277 status, reinit);
Nachiket Kukade8003d252017-03-30 15:55:58 +0530278
Houston Hoffmanc1f962e2016-04-13 16:35:44 -0700279 ret = qdf_status_to_os_return(status);
280 goto err_hif_close;
281 } else {
Yuanyuan Liu057fc4c2018-01-08 10:50:28 -0800282 cds_set_target_ready(true);
Houston Hoffmanc1f962e2016-04-13 16:35:44 -0700283 ret = hdd_napi_create();
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800284 hdd_debug("hdd_napi_create returned: %d", ret);
Manjunathappa Prakash9dd19132016-04-21 16:27:04 -0700285 if (ret == 0)
286 hdd_warn("NAPI: no instances are created");
287 else if (ret < 0) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800288 hdd_err("NAPI creation error, rc: 0x%x, reinit: %d",
Komal Seelamad5a90d2016-02-16 13:50:03 +0530289 ret, reinit);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800290 ret = -EFAULT;
Dustin Brownc2a156e2018-10-25 16:56:27 -0700291 goto mark_target_not_ready;
Govind Singh068c4b02016-08-17 16:37:13 +0530292 } else {
293 hdd_napi_event(NAPI_EVT_INI_FILE,
294 (void *)hdd_ctx->napi_enable);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800295 }
296 }
297
Himanshu Agarwal24aa27e2017-05-23 11:07:50 +0530298 hif_set_ce_service_max_yield_time(hif_ctx,
jitiphil377bcc12018-10-05 19:46:08 +0530299 cfg_get(hdd_ctx->psoc,
300 CFG_DP_CE_SERVICE_MAX_YIELD_TIME));
Wu Gaod7dd6e42018-10-16 17:22:56 +0800301 ucfg_pmo_psoc_set_hif_handle(hdd_ctx->psoc, hif_ctx);
Poddar, Siddarth04eed332017-06-28 14:20:26 +0530302 hif_set_ce_service_max_rx_ind_flush(hif_ctx,
jitiphil377bcc12018-10-05 19:46:08 +0530303 cfg_get(hdd_ctx->psoc,
304 CFG_DP_CE_SERVICE_MAX_RX_IND_FLUSH));
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800305 return 0;
306
Dustin Brownc2a156e2018-10-25 16:56:27 -0700307mark_target_not_ready:
308 cds_set_target_ready(false);
309
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800310err_hif_close:
Komal Seelamad5a90d2016-02-16 13:50:03 +0530311 hdd_deinit_cds_hif_context();
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800312 hif_close(hif_ctx);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800313 return ret;
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800314}
315
Jeff Johnson6bc79d82017-08-28 12:02:36 -0700316void hdd_hif_close(struct hdd_context *hdd_ctx, void *hif_ctx)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800317{
Sravan Kumar Kairam27296782017-04-21 22:04:18 +0530318 if (!hdd_ctx) {
319 hdd_err("hdd_ctx error");
320 return;
321 }
322
Jeff Johnsond36fa332019-03-18 13:42:25 -0700323 if (!hif_ctx)
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800324 return;
325
Dustin Brownc2a156e2018-10-25 16:56:27 -0700326 cds_set_target_ready(false);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800327 hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE);
328
329 hdd_napi_destroy(true);
330
Komal Seelamad5a90d2016-02-16 13:50:03 +0530331 hdd_deinit_cds_hif_context();
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800332 hif_close(hif_ctx);
Sravan Kumar Kairam27296782017-04-21 22:04:18 +0530333
Wu Gaod7dd6e42018-10-16 17:22:56 +0800334 ucfg_pmo_psoc_set_hif_handle(hdd_ctx->psoc, NULL);
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800335}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800336
337/**
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530338 * hdd_init_qdf_ctx() - API to initialize global QDF Device structure
Komal Seelam48152e12016-02-09 17:50:33 +0530339 * @dev: Device Pointer
340 * @bdev: Bus Device pointer
Arun Khandavallifae92942016-08-01 13:31:08 +0530341 * @bus_type: Underlying bus type
342 * @bid: Bus id passed by platform driver
Komal Seelam48152e12016-02-09 17:50:33 +0530343 *
Himanshu Agarwala89ce242017-11-17 17:36:34 +0530344 * Return: 0 - success, < 0 - failure
Komal Seelam48152e12016-02-09 17:50:33 +0530345 */
Himanshu Agarwala89ce242017-11-17 17:36:34 +0530346static int hdd_init_qdf_ctx(struct device *dev, void *bdev,
347 enum qdf_bus_type bus_type,
348 const struct hif_bus_id *bid)
Komal Seelam48152e12016-02-09 17:50:33 +0530349{
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530350 qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
Komal Seelam48152e12016-02-09 17:50:33 +0530351
Jeff Johnson615d4bb2016-07-20 11:03:04 -0700352 if (!qdf_dev) {
353 hdd_err("Invalid QDF device");
Himanshu Agarwala89ce242017-11-17 17:36:34 +0530354 return -EINVAL;
Jeff Johnson615d4bb2016-07-20 11:03:04 -0700355 }
356
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530357 qdf_dev->dev = dev;
358 qdf_dev->drv_hdl = bdev;
Govind Singh9db91ba2016-04-29 14:15:47 +0530359 qdf_dev->bus_type = bus_type;
Arun Khandavallifae92942016-08-01 13:31:08 +0530360 qdf_dev->bid = bid;
Yun Park45d35972018-03-02 09:57:54 -0800361
Sravan Kumar Kairam983a4452018-03-20 13:30:22 +0530362 if (cds_smmu_mem_map_setup(qdf_dev, ucfg_ipa_is_present()) !=
Himanshu Agarwala89ce242017-11-17 17:36:34 +0530363 QDF_STATUS_SUCCESS) {
364 hdd_err("cds_smmu_mem_map_setup() failed");
365 return -EFAULT;
366 }
367
368 return 0;
Komal Seelam48152e12016-02-09 17:50:33 +0530369}
370
371/**
Yuanyuan Liu5583b2c2017-10-09 17:30:13 -0700372 * check_for_probe_defer() - API to check return value
373 * @ret: Return Value
374 *
375 * Return: return -EPROBE_DEFER to platform driver if return value
376 * is -ENOMEM. Platform driver will try to re-probe.
377 */
378#ifdef MODULE
379static int check_for_probe_defer(int ret)
380{
381 return ret;
382}
383#else
384static int check_for_probe_defer(int ret)
385{
386 if (ret == -ENOMEM)
387 return -EPROBE_DEFER;
388 return ret;
389}
390#endif
391
Alan Chen32c60482019-08-08 17:26:54 -0700392#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
393static void hdd_abort_system_suspend(struct device *dev)
Alan Chene523cd92019-07-15 16:45:09 -0700394{
Alan Chene119c7d2019-11-14 15:05:37 -0800395 qdf_pm_system_wakeup();
Alan Chen32c60482019-08-08 17:26:54 -0700396}
397#else
398static void hdd_abort_system_suspend(struct device *dev)
399{
400}
401#endif
402
Alan Chen0f29e972019-09-04 12:04:22 -0700403int hdd_soc_idle_restart_lock(struct device *dev)
404{
Alan Chene523cd92019-07-15 16:45:09 -0700405 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_RESTART);
Alan Chen0f29e972019-09-04 12:04:22 -0700406
407 hdd_abort_system_suspend(dev);
408
Alan Chen0f29e972019-09-04 12:04:22 -0700409 return 0;
Alan Chene523cd92019-07-15 16:45:09 -0700410}
411
412void hdd_soc_idle_restart_unlock(void)
413{
414 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_RESTART);
415}
416
Dustin Brownb7487682019-03-19 13:48:55 -0700417static void hdd_soc_load_lock(struct device *dev)
Dustin Brown024c9cd2018-07-31 17:09:30 -0700418{
Dustin Brown024c9cd2018-07-31 17:09:30 -0700419 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
420 hdd_request_pm_qos(dev, DISABLE_KRAIT_IDLE_PS_VAL);
421}
422
423static void hdd_soc_load_unlock(struct device *dev)
424{
425 hdd_remove_pm_qos(dev);
426 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
Dustin Brown024c9cd2018-07-31 17:09:30 -0700427}
428
Dustin Browncfcb5762019-01-31 15:43:45 -0800429static int __hdd_soc_probe(struct device *dev,
430 void *bdev,
431 const struct hif_bus_id *bid,
432 enum qdf_bus_type bus_type)
433{
434 struct hdd_context *hdd_ctx;
435 QDF_STATUS status;
436 int errno;
437
438 hdd_info("probing driver");
439
Dustin Brownb7487682019-03-19 13:48:55 -0700440 hdd_soc_load_lock(dev);
Dustin Browncfcb5762019-01-31 15:43:45 -0800441 cds_set_load_in_progress(true);
442 cds_set_driver_in_bad_state(false);
443 cds_set_recovery_in_progress(false);
444
445 errno = hdd_init_qdf_ctx(dev, bdev, bus_type, bid);
446 if (errno)
447 goto unlock;
448
449 hdd_ctx = hdd_context_create(dev);
450 if (IS_ERR(hdd_ctx)) {
451 errno = PTR_ERR(hdd_ctx);
452 goto assert_fail_count;
453 }
454
455 errno = hdd_wlan_startup(hdd_ctx);
456 if (errno)
457 goto hdd_context_destroy;
458
459 status = hdd_psoc_create_vdevs(hdd_ctx);
460 if (QDF_IS_STATUS_ERROR(status)) {
461 errno = qdf_status_to_os_return(status);
462 goto wlan_exit;
463 }
464
465 probe_fail_cnt = 0;
466 cds_set_driver_loaded(true);
467 cds_set_load_in_progress(false);
468 hdd_start_complete(0);
469
470 hdd_soc_load_unlock(dev);
471
472 return 0;
473
474wlan_exit:
475 hdd_wlan_exit(hdd_ctx);
476
477hdd_context_destroy:
478 hdd_context_destroy(hdd_ctx);
479
480assert_fail_count:
481 probe_fail_cnt++;
482 hdd_err("consecutive probe failures:%u", probe_fail_cnt);
483 QDF_BUG(probe_fail_cnt < SSR_MAX_FAIL_CNT);
484
485unlock:
486 cds_set_load_in_progress(false);
487 hdd_soc_load_unlock(dev);
488
489 return check_for_probe_defer(errno);
490}
491
Dustin Brown32ffab32018-09-21 11:36:54 -0700492/**
493 * hdd_soc_probe() - perform SoC probe
494 * @dev: kernel device being probed
495 * @bdev: bus device structure
496 * @bid: bus identifier for shared busses
497 * @bus_type: underlying bus type
498 *
499 * A SoC probe indicates new SoC hardware has become available and needs to be
500 * initialized.
501 *
502 * Return: Errno
503 */
Dustin Brown024c9cd2018-07-31 17:09:30 -0700504static int hdd_soc_probe(struct device *dev,
505 void *bdev,
506 const struct hif_bus_id *bid,
507 enum qdf_bus_type bus_type)
508{
Dustin Brown363b4792019-02-05 16:11:55 -0800509 struct osif_psoc_sync *psoc_sync;
Dustin Brown024c9cd2018-07-31 17:09:30 -0700510 int errno;
511
512 hdd_info("probing driver");
513
Dustin Brownc1d81af2019-03-01 13:43:43 -0800514 errno = osif_psoc_sync_create_and_trans(&psoc_sync);
Dustin Browncfcb5762019-01-31 15:43:45 -0800515 if (errno)
516 return errno;
Dustin Brown623e7e32018-09-05 14:27:50 -0700517
Dustin Brown363b4792019-02-05 16:11:55 -0800518 osif_psoc_sync_register(dev, psoc_sync);
Dustin Browncfcb5762019-01-31 15:43:45 -0800519 errno = __hdd_soc_probe(dev, bdev, bid, bus_type);
520 if (errno)
521 goto destroy_sync;
Dustin Brown623e7e32018-09-05 14:27:50 -0700522
Dustin Brown363b4792019-02-05 16:11:55 -0800523 osif_psoc_sync_trans_stop(psoc_sync);
Dustin Browncfcb5762019-01-31 15:43:45 -0800524
525 return 0;
526
527destroy_sync:
Dustin Brown363b4792019-02-05 16:11:55 -0800528 osif_psoc_sync_unregister(dev);
529 osif_psoc_sync_wait_for_ops(psoc_sync);
Dustin Browncfcb5762019-01-31 15:43:45 -0800530
Dustin Brown363b4792019-02-05 16:11:55 -0800531 osif_psoc_sync_trans_stop(psoc_sync);
532 osif_psoc_sync_destroy(psoc_sync);
Dustin Browncfcb5762019-01-31 15:43:45 -0800533
534 return errno;
535}
536
537static int __hdd_soc_recovery_reinit(struct device *dev,
538 void *bdev,
539 const struct hif_bus_id *bid,
540 enum qdf_bus_type bus_type)
541{
542 int errno;
543
544 hdd_info("re-probing driver");
545
Dustin Brownb7487682019-03-19 13:48:55 -0700546 hdd_soc_load_lock(dev);
Dustin Brown024c9cd2018-07-31 17:09:30 -0700547 cds_set_driver_in_bad_state(false);
548
549 errno = hdd_init_qdf_ctx(dev, bdev, bus_type, bid);
550 if (errno)
551 goto unlock;
552
Dustin Browncfcb5762019-01-31 15:43:45 -0800553 errno = hdd_wlan_re_init();
554 if (errno) {
555 re_init_fail_cnt++;
Dustin Brown024c9cd2018-07-31 17:09:30 -0700556 goto assert_fail_count;
Dustin Brown623e7e32018-09-05 14:27:50 -0700557 }
558
Dustin Browncfcb5762019-01-31 15:43:45 -0800559 re_init_fail_cnt = 0;
560 cds_set_recovery_in_progress(false);
Dustin Brown024c9cd2018-07-31 17:09:30 -0700561
562 hdd_soc_load_unlock(dev);
563
564 return 0;
565
566assert_fail_count:
Dustin Browncfcb5762019-01-31 15:43:45 -0800567 hdd_err("consecutive reinit failures:%u", re_init_fail_cnt);
568 QDF_BUG(re_init_fail_cnt < SSR_MAX_FAIL_CNT);
Dustin Brown024c9cd2018-07-31 17:09:30 -0700569
570unlock:
Dustin Browncfcb5762019-01-31 15:43:45 -0800571 cds_set_driver_in_bad_state(true);
Dustin Brown024c9cd2018-07-31 17:09:30 -0700572 hdd_soc_load_unlock(dev);
573
574 return check_for_probe_defer(errno);
575}
576
Dustin Brown32ffab32018-09-21 11:36:54 -0700577/**
578 * hdd_soc_recovery_reinit() - perform PDR/SSR SoC reinit
579 * @dev: the kernel device being re-initialized
580 * @bdev: bus device structure
581 * @bid: bus identifier for shared busses
582 * @bus_type: underlying bus type
583 *
584 * When communication with firmware breaks down, a SoC recovery process kicks in
585 * with two phases: shutdown and reinit.
586 *
587 * SSR reinit is similar to a 'probe' but happens in response to an SSR
588 * shutdown. The idea is to re-initialize the SoC to as close to its old,
589 * pre-communications-breakdown configuration as possible. This is completely
590 * transparent from a userspace point of view.
591 *
592 * Return: Errno
593 */
594static int hdd_soc_recovery_reinit(struct device *dev,
595 void *bdev,
596 const struct hif_bus_id *bid,
597 enum qdf_bus_type bus_type)
Dustin Brown024c9cd2018-07-31 17:09:30 -0700598{
Dustin Brown363b4792019-02-05 16:11:55 -0800599 struct osif_psoc_sync *psoc_sync;
Dustin Brown024c9cd2018-07-31 17:09:30 -0700600 int errno;
601
Dustin Brownf967e482018-09-20 16:29:04 -0700602 /* SSR transition is initiated at the beginning of soc shutdown */
Dustin Brown363b4792019-02-05 16:11:55 -0800603 errno = osif_psoc_sync_trans_resume(dev, &psoc_sync);
Dustin Browncfcb5762019-01-31 15:43:45 -0800604 QDF_BUG(!errno);
Dustin Brown024c9cd2018-07-31 17:09:30 -0700605 if (errno)
Dustin Browncfcb5762019-01-31 15:43:45 -0800606 return errno;
Dustin Brown024c9cd2018-07-31 17:09:30 -0700607
Dustin Browncfcb5762019-01-31 15:43:45 -0800608 errno = __hdd_soc_recovery_reinit(dev, bdev, bid, bus_type);
609 if (errno)
610 return errno;
Dustin Brown024c9cd2018-07-31 17:09:30 -0700611
Dustin Brown363b4792019-02-05 16:11:55 -0800612 osif_psoc_sync_trans_stop(psoc_sync);
Dustin Brownf967e482018-09-20 16:29:04 -0700613
Dustin Brown024c9cd2018-07-31 17:09:30 -0700614 return 0;
Dustin Brown024c9cd2018-07-31 17:09:30 -0700615}
616
Dustin Browncfcb5762019-01-31 15:43:45 -0800617static void __hdd_soc_remove(struct device *dev)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800618{
Dustin Brown623e7e32018-09-05 14:27:50 -0700619 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Rajeev Kumarf10f1772018-12-28 12:00:15 -0800620
Dustin Browncfcb5762019-01-31 15:43:45 -0800621 QDF_BUG(hdd_ctx);
622 if (!hdd_ctx)
Rajeev Kumarf10f1772018-12-28 12:00:15 -0800623 return;
Dustin Brown623e7e32018-09-05 14:27:50 -0700624
Prashanth Bhatta5da711e2015-11-30 14:28:52 -0800625 pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME,
626 QWLAN_VERSIONSTR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800627
Prashanth Bhatta9e143052015-12-04 11:56:47 -0800628 cds_set_driver_loaded(false);
629 cds_set_unload_in_progress(true);
630
Rajeev Kumar Sirasanagandla197d4172018-02-15 19:03:29 +0530631 if (!hdd_wait_for_debugfs_threads_completion())
632 hdd_warn("Debugfs threads are still active attempting driver unload anyway");
633
Dustin Brown92bd8382018-10-31 15:49:46 -0700634 if (hdd_get_conparam() == QDF_GLOBAL_EPPING_MODE) {
Nirav Shah6aeecf92019-02-13 14:05:03 +0530635 hdd_wlan_stop_modules(hdd_ctx, false);
Guisen Yang2780b922019-06-03 16:21:39 +0800636 qdf_nbuf_deinit_replenish_timer();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800637 } else {
Dustin Brown623e7e32018-09-05 14:27:50 -0700638 hdd_wlan_exit(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800639 }
Nirav Shah6aeecf92019-02-13 14:05:03 +0530640
641 hdd_context_destroy(hdd_ctx);
642
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530643 cds_set_driver_in_bad_state(false);
Hanumanth Reddy Pothulafc70ea32017-01-18 18:19:08 +0530644 cds_set_unload_in_progress(false);
645
Mohit Khannafa99aea2016-05-12 21:43:13 -0700646 pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800647}
648
Dustin Browncfcb5762019-01-31 15:43:45 -0800649/**
650 * hdd_soc_remove() - perform SoC remove
651 * @dev: the kernel device being removed
652 *
653 * A SoC remove indicates the attached SoC hardware is about to go away and
654 * needs to be cleaned up.
655 *
656 * Return: void
657 */
658static void hdd_soc_remove(struct device *dev)
659{
Dustin Browncfcb5762019-01-31 15:43:45 -0800660 __hdd_soc_remove(dev);
Dustin Browncfcb5762019-01-31 15:43:45 -0800661}
662
Sen, Devendra154b3c42017-02-13 20:44:15 +0530663#ifdef FEATURE_WLAN_DIAG_SUPPORT
664/**
665 * hdd_wlan_ssr_shutdown_event()- send ssr shutdown state
666 *
667 * This Function send send ssr shutdown state diag event
668 *
669 * Return: void.
670 */
671static void hdd_wlan_ssr_shutdown_event(void)
672{
673 WLAN_HOST_DIAG_EVENT_DEF(ssr_shutdown,
674 struct host_event_wlan_ssr_shutdown);
675 qdf_mem_zero(&ssr_shutdown, sizeof(ssr_shutdown));
676 ssr_shutdown.status = SSR_SUB_SYSTEM_SHUTDOWN;
677 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_shutdown,
678 EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM);
679}
680#else
Dustin Brown92bd8382018-10-31 15:49:46 -0700681static inline void hdd_wlan_ssr_shutdown_event(void) { }
Sen, Devendra154b3c42017-02-13 20:44:15 +0530682#endif
683
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800684/**
Anurag Chouhan4085ff72017-10-05 18:09:56 +0530685 * hdd_send_hang_reason() - Send hang reason to the userspace
686 *
687 * Return: None
688 */
689static void hdd_send_hang_reason(void)
690{
Mahesh Kumar Kalikot Veetil9111a572017-10-10 16:11:11 -0700691 enum qdf_hang_reason reason = QDF_REASON_UNSPECIFIED;
Anurag Chouhan4085ff72017-10-05 18:09:56 +0530692 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
693
Sourav Mohapatra07b057f2019-10-29 11:31:39 +0530694 if (!hdd_ctx)
Anurag Chouhan4085ff72017-10-05 18:09:56 +0530695 return;
696
697 cds_get_recovery_reason(&reason);
698 cds_reset_recovery_reason();
699 wlan_hdd_send_hang_reason_event(hdd_ctx, reason);
700}
701
702/**
Dustin Brownaf8fea02018-10-29 11:31:49 -0700703 * hdd_psoc_shutdown_notify() - notify the various interested parties that the
704 * soc is starting recovery shutdown
705 * @hdd_ctx: the HDD context corresponding to the soc undergoing shutdown
706 *
707 * Return: None
708 */
709static void hdd_psoc_shutdown_notify(struct hdd_context *hdd_ctx)
710{
711 /* Notify external threads currently waiting on firmware by forcefully
712 * completing waiting events with a "reset" status. This will cause the
713 * event to fail early instead of timing out.
714 */
715 qdf_complete_wait_events();
716
717 wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, NULL);
718
719 if (ucfg_ipa_is_enabled()) {
720 ucfg_ipa_uc_force_pipe_shutdown(hdd_ctx->pdev);
721
Vevek Venkatesan789b6b32019-04-15 13:05:10 +0530722 if (pld_is_fw_rejuvenate(hdd_ctx->parent_dev) ||
723 pld_is_pdr(hdd_ctx->parent_dev))
Dustin Brownaf8fea02018-10-29 11:31:49 -0700724 ucfg_ipa_fw_rejuvenate_send_msg(hdd_ctx->pdev);
725 }
726
727 cds_shutdown_notifier_call();
728 cds_shutdown_notifier_purge();
729
730 hdd_wlan_ssr_shutdown_event();
731 hdd_send_hang_reason();
732}
733
Dustin Browncfcb5762019-01-31 15:43:45 -0800734static void __hdd_soc_recovery_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800735{
Dustin Brownaf8fea02018-10-29 11:31:49 -0700736 struct hdd_context *hdd_ctx;
Dustin Brown32ffab32018-09-21 11:36:54 -0700737 void *hif_ctx;
bings5f0ae142017-07-14 17:52:45 +0800738
Dustin Brownaf8fea02018-10-29 11:31:49 -0700739 /* recovery starts via firmware down indication; ensure we got one */
740 QDF_BUG(cds_is_driver_recovering());
741
742 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
743 if (!hdd_ctx) {
744 hdd_err("hdd_ctx is null");
745 return;
746 }
747
748 /* cancel/flush any pending/active idle shutdown work */
749 hdd_psoc_idle_timer_stop(hdd_ctx);
Arun Kumar Khandavallia4cedce2019-11-25 20:03:09 +0530750 hdd_bus_bw_compute_timer_stop(hdd_ctx);
Dustin Brownaf8fea02018-10-29 11:31:49 -0700751
752 /* nothing to do if the soc is already unloaded */
753 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
754 hdd_info("Driver modules are already closed");
Dustin Brown3da3a832019-03-19 15:51:54 -0700755 return;
Dustin Brownaf8fea02018-10-29 11:31:49 -0700756 }
757
Rajeev Kumarfec3dbe2016-01-19 15:23:52 -0800758 if (cds_is_load_or_unload_in_progress()) {
Dustin Brownaf8fea02018-10-29 11:31:49 -0700759 hdd_info("Load/unload in progress, ignore SSR shutdown");
Dustin Brown3da3a832019-03-19 15:51:54 -0700760 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761 }
Ashish Kumar Dhanotiyae4e6c5b2018-03-22 14:41:10 +0530762
Dustin Brown32ffab32018-09-21 11:36:54 -0700763 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
764 if (!hif_ctx) {
765 hdd_err("Failed to get HIF context, ignore SSR shutdown");
Dustin Brown3da3a832019-03-19 15:51:54 -0700766 return;
Dustin Brown32ffab32018-09-21 11:36:54 -0700767 }
768
769 /* mask the host controller interrupts */
770 hif_mask_interrupt_call(hif_ctx);
771
Dustin Brownaf8fea02018-10-29 11:31:49 -0700772 hdd_psoc_shutdown_notify(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800773
Rajeev Kumar Sirasanagandla197d4172018-02-15 19:03:29 +0530774 if (!hdd_wait_for_debugfs_threads_completion())
775 hdd_err("Debufs threads are still pending, attempting SSR anyway");
776
Houston Hoffman371d4a92016-04-14 17:02:37 -0700777 if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) {
bings5f0ae142017-07-14 17:52:45 +0800778 hif_disable_isr(hif_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800779 hdd_wlan_shutdown();
Yue Macd961442015-10-20 16:15:31 -0700780 }
Dustin Browncfcb5762019-01-31 15:43:45 -0800781}
782
783/**
784 * hdd_soc_recovery_shutdown() - perform PDR/SSR SoC shutdown
785 * @dev: the device to shutdown
786 *
787 * When communication with firmware breaks down, a SoC recovery process kicks in
788 * with two phases: shutdown and reinit.
789 *
790 * SSR shutdown is similar to a 'remove' but without communication with
791 * firmware. The idea is to retain as much SoC configuration as possible, so it
792 * can be re-initialized to the same state after a reset. This is completely
793 * transparent from a userspace point of view.
794 *
795 * Return: void
796 */
797static void hdd_soc_recovery_shutdown(struct device *dev)
798{
Dustin Brown363b4792019-02-05 16:11:55 -0800799 struct osif_psoc_sync *psoc_sync;
Dustin Browncfcb5762019-01-31 15:43:45 -0800800 int errno;
801
Dustin Brown363b4792019-02-05 16:11:55 -0800802 errno = osif_psoc_sync_trans_start_wait(dev, &psoc_sync);
Dustin Browncfcb5762019-01-31 15:43:45 -0800803 QDF_BUG(!errno);
804 if (errno)
805 return;
806
Dustin Brown363b4792019-02-05 16:11:55 -0800807 osif_psoc_sync_wait_for_ops(psoc_sync);
Dustin Browncfcb5762019-01-31 15:43:45 -0800808
809 __hdd_soc_recovery_shutdown();
Dustin Brownf967e482018-09-20 16:29:04 -0700810
Dustin Brown5a26dae2018-11-15 10:08:42 -0800811 /* SSR transition is concluded at the end of soc re-init */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800812}
813
814/**
815 * wlan_hdd_crash_shutdown() - wlan_hdd_crash_shutdown
816 *
Jeff Johnson37a41262018-05-06 17:09:55 -0700817 * HDD crash shutdown function: This function is called by
Jeff Johnson453e6c02018-05-06 15:52:11 -0700818 * platform driver's crash shutdown routine
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800819 *
820 * Return: void
821 */
Jeff Johnson7782cb92016-10-05 14:22:40 -0700822static void wlan_hdd_crash_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800823{
Yu Wang46082dc2017-09-19 12:25:38 +0800824 QDF_STATUS ret;
825 WMA_HANDLE wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
826
827 if (!wma_handle) {
828 hdd_err("wma_handle is null");
829 return;
830 }
831
832 /*
833 * When kernel panic happen, if WiFi FW is still active
834 * it may cause NOC errors/memory corruption, to avoid
835 * this, inject a fw crash first.
836 * send crash_inject to FW directly, because we are now
837 * in an atomic context, and preempt has been disabled,
838 * MCThread won't be scheduled at the moment, at the same
839 * time, TargetFailure event wont't be received after inject
840 * crash due to the same reason.
841 */
842 ret = wma_crash_inject(wma_handle, RECOVERY_SIM_ASSERT, 0);
843 if (QDF_IS_STATUS_ERROR(ret)) {
844 hdd_err("Failed to send crash inject:%d", ret);
845 return;
846 }
847
Anurag Chouhan6d760662016-02-20 16:05:43 +0530848 hif_crash_shutdown(cds_get_context(QDF_MODULE_ID_HIF));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800849}
850
851/**
852 * wlan_hdd_notify_handler() - wlan_hdd_notify_handler
853 *
854 * This function is called by the platform driver to notify the
855 * COEX
856 *
857 * @state: state
858 *
859 * Return: void
860 */
Jeff Johnson7782cb92016-10-05 14:22:40 -0700861static void wlan_hdd_notify_handler(int state)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800862{
Houston Hoffman371d4a92016-04-14 17:02:37 -0700863 if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) {
Jeff Johnson10251bc2017-03-24 15:30:52 -0700864 int ret;
865
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 ret = hdd_wlan_notify_modem_power_state(state);
867 if (ret < 0)
Jeff Johnsonbd561a92016-01-07 18:31:35 -0800868 hdd_err("Fail to send notify");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869 }
870}
871
Dustin Brown9ef609b2017-03-15 12:19:37 -0700872static int hdd_to_pmo_interface_pause(enum wow_interface_pause hdd_pause,
873 enum pmo_wow_interface_pause *pmo_pause)
874{
875 switch (hdd_pause) {
876 case WOW_INTERFACE_PAUSE_DEFAULT:
877 *pmo_pause = PMO_WOW_INTERFACE_PAUSE_DEFAULT;
878 break;
879 case WOW_INTERFACE_PAUSE_ENABLE:
880 *pmo_pause = PMO_WOW_INTERFACE_PAUSE_ENABLE;
881 break;
882 case WOW_INTERFACE_PAUSE_DISABLE:
883 *pmo_pause = PMO_WOW_INTERFACE_PAUSE_DISABLE;
884 break;
885 default:
886 hdd_err("Invalid interface pause: %d", hdd_pause);
887 return -EINVAL;
888 }
889
890 return 0;
891}
892
893static int hdd_to_pmo_resume_trigger(enum wow_resume_trigger hdd_trigger,
894 enum pmo_wow_resume_trigger *pmo_trigger)
895{
896 switch (hdd_trigger) {
897 case WOW_RESUME_TRIGGER_DEFAULT:
898 *pmo_trigger = PMO_WOW_RESUME_TRIGGER_DEFAULT;
899 break;
900 case WOW_RESUME_TRIGGER_HTC_WAKEUP:
901 *pmo_trigger = PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP;
902 break;
903 case WOW_RESUME_TRIGGER_GPIO:
904 *pmo_trigger = PMO_WOW_RESUME_TRIGGER_GPIO;
905 break;
906 default:
907 hdd_err("Invalid resume trigger: %d", hdd_trigger);
908 return -EINVAL;
909 }
910
911 return 0;
912}
913
914static int
915hdd_to_pmo_wow_enable_params(struct wow_enable_params *in_params,
916 struct pmo_wow_enable_params *out_params)
917{
918 int err;
919
920 /* unit-test suspend */
921 out_params->is_unit_test = in_params->is_unit_test;
922
923 /* interface pause */
924 err = hdd_to_pmo_interface_pause(in_params->interface_pause,
925 &out_params->interface_pause);
926 if (err)
927 return err;
928
929 /* resume trigger */
930 err = hdd_to_pmo_resume_trigger(in_params->resume_trigger,
931 &out_params->resume_trigger);
932 if (err)
933 return err;
934
935 return 0;
936}
937
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800938/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800939 * __wlan_hdd_bus_suspend() - handles platform supsend
Dustin Brown54096432017-02-23 13:00:44 -0800940 * @wow_params: collection of wow enable override parameters
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941 *
942 * Does precondtion validation. Ensures that a subsystem restart isn't in
Dustin Brown9ef609b2017-03-15 12:19:37 -0700943 * progress. Ensures that no load or unload is in progress. Does:
944 * data path suspend
945 * component (pmo) suspend
946 * hif (bus) suspend
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800947 *
948 * Return: 0 for success, -EFAULT for null pointers,
949 * -EBUSY or -EAGAIN if another opperation is in progress and
950 * wlan will not be ready to suspend in time.
951 */
Dustin Brown9ef609b2017-03-15 12:19:37 -0700952static int __wlan_hdd_bus_suspend(struct wow_enable_params wow_params)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953{
Dustin Brown562b9672016-12-22 15:25:33 -0800954 int err;
Dustin Brown9ef609b2017-03-15 12:19:37 -0700955 QDF_STATUS status;
Jeff Johnson6bc79d82017-08-28 12:02:36 -0700956 struct hdd_context *hdd_ctx;
Dustin Brown9ef609b2017-03-15 12:19:37 -0700957 void *hif_ctx;
Dustin Brown7ff24dd2017-05-10 15:49:59 -0700958 void *dp_soc;
Dustin Brown9ef609b2017-03-15 12:19:37 -0700959 struct pmo_wow_enable_params pmo_params;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800960
Rajeev Kumarb0ef9822017-12-15 18:14:43 -0800961 hdd_info("starting bus suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962
Dustin Brown9ef609b2017-03-15 12:19:37 -0700963 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Dustin Brown562b9672016-12-22 15:25:33 -0800964 err = wlan_hdd_validate_context(hdd_ctx);
965 if (err) {
Dustin Brown9ef609b2017-03-15 12:19:37 -0700966 hdd_err("Invalid hdd context: %d", err);
967 return err;
Dustin Brown562b9672016-12-22 15:25:33 -0800968 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800969
Rajeev Kumar99805a72016-08-29 13:53:52 -0700970 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -0800971 hdd_debug("Driver Module closed; skipping suspend");
Rajeev Kumar99805a72016-08-29 13:53:52 -0700972 return 0;
973 }
974
SaidiReddy Yenugad8323662016-07-20 15:45:34 +0530975 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Dustin Brown9ef609b2017-03-15 12:19:37 -0700976 if (!hif_ctx) {
Dustin Brown562b9672016-12-22 15:25:33 -0800977 hdd_err("Failed to get hif context");
Dustin Brown9ef609b2017-03-15 12:19:37 -0700978 return -EINVAL;
SaidiReddy Yenugad8323662016-07-20 15:45:34 +0530979 }
Arun Khandavallifae92942016-08-01 13:31:08 +0530980
Dustin Brown9ef609b2017-03-15 12:19:37 -0700981 err = hdd_to_pmo_wow_enable_params(&wow_params, &pmo_params);
982 if (err) {
983 hdd_err("Invalid WoW enable parameters: %d", err);
984 return err;
985 }
986
Dustin Brown7ff24dd2017-05-10 15:49:59 -0700987 dp_soc = cds_get_context(QDF_MODULE_ID_SOC);
Rakesh Pillaid2e53852019-09-13 04:20:13 +0530988 err = qdf_status_to_os_return(cdp_bus_suspend(dp_soc, OL_TXRX_PDEV_ID));
Dustin Brown562b9672016-12-22 15:25:33 -0800989 if (err) {
Dustin Brown9ef609b2017-03-15 12:19:37 -0700990 hdd_err("Failed cdp bus suspend: %d", err);
991 return err;
Dustin Brown562b9672016-12-22 15:25:33 -0800992 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800993
Mohit Khanna5b42d1b2019-11-04 17:28:00 -0800994 if (ucfg_ipa_is_tx_pending(hdd_ctx->pdev)) {
995 hdd_err("failed due to pending IPA TX comps");
996 err = -EBUSY;
997 goto resume_cdp;
998 }
999
Houston Hoffmane5cd52c2017-02-08 17:48:57 -08001000 err = hif_bus_early_suspend(hif_ctx);
1001 if (err) {
1002 hdd_err("Failed hif bus early suspend");
1003 goto resume_cdp;
1004 }
1005
Wu Gaod7dd6e42018-10-16 17:22:56 +08001006 status = ucfg_pmo_psoc_bus_suspend_req(hdd_ctx->psoc,
Dustin Brown9ef609b2017-03-15 12:19:37 -07001007 QDF_SYSTEM_SUSPEND,
1008 &pmo_params);
1009 err = qdf_status_to_os_return(status);
Dustin Brown562b9672016-12-22 15:25:33 -08001010 if (err) {
Dustin Brown9ef609b2017-03-15 12:19:37 -07001011 hdd_err("Failed pmo bus suspend: %d", status);
Houston Hoffmane5cd52c2017-02-08 17:48:57 -08001012 goto late_hif_resume;
Dustin Brown562b9672016-12-22 15:25:33 -08001013 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014
Komal Seelamc12e6752016-02-02 18:17:13 +05301015 err = hif_bus_suspend(hif_ctx);
Dustin Brown562b9672016-12-22 15:25:33 -08001016 if (err) {
Dustin Brown9ef609b2017-03-15 12:19:37 -07001017 hdd_err("Failed hif bus suspend: %d", err);
1018 goto resume_pmo;
Dustin Brown562b9672016-12-22 15:25:33 -08001019 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001020
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001021 hdd_info("bus suspend succeeded");
Dustin Brown2d228232016-09-22 15:06:19 -07001022 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001023
Dustin Brown9ef609b2017-03-15 12:19:37 -07001024resume_pmo:
Wu Gaod7dd6e42018-10-16 17:22:56 +08001025 status = ucfg_pmo_psoc_bus_resume_req(hdd_ctx->psoc,
Dustin Brown9ef609b2017-03-15 12:19:37 -07001026 QDF_SYSTEM_SUSPEND);
1027 QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
1028
Houston Hoffmane5cd52c2017-02-08 17:48:57 -08001029late_hif_resume:
1030 status = hif_bus_late_resume(hif_ctx);
1031 QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
1032
Dustin Brown9ef609b2017-03-15 12:19:37 -07001033resume_cdp:
Rakesh Pillaid2e53852019-09-13 04:20:13 +05301034 status = cdp_bus_resume(dp_soc, OL_TXRX_PDEV_ID);
Dustin Brown9ef609b2017-03-15 12:19:37 -07001035 QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
1036
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001037 return err;
1038}
1039
Dustin Brown9ef609b2017-03-15 12:19:37 -07001040int wlan_hdd_bus_suspend(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001041{
Dustin Brown54096432017-02-23 13:00:44 -08001042 struct wow_enable_params default_params = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043
Dustin Brownbda9e542019-02-27 10:24:34 -08001044 return __wlan_hdd_bus_suspend(default_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001045}
1046
Dustin Browne70fd972016-11-10 11:17:40 -08001047#ifdef WLAN_SUSPEND_RESUME_TEST
Dustin Brown9ef609b2017-03-15 12:19:37 -07001048int wlan_hdd_unit_test_bus_suspend(struct wow_enable_params wow_params)
Dustin Browne70fd972016-11-10 11:17:40 -08001049{
Dustin Brown96b98dd2019-03-06 12:39:37 -08001050 return __wlan_hdd_bus_suspend(wow_params);
Dustin Browne70fd972016-11-10 11:17:40 -08001051}
1052#endif
1053
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054/**
Dustin Brownbda9e542019-02-27 10:24:34 -08001055 * wlan_hdd_bus_suspend_noirq() - handle .suspend_noirq callback
Rajeev Kumar99805a72016-08-29 13:53:52 -07001056 *
1057 * This function is called by the platform driver to complete the
1058 * bus suspend callback when device interrupts are disabled by kernel.
1059 * Call HIF and WMA suspend_noirq callbacks to make sure there is no
1060 * wake up pending from FW before allowing suspend.
1061 *
1062 * Return: 0 for success and -EBUSY if FW is requesting wake up
1063 */
Dustin Brownbda9e542019-02-27 10:24:34 -08001064int wlan_hdd_bus_suspend_noirq(void)
Rajeev Kumar99805a72016-08-29 13:53:52 -07001065{
Jeff Johnson6bc79d82017-08-28 12:02:36 -07001066 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Rajeev Kumar99805a72016-08-29 13:53:52 -07001067 void *hif_ctx;
Dustin Brown05557182017-10-12 14:44:49 -07001068 int errno;
1069 uint32_t pending_events;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001070
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001071 hdd_info("start bus_suspend_noirq");
Dustin Brown05557182017-10-12 14:44:49 -07001072 errno = wlan_hdd_validate_context(hdd_ctx);
1073 if (errno) {
1074 hdd_err("Invalid HDD context: errno %d", errno);
1075 return errno;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001076 }
1077
1078 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
Dustin Brown05557182017-10-12 14:44:49 -07001079 hdd_debug("Driver module closed; skip bus-noirq suspend");
Rajeev Kumar99805a72016-08-29 13:53:52 -07001080 return 0;
1081 }
1082
1083 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Dustin Brown05557182017-10-12 14:44:49 -07001084 if (!hif_ctx) {
1085 hdd_err("hif_ctx is null");
1086 return -EINVAL;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001087 }
1088
Dustin Brown05557182017-10-12 14:44:49 -07001089 errno = hif_bus_suspend_noirq(hif_ctx);
1090 if (errno)
Rajeev Kumar99805a72016-08-29 13:53:52 -07001091 goto done;
1092
Wu Gaod7dd6e42018-10-16 17:22:56 +08001093 errno = ucfg_pmo_psoc_is_target_wake_up_received(hdd_ctx->psoc);
Dustin Brown05557182017-10-12 14:44:49 -07001094 if (errno == -EAGAIN) {
1095 hdd_err("Firmware attempting wakeup, try again");
1096 wlan_hdd_inc_suspend_stats(hdd_ctx,
1097 SUSPEND_FAIL_INITIAL_WAKEUP);
1098 }
1099 if (errno)
Rajeev Kumar99805a72016-08-29 13:53:52 -07001100 goto resume_hif_noirq;
1101
Dustin Brown05557182017-10-12 14:44:49 -07001102 pending_events = wma_critical_events_in_flight();
1103 if (pending_events) {
1104 hdd_err("%d critical event(s) in flight; try again",
1105 pending_events);
1106 errno = -EAGAIN;
1107 goto resume_hif_noirq;
1108 }
1109
Dustin Brownd9322482017-01-09 12:46:03 -08001110 hdd_ctx->suspend_resume_stats.suspends++;
1111
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001112 hdd_info("bus_suspend_noirq done");
Dustin Brown2d228232016-09-22 15:06:19 -07001113 return 0;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001114
1115resume_hif_noirq:
Dustin Brown05557182017-10-12 14:44:49 -07001116 QDF_BUG(!hif_bus_resume_noirq(hif_ctx));
Dustin Brown105d7902016-10-03 16:27:59 -07001117
Dustin Brown05557182017-10-12 14:44:49 -07001118done:
1119 hdd_err("suspend_noirq failed, status: %d", errno);
1120
1121 return errno;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001122}
1123
Rajeev Kumar99805a72016-08-29 13:53:52 -07001124/**
Dustin Brownbda9e542019-02-27 10:24:34 -08001125 * wlan_hdd_bus_resume() - handles platform resume
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001126 *
1127 * Does precondtion validation. Ensures that a subsystem restart isn't in
1128 * progress. Ensures that no load or unload is in progress. Ensures that
1129 * it has valid pointers for the required contexts.
1130 * Calls into hif to resume the bus opperation.
1131 * Calls into wma to handshake with firmware and notify it that the bus is up.
1132 * Calls into ol_txrx for symetry.
1133 * Failures are treated as catastrophic.
1134 *
1135 * return: error code or 0 for success
1136 */
Dustin Brownbda9e542019-02-27 10:24:34 -08001137int wlan_hdd_bus_resume(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001138{
Jeff Johnson6bc79d82017-08-28 12:02:36 -07001139 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
SaidiReddy Yenugad8323662016-07-20 15:45:34 +05301140 void *hif_ctx;
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001141 int status;
1142 QDF_STATUS qdf_status;
Dustin Brown7ff24dd2017-05-10 15:49:59 -07001143 void *dp_soc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001144
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001145 if (cds_is_driver_recovering())
1146 return 0;
1147
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001148 hdd_info("starting bus resume");
Dustin Brown562b9672016-12-22 15:25:33 -08001149
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001150 status = wlan_hdd_validate_context(hdd_ctx);
Dustin Brown562b9672016-12-22 15:25:33 -08001151 if (status) {
1152 hdd_err("Invalid hdd context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001153 return status;
Dustin Brown562b9672016-12-22 15:25:33 -08001154 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155
Arun Khandavallifae92942016-08-01 13:31:08 +05301156 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -08001157 hdd_debug("Driver Module closed; return success");
Arun Khandavallifae92942016-08-01 13:31:08 +05301158 return 0;
1159 }
1160
SaidiReddy Yenugad8323662016-07-20 15:45:34 +05301161 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Jeff Johnsond36fa332019-03-18 13:42:25 -07001162 if (!hif_ctx) {
Dustin Brown562b9672016-12-22 15:25:33 -08001163 hdd_err("Failed to get hif context");
SaidiReddy Yenugad8323662016-07-20 15:45:34 +05301164 return -EINVAL;
Dustin Brown562b9672016-12-22 15:25:33 -08001165 }
SaidiReddy Yenugad8323662016-07-20 15:45:34 +05301166
Komal Seelamc12e6752016-02-02 18:17:13 +05301167 status = hif_bus_resume(hif_ctx);
Dustin Brown562b9672016-12-22 15:25:33 -08001168 if (status) {
1169 hdd_err("Failed hif bus resume");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001170 goto out;
Dustin Brown562b9672016-12-22 15:25:33 -08001171 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001172
Wu Gaod7dd6e42018-10-16 17:22:56 +08001173 qdf_status = ucfg_pmo_psoc_bus_resume_req(hdd_ctx->psoc,
1174 QDF_SYSTEM_SUSPEND);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301175 status = qdf_status_to_os_return(qdf_status);
Dustin Brown562b9672016-12-22 15:25:33 -08001176 if (status) {
Dustin Brown05557182017-10-12 14:44:49 -07001177 hdd_err("Failed pmo bus resume");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001178 goto out;
Dustin Brown562b9672016-12-22 15:25:33 -08001179 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001180
Houston Hoffmane5cd52c2017-02-08 17:48:57 -08001181 status = hif_bus_late_resume(hif_ctx);
1182 if (status) {
1183 hdd_err("Failed hif bus late resume");
1184 goto out;
1185 }
1186
Dustin Brown7ff24dd2017-05-10 15:49:59 -07001187 dp_soc = cds_get_context(QDF_MODULE_ID_SOC);
Rakesh Pillaid2e53852019-09-13 04:20:13 +05301188 qdf_status = cdp_bus_resume(dp_soc, OL_TXRX_PDEV_ID);
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001189 status = qdf_status_to_os_return(qdf_status);
Dustin Brown562b9672016-12-22 15:25:33 -08001190 if (status) {
1191 hdd_err("Failed cdp bus resume");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001192 goto out;
Dustin Brown562b9672016-12-22 15:25:33 -08001193 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001194
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001195 hdd_info("bus resume succeeded");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001196 return 0;
1197
1198out:
Rajeev Kumar10466012018-01-24 14:12:20 -08001199 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() ||
1200 cds_is_fw_down())
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001201 return 0;
1202
1203 QDF_BUG(false);
1204
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205 return status;
1206}
1207
Mohit Khannafa99aea2016-05-12 21:43:13 -07001208/**
Dustin Brownbda9e542019-02-27 10:24:34 -08001209 * wlan_hdd_bus_resume_noirq(): handle bus resume no irq
Rajeev Kumar99805a72016-08-29 13:53:52 -07001210 *
1211 * This function is called by the platform driver to do bus
1212 * resume no IRQ before calling resume callback. Call WMA and HIF
1213 * layers to complete the resume_noirq.
1214 *
1215 * Return: 0 for success and negative error code for failure
1216 */
Dustin Brownbda9e542019-02-27 10:24:34 -08001217int wlan_hdd_bus_resume_noirq(void)
Rajeev Kumar99805a72016-08-29 13:53:52 -07001218{
Jeff Johnson6bc79d82017-08-28 12:02:36 -07001219 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Rajeev Kumar99805a72016-08-29 13:53:52 -07001220 void *hif_ctx;
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001221 int status;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301222 QDF_STATUS qdf_status;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001223
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001224 hdd_info("starting bus_resume_noirq");
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001225 if (cds_is_driver_recovering())
1226 return 0;
1227
1228 status = wlan_hdd_validate_context(hdd_ctx);
Rajeev Kumar99805a72016-08-29 13:53:52 -07001229 if (status) {
1230 hdd_err("Invalid HDD context: %d", status);
1231 return status;
1232 }
1233
1234 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
Srinivas Girigowda852c2542017-03-06 16:18:21 -08001235 hdd_debug("Driver Module closed return success");
Rajeev Kumar99805a72016-08-29 13:53:52 -07001236 return 0;
1237 }
1238
1239 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Jeff Johnsond36fa332019-03-18 13:42:25 -07001240 if (!hif_ctx)
Rajeev Kumar99805a72016-08-29 13:53:52 -07001241 return -EINVAL;
1242
Wu Gaod7dd6e42018-10-16 17:22:56 +08001243 qdf_status = ucfg_pmo_psoc_clear_target_wake_up(hdd_ctx->psoc);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301244 QDF_BUG(!qdf_status);
Rajeev Kumar99805a72016-08-29 13:53:52 -07001245
1246 status = hif_bus_resume_noirq(hif_ctx);
1247 QDF_BUG(!status);
1248
Rajeev Kumarb0ef9822017-12-15 18:14:43 -08001249 hdd_info("bus_resume_noirq done");
Dustin Brownbda9e542019-02-27 10:24:34 -08001250
Rajeev Kumar99805a72016-08-29 13:53:52 -07001251 return status;
1252}
1253
Rajeev Kumar99805a72016-08-29 13:53:52 -07001254/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07001255 * wlan_hdd_bus_reset_resume() - resume wlan bus after reset
1256 *
1257 * This function is called to tell the driver that the device has been resumed
1258 * and it has also been reset. The driver should redo any necessary
1259 * initialization. It is mainly used by the USB bus
1260 *
1261 * Return: int 0 for success, non zero for failure
1262 */
1263static int wlan_hdd_bus_reset_resume(void)
1264{
Dustin Brownbda9e542019-02-27 10:24:34 -08001265 struct hif_opaque_softc *scn = cds_get_context(QDF_MODULE_ID_HIF);
Anurag Chouhance6a4052016-09-14 18:20:42 +05301266
Anurag Chouhance6a4052016-09-14 18:20:42 +05301267 if (!scn) {
1268 hdd_err("Failed to get HIF context");
1269 return -EFAULT;
1270 }
Mohit Khannafa99aea2016-05-12 21:43:13 -07001271
Dustin Brownbda9e542019-02-27 10:24:34 -08001272 return hif_bus_reset_resume(scn);
Mohit Khannafa99aea2016-05-12 21:43:13 -07001273}
1274
Houston Hoffmane8937082015-11-10 16:49:12 -08001275#ifdef FEATURE_RUNTIME_PM
Houston Hoffmane8937082015-11-10 16:49:12 -08001276/**
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301277 * hdd_pld_runtime_suspend_cb() - Runtime suspend callback from PMO
1278 *
1279 * Return: 0 on success or error value otherwise
1280 */
1281static int hdd_pld_runtime_suspend_cb(void)
1282{
1283 qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
1284
1285 if (!qdf_dev) {
1286 hdd_err("Invalid context");
1287 return -EINVAL;
1288 }
1289
1290 return pld_auto_suspend(qdf_dev->dev);
1291}
1292
1293/**
Dustin Brownbda9e542019-02-27 10:24:34 -08001294 * wlan_hdd_runtime_suspend() - suspend the wlan bus without apps suspend
Houston Hoffmane8937082015-11-10 16:49:12 -08001295 *
1296 * Each layer is responsible for its own suspend actions. wma_runtime_suspend
1297 * takes care of the parts of the 802.11 suspend that we want to do for runtime
1298 * suspend.
1299 *
1300 * Return: 0 or errno
1301 */
Dustin Brownbda9e542019-02-27 10:24:34 -08001302static int wlan_hdd_runtime_suspend(struct device *dev)
Houston Hoffmane8937082015-11-10 16:49:12 -08001303{
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301304 int err;
1305 QDF_STATUS status;
Jeff Johnson6bc79d82017-08-28 12:02:36 -07001306 struct hdd_context *hdd_ctx;
Alan Chenabd19472019-08-30 12:07:03 -07001307 qdf_time_t delta;
Houston Hoffmane8937082015-11-10 16:49:12 -08001308
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301309 hdd_debug("Starting runtime suspend");
Houston Hoffmane8937082015-11-10 16:49:12 -08001310
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301311 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1312 err = wlan_hdd_validate_context(hdd_ctx);
1313 if (err)
1314 return err;
Houston Hoffmane8937082015-11-10 16:49:12 -08001315
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301316 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1317 hdd_debug("Driver module closed skipping runtime suspend");
1318 return 0;
1319 }
Houston Hoffmane8937082015-11-10 16:49:12 -08001320
Dustin Brown07901ec2018-09-07 11:02:41 -07001321 if (ucfg_scan_get_pdev_status(hdd_ctx->pdev) !=
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301322 SCAN_NOT_IN_PROGRESS) {
1323 hdd_debug("Scan in progress, ignore runtime suspend");
1324 return -EBUSY;
1325 }
Yue Ma1e11d792016-02-26 18:58:44 -08001326
Wu Gaod7dd6e42018-10-16 17:22:56 +08001327 status = ucfg_pmo_psoc_bus_runtime_suspend(hdd_ctx->psoc,
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301328 hdd_pld_runtime_suspend_cb);
1329 err = qdf_status_to_os_return(status);
Houston Hoffmane8937082015-11-10 16:49:12 -08001330
Alan Chenf8a46d52019-09-04 11:01:12 -07001331 hdd_ctx->runtime_suspend_done_time_stamp =
1332 qdf_get_log_timestamp_usecs();
Alan Chenabd19472019-08-30 12:07:03 -07001333 delta = hdd_ctx->runtime_suspend_done_time_stamp -
1334 hdd_ctx->runtime_resume_start_time_stamp;
1335
1336 if (hdd_ctx->runtime_suspend_done_time_stamp >
1337 hdd_ctx->runtime_resume_start_time_stamp)
Alan Chenf8a46d52019-09-04 11:01:12 -07001338 hdd_debug("Runtime suspend done result: %d total cxpc up time %lu microseconds",
Alan Chenabd19472019-08-30 12:07:03 -07001339 err, delta);
Houston Hoffmane8937082015-11-10 16:49:12 -08001340
Manjunathappa Prakashf065fcd2019-08-06 16:47:08 -07001341 if (status == QDF_STATUS_SUCCESS)
1342 hdd_bus_bw_compute_timer_stop(hdd_ctx);
1343
1344 hdd_debug("Runtime suspend done result: %d", err);
1345
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301346 return err;
Houston Hoffmane8937082015-11-10 16:49:12 -08001347}
1348
Houston Hoffmane8937082015-11-10 16:49:12 -08001349/**
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301350 * hdd_pld_runtime_resume_cb() - Runtime resume callback from PMO
1351 *
1352 * Return: 0 on success or error value otherwise
1353 */
1354static int hdd_pld_runtime_resume_cb(void)
1355{
1356 qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
1357
1358 if (!qdf_dev) {
1359 hdd_err("Invalid context");
1360 return -EINVAL;
1361 }
1362
1363 return pld_auto_resume(qdf_dev->dev);
1364}
1365
1366/**
Dustin Brownbda9e542019-02-27 10:24:34 -08001367 * wlan_hdd_runtime_resume() - resume the wlan bus from runtime suspend
Houston Hoffmane8937082015-11-10 16:49:12 -08001368 *
1369 * Sets the runtime pm state and coordinates resume between hif wma and
1370 * ol_txrx.
1371 *
1372 * Return: success since failure is a bug
1373 */
Dustin Brownbda9e542019-02-27 10:24:34 -08001374static int wlan_hdd_runtime_resume(struct device *dev)
Houston Hoffmane8937082015-11-10 16:49:12 -08001375{
Alan Chen35cb57c2019-09-11 12:02:50 -07001376 struct hdd_context *hdd_ctx;
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301377 QDF_STATUS status;
Alan Chenabd19472019-08-30 12:07:03 -07001378 qdf_time_t delta;
Komal Seelamc12e6752016-02-02 18:17:13 +05301379
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301380 hdd_debug("Starting runtime resume");
1381
Alan Chen35cb57c2019-09-11 12:02:50 -07001382 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301383 if (wlan_hdd_validate_context(hdd_ctx))
1384 return 0;
1385
1386 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1387 hdd_debug("Driver module closed skipping runtime resume");
1388 return 0;
1389 }
1390
Alan Chen35cb57c2019-09-11 12:02:50 -07001391 hdd_ctx->runtime_resume_start_time_stamp =
1392 qdf_get_log_timestamp_usecs();
1393 delta = hdd_ctx->runtime_resume_start_time_stamp -
1394 hdd_ctx->runtime_suspend_done_time_stamp;
1395 hdd_debug("Starting runtime resume total cxpc down time %lu microseconds",
1396 delta);
1397
Wu Gaod7dd6e42018-10-16 17:22:56 +08001398 status = ucfg_pmo_psoc_bus_runtime_resume(hdd_ctx->psoc,
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301399 hdd_pld_runtime_resume_cb);
Manjunathappa Prakashf065fcd2019-08-06 16:47:08 -07001400 if (status != QDF_STATUS_SUCCESS) {
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301401 hdd_err("PMO Runtime resume failed: %d", status);
Manjunathappa Prakashf065fcd2019-08-06 16:47:08 -07001402 } else {
1403 if (policy_mgr_get_connection_count(hdd_ctx->psoc))
1404 hdd_bus_bw_compute_timer_start(hdd_ctx);
1405 }
Sravan Kumar Kairam27296782017-04-21 22:04:18 +05301406
1407 hdd_debug("Runtime resume done");
1408
Houston Hoffmane8937082015-11-10 16:49:12 -08001409 return 0;
1410}
Houston Hoffmane8937082015-11-10 16:49:12 -08001411#endif
1412
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001413/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001414 * wlan_hdd_pld_probe() - probe function registered to PLD
1415 * @dev: device
1416 * @pld_bus_type: PLD bus type
1417 * @bdev: bus device structure
1418 * @id: bus identifier for shared busses
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001419 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001420 * Return: 0 on success
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001421 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001422static int wlan_hdd_pld_probe(struct device *dev,
Dustin Brown32ffab32018-09-21 11:36:54 -07001423 enum pld_bus_type pld_bus_type,
1424 void *bdev,
1425 void *id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426{
Dustin Brown32ffab32018-09-21 11:36:54 -07001427 enum qdf_bus_type bus_type = to_bus_type(pld_bus_type);
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001428
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001429 if (bus_type == QDF_BUS_TYPE_NONE) {
Dustin Brown32ffab32018-09-21 11:36:54 -07001430 hdd_err("Invalid bus type %d->%d", pld_bus_type, bus_type);
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001431 return -EINVAL;
1432 }
1433
Dustin Brown32ffab32018-09-21 11:36:54 -07001434 return hdd_soc_probe(dev, bdev, id, bus_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435}
1436
1437/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001438 * wlan_hdd_pld_remove() - remove function registered to PLD
Dustin Brown32ffab32018-09-21 11:36:54 -07001439 * @dev: device to remove
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001440 * @pld_bus_type: PLD bus type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001441 *
1442 * Return: void
1443 */
Dustin Brown32ffab32018-09-21 11:36:54 -07001444static void wlan_hdd_pld_remove(struct device *dev, enum pld_bus_type bus_type)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445{
Dustin Brown491d54b2018-03-14 12:39:11 -07001446 hdd_enter();
Nachiket Kukadebe8850b2017-09-18 15:37:00 +05301447
Dustin Brown32ffab32018-09-21 11:36:54 -07001448 hdd_soc_remove(dev);
Nachiket Kukadebe8850b2017-09-18 15:37:00 +05301449
Dustin Browne74003f2018-03-14 12:51:58 -07001450 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001451}
1452
1453/**
Rajeev Kumar473f9af2019-04-05 14:25:56 -07001454 * wlan_hdd_pld_idle_shutdown() - wifi module idle shutdown after interface
1455 * inactivity timeout has trigerred idle shutdown
1456 * @dev: device to remove
1457 * @pld_bus_type: PLD bus type
1458 *
1459 * Return: 0 for success and negative error code for failure
1460 */
1461static int wlan_hdd_pld_idle_shutdown(struct device *dev,
1462 enum pld_bus_type bus_type)
1463{
1464 return hdd_psoc_idle_shutdown(dev);
1465}
1466
1467/**
1468 * wlan_hdd_pld_idle_restart() - wifi module idle restart after idle shutdown
1469 * @dev: device to remove
1470 * @pld_bus_type: PLD bus type
1471 *
1472 * Return: 0 for success and negative error code for failure
1473 */
1474static int wlan_hdd_pld_idle_restart(struct device *dev,
1475 enum pld_bus_type bus_type)
1476{
1477 return hdd_psoc_idle_restart(dev);
1478}
1479
1480/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001481 * wlan_hdd_pld_shutdown() - shutdown function registered to PLD
Dustin Brown32ffab32018-09-21 11:36:54 -07001482 * @dev: device to shutdown
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001483 * @pld_bus_type: PLD bus type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484 *
1485 * Return: void
1486 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001487static void wlan_hdd_pld_shutdown(struct device *dev,
Dustin Brown32ffab32018-09-21 11:36:54 -07001488 enum pld_bus_type bus_type)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489{
Dustin Brown491d54b2018-03-14 12:39:11 -07001490 hdd_enter();
Dustin Brown32ffab32018-09-21 11:36:54 -07001491
Dustin Browncfcb5762019-01-31 15:43:45 -08001492 hdd_soc_recovery_shutdown(dev);
Nachiket Kukadebe8850b2017-09-18 15:37:00 +05301493
Dustin Browne74003f2018-03-14 12:51:58 -07001494 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001495}
1496
1497/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001498 * wlan_hdd_pld_reinit() - reinit function registered to PLD
1499 * @dev: device
1500 * @pld_bus_type: PLD bus type
1501 * @bdev: bus device structure
1502 * @id: bus identifier for shared busses
1503 *
1504 * Return: 0 on success
1505 */
1506static int wlan_hdd_pld_reinit(struct device *dev,
Dustin Brown32ffab32018-09-21 11:36:54 -07001507 enum pld_bus_type pld_bus_type,
1508 void *bdev,
1509 void *id)
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001510{
Dustin Brown32ffab32018-09-21 11:36:54 -07001511 enum qdf_bus_type bus_type = to_bus_type(pld_bus_type);
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001512
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001513 if (bus_type == QDF_BUS_TYPE_NONE) {
Dustin Brown32ffab32018-09-21 11:36:54 -07001514 hdd_err("Invalid bus type %d->%d", pld_bus_type, bus_type);
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001515 return -EINVAL;
1516 }
1517
Dustin Brown32ffab32018-09-21 11:36:54 -07001518 return hdd_soc_recovery_reinit(dev, bdev, id, bus_type);
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001519}
1520
1521/**
1522 * wlan_hdd_pld_crash_shutdown() - crash_shutdown function registered to PLD
1523 * @dev: device
1524 * @pld_bus_type: PLD bus type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525 *
1526 * Return: void
1527 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001528static void wlan_hdd_pld_crash_shutdown(struct device *dev,
1529 enum pld_bus_type bus_type)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001530{
1531 wlan_hdd_crash_shutdown();
1532}
1533
1534/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001535 * wlan_hdd_pld_suspend() - suspend function registered to PLD
1536 * @dev: device
1537 * @pld_bus_type: PLD bus type
1538 * @state: PM state
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001539 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001540 * Return: 0 on success
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001542static int wlan_hdd_pld_suspend(struct device *dev,
Dustin Brown9ef609b2017-03-15 12:19:37 -07001543 enum pld_bus_type bus_type,
1544 pm_message_t state)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001545
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001546{
Dustin Brownbda9e542019-02-27 10:24:34 -08001547 struct osif_psoc_sync *psoc_sync;
1548 int errno;
1549
1550 errno = osif_psoc_sync_op_start(dev, &psoc_sync);
1551 if (errno)
1552 return errno;
1553
1554 errno = wlan_hdd_bus_suspend();
1555
1556 osif_psoc_sync_op_stop(psoc_sync);
1557
1558 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001559}
1560
1561/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001562 * wlan_hdd_pld_resume() - resume function registered to PLD
1563 * @dev: device
1564 * @pld_bus_type: PLD bus type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001565 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001566 * Return: 0 on success
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001568static int wlan_hdd_pld_resume(struct device *dev,
1569 enum pld_bus_type bus_type)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001570{
Dustin Brownbda9e542019-02-27 10:24:34 -08001571 struct osif_psoc_sync *psoc_sync;
1572 int errno;
Houston Hoffmane8937082015-11-10 16:49:12 -08001573
Dustin Brownbda9e542019-02-27 10:24:34 -08001574 errno = osif_psoc_sync_op_start(dev, &psoc_sync);
1575 if (errno)
1576 return errno;
1577
1578 errno = wlan_hdd_bus_resume();
1579
1580 osif_psoc_sync_op_stop(psoc_sync);
1581
1582 return errno;
1583}
Rajeev Kumar99805a72016-08-29 13:53:52 -07001584
1585/**
1586 * wlan_hdd_pld_suspend_noirq() - handle suspend no irq
1587 * @dev: device
1588 * @pld_bus_type: PLD bus type
1589 *
1590 * Complete the actions started by suspend(). Carry out any
1591 * additional operations required for suspending the device that might be
1592 * racing with its driver's interrupt handler, which is guaranteed not to
1593 * run while suspend_noirq() is being executed. Make sure to resume device
1594 * if FW has sent initial wake up message and expecting APPS to wake up.
1595 *
1596 * Return: 0 on success
1597 */
1598static int wlan_hdd_pld_suspend_noirq(struct device *dev,
Dustin Brownbda9e542019-02-27 10:24:34 -08001599 enum pld_bus_type bus_type)
Rajeev Kumar99805a72016-08-29 13:53:52 -07001600{
Dustin Brownbda9e542019-02-27 10:24:34 -08001601 struct osif_psoc_sync *psoc_sync;
1602 int errno;
1603
1604 errno = osif_psoc_sync_op_start(dev, &psoc_sync);
1605 if (errno)
1606 return errno;
1607
1608 errno = wlan_hdd_bus_suspend_noirq();
1609
1610 osif_psoc_sync_op_stop(psoc_sync);
1611
1612 return errno;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001613}
1614
1615/**
1616 * wlan_hdd_pld_resume_noirq() - handle resume no irq
1617 * @dev: device
1618 * @pld_bus_type: PLD bus type
1619 *
1620 * Prepare for the execution of resume() by carrying out any
1621 * operations required for resuming the device that might be racing with
1622 * its driver's interrupt handler, which is guaranteed not to run while
1623 * resume_noirq() is being executed. Make sure to clear target initial
1624 * wake up request such that next suspend can happen cleanly.
1625 *
1626 * Return: 0 on success
1627 */
1628static int wlan_hdd_pld_resume_noirq(struct device *dev,
Dustin Brownbda9e542019-02-27 10:24:34 -08001629 enum pld_bus_type bus_type)
Rajeev Kumar99805a72016-08-29 13:53:52 -07001630{
Dustin Brownbda9e542019-02-27 10:24:34 -08001631 struct osif_psoc_sync *psoc_sync;
1632 int errno;
1633
1634 errno = osif_psoc_sync_op_start(dev, &psoc_sync);
1635 if (errno)
1636 return errno;
1637
1638 errno = wlan_hdd_bus_resume_noirq();
1639
1640 osif_psoc_sync_op_stop(psoc_sync);
1641
1642 return errno;
Rajeev Kumar99805a72016-08-29 13:53:52 -07001643}
1644
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001645/**
Mohit Khannafa99aea2016-05-12 21:43:13 -07001646 * wlan_hdd_pld_reset_resume() - reset resume function registered to PLD
1647 * @dev: device
1648 * @pld_bus_type: PLD bus type
1649 *
1650 * Return: 0 on success
1651 */
1652static int wlan_hdd_pld_reset_resume(struct device *dev,
Dustin Brownbda9e542019-02-27 10:24:34 -08001653 enum pld_bus_type bus_type)
Mohit Khannafa99aea2016-05-12 21:43:13 -07001654{
Dustin Brownbda9e542019-02-27 10:24:34 -08001655 struct osif_psoc_sync *psoc_sync;
1656 int errno;
1657
1658 errno = osif_psoc_sync_op_start(dev, &psoc_sync);
1659 if (errno)
1660 return errno;
1661
1662 errno = wlan_hdd_bus_reset_resume();
1663
1664 osif_psoc_sync_op_stop(psoc_sync);
1665
1666 return errno;
Mohit Khannafa99aea2016-05-12 21:43:13 -07001667}
1668
1669/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001670 * wlan_hdd_pld_notify_handler() - notify_handler function registered to PLD
1671 * @dev: device
1672 * @pld_bus_type: PLD bus type
1673 * @state: Modem power state
1674 *
1675 * Return: void
1676 */
1677static void wlan_hdd_pld_notify_handler(struct device *dev,
1678 enum pld_bus_type bus_type,
1679 int state)
1680{
1681 wlan_hdd_notify_handler(state);
1682}
1683
Dustin Brown8f05f652018-10-25 15:17:30 -07001684/**
1685 * wlan_hdd_pld_uevent() - platform uevent handler
1686 * @dev: device on which the uevent occurred
1687 * @event_data: uevent parameters
1688 *
1689 * Return: None
1690 */
1691static void
1692wlan_hdd_pld_uevent(struct device *dev, struct pld_uevent_data *event_data)
1693{
Dustin Brown8f05f652018-10-25 15:17:30 -07001694 switch (event_data->uevent) {
1695 case PLD_FW_DOWN:
Dustin Brownaf8fea02018-10-29 11:31:49 -07001696 hdd_info("Received firmware down indication");
1697
1698 /* NOTE! SSR cleanup logic goes in pld shutdown, not here */
1699
1700 cds_set_target_ready(false);
1701 cds_set_recovery_in_progress(true);
1702
1703 /* SSR cleanup happens in pld shutdown, which is serialized by
1704 * the platform driver. Other operations are also serialized by
1705 * platform driver, such as probe, remove, and reinit. If the
1706 * firmware goes down during one of these operations, the driver
1707 * would normally have to wait for a timeout before shutdown
1708 * could begin. Instead, forcefully complete events waiting on
1709 * firmware with a "reset" status to avoid waiting to time out
1710 * on a firmware we already know is down.
1711 */
1712 qdf_complete_wait_events();
1713
Kabilan Kannand48b0162017-11-22 14:00:44 -08001714 break;
Kabilan Kannand48b0162017-11-22 14:00:44 -08001715 default:
Dustin Brownaf8fea02018-10-29 11:31:49 -07001716 /* other events intentionally not handled */
1717 hdd_debug("Received uevent %d", event_data->uevent);
Kabilan Kannand48b0162017-11-22 14:00:44 -08001718 break;
1719 }
1720}
1721
Houston Hoffmane8937082015-11-10 16:49:12 -08001722#ifdef FEATURE_RUNTIME_PM
1723/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001724 * wlan_hdd_pld_runtime_suspend() - runtime suspend function registered to PLD
1725 * @dev: device
1726 * @pld_bus_type: PLD bus type
Houston Hoffmane8937082015-11-10 16:49:12 -08001727 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001728 * Return: 0 on success
Houston Hoffmane8937082015-11-10 16:49:12 -08001729 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001730static int wlan_hdd_pld_runtime_suspend(struct device *dev,
1731 enum pld_bus_type bus_type)
Houston Hoffmane8937082015-11-10 16:49:12 -08001732{
Dustin Brownbda9e542019-02-27 10:24:34 -08001733 struct osif_psoc_sync *psoc_sync;
1734 int errno;
1735
1736 errno = osif_psoc_sync_op_start(dev, &psoc_sync);
1737 if (errno)
1738 return errno;
1739
1740 errno = wlan_hdd_runtime_suspend(dev);
1741
1742 osif_psoc_sync_op_stop(psoc_sync);
1743
1744 return errno;
Houston Hoffmane8937082015-11-10 16:49:12 -08001745}
1746
1747/**
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001748 * wlan_hdd_pld_runtime_resume() - runtime resume function registered to PLD
1749 * @dev: device
1750 * @pld_bus_type: PLD bus type
Houston Hoffmane8937082015-11-10 16:49:12 -08001751 *
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001752 * Return: 0 on success
Houston Hoffmane8937082015-11-10 16:49:12 -08001753 */
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001754static int wlan_hdd_pld_runtime_resume(struct device *dev,
1755 enum pld_bus_type bus_type)
Houston Hoffmane8937082015-11-10 16:49:12 -08001756{
Yue Ma80fb30c2019-04-29 15:11:40 -07001757 /* As opposite to suspend, Runtime PM resume can happen
1758 * synchronously during driver shutdown or idle shutown,
1759 * so remove PSOC sync protection here.
1760 */
1761 return wlan_hdd_runtime_resume(dev);
Houston Hoffmane8937082015-11-10 16:49:12 -08001762}
1763#endif
1764
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001765struct pld_driver_ops wlan_drv_ops = {
1766 .probe = wlan_hdd_pld_probe,
1767 .remove = wlan_hdd_pld_remove,
Rajeev Kumar473f9af2019-04-05 14:25:56 -07001768 .idle_shutdown = wlan_hdd_pld_idle_shutdown,
1769 .idle_restart = wlan_hdd_pld_idle_restart,
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001770 .shutdown = wlan_hdd_pld_shutdown,
1771 .reinit = wlan_hdd_pld_reinit,
1772 .crash_shutdown = wlan_hdd_pld_crash_shutdown,
1773 .suspend = wlan_hdd_pld_suspend,
1774 .resume = wlan_hdd_pld_resume,
Rajeev Kumar99805a72016-08-29 13:53:52 -07001775 .suspend_noirq = wlan_hdd_pld_suspend_noirq,
1776 .resume_noirq = wlan_hdd_pld_resume_noirq,
Mohit Khannafa99aea2016-05-12 21:43:13 -07001777 .reset_resume = wlan_hdd_pld_reset_resume,
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001778 .modem_status = wlan_hdd_pld_notify_handler,
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +05301779 .uevent = wlan_hdd_pld_uevent,
Houston Hoffmane8937082015-11-10 16:49:12 -08001780#ifdef FEATURE_RUNTIME_PM
Jeff Johnson330292a2016-05-16 16:09:49 -07001781 .runtime_suspend = wlan_hdd_pld_runtime_suspend,
1782 .runtime_resume = wlan_hdd_pld_runtime_resume,
Houston Hoffmane8937082015-11-10 16:49:12 -08001783#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001785
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786int wlan_hdd_register_driver(void)
1787{
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001788 return pld_register_driver(&wlan_drv_ops);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789}
1790
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001791void wlan_hdd_unregister_driver(void)
1792{
Yuanyuan Liu1d8045c2016-04-06 16:40:49 -07001793 pld_unregister_driver();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794}