Ver Fonte

qcacld-3.0: Restart SAP through (E)CSA on channel avoidance event

Restart SAP through (E)CSA on receiving channel avoidance event
from FW instead of doing a hard restart. This provides the
advantage of not disconnecting the connected clients.

Change-Id: Ibaa74dc8d7c75ed793faa418ee8c179b4210b35e
CRs-Fixed: 1020771
Manishekar Chandrasekaran há 8 anos atrás
pai
commit
c67b2bb16c
3 ficheiros alterados com 214 adições e 100 exclusões
  1. 2 0
      core/cds/inc/cds_concurrency.h
  2. 28 0
      core/cds/src/cds_concurrency.c
  3. 184 100
      core/hdd/src/wlan_hdd_main.c

+ 2 - 0
core/cds/inc/cds_concurrency.h

@@ -614,6 +614,8 @@ QDF_STATUS cds_change_mcc_go_beacon_interval(hdd_adapter_t *pHostapdAdapter);
 int cds_go_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapter,
 		uint32_t set_value);
 void cds_set_mcc_latency(hdd_adapter_t *adapter, int set_value);
+void cds_change_sap_channel_with_csa(hdd_adapter_t *adapter,
+						hdd_ap_ctx_t *hdd_ap_ctx);
 #if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) || \
 		defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE)
 void cds_restart_sap(hdd_adapter_t *ap_adapter);

+ 28 - 0
core/cds/src/cds_concurrency.c

@@ -7494,6 +7494,34 @@ void cds_set_mcc_latency(hdd_adapter_t *adapter, int set_value)
 	}
 }
 
+/**
+ * cds_change_sap_channel_with_csa() - Move SAP channel using (E)CSA
+ * @adapter: AP adapter
+ * @hdd_ap_ctx: AP context
+ *
+ * Invoke the callback function to change SAP channel using (E)CSA
+ *
+ * Return: None
+ */
+void cds_change_sap_channel_with_csa(hdd_adapter_t *adapter,
+					hdd_ap_ctx_t *hdd_ap_ctx)
+{
+	p_cds_contextType cds_ctx;
+
+	cds_ctx = cds_get_global_context();
+	if (!cds_ctx) {
+		cds_err("Invalid CDS context");
+		return;
+	}
+
+	if (cds_ctx->sap_restart_chan_switch_cb) {
+		cds_info("SAP change change without restart");
+		cds_ctx->sap_restart_chan_switch_cb(adapter,
+				hdd_ap_ctx->sapConfig.channel,
+				hdd_ap_ctx->sapConfig.ch_params.ch_width);
+	}
+}
+
 #if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) || \
 			defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE)
 /**

+ 184 - 100
core/hdd/src/wlan_hdd_main.c

@@ -5046,72 +5046,148 @@ static void hdd_set_thermal_level_cb(void *context, u_int8_t level)
 }
 
 /**
- * hdd_find_prefd_safe_chnl() - find safe channel within preferred channel
- * @hdd_ctxt:	hdd context pointer
- * @ap_adapter: hdd hostapd adapter pointer
+ * hdd_get_safe_channel_from_pcl_and_acs_range() - Get safe channel for SAP
+ * restart
+ * @adapter: AP adapter
  *
- * Try to find safe channel within preferred channel
- * In case auto channel selection enabled
- *  - Preferred and safe channel should be used
- *  - If no overlapping, preferred channel should be used
+ * Get a safe channel to restart SAP. PCL already takes into account the
+ * unsafe channels. So, the PCL is validated with the ACS range to provide
+ * a safe channel for the SAP to restart.
  *
- * Return: 1: found preferred safe channel
- *         0: could not found preferred safe channel
+ * Return: Channel number to restart SAP in case of success. In case of any
+ * failure, the channel number returned is zero.
  */
