Browse Source

qcacld-3.0: Trigger SSR on wakeup from pagefault

According to new requirement, use INIs
max_pagefault_wakeups_for_ssr,
interval_for_pagefault_wakeup_counts and
ssr_frequency_on_pagefault
to trigger SSR if host wakes up because of pagefault.
For ex: If max_pagefault_wakeups_for_ssr = 30,
interval_for_pagefault_wakeup_counts = 180000 (3 mins) and
ssr_frequency_on_pagefault = 3600000 (1hr), in this case host
will trigger the SSR if it receives 30 wakeups because of
pagefaults in 3 mins, host will trigger SSR only once in 1 hr.
Once the SSR is triggered, host will not trigger next SSR for
next 1 hr even if it receives 30 wakeups from fw because of
pagefaults. This 1 hr time is getting monitored from last SSR.

Change-Id: Ia06f87aff6d1552e37c582e7464f1b2451543502
CRs-Fixed: 3378502
Ashish Kumar Dhanotiya 2 years ago
parent
commit
21ec244877

+ 3 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1915,6 +1915,8 @@ enum wlan_state_ctrl_str_id {
  * @oem_data_len:
  * @file_name:
  * @dbam_mode:
+ * @last_pagefault_ssr_time: Time when last recovery was triggered because of
+ * @host wakeup from fw with reason as pagefault
  */
 struct hdd_context {
 	struct wlan_objmgr_psoc *psoc;
@@ -2197,6 +2199,7 @@ struct hdd_context {
 #ifdef WLAN_FEATURE_DBAM_CONFIG
 	enum coex_dbam_config_mode dbam_mode;
 #endif
+	qdf_time_t last_pagefault_ssr_time;
 };
 
 /**

+ 37 - 0
core/hdd/src/wlan_hdd_main.c

@@ -15902,6 +15902,39 @@ QDF_STATUS hdd_md_bl_evt_cb(void *ctx, struct sir_md_bl_evt *event)
 }
 #endif /* WLAN_FEATURE_MOTION_DETECTION */
 
+/**
+ * hdd_ssr_on_pagefault_cb - Callback to trigger SSR because
+ * of host wake up by firmware with reason pagefault
+ *
+ * Return: None
+ */
+static void hdd_ssr_on_pagefault_cb(void)
+{
+	uint32_t ssr_frequency_on_pagefault;
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	qdf_time_t curr_time;
+
+	hdd_enter();
+
+	if (!hdd_ctx)
+		return;
+
+	ssr_frequency_on_pagefault =
+		ucfg_pmo_get_ssr_frequency_on_pagefault(hdd_ctx->psoc);
+
+	curr_time = qdf_get_time_of_the_day_ms();
+
+	if (!hdd_ctx->last_pagefault_ssr_time ||
+	    (curr_time - hdd_ctx->last_pagefault_ssr_time) >=
+					ssr_frequency_on_pagefault) {
+		hdd_info("curr_time %lu last_pagefault_ssr_time %lu ssr_frequency %d",
+			 curr_time, hdd_ctx->last_pagefault_ssr_time,
+			 ssr_frequency_on_pagefault);
+		hdd_ctx->last_pagefault_ssr_time = curr_time;
+		cds_trigger_recovery(QDF_HOST_WAKEUP_REASON_PAGEFAULT);
+	}
+}
+
 /**
  * hdd_register_cb - Register HDD callbacks.
  * @hdd_ctx: HDD context
@@ -16013,6 +16046,8 @@ int hdd_register_cb(struct hdd_context *hdd_ctx)
 	sme_async_oem_event_init(mac_handle,
 				 hdd_oem_event_async_cb);
 
+	sme_register_ssr_on_pagefault_cb(mac_handle, hdd_ssr_on_pagefault_cb);
+
 	hdd_exit();
 
 	return ret;
@@ -16040,6 +16075,8 @@ void hdd_deregister_cb(struct hdd_context *hdd_ctx)
 
 	mac_handle = hdd_ctx->mac_handle;
 
+	sme_deregister_ssr_on_pagefault_cb(mac_handle);
+
 	sme_async_oem_event_deinit(mac_handle);
 
 	sme_deregister_tx_queue_cb(mac_handle);

+ 19 - 0
core/sme/inc/sme_api.h

@@ -802,6 +802,25 @@ QDF_STATUS sme_neighbor_report_request(mac_handle_t mac_handle,
 		tpRrmNeighborReq pRrmNeighborReq,
 		tpRrmNeighborRspCallbackInfo callbackInfo);
 
+/**
+ * sme_register_ssr_on_pagefault_cb() - Register cb to trigger SSR on pagefault
+ * @mac_handle: Opaque handle to the global MAC context.
+ * @hdd_ssr_on_pagefault_cb: Callback which needs to be registered
+ *
+ * Return: None
+ */
+void sme_register_ssr_on_pagefault_cb(mac_handle_t mac_handle,
+				      void (*hdd_ssr_on_pagefault_cb)(void));
+
+/**
+ * sme_deregister_ssr_on_pagefault_cb() - Deregister cb to trigger SSR on
+ * pagefault
+ * @mac_handle: Opaque handle to the global MAC context.
+ *
+ * Return: None
+ */
+void sme_deregister_ssr_on_pagefault_cb(mac_handle_t mac_handle);
+
 #ifdef FEATURE_OEM_DATA
 /**
  * sme_oem_data_cmd() - the wrapper to send oem data cmd to wma

+ 2 - 0
core/sme/inc/sme_internal.h

@@ -506,6 +506,8 @@ struct sme_context {
 			(const struct oem_data *oem_event_data);
 #endif
 
+	void (*ssr_on_pagefault_cb)(void);
+
 #ifdef MULTI_CLIENT_LL_SUPPORT
 	void (*latency_level_event_handler_cb)
 			(const struct latency_level_data *event_data,

+ 33 - 0
core/sme/src/common/sme_api.c

@@ -3945,6 +3945,39 @@ QDF_STATUS sme_neighbor_report_request(
 	return status;
 }
 
+void sme_register_ssr_on_pagefault_cb(mac_handle_t mac_handle,
+				      void (*hdd_ssr_on_pagefault_cb)(void))
+{
+	QDF_STATUS status;
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+
+	SME_ENTER();
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mac->sme.ssr_on_pagefault_cb = hdd_ssr_on_pagefault_cb;
+		sme_release_global_lock(&mac->sme);
+	}
+
+	SME_EXIT();
+}
+
+void sme_deregister_ssr_on_pagefault_cb(mac_handle_t mac_handle)
+{
+	QDF_STATUS status;
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+
+	SME_ENTER();
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mac->sme.ssr_on_pagefault_cb = NULL;
+		sme_release_global_lock(&mac->sme);
+	}
+
+	SME_EXIT();
+}
+
 #ifdef FEATURE_OEM_DATA_SUPPORT
 QDF_STATUS sme_oem_req_cmd(mac_handle_t mac_handle,
 			   struct oem_data_req *oem_req)

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

@@ -914,6 +914,10 @@ struct wma_wlm_stats_data {
  * * @fw_therm_throt_support: FW Supports thermal throttling?
  * @eht_cap: 802.11be capabilities
  * @set_hw_mode_resp_status: Set HW mode response status
+ * @pagefault_wakeups_ts: Stores timestamps at which host wakes up by fw
+ * because of pagefaults
+ * @num_page_fault_wakeups: Stores the number of times host wakes up by fw
+ * because of pagefaults
  *
  * This structure is the global wma context.  It contains global wma
  * module parameters and handles of other modules.
@@ -1050,6 +1054,8 @@ typedef struct {
 	qdf_wake_lock_t sap_d3_wow_wake_lock;
 	qdf_wake_lock_t go_d3_wow_wake_lock;
 	enum set_hw_mode_status set_hw_mode_resp_status;
+	qdf_time_t *pagefault_wakeups_ts;
+	uint8_t num_page_fault_wakeups;
 } t_wma_handle, *tp_wma_handle;
 
 /**

+ 61 - 0
core/wma/src/wma_features.c

@@ -3051,6 +3051,66 @@ static void wma_wake_event_log_reason(t_wma_handle *wma,
 	qdf_wma_wow_wakeup_stats_event(wma);
 }
 
+/**
+ * wma_wow_wakeup_host_trigger_ssr() - Trigger SSR on host wakeup
+ * @handle: wma handle
+ * @reason: Host wakeup reason
+ *
+ * This function triggers SSR if host is woken up by fw with reason as pagefault
+ *
+ * Return: None
+ */
+static void
+wma_wow_wakeup_host_trigger_ssr(t_wma_handle *wma, uint32_t reason)
+{
+	uint8_t pagefault_wakeups_for_ssr;
+	uint32_t interval_for_pagefault_wakeup_counts;
+	qdf_time_t curr_time;
+	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
+
+	if (!mac) {
+		wma_debug("NULL mac ptr");
+		return;
+	}
+	if (WOW_REASON_PAGE_FAULT != reason)
+		return;
+
+	if (!mac->sme.ssr_on_pagefault_cb) {
+		wma_debug("NULL SSR on pagefault cb");
+		return;
+	}
+
+	if (!wlan_pmo_enable_ssr_on_page_fault(wma->psoc))
+		return;
+
+	pagefault_wakeups_for_ssr =
+			wlan_pmo_get_max_pagefault_wakeups_for_ssr(wma->psoc);
+
+	interval_for_pagefault_wakeup_counts =
+		wlan_pmo_get_interval_for_pagefault_wakeup_counts(wma->psoc);
+
+	curr_time = qdf_get_time_of_the_day_ms();
+
+	if (wma->num_page_fault_wakeups == pagefault_wakeups_for_ssr) {
+		qdf_mem_copy(&wma->pagefault_wakeups_ts[0],
+			     &wma->pagefault_wakeups_ts[1],
+			     (pagefault_wakeups_for_ssr - 1) *
+			     sizeof(qdf_time_t));
+		wma->num_page_fault_wakeups--;
+	}
+
+	wma->pagefault_wakeups_ts[wma->num_page_fault_wakeups++] = curr_time;
+
+	wma_nofl_debug("num pagefault wakeups %d", wma->num_page_fault_wakeups);
+
+	if (wma->num_page_fault_wakeups < pagefault_wakeups_for_ssr)
+		return;
+
+	if (curr_time - wma->pagefault_wakeups_ts[0] <=
+					interval_for_pagefault_wakeup_counts)
+		mac->sme.ssr_on_pagefault_cb();
+}
+
 /**
  * wma_wow_wakeup_host_event() - wakeup host event handler
  * @handle: wma handle
@@ -3083,6 +3143,7 @@ int wma_wow_wakeup_host_event(void *handle, uint8_t *event, uint32_t len)
 	}
 
 	wma_wake_event_log_reason(wma, wake_info);
+	wma_wow_wakeup_host_trigger_ssr(wma, wake_info->wake_reason);
 
 	if (wake_info->wake_reason == WOW_REASON_LOCAL_DATA_UC_DROP)
 		hif_rtpm_set_autosuspend_delay(WOW_LARGE_RX_RTPM_DELAY);

+ 12 - 0
core/wma/src/wma_main.c

@@ -3406,6 +3406,15 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc,
 	}
 	wma_handle->psoc = psoc;
 
+	if (wlan_pmo_enable_ssr_on_page_fault(psoc)) {
+		wma_handle->pagefault_wakeups_ts =
+			qdf_mem_malloc(
+			wlan_pmo_get_max_pagefault_wakeups_for_ssr(psoc) *
+			sizeof(qdf_time_t));
+		if (!wma_handle->pagefault_wakeups_ts)
+			goto err_wma_handle;
+	}
+
 	wma_target_if_open(wma_handle);
 
 	/*
@@ -4831,6 +4840,9 @@ QDF_STATUS wma_close(void)
 	if (wmi_validate_handle(wmi_handle))
 		return QDF_STATUS_E_INVAL;
 
+	if (wlan_pmo_enable_ssr_on_page_fault(wma_handle->psoc))
+		qdf_mem_free(wma_handle->pagefault_wakeups_ts);
+
 	qdf_atomic_set(&wma_handle->sap_num_clients_connected, 0);
 	qdf_atomic_set(&wma_handle->go_num_clients_connected, 0);