Browse Source

qcacld-3.0: Add support for 5/10 MHz for STA and SAP role

Add support for 5/10 MHz channel width for STA and SAP role. To
enable/disable feature, following ini parameter will be used:
 * gSub20ChannelWidth=0: indicates do not use Sub 20 MHz bandwidth
   this is also the default value.
 * gSub20ChannelWidth=1: Bring up SAP/STA in 5 MHz bandwidth
 * gSub20ChannelWidth=2: Bring up SAP/STA in 10 MHz bandwidth

Change-Id: Ic6d534dc1eae60fcd2fb7533c934b9ea28e6dd78
CRs-Fixed: 1013211
Naveen Rawat 9 years ago
parent
commit
64e477ea40

+ 3 - 0
core/cds/inc/cds_api.h

@@ -283,4 +283,7 @@ void cds_init_ini_config(struct cds_config_info *cds_cfg);
 void cds_deinit_ini_config(void);
 struct cds_config_info *cds_get_ini_config(void);
 
+bool cds_is_5_mhz_enabled(void);
+bool cds_is_10_mhz_enabled(void);
+bool cds_is_sub_20_mhz_enabled(void);
 #endif /* if !defined __CDS_API_H */

+ 13 - 1
core/cds/inc/cds_config.h

@@ -40,6 +40,17 @@ enum driver_type {
 	DRIVER_TYPE_MFG = 1,
 };
 
+/**
+ * enum cfg_sub_20_channel_width: ini values for su 20 mhz channel width
+ * @WLAN_SUB_20_CH_WIDTH_5: Use 5 mhz channel width
+ * @WLAN_SUB_20_CH_WIDTH_10: Use 10 mhz channel width
+ */
+enum cfg_sub_20_channel_width {
+	WLAN_SUB_20_CH_WIDTH_NONE = 0,
+	WLAN_SUB_20_CH_WIDTH_5 = 1,
+	WLAN_SUB_20_CH_WIDTH_10 = 2,
+};
+
 /**
  * struct cds_config_info - Place Holder for cds configuration
  * @max_station: Max station supported
@@ -82,7 +93,7 @@ enum driver_type {
  * @is_nan_enabled: Indicate whether NAN is enabled or not
  * @tx_chain_mask_cck: Tx chain mask enabled or not
  * @self_gen_frm_pwr: Self gen from power
- *
+ * @sub_20_channel_width: Sub 20 MHz ch width, ini intersected with fw cap
  * Structure for holding cds ini parameters.
  */
 
@@ -131,5 +142,6 @@ struct cds_config_info {
 #endif
 	bool tx_chain_mask_cck;
 	uint16_t self_gen_frm_pwr;
+	enum cfg_sub_20_channel_width sub_20_channel_width;
 };
 #endif /* !defined( __CDS_CONFIG_H ) */

+ 66 - 0
core/cds/src/cds_api.c

@@ -2213,3 +2213,69 @@ struct cds_config_info *cds_get_ini_config(void)
 
 	return cds_ctx->cds_cfg;
 }