-static uint8_t hdd_find_prefd_safe_chnl(hdd_context_t *hdd_ctxt,
-					hdd_adapter_t *ap_adapter)
+static uint8_t hdd_get_safe_channel_from_pcl_and_acs_range(
+				hdd_adapter_t *adapter)
 {
-	uint16_t safe_channels[NUM_CHANNELS];
-	uint16_t safe_channel_count;
-	uint16_t unsafe_channel_count;
-	uint8_t is_unsafe = 1;
-	uint16_t i;
-	uint16_t channel_loop;
+	struct sir_pcl_list pcl;
+	QDF_STATUS status;
+	uint32_t i, j;
+	tHalHandle *hal_handle;
+	hdd_context_t *hdd_ctx;
+	bool found = false;
 
-	if (!hdd_ctxt || !ap_adapter) {
-		hdd_err("invalid context/adapter");
-		return 0;
+	hal_handle = WLAN_HDD_GET_HAL_CTX(adapter);
+	if (!hal_handle) {
+		hdd_err("invalid HAL handle");
+		return INVALID_CHANNEL_ID;
 	}
 
-	safe_channel_count = 0;
-	unsafe_channel_count = QDF_MIN((uint16_t)hdd_ctxt->unsafe_channel_count,
-				       (uint16_t)NUM_CHANNELS);
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	if (!hdd_ctx) {
+		hdd_err("invalid HDD context");
+		return INVALID_CHANNEL_ID;
+	}
+
+	status = cds_get_pcl_for_existing_conn(CDS_SAP_MODE,
+			pcl.pcl_list, &pcl.pcl_len,
+			pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list));
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Get PCL failed");
+		return INVALID_CHANNEL_ID;
+	}
+
+	if (!pcl.pcl_len) {
+		hdd_alert("pcl length is zero. this is not expected");
+		return INVALID_CHANNEL_ID;
+	}
+
+	hdd_info("start:%d end:%d",
+		adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch,
+		adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch);
+
+	/* PCL already takes unsafe channel into account */
+	for (i = 0; i < pcl.pcl_len; i++) {
+		hdd_info("chan[%d]:%d", i, pcl.pcl_list[i]);
+		if ((pcl.pcl_list[i] >=
+		   adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch) &&
+		   (pcl.pcl_list[i] <=
+		   adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch)) {
+			hdd_info("found PCL safe chan:%d", pcl.pcl_list[i]);
+			return pcl.pcl_list[i];
+		}
+	}
+
+	hdd_info("no safe channel from PCL found in ACS range");
 
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		is_unsafe = 0;
-		for (channel_loop = 0;
-		     channel_loop < unsafe_channel_count; channel_loop++) {
-			if (CDS_CHANNEL_NUM(i) ==
-			    hdd_ctxt->unsafe_channel_list[channel_loop]) {
-				is_unsafe = 1;
+	/* Try for safe channel from all valid channel */
+	pcl.pcl_len = MAX_NUM_CHAN;
+	status = sme_get_cfg_valid_channels(hal_handle, pcl.pcl_list,
+					&pcl.pcl_len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("error in getting valid channel list");
+		return INVALID_CHANNEL_ID;
+	}
+
+	for (i = 0; i < pcl.pcl_len; i++) {
+		hdd_info("chan[%d]:%d", i, pcl.pcl_list[i]);
+		found = false;
+		for (j = 0; j < hdd_ctx->unsafe_channel_count; j++) {
+			if (cds_chan_to_freq(pcl.pcl_list[i]) ==
+			   hdd_ctx->unsafe_channel_list[j]) {
+				hdd_info("unsafe chan:%d", pcl.pcl_list[i]);
+				found = true;
 				break;
 			}
 		}
-		if (!is_unsafe) {
-			safe_channels[safe_channel_count] =
-			  CDS_CHANNEL_NUM(i);
-			hddLog(QDF_TRACE_LEVEL_INFO_HIGH,
-			       FL("safe channel %d"),
-			       safe_channels[safe_channel_count]);
-			safe_channel_count++;
+
+		if (found)
+			continue;
+
+		if ((pcl.pcl_list[i] >=
+		   adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch) &&
+		   (pcl.pcl_list[i] <=
+		   adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch)) {
+			hdd_info("found safe chan:%d", pcl.pcl_list[i]);
+			return pcl.pcl_list[i];
 		}
 	}
-	hddLog(QDF_TRACE_LEVEL_INFO_HIGH,
-	       FL("perferred range %d - %d"),
-		ap_adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch,
-		ap_adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch);
-	for (i = 0; i < safe_channel_count; i++) {
-		if (safe_channels[i] >=
-			ap_adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch
-		    && safe_channels[i] <=
-			ap_adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch) {
-			hddLog(QDF_TRACE_LEVEL_INFO_HIGH,
-			       FL("safe channel %d is in perferred range"),
-			       safe_channels[i]);
-			return 1;
-		}
+
+	return INVALID_CHANNEL_ID;
+}
+
+/**
+ * hdd_restart_sap() - Restarts SAP on the given channel
+ * @adapter: AP adapter
+ * @channel: Channel
+ *
+ * Restarts the SAP interface by invoking the function which executes the
+ * callback to perform channel switch using (E)CSA.
+ *
+ * Return: None
+ */
+void hdd_restart_sap(hdd_adapter_t *adapter, uint8_t channel)
+{
+	hdd_ap_ctx_t *hdd_ap_ctx;
+	tHalHandle *hal_handle;
+
+	if (!adapter) {
+		hdd_err("invalid adapter");
+		return;
 	}
-	return 0;
+
+	hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
+
+	hal_handle = WLAN_HDD_GET_HAL_CTX(adapter);
+	if (!hal_handle) {
+		hdd_err("invalid HAL handle");
+		return;
+	}
+
+	hdd_ap_ctx->sapConfig.channel = channel;
+	hdd_ap_ctx->sapConfig.ch_params.ch_width =
+		hdd_ap_ctx->sapConfig.ch_width_orig;
+
+	hdd_info("chan:%d width:%d",
+		channel, hdd_ap_ctx->sapConfig.ch_width_orig);
+
+	sme_set_ch_params(hal_handle,
+			hdd_ap_ctx->sapConfig.SapHw_mode,
+			hdd_ap_ctx->sapConfig.channel,
+			hdd_ap_ctx->sapConfig.sec_ch,
+			&hdd_ap_ctx->sapConfig.ch_params);
+
+	cds_change_sap_channel_with_csa(adapter, hdd_ap_ctx);
 }
 
 /**
@@ -5127,7 +5203,6 @@ static uint8_t hdd_find_prefd_safe_chnl(hdd_context_t *hdd_ctxt,
  */
 static void hdd_ch_avoid_cb(void *hdd_context, void *indi_param)
 {
-	hdd_adapter_t *hostapd_adapter = NULL;
 	hdd_context_t *hdd_ctxt;
 	tSirChAvoidIndType *ch_avoid_indi;
 	uint8_t range_loop;
@@ -5136,9 +5211,13 @@ static void hdd_ch_avoid_cb(void *hdd_context, void *indi_param)
 	uint16_t start_channel;
 	uint16_t end_channel;
 	v_CONTEXT_t cds_context;
-	static int restart_sap_in_progress;
 	tHddAvoidFreqList hdd_avoid_freq_list;
 	uint32_t i;
+	QDF_STATUS status;
+	hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
+	hdd_adapter_t *adapter_temp;
+	uint8_t restart_chan;
+	bool found = false;
 
 	/* Basic sanity */
 	if (!hdd_context || !indi_param) {
@@ -5260,56 +5339,61 @@ static void hdd_ch_avoid_cb(void *hdd_context, void *indi_param)
 		       hdd_ctxt->unsafe_channel_list[channel_loop]);
 	}
 
-	/*
-	 * If auto channel select is enabled
-	 * preferred channel is in safe channel,
-	 * re-start softap interface with safe channel.
-	 * no overlap with preferred channel and safe channel
-	 * do not re-start softap interface
-	 * stay current operating channel.
+	if (!hdd_ctxt->unsafe_channel_count) {
+		hdd_info("no unsafe channels - not restarting SAP");
+		return;
+	}
+
+	/* No channel change is done for fixed channel SAP.
+	 * Loop through all ACS SAP interfaces and change the channels for
+	 * the ones operating on unsafe channels.
 	 */
-	if (hdd_ctxt->unsafe_channel_count) {
-		hostapd_adapter = hdd_get_adapter(hdd_ctxt, QDF_SAP_MODE);
-		if (hostapd_adapter) {
-			if ((hostapd_adapter->sessionCtx.ap.sapConfig.
-				acs_cfg.acs_mode) &&
-				(!hdd_find_prefd_safe_chnl(hdd_ctxt,
-				hostapd_adapter)))
-				return;
+	status = hdd_get_front_adapter(hdd_ctxt, &adapter_node);
+	while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
+		adapter_temp = adapter_node->pAdapter;
+
+		if (!((adapter_temp->device_mode == QDF_SAP_MODE) &&
+		   (adapter_temp->sessionCtx.ap.sapConfig.acs_cfg.acs_mode))) {
+			hdd_info("skip device mode:%d acs:%d",
+				adapter_temp->device_mode,
+				adapter_temp->sessionCtx.ap.sapConfig.
+				acs_cfg.acs_mode);
+			goto next_adapater;
+		}
 
-			hddLog(QDF_TRACE_LEVEL_INFO,
-			       FL(
-				  "Current operation channel %d, sessionCtx.ap.sapConfig.channel %d"
-				 ),
-			       hostapd_adapter->sessionCtx.ap.
-			       operatingChannel,
-			       hostapd_adapter->sessionCtx.ap.sapConfig.
-			       channel);
-			for (channel_loop = 0;
-			     channel_loop < hdd_ctxt->unsafe_channel_count;
-			     channel_loop++) {
-				if (((hdd_ctxt->
-					unsafe_channel_list[channel_loop] ==
-						hostapd_adapter->sessionCtx.ap.
-						      operatingChannel)) &&
-					(hostapd_adapter->sessionCtx.ap.
-						sapConfig.acs_cfg.acs_mode
-								 == true) &&
-					!restart_sap_in_progress) {
-					hddLog(QDF_TRACE_LEVEL_INFO,
-					       FL("Restarting SAP"));
-					wlan_hdd_send_svc_nlink_msg
-						(WLAN_SVC_LTE_COEX_IND, NULL, 0);
-					restart_sap_in_progress = 1;
-					/*
-					 * current operating channel is un-safe
-					 * channel, restart driver
-					 */
-					hdd_hostapd_stop(hostapd_adapter->dev);
-					break;
-				}
+		found = false;
+		for (i = 0; i < hdd_ctxt->unsafe_channel_count; i++) {
+			if (cds_chan_to_freq(
+				adapter_temp->sessionCtx.ap.operatingChannel) ==
+				hdd_ctxt->unsafe_channel_list[i]) {
+				found = true;
+				hdd_info("operating ch:%d is unsafe",
+				  adapter_temp->sessionCtx.ap.operatingChannel);
+				break;
 			}
 		}
+
+		if (!found) {
+			hdd_info("ch:%d is safe. no need to change channel",
+				adapter_temp->sessionCtx.ap.operatingChannel);
+			goto next_adapater;
+		}
+
+		restart_chan =
+			hdd_get_safe_channel_from_pcl_and_acs_range(
+					adapter_temp);
+		if (!restart_chan) {
+			hdd_alert("fail to restart SAP");
+		} else {
+			hdd_info("sending coex indication");
+			wlan_hdd_send_svc_nlink_msg
+				(WLAN_SVC_LTE_COEX_IND, NULL, 0);
+			hdd_restart_sap(adapter_temp, restart_chan);
+		}
+
+next_adapater:
+		status = hdd_get_next_adapter(hdd_ctxt, adapter_node, &next);
+		adapter_node = next;
 	}
 	return;
 }