diff options
| -rw-r--r-- | core/hdd/inc/wlan_hdd_driver_ops.h | 2 | ||||
| -rw-r--r-- | core/hdd/inc/wlan_hdd_power.h | 22 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_power.c | 157 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_wext.c | 40 | ||||
| -rw-r--r-- | core/pld/inc/pld_common.h | 3 |
5 files changed, 188 insertions, 36 deletions
diff --git a/core/hdd/inc/wlan_hdd_driver_ops.h b/core/hdd/inc/wlan_hdd_driver_ops.h index 3ea44449b55c..f919e8decf1c 100644 --- a/core/hdd/inc/wlan_hdd_driver_ops.h +++ b/core/hdd/inc/wlan_hdd_driver_ops.h @@ -38,7 +38,9 @@ int wlan_hdd_register_driver(void); void wlan_hdd_unregister_driver(void); int wlan_hdd_bus_suspend(pm_message_t state); +int wlan_hdd_bus_suspend_noirq(void); int wlan_hdd_bus_resume(void); +int wlan_hdd_bus_resume_noirq(void); void hdd_hif_close(void *hif_ctx); int hdd_hif_open(struct device *dev, void *bdev, const hif_bus_id *bid, enum qdf_bus_type bus_type, bool reinit); diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h index e173d4f517db..61f4d6d490c9 100644 --- a/core/hdd/inc/wlan_hdd_power.h +++ b/core/hdd/inc/wlan_hdd_power.h @@ -200,4 +200,26 @@ void hdd_wlan_suspend_resume_event(uint8_t state) {} #endif /* FEATURE_WLAN_DIAG_SUPPORT */ +/* + * Unit-test suspend/resume is a testing feature that allows putting firmware + * into WoW suspend irrespective of Apps suspend status. It emulates the chain + * of events that occur durring normal system-level suspend/resume, such as + * initiating all of the suspend/resume stages in the correct order, and + * enabling/disabling appropriate copy engine irqs. + */ +#ifdef WLAN_SUSPEND_RESUME_TEST +int hdd_wlan_fake_apps_resume(struct wiphy *wiphy); +int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy); +#else +static inline int hdd_wlan_fake_apps_resume(struct wiphy *wiphy) +{ + return 0; +} + +static inline int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy) +{ + return 0; +} +#endif /* WLAN_SUSPEND_RESUME_TEST */ + #endif /* __WLAN_HDD_POWER_H */ diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 7e82be6f9ae7..26e5f6641987 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -74,6 +74,7 @@ #include "cds_concurrency.h" #include "cdp_txrx_flow_ctrl_v2.h" #include "pld_common.h" +#include "wlan_hdd_driver_ops.h" /* Preprocessor definitions and constants */ #define HDD_SSR_BRING_UP_TIME 30000 @@ -2349,3 +2350,159 @@ int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter, } return 0; } + +#ifdef WLAN_SUSPEND_RESUME_TEST +/* + * On Rome/iHelium there are 12 CE irqs and #2 is the wake irq. This may not be + * a valid assumption on future platforms. + */ +#define CE_IRQ_COUNT 12 +#define CE_WAKE_IRQ 2 +static struct wiphy *g_wiphy; + +#define HDD_FA_SUSPENDED_BIT (0) +static unsigned long fake_apps_state; + +static int __hdd_wlan_fake_apps_resume(struct wiphy *wiphy); + +/** + * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming + * from unit-test initiated suspend from irq wakeup signal + * @val: interrupt val + * + * Resume wlan after getting very 1st CE interrupt from target + * + * Return: none + */ +static void hdd_wlan_fake_apps_resume_irq_callback(uint32_t val) +{ + hdd_info("Trigger unit-test resume WLAN; val: 0x%x", val); + + QDF_BUG(g_wiphy); + __hdd_wlan_fake_apps_resume(g_wiphy); + g_wiphy = NULL; +} + +/** + * hdd_wlan_fake_apps_suspend() - Initiate a unit-test triggered suspend + * @wiphy: wiphy struct from a validated hdd context + * + * Return: Zero on success, suspend related non-zero error code on failure + */ +int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy) +{ + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct hif_opaque_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + pm_message_t state; + int i, resume_err, suspend_err; + + hdd_info("Unit-test suspend WLAN"); + if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) { + hdd_info("Already unit-test suspended; Nothing to do"); + return 0; + } + + suspend_err = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL); + if (suspend_err) + goto resume_done; + + state.event = PM_EVENT_SUSPEND; + suspend_err = wlan_hdd_bus_suspend(state); + if (suspend_err) + goto cfg80211_resume; + + /* simulate kernel disabling irqs */ + for (i = 0; i < CE_IRQ_COUNT; i++) + pld_disable_irq(qdf_dev->dev, i); + + suspend_err = wlan_hdd_bus_suspend_noirq(); + if (suspend_err) + goto enable_irqs_and_bus_resume; + + /* re-enable wake irq */ + pld_enable_irq(qdf_dev->dev, CE_WAKE_IRQ); + + /* pass wiphy to callback via global variable */ + g_wiphy = wiphy; + hif_fake_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback); + + return 0; + +enable_irqs_and_bus_resume: + /* re-enable irqs */ + for (i = 0; i < CE_IRQ_COUNT; i++) + pld_enable_irq(qdf_dev->dev, i); + + resume_err = wlan_hdd_bus_resume(); + QDF_BUG(resume_err == 0); + +cfg80211_resume: + resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy); + QDF_BUG(resume_err == 0); + +resume_done: + clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state); + hdd_err("Unit-test suspend failed: %d", suspend_err); + return suspend_err; +} + +/** + * hdd_wlan_fake_apps_resume() - Resume from unit-test triggered suspend + * @wiphy: wiphy struct from a validated hdd context + * + * Return: Zero on success, calls QDF_BUG() on failure + */ +int hdd_wlan_fake_apps_resume(struct wiphy *wiphy) +{ + struct hif_opaque_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + int err; + + hif_fake_apps_resume(hif_ctx); + err = __hdd_wlan_fake_apps_resume(wiphy); + if (err) { + hif_fake_apps_suspend(hif_ctx, + hdd_wlan_fake_apps_resume_irq_callback); + return err; + } + + return 0; +} + +/** + * __hdd_wlan_fake_apps_resume() - The core logic for + * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(), + * which is only need for non-irq resume + * @wiphy: wiphy struct from a validated hdd context + * + * Return: Zero on success, calls QDF_BUG() on failure + */ +static int __hdd_wlan_fake_apps_resume(struct wiphy *wiphy) +{ + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + int i, resume_err; + + hdd_info("Unit-test resume WLAN"); + if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) { + hdd_info("Not unit-test suspended; Nothing to do"); + return 0; + } + + /* disable wake irq */ + pld_disable_irq(qdf_dev->dev, CE_WAKE_IRQ); + + resume_err = wlan_hdd_bus_resume_noirq(); + QDF_BUG(resume_err == 0); + + /* simulate kernel enable irqs */ + for (i = 0; i < CE_IRQ_COUNT; i++) + pld_enable_irq(qdf_dev->dev, i); + + resume_err = wlan_hdd_bus_resume(); + QDF_BUG(resume_err == 0); + + resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy); + QDF_BUG(resume_err == 0); + + return 0; +} +#endif diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 9992c4b41a8d..397bdcd2d019 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -92,6 +92,7 @@ #ifdef WLAN_SUSPEND_RESUME_TEST #include "wlan_hdd_driver_ops.h" #include "hif.h" +#include "pld_common.h" #endif #define HDD_FINISH_ULA_TIME_OUT 800 @@ -439,10 +440,9 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { #define WE_ENABLE_FW_PROFILE 4 #define WE_SET_FW_PROFILE_HIST_INTVL 5 -#ifdef WLAN_SUSPEND_RESUME_TEST +/* Private sub-ioctl for initiating WoW suspend without Apps suspend */ #define WE_SET_WLAN_SUSPEND 6 #define WE_SET_WLAN_RESUME 7 -#endif /* (SIOCIWFIRSTPRIV + 29) is currently unused */ @@ -9782,25 +9782,6 @@ static int wlan_hdd_set_mon_chan(hdd_adapter_t *adapter, uint32_t chan, return qdf_status_to_os_return(status); } -#ifdef WLAN_SUSPEND_RESUME_TEST -static void *g_wiphy; - -/** - * hdd_wlan_trigger_resume() - resume wlan - * @val: interrupt val - * - * Resume wlan after getting very 1st CE interrupt from target - * - * Return: none - */ -static void hdd_wlan_trigger_resume(uint32_t val) -{ - hdd_err("Resume WLAN val 0x%x", val); - wlan_hdd_bus_resume(); - wlan_hdd_cfg80211_resume_wlan(g_wiphy); -} -#endif - static int __iw_set_two_ints_getnone(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -9810,10 +9791,6 @@ static int __iw_set_two_ints_getnone(struct net_device *dev, int sub_cmd = value[0]; int ret; hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); -#ifdef WLAN_SUSPEND_RESUME_TEST - pm_message_t state; -#endif - ENTER_DEV(dev); @@ -9877,21 +9854,12 @@ static int __iw_set_two_ints_getnone(struct net_device *dev, case WE_SET_MON_MODE_CHAN: ret = wlan_hdd_set_mon_chan(pAdapter, value[1], value[2]); break; -#ifdef WLAN_SUSPEND_RESUME_TEST case WE_SET_WLAN_SUSPEND: - hdd_err("Suspend WLAN"); - g_wiphy = hdd_ctx->wiphy; - state.event = PM_EVENT_SUSPEND; - ret = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL); - wlan_hdd_bus_suspend(state); - hif_fake_apps_suspend(hdd_wlan_trigger_resume); + ret = hdd_wlan_fake_apps_suspend(hdd_ctx->wiphy); break; case WE_SET_WLAN_RESUME: - hdd_err("Resume WLAN"); - wlan_hdd_bus_resume(); - ret = wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy); + ret = hdd_wlan_fake_apps_resume(hdd_ctx->wiphy); break; -#endif default: hdd_err("Invalid IOCTL command %d", sub_cmd); break; diff --git a/core/pld/inc/pld_common.h b/core/pld/inc/pld_common.h index bcf647b0b1a4..4bb77b27cb94 100644 --- a/core/pld/inc/pld_common.h +++ b/core/pld/inc/pld_common.h @@ -379,4 +379,7 @@ void *pld_smmu_get_mapping(struct device *dev); int pld_smmu_map(struct device *dev, phys_addr_t paddr, uint32_t *iova_addr, size_t size); unsigned int pld_socinfo_get_serial_number(struct device *dev); + +void pld_enable_irq(struct device *dev, unsigned int ce_id); +void pld_disable_irq(struct device *dev, unsigned int ce_id); #endif |
