Преглед изворни кода

qcacld-3.0: On demand OBSS scan of SAP

qcacld-2.0 to qcacld-3.0 propagation

To shorten the SAP starting time, the OBSS scan
can be skipped if the ACS scan is performed
and the ACS scan channels cover the OBSS scan
channel list.
This change caches the ACS channel list and
skip the OBSS scan if necessary.

Change-Id: Iae54115051ae037c83b8dd2b639754f941c1d0f5
CRs-Fixed: 1073053
Liangwei Dong пре 8 година
родитељ
комит
aef84347a8

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

@@ -1460,6 +1460,9 @@ struct hdd_context_s {
 #ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
 	qdf_mc_timer_t skip_acs_scan_timer;
 	uint8_t skip_acs_scan_status;
+	uint8_t *last_acs_channel_list;
+	uint8_t num_of_channels;
+	qdf_spinlock_t acs_skip_lock;
 #endif
 
 	qdf_wake_lock_t sap_dfs_wakelock;

+ 73 - 14
core/hdd/src/wlan_hdd_hostapd.c

@@ -961,6 +961,78 @@ static void wlan_hdd_sap_pre_cac_success(void *data)
 	}
 }
 
+#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
+/**
+ * hdd_handle_acs_scan_event() - handle acs scan event for SAP
+ * @sap_event: tpSap_Event
+ * @adapter: hdd_adapter_t for SAP
+ *
+ * The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event.
+ * It will update scan result to cfg80211 and start a timer to flush the
+ * cached acs scan result.
+ *
+ * Return: QDF_STATUS_SUCCESS on success,
+ *      other value on failure
+ */
+static QDF_STATUS hdd_handle_acs_scan_event(tpSap_Event sap_event,
+		hdd_adapter_t *adapter)
+{
+	hdd_context_t *hdd_ctx;
+	struct sap_acs_scan_complete_event *comp_evt;
+	QDF_STATUS qdf_status;
+	int chan_list_size;
+
+	hdd_ctx = (hdd_context_t *)(adapter->pHddCtx);
+	if (!hdd_ctx) {
+		hdd_err("HDD context is null");
+		return QDF_STATUS_E_FAILURE;
+	}
+	comp_evt = &sap_event->sapevt.sap_acs_scan_comp;
+	hdd_ctx->skip_acs_scan_status = eSAP_SKIP_ACS_SCAN;
+	qdf_spin_lock(&hdd_ctx->acs_skip_lock);
+	qdf_mem_free(hdd_ctx->last_acs_channel_list);
+	hdd_ctx->last_acs_channel_list = NULL;
+	hdd_ctx->num_of_channels = 0;
+	/* cache the previous ACS scan channel list .
+	 * If the following OBSS scan chan list is covered by ACS chan list,
+	 * we can skip OBSS Scan to save SAP starting total time.
+	 */
+	if (comp_evt->num_of_channels && comp_evt->channellist) {
+		chan_list_size = comp_evt->num_of_channels *
+			sizeof(comp_evt->channellist[0]);
+		hdd_ctx->last_acs_channel_list = qdf_mem_malloc(
+			chan_list_size);
+		if (hdd_ctx->last_acs_channel_list) {
+			qdf_mem_copy(hdd_ctx->last_acs_channel_list,
+				comp_evt->channellist,
+				chan_list_size);
+			hdd_ctx->num_of_channels = comp_evt->num_of_channels;
+		}
+	}
+	qdf_spin_unlock(&hdd_ctx->acs_skip_lock);
+	/* Update ACS scan result to cfg80211. Then OBSS scan can reuse the
+	 * scan result.
+	 */
+	if (wlan_hdd_cfg80211_update_bss(hdd_ctx->wiphy, adapter, 0))
+		hdd_info("NO SCAN result");
+
+	hdd_info("Reusing Last ACS scan result for %d sec",
+		ACS_SCAN_EXPIRY_TIMEOUT_S);
+	qdf_mc_timer_stop(&hdd_ctx->skip_acs_scan_timer);
+	qdf_status = qdf_mc_timer_start(&hdd_ctx->skip_acs_scan_timer,
+			ACS_SCAN_EXPIRY_TIMEOUT_S * 1000);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status))
+		hdd_err("Failed to start ACS scan expiry timer");
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS hdd_handle_acs_scan_event(tpSap_Event sap_event,
+		hdd_adapter_t *adapter)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 				    void *usrDataForCallback)
 {
@@ -1880,21 +1952,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 			return hdd_chan_change_notify(pHostapdAdapter, dev,
 							chan_change);
 		}
