Procházet zdrojové kódy

qcacld-3.0: avoid duplicated LTE_COEX event

For each WLAN_SVC_LTE_COEX_IND event, SCM
will stop/start hostapd. In middle of
Stop/restart hostapd, the current unsafe
operation channel is not changed. If multiple
FW LTE coex event are uploaded during this
time, the WLAN_SVC_LTE_COEX_IND could be
delivered multiple times. And then the hostapd
will stop/start several times.
Fix by skipping unsafe channel checking
and SAP restart when the unsafe channel list
has no change.

Change-Id: I756f317ba39f97c673fa54b382191a6429435b1e
CRs-Fixed: 2078725
Liangwei Dong před 7 roky
rodič
revize
6e1a209be5

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

@@ -2465,6 +2465,35 @@ void hdd_ch_avoid_ind(hdd_context_t *hdd_ctxt,
 		struct ch_avoid_ind_type *avoid_freq_list);
 enum  sap_acs_dfs_mode wlan_hdd_get_dfs_mode(enum dfs_mode mode);
 void hdd_unsafe_channel_restart_sap(hdd_context_t *hdd_ctx);
+/**
+ * hdd_clone_local_unsafe_chan() - clone hdd ctx unsafe chan list
+ * @hdd_ctx: hdd context pointer
+ * @local_unsafe_list: copied unsafe chan list array
+ * @local_unsafe_list_count: channel number in returned local_unsafe_list
+ *
+ * The function will allocate memory and make a copy the current unsafe
+ * channels from hdd ctx. The caller need to free the local_unsafe_list
+ * memory after use.
+ *
+ * Return: 0 if successfully clone unsafe chan list.
+ */
+int hdd_clone_local_unsafe_chan(struct hdd_context *hdd_ctx,
+	uint16_t **local_unsafe_list, uint16_t *local_unsafe_list_count);
+
+/**
+ * hdd_local_unsafe_channel_updated() - check unsafe chan list same or not
+ * @hdd_ctx: hdd context pointer
+ * @local_unsafe_list: unsafe chan list to be compared with hdd_ctx's list
+ * @local_unsafe_list_count: channel number in local_unsafe_list
+ *
+ * The function checked the input channel is same as current unsafe chan
+ * list in hdd_ctx.
+ *
+ * Return: true if input channel list is same as the list in hdd_ctx
+ */
+bool hdd_local_unsafe_channel_updated(struct hdd_context *hdd_ctx,
+	uint16_t *local_unsafe_list, uint16_t local_unsafe_list_count);
+
 int hdd_enable_disable_ca_event(hdd_context_t *hddctx,
 				uint8_t set_value);
 void wlan_hdd_undo_acs(hdd_adapter_t *adapter);

+ 15 - 1
core/hdd/src/wlan_hdd_cfg80211.c

@@ -9447,6 +9447,8 @@ __wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy,
 	uint16_t unsafe_channel_count;
 	int unsafe_channel_index;
 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
+	uint16_t *local_unsafe_list;
+	uint16_t local_unsafe_list_count;
 
 	ENTER_DEV(wdev->netdev);
 
@@ -9463,6 +9465,14 @@ __wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy,
 	ret = wlan_hdd_validate_context(hdd_ctx);
 	if (0 != ret)
 		return ret;
+	ret = hdd_clone_local_unsafe_chan(hdd_ctx,
+					  &local_unsafe_list,
+					  &local_unsafe_list_count);
+	if (0 != ret) {
+		hdd_err("failed to clone the cur unsafe chan list");
+		return ret;
+	}
+
 	pld_get_wlan_unsafe_channel(qdf_ctx->dev, hdd_ctx->unsafe_channel_list,
 			&(hdd_ctx->unsafe_channel_count),
 			sizeof(hdd_ctx->unsafe_channel_list));
@@ -9475,7 +9485,11 @@ __wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy,
 		hdd_debug("Channel %d is not safe",
 			hdd_ctx->unsafe_channel_list[unsafe_channel_index]);
 	}
-	hdd_unsafe_channel_restart_sap(hdd_ctx);
+	if (hdd_local_unsafe_channel_updated(hdd_ctx, local_unsafe_list,
+					     local_unsafe_list_count))
+		hdd_unsafe_channel_restart_sap(hdd_ctx);
+	qdf_mem_free(local_unsafe_list);
+
 	return 0;
 }
 

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

@@ -7371,6 +7371,62 @@ static void hdd_lte_coex_restart_sap(hdd_adapter_t *adapter,
 				    WLAN_SVC_LTE_COEX_IND, NULL, 0);
 	hdd_switch_sap_channel(adapter, restart_chan);
 }
