From 6bdbda50fbe0c0eb6ce7fef1926d50daa9f94993 Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Tue, 27 Sep 2016 15:52:30 -0700 Subject: [PATCH] qcacmn: Power offload unit test framework enhancements Recently host power offload suspend/resume has switched to 3 stage process. Enhance power offload unit test framework accordingly, and improve error handling. This is a companion change for I8cc1e955fbaca631ee7fd76b0c907d1e68c836bf in qcacld-3.0. Change-Id: I8c4e062d4a51a7a245500bc135571fc67cf1b4d0 CRs-Fixed: 1072424 --- hif/inc/hif.h | 6 +- hif/src/ce/ce_main.c | 12 ++++ hif/src/ce/ce_tasklet.c | 143 +++++++++++++++++++++++++--------------- hif/src/hif_main.h | 20 ++++++ 4 files changed, 127 insertions(+), 54 deletions(-) diff --git a/hif/inc/hif.h b/hif/inc/hif.h index b693f5790652..6ce3a09769e1 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -724,8 +724,10 @@ void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled, int hif_bus_reset_resume(struct hif_opaque_softc *scn); #ifdef WLAN_SUSPEND_RESUME_TEST -typedef void (*hdd_fake_resume_callback)(uint32_t val); -void hif_fake_apps_suspend(hdd_fake_resume_callback callback); +typedef void (*hif_fake_resume_callback)(uint32_t val); +void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx, + hif_fake_resume_callback callback); +void hif_fake_apps_resume(struct hif_opaque_softc *hif_ctx); #endif uint32_t hif_register_ext_group_int_handler(struct hif_opaque_softc *hif_ctx, diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c index c4a7a1b5bb89..b86f9e4bc4de 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -2155,6 +2155,16 @@ static inline void hif_post_static_buf_to_target(struct hif_softc *scn) } #endif +#ifdef WLAN_SUSPEND_RESUME_TEST +static void hif_fake_apps_init_ctx(struct hif_softc *scn) +{ + INIT_WORK(&scn->fake_apps_ctx.resume_work, + hif_fake_apps_resume_work); +} +#else +static inline void hif_fake_apps_init_ctx(struct hif_softc *scn) {} +#endif + /** * hif_config_ce() - configure copy engines * @scn: hif context @@ -2240,6 +2250,7 @@ int hif_config_ce(struct hif_softc *scn) HIF_INFO_MED("%s: ce_init done", __func__); init_tasklet_workers(hif_hdl); + hif_fake_apps_init_ctx(scn); HIF_TRACE("%s: X, ret = %d", __func__, rv); @@ -2990,3 +3001,4 @@ void hif_wlan_disable(struct hif_softc *scn) pld_wlan_disable(scn->qdf_dev->dev, mode); } + diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index 958efdba090a..9ec8602f821c 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/hif/src/ce/ce_tasklet.c @@ -253,11 +253,12 @@ void ce_tasklet_kill(struct hif_softc *scn) int hif_drain_tasklets(struct hif_softc *scn) { uint32_t ce_drain_wait_cnt = 0; + int32_t tasklet_cnt; - while (qdf_atomic_read(&scn->active_tasklet_cnt)) { + while ((tasklet_cnt = qdf_atomic_read(&scn->active_tasklet_cnt))) { if (++ce_drain_wait_cnt > HIF_CE_DRAIN_WAIT_CNT) { - HIF_ERROR("%s: CE still not done with access", - __func__); + HIF_ERROR("%s: CE still not done with access: %d", + __func__, tasklet_cnt); return -EFAULT; } @@ -267,55 +268,81 @@ int hif_drain_tasklets(struct hif_softc *scn) return 0; } - - #ifdef WLAN_SUSPEND_RESUME_TEST -static bool g_hif_apps_fake_suspended; -static hdd_fake_resume_callback hdd_fake_apps_resume; - -static void hif_wlan_resume_work_handler(struct work_struct *work) -{ - hdd_fake_apps_resume(0); -} - -static DECLARE_WORK(hif_resume_work, hif_wlan_resume_work_handler); - /** - * hif_fake_apps_suspend(): Suspend WLAN - * - * Set the fake suspend flag such that hif knows that it will need - * to fake the apps resume process using the hdd_fake_apps_resume + * hif_fake_apps_resume_work() - Work handler for fake apps resume callback + * @work: The work struct being passed from the linux kernel * * Return: none */ -void hif_fake_apps_suspend(hdd_fake_resume_callback callback) +void hif_fake_apps_resume_work(struct work_struct *work) { - hdd_fake_apps_resume = callback; - g_hif_apps_fake_suspended = true; + struct fake_apps_context *ctx = + container_of(work, struct fake_apps_context, resume_work); + + QDF_BUG(ctx->resume_callback); + ctx->resume_callback(0); + ctx->resume_callback = NULL; } /** - * hif_fake_apps_resume(): trigger WLAN resume if needed - * @fid_hdl: hif context - * @ce_id: copy engine Id + * hif_fake_apps_suspend(): Setup unit-test related suspend state. Call after + * a normal WoW suspend has been completed. + * @hif_ctx: The HIF context to operate on + * @callback: The function to call when fake apps resume is triggered * - * Return: True if a fake apps resume has been been triggered, - * returns false if regular interrupt processing is needed. - * Ensures copy engine Id matches mapped Irq + * Set the fake suspend flag such that hif knows that it will need + * to fake the apps resume process using hdd_trigger_fake_apps_resume + * + * Return: none */ -static bool hif_fake_apps_resume(struct hif_opaque_softc *hif_hdl, int ce_id) +void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx, + hif_fake_resume_callback callback) { + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + scn->fake_apps_ctx.resume_callback = callback; + set_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state); +} + +/** + * hif_fake_apps_resume(): Cleanup unit-test related suspend state. Call before + * doing a normal WoW resume if suspend was initiated via fake apps + * suspend. + * @hif_ctx: The HIF context to operate on + * + * Return: none + */ +void hif_fake_apps_resume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + clear_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state); + scn->fake_apps_ctx.resume_callback = NULL; +} + +/** + * hif_interrupt_is_fake_apps_resume(): Determines if the raised irq should + * trigger a fake apps resume. + * @hif_ctx: The HIF context to operate on + * @ce_id: The copy engine Id from the originating interrupt + * + * Return: true if the raised irq should trigger a fake apps resume + */ +static bool hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx, + int ce_id) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); uint8_t ul_pipe, dl_pipe; int ul_is_polled, dl_is_polled; QDF_STATUS status; - /* can't resume if not already suspended */ - if (!g_hif_apps_fake_suspended) + if (!test_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state)) return false; - /* ensure passed copy engine Id matches Id from irq map */ - - status = hif_map_service_to_pipe(hif_hdl, HTC_CTRL_RSVD_SVC, + /* ensure passed ce_id matches wake irq */ + /* dl_pipe will be populated with the wake irq number */ + status = hif_map_service_to_pipe(hif_ctx, HTC_CTRL_RSVD_SVC, &ul_pipe, &dl_pipe, &ul_is_polled, &dl_is_polled); @@ -324,29 +351,40 @@ static bool hif_fake_apps_resume(struct hif_opaque_softc *hif_hdl, int ce_id) return false; } - /* dl_pipe is equivalent to a copy engine Id at this point */ - if (ce_id != dl_pipe) - return false; + return ce_id == dl_pipe; +} - /* trigger fake apps resume */ - g_hif_apps_fake_suspended = false; - schedule_work(&hif_resume_work); - return true; +/** + * hif_trigger_fake_apps_resume(): Trigger a fake apps resume by scheduling the + * previously registered callback for execution + * @hif_ctx: The HIF context to operate on + * + * Return: None + */ +static void hif_trigger_fake_apps_resume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (!test_and_clear_bit(HIF_FA_SUSPENDED_BIT, + &scn->fake_apps_ctx.state)) + return; + + schedule_work(&scn->fake_apps_ctx.resume_work); } #else -/** - * hif_fake_apps_resume(): trigger WLAN resume if needed - * @hif_hdl: hif context - * @ce_id: copy engine Id - * - * Return: always false if WLAN_SUSPEND_RESUME_TEST is not defined - */ -static bool hif_fake_apps_resume(struct hif_opaque_softc *hif_hdl, int ce_id) +static inline bool +hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx, int ce_id) { return false; } + +static inline void +hif_trigger_fake_apps_resume(struct hif_opaque_softc *hif_ctx) +{ +} + #endif /* End of WLAN_SUSPEND_RESUME_TEST */ /** @@ -447,16 +485,17 @@ irqreturn_t ce_dispatch_interrupt(int ce_id, return IRQ_NONE; } hif_irq_disable(scn, ce_id); - qdf_atomic_inc(&scn->active_tasklet_cnt); hif_record_ce_desc_event(scn, ce_id, HIF_IRQ_EVENT, NULL, NULL, 0); hif_ce_increment_interrupt_count(hif_ce_state, ce_id); - if (unlikely(hif_fake_apps_resume(hif_hdl, ce_id))) { - HIF_ERROR("received resume interrupt"); + if (unlikely(hif_interrupt_is_fake_apps_resume(hif_hdl, ce_id))) { + hif_trigger_fake_apps_resume(hif_hdl); hif_irq_enable(scn, ce_id); return IRQ_HANDLED; } + qdf_atomic_inc(&scn->active_tasklet_cnt); + if (hif_napi_enabled(hif_hdl, ce_id)) hif_napi_schedule(hif_hdl, ce_id); else diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index 62bcdd041bee..a6caf7fc8d8c 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -111,6 +111,22 @@ struct hif_ce_stats { int ce_ring_delta_fail_count; }; +#ifdef WLAN_SUSPEND_RESUME_TEST +struct fake_apps_context { + unsigned long state; + hif_fake_resume_callback resume_callback; + struct work_struct resume_work; +}; + +enum hif_fake_apps_state_bits { + HIF_FA_SUSPENDED_BIT = 0 +}; + +void hif_fake_apps_resume_work(struct work_struct *work); +#else +static inline void hif_init_fake_apps_ctx(struct hif_softc *scn) {} +#endif /* WLAN_SUSPEND_RESUME_TEST */ + struct hif_softc { struct hif_opaque_softc osc; struct hif_config_info hif_config; @@ -156,6 +172,9 @@ struct hif_softc { uint32_t nss_wifi_ol_mode; #endif void *hal_soc; +#ifdef WLAN_SUSPEND_RESUME_TEST + struct fake_apps_context fake_apps_ctx; +#endif /* WLAN_SUSPEND_RESUME_TEST */ }; #ifdef QCA_NSS_WIFI_OFFLOAD_SUPPORT @@ -224,4 +243,5 @@ static inline void hif_ramdump_handler(struct hif_opaque_softc *scn) {} #endif void hif_ext_grp_tasklet(unsigned long data); void hif_grp_tasklet_kill(struct hif_softc *scn); + #endif /* __HIF_MAIN_H__ */