-
-#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
 	case eSAP_ACS_SCAN_SUCCESS_EVENT:
-		pHddCtx->skip_acs_scan_status = eSAP_SKIP_ACS_SCAN;
-		hdd_notice("Reusing Last ACS scan result for %d sec",
-		       ACS_SCAN_EXPIRY_TIMEOUT_S);
-		qdf_mc_timer_stop(&pHddCtx->skip_acs_scan_timer);
-		qdf_status = qdf_mc_timer_start(&pHddCtx->skip_acs_scan_timer,
-						ACS_SCAN_EXPIRY_TIMEOUT_S *
-						1000);
-		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
-			hdd_err("Failed to start ACS scan expiry timer");
-		return QDF_STATUS_SUCCESS;
-#endif
-
+		return hdd_handle_acs_scan_event(pSapEvent, pHostapdAdapter);
 	case eSAP_DFS_NOL_GET:
 		hdd_notice("Received eSAP_DFS_NOL_GET event");
 

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

@@ -4839,6 +4839,11 @@ static void hdd_wlan_exit(hdd_context_t *hdd_ctx)
 		    (qdf_mc_timer_destroy(&hdd_ctx->skip_acs_scan_timer))) {
 		hdd_err("Cannot deallocate ACS Skip timer");
 	}
+	qdf_spin_lock(&hdd_ctx->acs_skip_lock);
+	qdf_mem_free(hdd_ctx->last_acs_channel_list);
+	hdd_ctx->last_acs_channel_list = NULL;
+	hdd_ctx->num_of_channels = 0;
+	qdf_spin_unlock(&hdd_ctx->acs_skip_lock);
 #endif
 
 	mutex_lock(&hdd_ctx->iface_change_lock);
@@ -4945,12 +4950,27 @@ void __hdd_wlan_exit(void)
 }
 
 #ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
+/**
+ * hdd_skip_acs_scan_timer_handler() - skip ACS scan timer timeout handler
+ * @data: pointer to hdd_context_t
+ *
+ * This function will reset acs_scan_status to eSAP_DO_NEW_ACS_SCAN.
+ * Then new ACS request will do a fresh scan without reusing the cached
+ * scan information.
+ *
+ * Return: void
+ */
 void hdd_skip_acs_scan_timer_handler(void *data)
 {
 	hdd_context_t *hdd_ctx = (hdd_context_t *) data;
 
 	hdd_notice("ACS Scan result expired. Reset ACS scan skip");
 	hdd_ctx->skip_acs_scan_status = eSAP_DO_NEW_ACS_SCAN;
+	qdf_spin_lock(&hdd_ctx->acs_skip_lock);
+	qdf_mem_free(hdd_ctx->last_acs_channel_list);
+	hdd_ctx->last_acs_channel_list = NULL;
+	hdd_ctx->num_of_channels = 0;
+	qdf_spin_unlock(&hdd_ctx->acs_skip_lock);
 
 	if (!hdd_ctx->hHal)
 		return;
@@ -8098,6 +8118,7 @@ int hdd_wlan_startup(struct device *dev)
 				   (void *)hdd_ctx);
 	if (!QDF_IS_STATUS_SUCCESS(status))
 		hdd_err("Failed to init ACS Skip timer");
+	qdf_spinlock_create(&hdd_ctx->acs_skip_lock);
 #endif
 
 	hdd_bus_bandwidth_init(hdd_ctx);

+ 70 - 0
core/hdd/src/wlan_hdd_scan.c

@@ -1294,6 +1294,65 @@ allow_suspend:
 	return 0;
 }
 
