From 3ecc87863e5ebb06114dd111647ea83743d7487d Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Wed, 19 Sep 2018 16:37:13 -0700 Subject: [PATCH] qcacld-3.0: Integrate DSC (psoc idle shutdown/restart) The Driver Synchronization Core (DSC) is a set of synchronization primitives for use by the driver's orchestration layer. It provides APIs for ensuring safe state transitions (including bring up and tear down) of major driver objects: a single driver, associated psocs, and their associated vdevs. As part of integrating the DSC APIs into HDD, protect psoc idle shutdown and restart. Change-Id: I416a8f4cfb67fabce377ff96715e3a372a3aed7d CRs-Fixed: 2347019 --- core/hdd/inc/wlan_hdd_main.h | 34 ++++++++++ core/hdd/src/wlan_hdd_cfg80211.c | 4 +- core/hdd/src/wlan_hdd_hostapd.c | 6 +- core/hdd/src/wlan_hdd_main.c | 107 ++++++++++++++++++------------- core/hdd/src/wlan_hdd_p2p.c | 12 ++-- 5 files changed, 105 insertions(+), 58 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 89b35421cf92..6af5b2ee12e5 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -2897,7 +2897,31 @@ int hdd_start_station_adapter(struct hdd_adapter *adapter); int hdd_start_ap_adapter(struct hdd_adapter *adapter); int hdd_configure_cds(struct hdd_context *hdd_ctx); int hdd_set_fw_params(struct hdd_adapter *adapter); + +/** + * hdd_wlan_start_modules() - Single driver state machine for starting modules + * @hdd_ctx: HDD context + * @reinit: flag to indicate from SSR or normal path + * + * This function maintains the driver state machine it will be invoked from + * startup, reinit and change interface. Depending on the driver state shall + * perform the opening of the modules. + * + * Return: Errno + */ int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit); + +/** + * hdd_wlan_stop_modules - Single driver state machine for stoping modules + * @hdd_ctx: HDD context + * @ftm_mode: ftm mode + * + * This function maintains the driver state machine it will be invoked from + * exit, shutdown and con_mode change handler. Depending on the driver state + * shall perform the stopping/closing of the modules. + * + * Return: Errno + */ int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode); /** @@ -2916,6 +2940,16 @@ void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx); */ void hdd_psoc_idle_timer_stop(struct hdd_context *hdd_ctx); +/** + * hdd_psoc_idle_restart() - restart a previously shutdown idle psoc, if needed + * @hdd_ctx: the hdd context which should be restarted + * + * This API does nothing if the given psoc is already active. + * + * Return: Errno + */ +int hdd_psoc_idle_restart(struct hdd_context *hdd_ctx); + int hdd_start_adapter(struct hdd_adapter *adapter); void hdd_populate_random_mac_addr(struct hdd_context *hdd_ctx, uint32_t num); /** diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 2f6977253cdf..ddfbc4dc4630 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -13190,9 +13190,9 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, qdf_opmode_str(adapter->device_mode), qdf_opmode_str(new_mode)); - errno = hdd_wlan_start_modules(hdd_ctx, false); + errno = hdd_psoc_idle_restart(hdd_ctx); if (errno) { - hdd_err("Failed to start modules; errno:%d", errno); + hdd_err("Failed to restart psoc; errno:%d", errno); return -EINVAL; } diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 5cea9f6a15c7..77c5807847c6 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -421,11 +421,9 @@ static int __hdd_hostapd_open(struct net_device *dev) ret = wlan_hdd_validate_context(hdd_ctx); if (ret) return ret; - /* - * Check statemachine state and also stop iface change timer if running - */ - ret = hdd_wlan_start_modules(hdd_ctx, false); + /* ensure the physical soc is up */ + ret = hdd_psoc_idle_restart(hdd_ctx); if (ret) { hdd_err("Failed to start WLAN modules return"); return ret; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 46b744dcb0df..515da1d75681 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -2080,7 +2080,7 @@ static int __hdd_mon_open(struct net_device *dev) hdd_mon_mode_ether_setup(dev); if (con_mode == QDF_GLOBAL_MONITOR_MODE) { - ret = hdd_wlan_start_modules(hdd_ctx, false); + ret = hdd_psoc_idle_restart(hdd_ctx); if (ret) { hdd_err("Failed to start WLAN modules return"); return ret; @@ -2631,17 +2631,6 @@ static int hdd_update_country_code(struct hdd_context *hdd_ctx) return hdd_reg_set_country(hdd_ctx, country_code); } -/** - * hdd_wlan_start_modules() - Single driver state machine for starting modules - * @hdd_ctx: HDD context - * @reinit: flag to indicate from SSR or normal path - * - * This function maintains the driver state machine it will be invoked from - * startup, reinit and change interface. Depending on the driver state shall - * perform the opening of the modules. - * - * Return: 0 for success; non-zero for failure - */ int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit) { int ret = 0; @@ -2990,14 +2979,12 @@ static int __hdd_open(struct net_device *dev) goto err_hdd_hdd_init_deinit_lock; } - - ret = hdd_wlan_start_modules(hdd_ctx, false); + ret = hdd_psoc_idle_restart(hdd_ctx); if (ret) { hdd_err("Failed to start WLAN modules return"); goto err_hdd_hdd_init_deinit_lock; } - if (!test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { ret = hdd_start_adapter(adapter); if (ret) { @@ -3136,7 +3123,6 @@ static int __hdd_stop(struct net_device *dev) /* DeInit the adapter. This ensures datapath cleanup as well */ hdd_deinit_adapter(hdd_ctx, adapter, true); - /* * Upon wifi turn off, DUT has to flush the scan results so if * this is the last cli iface, flush the scan database. @@ -8904,31 +8890,75 @@ void hdd_psoc_idle_timer_stop(struct hdd_context *hdd_ctx) } /** - * hdd_iface_change_callback() - Function invoked when stop modules expires - * @priv: pointer to hdd context + * hdd_psoc_idle_shutdown() - perform an idle shutdown on the given psoc + * @hdd_ctx: the hdd context which should be shutdown * - * This function is invoked when the timer waiting for the interface change - * expires, it shall cut-down the power to wlan and stop all the modules. + * When no interfaces are "up" on a psoc, an idle shutdown timer is started. + * If no interfaces are brought up before the timer expires, we do an + * "idle shutdown," cutting power to the physical SoC to save power. This is + * done completely transparently from the perspective of userspace. * - * Return: void + * Return: None */ -static void hdd_iface_change_callback(void *priv) +static void hdd_psoc_idle_shutdown(struct hdd_context *hdd_ctx) { - struct hdd_context *hdd_ctx = (struct hdd_context *) priv; - int ret; - int status = wlan_hdd_validate_context(hdd_ctx); - - if (status) - return; + struct hdd_psoc *hdd_psoc = hdd_ctx->hdd_psoc; + QDF_STATUS status; hdd_enter(); - hdd_debug("Interface change timer expired close the modules!"); - ret = hdd_wlan_stop_modules(hdd_ctx, false); - if (ret) - hdd_err("Failed to stop modules"); + + status = dsc_psoc_trans_start(hdd_psoc->dsc_psoc, "idle shutdown"); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_info("psoc busy, abort idle shutdown; status:%u", status); + return; + } + + QDF_BUG(!hdd_wlan_stop_modules(hdd_ctx, false)); + + hdd_psoc->state = psoc_state_idle; + dsc_psoc_trans_stop(hdd_psoc->dsc_psoc); + hdd_exit(); } +int hdd_psoc_idle_restart(struct hdd_context *hdd_ctx) +{ + struct hdd_psoc *hdd_psoc = hdd_ctx->hdd_psoc; + QDF_STATUS status; + int errno; + + status = dsc_psoc_trans_start_wait(hdd_psoc->dsc_psoc, "idle restart"); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_info("unable to start 'idle restart'; status:%u", status); + return qdf_status_to_os_return(status); + } + + errno = hdd_wlan_start_modules(hdd_ctx, false); + if (!errno) + hdd_psoc->state = psoc_state_active; + + dsc_psoc_trans_stop(hdd_psoc->dsc_psoc); + + return errno; +} + +/** + * hdd_psoc_idle_timeout_callback() - Handler for psoc idle timeout + * @priv: pointer to hdd context + * + * Return: None + */ +static void hdd_psoc_idle_timeout_callback(void *priv) +{ + struct hdd_context *hdd_ctx = priv; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_debug("Psoc idle timeout elapsed; starting psoc shutdown"); + hdd_psoc_idle_shutdown(hdd_ctx); +} + #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE static void hdd_set_wlan_logging(struct hdd_context *hdd_ctx) { @@ -9042,7 +9072,7 @@ struct hdd_context *hdd_context_create(struct device *dev) } qdf_create_delayed_work(&hdd_ctx->psoc_idle_timeout_work, - hdd_iface_change_callback, + hdd_psoc_idle_timeout_callback, hdd_ctx); mutex_init(&hdd_ctx->iface_change_lock); @@ -10870,17 +10900,6 @@ static void hdd_deregister_policy_manager_callback( } #endif -/** - * hdd_wlan_stop_modules - Single driver state machine for stoping modules - * @hdd_ctx: HDD context - * @ftm_mode: ftm mode - * - * This function maintains the driver state machine it will be invoked from - * exit, shutdown and con_mode change handler. Depending on the driver state - * shall perform the stopping/closing of the modules. - * - * Return: 0 for success; non-zero for failure - */ int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode) { void *hif_ctx; diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c index 5ffa4b397b72..c2e09167824c 100644 --- a/core/hdd/src/wlan_hdd_p2p.c +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -696,12 +696,8 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-ENOSPC); } - /* - * Add interface can be requested from the upper layer at any time - * check the statemachine for modules state and if they are closed - * open the modules. - */ - ret = hdd_wlan_start_modules(hdd_ctx, false); + /* ensure physcial soc is up */ + ret = hdd_psoc_idle_restart(hdd_ctx); if (ret) { hdd_err("Failed to start the wlan_modules"); goto close_adapter; @@ -840,8 +836,8 @@ int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) if (errno) return errno; - /* check state machine state and kickstart modules if they are closed */ - errno = hdd_wlan_start_modules(hdd_ctx, false); + /* ensure physical soc is up */ + errno = hdd_psoc_idle_restart(hdd_ctx); if (errno) return errno;