浏览代码

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
Dustin Brown 7 年之前
父节点
当前提交
05557181ba
共有 4 个文件被更改,包括 80 次插入26 次删除
  1. 33 26
      core/hdd/src/wlan_hdd_driver_ops.c
  2. 2 0
      core/wma/inc/wma.h
  3. 10 0
      core/wma/inc/wma_api.h
  4. 35 0
      core/wma/src/wma_main.c

+ 33 - 26
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);
 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
 	void *hif_ctx;
 	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) {
 	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) {
-		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;
 		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;
 		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(!status);
+	QDF_BUG(!hif_bus_resume_noirq(hif_ctx));
+
 done:
 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);
-	}
+	hdd_err("suspend_noirq failed, status: %d", errno);
 
 
-	return err;
+	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;
 	}
 	}
 
 

+ 2 - 0
core/wma/inc/wma.h

@@ -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;
 
 
 /**
 /**

+ 10 - 0
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,
 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.

+ 35 - 0
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_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;