+#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
+/**
+ * wlan_hdd_sap_skip_scan_check() - The function will check OBSS
+ *         scan skip or not for SAP.
+ * @hdd_ctx: pointer to hdd context.
+ * @request: pointer to scan request.
+ *
+ * This function will check the scan request's chan list against the
+ * previous ACS scan chan list. If all the chan are covered by
+ * previous ACS scan, we can skip the scan and return scan complete
+ * to save the SAP starting time.
+ *
+ * Return: true to skip the scan,
+ *            false to continue the scan
+ */
+static bool wlan_hdd_sap_skip_scan_check(hdd_context_t *hdd_ctx,
+	struct cfg80211_scan_request *request)
+{
+	int i, j;
+	bool skip;
+
+	hdd_info("HDD_ACS_SKIP_STATUS = %d",
+		hdd_ctx->skip_acs_scan_status);
+	if (hdd_ctx->skip_acs_scan_status != eSAP_SKIP_ACS_SCAN)
+		return false;
+	qdf_spin_lock(&hdd_ctx->acs_skip_lock);
+	if (hdd_ctx->last_acs_channel_list == NULL ||
+	   hdd_ctx->num_of_channels == 0 ||
+	   request->n_channels == 0) {
+		qdf_spin_unlock(&hdd_ctx->acs_skip_lock);
+		return false;
+	}
+	skip = true;
+	for (i = 0; i < request->n_channels ; i++) {
+		bool find = false;
+		for (j = 0; j < hdd_ctx->num_of_channels; j++) {
+			if (hdd_ctx->last_acs_channel_list[j] ==
+			   request->channels[i]->hw_value) {
+				find = true;
+				break;
+			}
+		}
+		if (!find) {
+			skip = false;
+			hdd_info("Chan %d isn't in ACS chan list",
+				request->channels[i]->hw_value);
+			break;
+		}
+	}
+	qdf_spin_unlock(&hdd_ctx->acs_skip_lock);
+	return skip;
+}
+#else
+static bool wlan_hdd_sap_skip_scan_check(hdd_context_t *hdd_ctx,
+	struct cfg80211_scan_request *request)
+{
+	return false;
+}
+#endif
 
 /**
  * wlan_hdd_cfg80211_scan_block_cb() - scan block work handler
@@ -1483,6 +1542,7 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
 			 * If we return scan failure hostapd fails secondary AP
 			 * startup.
 			 */
+			hdd_err("##In DFS Master mode. Scan aborted");
 			pAdapter->request = request;
 
 			INIT_WORK(&pAdapter->scan_block_work,
@@ -1536,6 +1596,16 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
 		hdd_err("Scan not allowed");
 		return -EBUSY;
 	}
+	/* Check whether SAP scan can be skipped or not */
+	if (pAdapter->device_mode == QDF_SAP_MODE &&
+	   wlan_hdd_sap_skip_scan_check(pHddCtx, request)) {
+		hdd_err("sap scan skipped");
+		pAdapter->request = request;
+		INIT_WORK(&pAdapter->scan_block_work,
+			wlan_hdd_cfg80211_scan_block_cb);
+		schedule_work(&pAdapter->scan_block_work);
+		return 0;
+	}
 
 	qdf_mem_zero(&scan_req, sizeof(scan_req));
 

+ 13 - 2
core/sap/inc/sap_api.h

@@ -179,9 +179,7 @@ typedef enum {
 	eSAP_DFS_NOL_SET,
 	/* No ch available after DFS RADAR detect */
 	eSAP_DFS_NO_AVAILABLE_CHANNEL,
-#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
 	eSAP_ACS_SCAN_SUCCESS_EVENT,
-#endif
 	eSAP_ACS_CHANNEL_SELECTED,
 	eSAP_ECSA_CHANGE_CHAN_IND,
 } eSapHddEvent;
@@ -405,6 +403,18 @@ struct sap_roc_ready_ind_s {
 	uint32_t scan_id;
 };
 
+/**
+ * struct sap_acs_scan_complete_event - acs scan complete event
+ * @status: status of acs scan
+ * @channellist: acs scan channels
+ * @num_of_channels: number of channels
+ */
+struct sap_acs_scan_complete_event{
+	uint8_t status;
+	uint8_t *channellist;
+	uint8_t num_of_channels;
+};
+
 /**
  * struct sap_ch_change_ind - channel change indication
  * @new_chan: channel to change
@@ -454,6 +464,7 @@ typedef struct sap_Event_s {
 		struct sap_ch_selected_s sap_ch_selected;
 		struct sap_roc_ready_ind_s sap_roc_ind;
 		struct sap_ch_change_ind sap_chan_cng_ind;
+		struct sap_acs_scan_complete_event sap_acs_scan_comp;
 	} sapevt;
 } tSap_Event, *tpSap_Event;
 

+ 2 - 0
core/sap/src/sap_api_link_cntl.c

@@ -207,6 +207,7 @@ QDF_STATUS wlansap_scan_callback(tHalHandle hal_handle,
 		 * the result */
 		qdf_mem_free(sap_ctx->channelList);
 		sap_ctx->channelList = NULL;