+
+/**
+ * cds_is_5_mhz_enabled() - API to get 5MHZ enabled
+ *
+ * Return: true if 5 mhz is enabled, false otherwise
+ */
+bool cds_is_5_mhz_enabled(void)
+{
+	p_cds_contextType p_cds_context;
+
+	p_cds_context = cds_get_context(QDF_MODULE_ID_QDF);
+	if (!p_cds_context) {
+		cds_err("%s: cds context is invalid", __func__);
+		return false;
+	}
+
+	if (p_cds_context->cds_cfg)
+		return (p_cds_context->cds_cfg->sub_20_channel_width ==
+						WLAN_SUB_20_CH_WIDTH_5);
+
+	return false;
+}
+
+/**
+ * cds_is_10_mhz_enabled() - API to get 10-MHZ enabled
+ *
+ * Return: true if 10 mhz is enabled, false otherwise
+ */
+bool cds_is_10_mhz_enabled(void)
+{
+	p_cds_contextType p_cds_context;
+
+	p_cds_context = cds_get_context(QDF_MODULE_ID_QDF);
+	if (!p_cds_context) {
+		cds_err("%s: cds context is invalid", __func__);
+		return false;
+	}
+
+	if (p_cds_context->cds_cfg)
+		return (p_cds_context->cds_cfg->sub_20_channel_width ==
+						WLAN_SUB_20_CH_WIDTH_10);
+
+	return false;
+}
+
+/**
+ * cds_is_sub_20_mhz_enabled() - API to get sub 20-MHZ enabled
+ *
+ * Return: true if 5 or 10 mhz is enabled, false otherwise
+ */
+bool cds_is_sub_20_mhz_enabled(void)
+{
+	p_cds_contextType p_cds_context;
+
+	p_cds_context = cds_get_context(QDF_MODULE_ID_QDF);
+	if (!p_cds_context) {
+		cds_err("%s: cds context is invalid", __func__);
+		return false;
+	}
+
+	if (p_cds_context->cds_cfg)
+		return p_cds_context->cds_cfg->sub_20_channel_width;
+
+	return false;
+}
+

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

