diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index eb169533db..3bcefdb2a3 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -828,53 +828,60 @@ static int __wlan_hdd_bus_suspend_noirq(void) { struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); void *hif_ctx; - int err; - int status; + int errno; + uint32_t pending_events; - err = wlan_hdd_validate_context(hdd_ctx); - if (err) { - hdd_err("Invalid HDD context: %d", err); - return err; + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) { + hdd_err("Invalid HDD context: errno %d", errno); + return errno; } if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { - hdd_debug("Driver Module closed return success"); + hdd_debug("Driver module closed; skip bus-noirq suspend"); return 0; } hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); - if (NULL == hif_ctx) { - err = -EINVAL; - goto done; + if (!hif_ctx) { + hdd_err("hif_ctx is null"); + return -EINVAL; } - err = hif_bus_suspend_noirq(hif_ctx); - if (err) + errno = hif_bus_suspend_noirq(hif_ctx); + if (errno) goto done; - err = pmo_ucfg_psoc_is_target_wake_up_received( - hdd_ctx->hdd_psoc); - if (err) + errno = pmo_ucfg_psoc_is_target_wake_up_received(hdd_ctx->hdd_psoc); + if (errno == -EAGAIN) { + hdd_err("Firmware attempting wakeup, try again"); + wlan_hdd_inc_suspend_stats(hdd_ctx, + SUSPEND_FAIL_INITIAL_WAKEUP); + } + if (errno) goto resume_hif_noirq; + pending_events = wma_critical_events_in_flight(); + if (pending_events) { + hdd_err("%d critical event(s) in flight; try again", + pending_events); + errno = -EAGAIN; + goto resume_hif_noirq; + } + hdd_ctx->suspend_resume_stats.suspends++; hdd_debug("suspend_noirq done"); + return 0; resume_hif_noirq: - status = hif_bus_resume_noirq(hif_ctx); - QDF_BUG(!status); -done: - if (err == -EAGAIN) { - hdd_err("Firmware attempting wakeup, try again"); - wlan_hdd_inc_suspend_stats(hdd_ctx, - SUSPEND_FAIL_INITIAL_WAKEUP); - } else { - hdd_err("suspend_noirq failed, status: %d", err); - } + QDF_BUG(!hif_bus_resume_noirq(hif_ctx)); - return err; +done: + hdd_err("suspend_noirq failed, status: %d", errno); + + return errno; } int wlan_hdd_bus_suspend_noirq(void) @@ -942,7 +949,7 @@ static int __wlan_hdd_bus_resume(void) QDF_SYSTEM_SUSPEND); status = qdf_status_to_os_return(qdf_status); if (status) { - hdd_err("Failed wma bus resume"); + hdd_err("Failed pmo bus resume"); goto out; } diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 3ccf456cb7..2dd2648ff9 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1384,6 +1384,7 @@ struct hw_mode_idx_to_mac_cap_idx { * @bandcapability: band capability configured through ini * @ito_repeat_count: Indicates ito repeated count * @fw_mem_dump_enabled: Fw memory dump support + * @critical_events_in_flight: number of suspend preventing events in flight */ typedef struct { void *wmi_handle; @@ -1581,6 +1582,7 @@ typedef struct { bool in_imps; uint8_t ito_repeat_count; bool fw_mem_dump_enabled; + qdf_atomic_t critical_events_in_flight; } t_wma_handle, *tp_wma_handle; /** diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index 6beab5dfd9..8cd816e770 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -338,6 +338,16 @@ tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type); QDF_STATUS wma_crash_inject(WMA_HANDLE wma_handle, uint32_t type, uint32_t delay_time_ms); +/** + * wma_critical_events_in_flight() - get the number of critical events in flight + * + * This API gets the number of events in flight which should prevent power + * collapse. + * + * Return: the number of critical events in flight + */ +uint32_t wma_critical_events_in_flight(void); + /** * wma_set_vc_mode_config() - set voltage corner mode config to FW. * @wma_handle: pointer to wma handle. diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 416f878c48..ae85f5db15 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -1686,6 +1686,27 @@ static void wma_process_cli_set_cmd(tp_wma_handle wma, } } +uint32_t wma_critical_events_in_flight(void) +{ + t_wma_handle *wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return 0; + + return qdf_atomic_read(&wma->critical_events_in_flight); +} + +static bool wma_event_is_critical(uint32_t event_id) +{ + switch (event_id) { + case WMI_ROAM_SYNCH_EVENTID: + return true; + default: + return false; + } +} + /** * wma_process_fw_event() - process any fw event * @wma: wma handle @@ -1699,8 +1720,14 @@ static int wma_process_fw_event(tp_wma_handle wma, wma_process_fw_event_params *buf) { struct wmi_unified *wmi_handle = (struct wmi_unified *)buf->wmi_handle; + uint32_t event_id = WMI_GET_FIELD(qdf_nbuf_data(buf->evt_buf), + WMI_CMD_HDR, COMMANDID); wmi_process_fw_event(wmi_handle, buf->evt_buf); + + if (wma_event_is_critical(event_id)) + qdf_atomic_dec(&wma->critical_events_in_flight); + return 0; } @@ -1787,6 +1814,8 @@ static int wma_process_fw_event_mc_thread_ctx(void *ctx, void *ev) { wma_process_fw_event_params *params_buf; struct scheduler_msg cds_msg = { 0 }; + tp_wma_handle wma; + uint32_t event_id; params_buf = qdf_mem_malloc(sizeof(wma_process_fw_event_params)); if (!params_buf) { @@ -1798,6 +1827,12 @@ static int wma_process_fw_event_mc_thread_ctx(void *ctx, void *ev) params_buf->wmi_handle = (struct wmi_unified *)ctx; params_buf->evt_buf = (wmi_buf_t *)ev; + wma = cds_get_context(QDF_MODULE_ID_WMA); + event_id = WMI_GET_FIELD(qdf_nbuf_data(params_buf->evt_buf), + WMI_CMD_HDR, COMMANDID); + if (wma && wma_event_is_critical(event_id)) + qdf_atomic_inc(&wma->critical_events_in_flight); + cds_msg.type = WMA_PROCESS_FW_EVENT; cds_msg.bodyptr = params_buf; cds_msg.bodyval = 0;