+		sap_ctx->num_of_channel = 0;
 	}
 #endif
 
@@ -412,6 +413,7 @@ wlansap_pre_start_bss_acs_scan_callback(tHalHandle hal_handle, void *pcontext,
 		*/
 		qdf_mem_free(sap_ctx->channelList);
 		sap_ctx->channelList = NULL;
+		sap_ctx->num_of_channel = 0;
 	}
 #endif
 	QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,

+ 34 - 5
core/sap/src/sap_fsm.c

@@ -2328,7 +2328,7 @@ QDF_STATUS sap_goto_channel_sel(ptSapContext sap_context,
 			eCSR_SCAN_SOFTAP_CHANNEL_RANGE;
 
 		sap_context->channelList = channel_list;
-
+		sap_context->num_of_channel = num_of_channels;
 #endif
 		/* Set requestType to Full scan */
 
@@ -2382,6 +2382,7 @@ QDF_STATUS sap_goto_channel_sel(ptSapContext sap_context,
 				qdf_mem_free(sap_context->
 					channelList);
 				sap_context->channelList = NULL;
+				sap_context->num_of_channel = 0;
 			}
 #endif
 			if (true == sap_do_acs_pre_start_bss) {
@@ -2705,6 +2706,34 @@ static QDF_STATUS sap_goto_disconnected(ptSapContext sapContext)
 	return qdf_status;
 }
 
+#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
+/**
+ * sap_handle_acs_scan_event() - handle acs scan event for SAP
+ * @sap_context: ptSapContext
+ * @sap_event: tSap_Event
+ * @status: status of acs scan
+ *
+ * The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event.
+ *
+ * Return: void
+ */
+static void sap_handle_acs_scan_event(ptSapContext sap_context,
+		tSap_Event *sap_event, eSapStatus status)
+{
+	sap_event->sapHddEventCode = eSAP_ACS_SCAN_SUCCESS_EVENT;
+	sap_event->sapevt.sap_acs_scan_comp.status = status;
+	sap_event->sapevt.sap_acs_scan_comp.num_of_channels =
+			sap_context->num_of_channel;
+	sap_event->sapevt.sap_acs_scan_comp.channellist =
+			sap_context->channelList;
+}
+#else
+static void sap_handle_acs_scan_event(ptSapContext sap_context,
+		tSap_Event *sap_event, eSapStatus status)
+{
+}
+#endif
+
 /**
  * sap_signal_hdd_event() - send event notification
  * @sap_ctx: Sap Context
@@ -2808,14 +2837,14 @@ QDF_STATUS sap_signal_hdd_event(ptSapContext sap_ctx,
 	case eSAP_DFS_RADAR_DETECT:
 	case eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC:
 	case eSAP_DFS_NO_AVAILABLE_CHANNEL:
-#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
-	case eSAP_ACS_SCAN_SUCCESS_EVENT:
-#endif
 		sap_ap_event.sapHddEventCode = sap_hddevent;
 		sap_ap_event.sapevt.sapStopBssCompleteEvent.status =
 			(eSapStatus) context;
 		break;
-
+	case eSAP_ACS_SCAN_SUCCESS_EVENT:
+		sap_handle_acs_scan_event(sap_ctx, &sap_ap_event,
+			(eSapStatus)context);
+		break;
 	case eSAP_ACS_CHANNEL_SELECTED:
 		sap_ap_event.sapHddEventCode = sap_hddevent;
 		acs_selected = &sap_ap_event.sapevt.sap_ch_selected;

+ 1 - 0
core/sap/src/sap_internal.h

@@ -210,6 +210,7 @@ typedef struct sSapContext {
 	uint32_t nStaAddIeLength;
 	uint8_t pStaAddIE[MAX_ASSOC_IND_IE_LEN];
 	uint8_t *channelList;
+	uint8_t num_of_channel;
 	tSapChannelListInfo SapChnlList;
 	uint16_t ch_width_orig;
 	struct ch_params_s ch_params;