+
+int hdd_clone_local_unsafe_chan(struct hdd_context *hdd_ctx,
+	uint16_t **local_unsafe_list, uint16_t *local_unsafe_list_count)
+{
+	uint32_t size;
+	uint16_t *unsafe_list;
+	uint16_t chan_count;
+
+	if (!hdd_ctx || !local_unsafe_list_count || !local_unsafe_list_count)
+		return -EINVAL;
+
+	chan_count = QDF_MIN(hdd_ctx->unsafe_channel_count,
+			     NUM_CHANNELS);
+	if (chan_count) {
+		size = chan_count * sizeof(hdd_ctx->unsafe_channel_list[0]);
+		unsafe_list = qdf_mem_malloc(size);
+		if (!unsafe_list) {
+			hdd_err("No memory for unsafe chan list size%d",
+				size);
+			return -ENOMEM;
+		}
+		qdf_mem_copy(unsafe_list, hdd_ctx->unsafe_channel_list, size);
+	} else {
+		unsafe_list = NULL;
+	}
+
+	*local_unsafe_list = unsafe_list;
+	*local_unsafe_list_count = chan_count;
+
+	return 0;
+}
+
+bool hdd_local_unsafe_channel_updated(struct hdd_context *hdd_ctx,
+	uint16_t *local_unsafe_list, uint16_t local_unsafe_list_count)
+{
+	int i, j;
+
+	if (local_unsafe_list_count != hdd_ctx->unsafe_channel_count)
+		return true;
+	if (local_unsafe_list_count == 0)
+		return false;
+	for (i = 0; i < local_unsafe_list_count; i++) {
+		for (j = 0; j < local_unsafe_list_count; j++)
+			if (local_unsafe_list[i] ==
+			    hdd_ctx->unsafe_channel_list[j])
+				break;
+		if (j >= local_unsafe_list_count)
+			break;
+	}
+	if (i >= local_unsafe_list_count) {
+		hdd_info("unsafe chan list same");
+		return false;
+	}
+
+	return true;
+}
 #else
 static void hdd_init_channel_avoidance(hdd_context_t *hdd_ctx)
 {

+ 18 - 2
core/hdd/src/wlan_hdd_regulatory.c

@@ -862,6 +862,8 @@ void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt,
 		struct unsafe_ch_list *unsafe_chan_list,
 		struct ch_avoid_ind_type *avoid_freq_list)
 {
+	uint16_t *local_unsafe_list;
+	uint16_t local_unsafe_list_count;
 
 	/* Basic sanity */
 	if (!hdd_ctxt) {
@@ -874,6 +876,13 @@ void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt,
 			sizeof(struct ch_avoid_ind_type));
 	mutex_unlock(&hdd_ctxt->avoid_freq_lock);
 
+	if (hdd_clone_local_unsafe_chan(hdd_ctxt,
+					&local_unsafe_list,
+					&local_unsafe_list_count) != 0) {
+		hdd_err("failed to clone cur unsafe chan list");
+		return;
+	}
+
 	/* clear existing unsafe channel cache */
 	hdd_ctxt->unsafe_channel_count = 0;
 	qdf_mem_zero(hdd_ctxt->unsafe_channel_list,
@@ -895,7 +904,7 @@ void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt,
 		hdd_ctxt->unsafe_channel_count = 0;
 		qdf_mem_zero(hdd_ctxt->unsafe_channel_list,
 			sizeof(hdd_ctxt->unsafe_channel_list));
-
+		qdf_mem_free(local_unsafe_list);
 		return;
 	}
 
@@ -905,6 +914,7 @@ void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt,
 					&hdd_ctxt->dnbs_avoid_freq_list)) {
 			mutex_unlock(&hdd_ctxt->avoid_freq_lock);
 			hdd_debug("unable to merge avoid freqs");
+			qdf_mem_free(local_unsafe_list);
 			return;
 	}
 	mutex_unlock(&hdd_ctxt->avoid_freq_lock);
@@ -916,9 +926,15 @@ void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt,
 
 	if (!hdd_ctxt->unsafe_channel_count) {
 		hdd_debug("no unsafe channels - not restarting SAP");
+		qdf_mem_free(local_unsafe_list);
 		return;
 	}
-	hdd_unsafe_channel_restart_sap(hdd_ctxt);
+	if (hdd_local_unsafe_channel_updated(hdd_ctxt,
+					    local_unsafe_list,
+					    local_unsafe_list_count))
+		hdd_unsafe_channel_restart_sap(hdd_ctxt);
+	qdf_mem_free(local_unsafe_list);
+
 }