qcacld-3.0: Abort suspend if critical events are in flight
There are some events from firmware that the driver would prefer to process immediately. In some cases, these events can race with the suspend process such that the event is not processed until the device resumes. Keep a counter of so called "critical events" so the suspend process can be aborted in the event of the aforementioned race condition. Change-Id: Ic8a557368d6cb62bed9fba424c851b48b16bc574 CRs-Fixed: 2125904
This commit is contained in:
@@ -828,53 +828,60 @@ static int __wlan_hdd_bus_suspend_noirq(void)
|
|||||||
{
|
{
|
||||||
struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
|
struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
|
||||||
void *hif_ctx;
|
void *hif_ctx;
|
||||||
int err;
|
int errno;
|
||||||
int status;
|
uint32_t pending_events;
|
||||||
|
|
||||||
err = wlan_hdd_validate_context(hdd_ctx);
|
errno = wlan_hdd_validate_context(hdd_ctx);
|
||||||
if (err) {
|
if (errno) {
|
||||||
hdd_err("Invalid HDD context: %d", err);
|
hdd_err("Invalid HDD context: errno %d", errno);
|
||||||
return err;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
|
hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
|
||||||
if (NULL == hif_ctx) {
|
if (!hif_ctx) {
|
||||||
err = -EINVAL;
|
hdd_err("hif_ctx is null");
|
||||||
goto done;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hif_bus_suspend_noirq(hif_ctx);
|
errno = hif_bus_suspend_noirq(hif_ctx);
|
||||||
if (err)
|
if (errno)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
err = pmo_ucfg_psoc_is_target_wake_up_received(
|
errno = pmo_ucfg_psoc_is_target_wake_up_received(hdd_ctx->hdd_psoc);
|
||||||
hdd_ctx->hdd_psoc);
|
if (errno == -EAGAIN) {
|
||||||
if (err)
|
hdd_err("Firmware attempting wakeup, try again");
|
||||||
|
wlan_hdd_inc_suspend_stats(hdd_ctx,
|
||||||
|
SUSPEND_FAIL_INITIAL_WAKEUP);
|
||||||
|
}
|
||||||
|
if (errno)
|
||||||
goto resume_hif_noirq;
|
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_ctx->suspend_resume_stats.suspends++;
|
||||||
|
|
||||||
hdd_debug("suspend_noirq done");
|
hdd_debug("suspend_noirq done");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
resume_hif_noirq:
|
resume_hif_noirq:
|
||||||
status = hif_bus_resume_noirq(hif_ctx);
|
QDF_BUG(!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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
done:
|
||||||
|
hdd_err("suspend_noirq failed, status: %d", errno);
|
||||||
|
|
||||||
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wlan_hdd_bus_suspend_noirq(void)
|
int wlan_hdd_bus_suspend_noirq(void)
|
||||||
@@ -942,7 +949,7 @@ static int __wlan_hdd_bus_resume(void)
|
|||||||
QDF_SYSTEM_SUSPEND);
|
QDF_SYSTEM_SUSPEND);
|
||||||
status = qdf_status_to_os_return(qdf_status);
|
status = qdf_status_to_os_return(qdf_status);
|
||||||
if (status) {
|
if (status) {
|
||||||
hdd_err("Failed wma bus resume");
|
hdd_err("Failed pmo bus resume");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1384,6 +1384,7 @@ struct hw_mode_idx_to_mac_cap_idx {
|
|||||||
* @bandcapability: band capability configured through ini
|
* @bandcapability: band capability configured through ini
|
||||||
* @ito_repeat_count: Indicates ito repeated count
|
* @ito_repeat_count: Indicates ito repeated count
|
||||||
* @fw_mem_dump_enabled: Fw memory dump support
|
* @fw_mem_dump_enabled: Fw memory dump support
|
||||||
|
* @critical_events_in_flight: number of suspend preventing events in flight
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *wmi_handle;
|
void *wmi_handle;
|
||||||
@@ -1581,6 +1582,7 @@ typedef struct {
|
|||||||
bool in_imps;
|
bool in_imps;
|
||||||
uint8_t ito_repeat_count;
|
uint8_t ito_repeat_count;
|
||||||
bool fw_mem_dump_enabled;
|
bool fw_mem_dump_enabled;
|
||||||
|
qdf_atomic_t critical_events_in_flight;
|
||||||
} t_wma_handle, *tp_wma_handle;
|
} t_wma_handle, *tp_wma_handle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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,
|
QDF_STATUS wma_crash_inject(WMA_HANDLE wma_handle, uint32_t type,
|
||||||
uint32_t delay_time_ms);
|
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_set_vc_mode_config() - set voltage corner mode config to FW.
|
||||||
* @wma_handle: pointer to wma handle.
|
* @wma_handle: pointer to wma handle.
|
||||||
|
@@ -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_process_fw_event() - process any fw event
|
||||||
* @wma: wma handle
|
* @wma: wma handle
|
||||||
@@ -1699,8 +1720,14 @@ static int wma_process_fw_event(tp_wma_handle wma,
|
|||||||
wma_process_fw_event_params *buf)
|
wma_process_fw_event_params *buf)
|
||||||
{
|
{
|
||||||
struct wmi_unified *wmi_handle = (struct wmi_unified *)buf->wmi_handle;
|
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);
|
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;
|
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;
|
wma_process_fw_event_params *params_buf;
|
||||||
struct scheduler_msg cds_msg = { 0 };
|
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));
|
params_buf = qdf_mem_malloc(sizeof(wma_process_fw_event_params));
|
||||||
if (!params_buf) {
|
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->wmi_handle = (struct wmi_unified *)ctx;
|
||||||
params_buf->evt_buf = (wmi_buf_t *)ev;
|
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.type = WMA_PROCESS_FW_EVENT;
|
||||||
cds_msg.bodyptr = params_buf;
|
cds_msg.bodyptr = params_buf;
|
||||||
cds_msg.bodyval = 0;
|
cds_msg.bodyval = 0;
|
||||||
|
Reference in New Issue
Block a user