@@ -5252,6 +5252,12 @@ bool cds_allow_concurrency(enum cds_con_mode mode,
 	/* find the current connection state from conc_connection_list*/
 	num_connections = cds_get_connection_count();
 
+	if (num_connections && cds_is_sub_20_mhz_enabled()) {
+		/* dont allow concurrency if Sub 20 MHz is enabled */
+		status = false;
+		goto done;
+	}
+
 	if (cds_max_concurrent_connections_reached()) {
 		cds_err("Reached max concurrent connections: %d",
 			hdd_ctx->config->gMaxConcurrentActiveSessions);

+ 10 - 0
core/hdd/inc/wlan_hdd_cfg.h

@@ -3399,6 +3399,15 @@ enum dot11p_mode {
 #define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MAX      (4)
 #define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_DEFAULT  (0)
 
+/*
+ * gSub20ChannelWidth=0: indicates do not use Sub 20 MHz bandwidth
+ * gSub20ChannelWidth=1: Bring up SAP/STA in 5 MHz bandwidth
+ * gSub20ChannelWidth=2: Bring up SAP/STA in 10 MHz bandwidth
+ */
+#define CFG_SUB_20_CHANNEL_WIDTH_NAME              "gSub20ChannelWidth"
+#define CFG_SUB_20_CHANNEL_WIDTH_MIN               (WLAN_SUB_20_CH_WIDTH_NONE)
+#define CFG_SUB_20_CHANNEL_WIDTH_MAX               (WLAN_SUB_20_CH_WIDTH_10)
+#define CFG_SUB_20_CHANNEL_WIDTH_DEFAULT           (WLAN_SUB_20_CH_WIDTH_NONE)
 /*---------------------------------------------------------------------------
    Type declarations
    -------------------------------------------------------------------------*/
@@ -4058,6 +4067,7 @@ struct hdd_config {
 	uint8_t nan_datapath_ndi_channel;
 #endif
 	uint32_t iface_change_wait_time;
+	enum cfg_sub_20_channel_width enable_sub_20_channel_width;
 };
 
 #define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var))

+ 10 - 0
core/hdd/src/wlan_hdd_cfg.c

@@ -3968,6 +3968,13 @@ REG_TABLE_ENTRY g_registry_table[] = {
 		CFG_ADAPT_DWELL_LPF_WEIGHT_MIN,
 		CFG_ADAPT_DWELL_LPF_WEIGHT_MAX),
 
+	REG_VARIABLE(CFG_SUB_20_CHANNEL_WIDTH_NAME, WLAN_PARAM_Integer,
+		     struct hdd_config, enable_sub_20_channel_width,
+		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+		     CFG_SUB_20_CHANNEL_WIDTH_DEFAULT,
+		     CFG_SUB_20_CHANNEL_WIDTH_MIN,
+		     CFG_SUB_20_CHANNEL_WIDTH_MAX),
+
 	REG_VARIABLE(CFG_ADAPT_DWELL_PASMON_INTVAL_NAME, WLAN_PARAM_Integer,
 		struct hdd_config, adapt_dwell_passive_mon_intval,
 		VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
@@ -5662,6 +5669,9 @@ void hdd_cfg_print(hdd_context_t *pHddCtx)
 	hdd_info("Name = [%s] Value = [%u]",
 		CFG_ADAPT_DWELL_WIFI_THRESH_NAME,
 		pHddCtx->config->adapt_dwell_wifi_act_threshold);
+	hdd_info("Name = [%s] value = [%u]",
+		 CFG_SUB_20_CHANNEL_WIDTH_NAME,
+		 pHddCtx->config->enable_sub_20_channel_width);
 	hdd_ndp_print_ini_config(pHddCtx);
 	hdd_info("Name = [%s] Value = [%s]",
 		CFG_RM_CAPABILITY_NAME,

+ 12 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -1437,6 +1437,12 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
 	if (status)
 		goto out;
 
+	if (cds_is_sub_20_mhz_enabled()) {
+		hdd_err("ACS not supported in sub 20 MHz ch wd.");
+		status = -EINVAL;
+		goto out;
+	}
+
 	sap_config = &adapter->sessionCtx.ap.sapConfig;
 	qdf_mem_zero(&sap_config->acs_cfg, sizeof(struct sap_acs_cfg));
 
@@ -8452,6 +8458,12 @@ static int __wlan_hdd_change_station(struct wiphy *wiphy,
 		   (pAdapter->device_mode == QDF_P2P_CLIENT_MODE)) {
 #ifdef FEATURE_WLAN_TDLS
 		if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
+
+			if (cds_is_sub_20_mhz_enabled()) {
+				hdd_err("TDLS not allowed with sub 20 MHz");
+				return -EINVAL;
+			}
+
 			StaParams.capability = params->capability;
 			StaParams.uapsd_queues = params->uapsd_queues;
 			StaParams.max_sp = params->max_sp;

+ 1 - 0
core/hdd/src/wlan_hdd_ftm.c

@@ -150,6 +150,7 @@ int hdd_update_cds_config_ftm(hdd_context_t *hdd_ctx)
 	 * frame translation 802.11 <-> 802.3
 	 */
 	cds_cfg->frame_xln_reqd = 1;
+	cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE;
 	cds_init_ini_config(cds_cfg);
 
 	return 0;

+ 33 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -8371,6 +8371,39 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
 	channel = ieee80211_frequency_to_channel(
 				params->chandef.chan->center_freq);
 
+	if (cds_is_sub_20_mhz_enabled()) {
+		enum channel_state ch_state;
+		enum phy_ch_width sub_20_ch_width = CH_WIDTH_INVALID;
+		/* Avoid ACS/DFS, and overwrite ch wd to 20 */
+		if (channel == 0) {
+			hdd_err("Can't start SAP-ACS (channel=0) with sub 20 MHz ch width.");
+			return -EINVAL;
+		}
+		if (CHANNEL_STATE_DFS == cds_get_channel_state(channel)) {
+			hdd_err("Can't start SAP-DFS (channel=%d)with sub 20 MHz ch wd",
+				channel);
+			return -EINVAL;
+		}
+		if (channel_width != HW_MODE_20_MHZ) {
+			hdd_err("Hostapd (20+ MHz) conflits with config.ini (sub 20 MHz)");
+			return -EINVAL;
+		}
+		if (cds_is_5_mhz_enabled())
+			sub_20_ch_width = CH_WIDTH_5MHZ;
+		if (cds_is_10_mhz_enabled())
+			sub_20_ch_width = CH_WIDTH_10MHZ;
+		if (CDS_IS_CHANNEL_5GHZ(channel))
+			ch_state = cds_get_5g_bonded_channel_state(channel,
+							  sub_20_ch_width);
+		else
+			ch_state = cds_get_2g_bonded_channel_state(channel,
+							  sub_20_ch_width, 0);
+		if (CHANNEL_STATE_DISABLE == ch_state) {
+			hdd_err("Given ch width not supported by reg domain.");
+			return -EINVAL;
+		}
+	}
+
 	/* check if concurrency is allowed */
 	if (!cds_allow_concurrency(
 				cds_convert_device_mode_to_qdf_type(

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

@@ -1347,6 +1347,19 @@ void hdd_update_tgt_cfg(void *context, void *param)
 	hdd_context_t *hdd_ctx = (hdd_context_t *) context;
 	struct wma_tgt_cfg *cfg = param;
 	uint8_t temp_band_cap;
+	struct cds_config_info *cds_cfg = cds_get_ini_config();
+
+	if (cds_cfg) {
+		if (hdd_ctx->config->enable_sub_20_channel_width !=
+			WLAN_SUB_20_CH_WIDTH_NONE && !cfg->sub_20_support) {
+			hdd_err("User requested sub 20 MHz channel width but unsupported by FW.");
+			cds_cfg->sub_20_channel_width =
+				WLAN_SUB_20_CH_WIDTH_NONE;
+		} else {
+			cds_cfg->sub_20_channel_width =
+				hdd_ctx->config->enable_sub_20_channel_width;
+		}
+	}
 
 	/* first store the INI band capability */
 	temp_band_cap = hdd_ctx->config->nBandCapability;
@@ -6518,6 +6531,7 @@ int hdd_update_cds_config(hdd_context_t *hdd_ctx)
 	cds_cfg->tx_chain_mask_cck = hdd_ctx->config->tx_chain_mask_cck;
 	cds_cfg->self_gen_frm_pwr = hdd_ctx->config->self_gen_frm_pwr;
 	cds_cfg->max_station = hdd_ctx->config->maxNumberOfPeers;
+	cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE;
 
 	hdd_ra_populate_cds_config(cds_cfg, hdd_ctx);
 	hdd_txrx_populate_cds_config(cds_cfg, hdd_ctx);

+ 16 - 0
core/mac/src/pe/lim/lim_assoc_utils.c

@@ -3987,6 +3987,14 @@ tSirRetStatus lim_sta_send_add_bss(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp,
 	/* we need to defer the message until we get the response back from HAL. */
 	SET_LIM_PROCESS_DEFD_MESGS(pMac, false);
 
+	if (cds_is_5_mhz_enabled()) {
+		pAddBssParams->ch_width = CH_WIDTH_5MHZ;
+		pAddBssParams->staContext.ch_width = CH_WIDTH_5MHZ;
+	} else if (cds_is_10_mhz_enabled()) {
+		pAddBssParams->ch_width = CH_WIDTH_10MHZ;
+		pAddBssParams->staContext.ch_width = CH_WIDTH_10MHZ;
+	}
+
 	msgQ.type = WMA_ADD_BSS_REQ;
 	/** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/
 	msgQ.reserved = 0;
@@ -4464,6 +4472,14 @@ tSirRetStatus lim_sta_send_add_bss_pre_assoc(tpAniSirGlobal pMac, uint8_t update
 	/* we need to defer the message until we get the response back from HAL. */
 	SET_LIM_PROCESS_DEFD_MESGS(pMac, false);
 
+	if (cds_is_5_mhz_enabled()) {
+		pAddBssParams->ch_width = CH_WIDTH_5MHZ;
+		pAddBssParams->staContext.ch_width = CH_WIDTH_5MHZ;
+	} else if (cds_is_10_mhz_enabled()) {
+		pAddBssParams->ch_width = CH_WIDTH_10MHZ;
+		pAddBssParams->staContext.ch_width = CH_WIDTH_10MHZ;
+	}
+
 	msgQ.type = WMA_ADD_BSS_REQ;
 	/** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/
 	msgQ.reserved = 0;

+ 8 - 0
core/mac/src/pe/lim/lim_process_mlm_req_messages.c

@@ -599,6 +599,14 @@ lim_mlm_add_bss(tpAniSirGlobal mac_ctx,
 	lim_log(mac_ctx, LOG2, FL("dot11_mode:%d nss value:%d"),
 			addbss_param->dot11_mode, addbss_param->nss);
 
+	if (cds_is_5_mhz_enabled()) {
+		addbss_param->ch_width = CH_WIDTH_5MHZ;
+		addbss_param->staContext.ch_width = CH_WIDTH_5MHZ;
+	} else if (cds_is_10_mhz_enabled()) {
+		addbss_param->ch_width = CH_WIDTH_10MHZ;
+		addbss_param->staContext.ch_width = CH_WIDTH_10MHZ;
+	}
+
 	msg_buf.type = WMA_ADD_BSS_REQ;
 	msg_buf.reserved = 0;
 	msg_buf.bodyptr = addbss_param;

+ 5 - 0
core/mac/src/pe/lim/lim_send_messages.c

@@ -262,6 +262,11 @@ tSirRetStatus lim_send_switch_chnl_params(tpAniSirGlobal pMac,
 
 	pChnlParams->restart_on_chan_switch = is_restart;
 
+	if (cds_is_5_mhz_enabled())
+		pChnlParams->ch_width = CH_WIDTH_5MHZ;
+	else if (cds_is_10_mhz_enabled())
+		pChnlParams->ch_width = CH_WIDTH_10MHZ;
+
 	/* we need to defer the message until we
 	 * get the response back from WMA
 	 */

+ 20 - 10
core/sme/src/csr/csr_api_roam.c

@@ -720,11 +720,16 @@ QDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac)
 			else
 				pChanList->chanParam[num_channel].dfsSet =
 					true;
-		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO,
+			QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO,
 				"channel:%d, pwr=%d, DFS=%d\n",
 				pChanList->chanParam[num_channel].chanId,
 				pChanList->chanParam[num_channel].pwr,
 				pChanList->chanParam[num_channel].dfsSet);
+			if (cds_is_5_mhz_enabled())
+				pChanList->chanParam[num_channel].quarter_rate
+					= 1;
+			else if (cds_is_10_mhz_enabled())
+				pChanList->chanParam[num_channel].half_rate = 1;
 			num_channel++;
 		}
 	}
@@ -732,15 +737,20 @@ QDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac)
 	if (CSR_IS_5G_BAND_ONLY(pMac)) {
 		for (j = 0; j < MAX_SOCIAL_CHANNELS; j++) {
 			if (cds_get_channel_state(social_channel[j])
-			    == CHANNEL_STATE_ENABLE) {
-				pChanList->chanParam[num_channel].chanId =
-					social_channel[j];
-				pChanList->chanParam[num_channel].pwr =
-					csr_find_channel_pwr(pScan->defaultPowerTable,
-							  social_channel[j]);
-				pChanList->chanParam[num_channel].dfsSet = false;
-				num_channel++;
-			}
+			    != CHANNEL_STATE_ENABLE)
+				continue;
+			pChanList->chanParam[num_channel].chanId =
+				social_channel[j];
+			pChanList->chanParam[num_channel].pwr =
+				csr_find_channel_pwr(pScan->defaultPowerTable,
+						     social_channel[j]);
+			pChanList->chanParam[num_channel].dfsSet = false;
+			if (cds_is_5_mhz_enabled())
+				pChanList->chanParam[num_channel].quarter_rate
+									= 1;
+			else if (cds_is_10_mhz_enabled())
+				pChanList->chanParam[num_channel].half_rate = 1;
+			num_channel++;
 		}
 	}
 	if (pMac->roam.configParam.early_stop_scan_enable)

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

@@ -1438,6 +1438,7 @@ typedef struct {
 	bool nan_datapath_enabled;
 	QDF_STATUS (*pe_ndp_event_handler)(tpAniSirGlobal mac_ctx,
 					   cds_msg_t *msg);
+	bool sub_20_support;
 } t_wma_handle, *tp_wma_handle;
 
 /**

+ 1 - 0
core/wma/inc/wma_tgt_cfg.h

@@ -172,5 +172,6 @@ struct wma_tgt_cfg {
 #ifdef WLAN_FEATURE_NAN_DATAPATH
 	bool nan_datapath_enabled;
 #endif
+	bool sub_20_support;
 };
 #endif /* WMA_TGT_CFG_H */

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

@@ -2747,6 +2747,12 @@ static void wma_add_bss_ap_mode(tp_wma_handle wma, tpAddBssParams add_bss)
 	req.vdev_id = vdev_id;
 	req.chan = add_bss->currentOperChannel;
 	req.chan_width = add_bss->ch_width;
+
+	if (add_bss->ch_width == CH_WIDTH_10MHZ)
+		req.is_half_rate = 1;
+	else if (add_bss->ch_width == CH_WIDTH_5MHZ)
+		req.is_quarter_rate = 1;
+
 	req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0;
 	req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1;
 	req.vht_capable = add_bss->vhtCapable;
@@ -3089,6 +3095,12 @@ static void wma_add_bss_sta_mode(tp_wma_handle wma, tpAddBssParams add_bss)
 			req.vdev_id = vdev_id;
 			req.chan = add_bss->currentOperChannel;
 			req.chan_width = add_bss->ch_width;
+
+			if (add_bss->ch_width == CH_WIDTH_10MHZ)
+				req.is_half_rate = 1;
+			else if (add_bss->ch_width == CH_WIDTH_5MHZ)
+				req.is_quarter_rate = 1;
+
 			req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0;
 			req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1;
 			req.max_txpow = add_bss->maxTxPower;

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

@@ -3913,6 +3913,8 @@ static void wma_update_hdd_cfg(tp_wma_handle wma_handle)
 	void *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
 
 	qdf_mem_zero(&tgt_cfg, sizeof(struct wma_tgt_cfg));
+
+	tgt_cfg.sub_20_support = wma_handle->sub_20_support;
 	tgt_cfg.reg_domain = wma_handle->reg_cap.eeprom_rd;
 	tgt_cfg.eeprom_rd_ext = wma_handle->reg_cap.eeprom_rd_ext;
 
@@ -4771,6 +4773,9 @@ int wma_rx_ready_event(void *handle, uint8_t *cmd_param_info,
 	ev = param_buf->fixed_param;
 	/* Indicate to the waiting thread that the ready
 	 * event was received */
+	wma_handle->sub_20_support =
+		WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
+				WMI_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT);
 	wma_handle->wmi_ready = true;
 	wma_handle->wlan_init_status = ev->status;
 

+ 6 - 0
core/wma/src/wma_scan_roam.c

@@ -2798,6 +2798,12 @@ void wma_set_channel(tp_wma_handle wma, tpSwitchChannelParams params)
 	}
 	req.chan = params->channelNumber;
 	req.chan_width = params->ch_width;
+
+	if (params->ch_width == CH_WIDTH_10MHZ)
+		req.is_half_rate = 1;
+	else if (params->ch_width == CH_WIDTH_5MHZ)
+		req.is_quarter_rate = 1;
+
 	req.vht_capable = params->vhtCapable;
 	req.ch_center_freq_seg0 = params->ch_center_freq_seg0;
 	req.ch_center_freq_seg1 = params->ch_center_freq_seg1;