From 121bf2115a50053da526c7548df2fcc950d1cfd7 Mon Sep 17 00:00:00 2001 From: "Gupta, Kapil" Date: Wed, 25 Nov 2015 19:21:29 +0530 Subject: [PATCH] qcacld-3.0: Support for handling of op class in xcsa action frame qcacld-2.0 to qcacld-3.0 propagation Add support to parse operating class from xcsa frame and select channel bandwidth on basis of new operating class. Change-Id: I33d794e77220ef82cca793767d459979eb940669 CRs-Fixed: 942104 --- core/cds/inc/cds_regdomain_common.h | 2 + core/cds/src/cds_regdomain.c | 44 +++++++ .../src/pe/lim/lim_send_sme_rsp_messages.c | 107 +++++++++++++++++- core/mac/src/pe/lim/lim_utils.h | 53 +++++++++ core/wma/inc/wma_if.h | 1 + core/wma/src/wma_features.c | 1 + 6 files changed, 206 insertions(+), 2 deletions(-) diff --git a/core/cds/inc/cds_regdomain_common.h b/core/cds/inc/cds_regdomain_common.h index 7feaf55c3928..36c480b9a309 100644 --- a/core/cds/inc/cds_regdomain_common.h +++ b/core/cds/inc/cds_regdomain_common.h @@ -2214,5 +2214,7 @@ typedef struct _regdm_supp_op_classes { uint16_t cds_regdm_get_opclass_from_channel(uint8_t *country, uint8_t channel, uint8_t offset); +uint16_t cds_regdm_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel, + uint8_t opclass); uint16_t cds_regdm_set_curr_opclasses(uint8_t num_classes, uint8_t *class); uint16_t cds_regdm_get_curr_opclasses(uint8_t *num_classes, uint8_t *class); diff --git a/core/cds/src/cds_regdomain.c b/core/cds/src/cds_regdomain.c index 3a935293c289..e3c897c81c82 100644 --- a/core/cds/src/cds_regdomain.c +++ b/core/cds/src/cds_regdomain.c @@ -622,6 +622,50 @@ uint16_t cds_get_regdmn_5g(uint32_t reg_dmn) return 0; } +/** + * cds_regdm_get_chanwidth_from_opclass() - return chan width based on opclass + * @country: country name + * @channel: operating channel + * @opclass: operating class + * + * Given a value of country, channel and opclass this API will return value of + * channel width. + * + * Return: channel width + * + */ +uint16_t cds_regdm_get_chanwidth_from_opclass(uint8_t *country, + uint8_t channel, + uint8_t opclass) +{ + regdm_op_class_map_t *class; + uint16_t i; + + if (true == cdf_mem_compare(country, "US", 2)) + class = us_op_class; + else if (true == cdf_mem_compare(country, "EU", 2)) + class = euro_op_class; + else if (true == cdf_mem_compare(country, "JP", 2)) + class = japan_op_class; + else + class = global_op_class; + + while (class->op_class) { + if (opclass == class->op_class) { + for (i = 0; + (i < MAX_CHANNELS_PER_OPERATING_CLASS && + class->channels[i]); + i++) { + if (channel == class->channels[i]) + return class->ch_spacing; + } + } + class++; + } + return 0; +} + + /* * Get operating class for a given channel */ diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c index bde6cba7038f..eee97bae7934 100644 --- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -55,6 +55,8 @@ #include "lim_session_utils.h" #include "lim_types.h" #include "sir_api.h" +#include "cds_regdomain_common.h" +#include "lim_send_messages.h" static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx, tpPESession session_entry, tSirResultCodes result_code, @@ -2010,6 +2012,9 @@ void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) tpDphHashNode sta_ds = NULL; uint8_t session_id; uint16_t aid = 0; + uint16_t chan_space = 0; + int cb_mode = 0; + tLimWiderBWChannelSwitchInfo *chnl_switch_info = NULL; if (!csa_params) { @@ -2052,10 +2057,13 @@ void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; session_entry->gLimChannelSwitch.ch_width = CH_WIDTH_20MHZ; + session_entry->gLimChannelSwitch.ch_center_freq_seg0 = 0; + session_entry->gLimChannelSwitch.ch_center_freq_seg1 = 0; + chnl_switch_info = + &session_entry->gLimWiderBWChannelSwitch; + if (session_entry->vhtCapability && session_entry->htSupportedChannelWidthSet) { - chnl_switch_info = - &session_entry->gLimWiderBWChannelSwitch; if (csa_params->ies_present_flag & lim_wbw_ie_present) { chnl_switch_info->newChanWidth = csa_params->new_ch_width; @@ -2067,8 +2075,103 @@ void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; session_entry->gLimChannelSwitch.ch_width = csa_params->new_ch_width + 1; + } else if (csa_params->ies_present_flag + & lim_xcsa_ie_present) { + chan_space = + cds_regdm_get_chanwidth_from_opclass( + mac_ctx->scan.countryCodeCurrent, + csa_params->channel, + csa_params->new_op_class); + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + + if (chan_space == 80) { + chnl_switch_info->newChanWidth = + CH_WIDTH_80MHZ; + } else if (chan_space == 40) { + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + } else { + chnl_switch_info->newChanWidth = + CH_WIDTH_20MHZ; + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + } + + cb_mode = lim_select_cb_mode_for_sta( + session_entry, + csa_params->channel, + chan_space); + + chnl_switch_info->newCenterChanFreq0 = + lim_get_center_channel(mac_ctx, + csa_params->channel, + cb_mode, + chnl_switch_info->newChanWidth); + /* + * This is not applicable for 20/40/80 MHz. + * Only used when we support 80+80 MHz operation. + * In case of 80+80 MHz, this parameter indicates + * center channel frequency index of 80 MHz + * channel offrequency segment 1. + */ + chnl_switch_info->newCenterChanFreq1 = 0; + } + session_entry->gLimChannelSwitch.ch_center_freq_seg0 = + chnl_switch_info->newCenterChanFreq0; + session_entry->gLimChannelSwitch.ch_center_freq_seg1 = + chnl_switch_info->newCenterChanFreq1; + session_entry->gLimChannelSwitch.ch_width = + chnl_switch_info->newChanWidth; + } else if (session_entry->htSupportedChannelWidthSet) { + if (csa_params->ies_present_flag + & lim_xcsa_ie_present) { + chan_space = + cds_regdm_get_chanwidth_from_opclass( + mac_ctx->scan.countryCodeCurrent, + csa_params->channel, + csa_params->new_op_class); + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + if (chan_space == 40) { + session_entry-> + gLimChannelSwitch.ch_width = + CH_WIDTH_40MHZ; + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + cb_mode = lim_select_cb_mode_for_sta( + session_entry, + csa_params->channel, + chan_space); + if (cb_mode == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + session_entry-> + gLimChannelSwitch. + ch_center_freq_seg0 = + csa_params->channel + 2; + } else if (cb_mode == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) { + session_entry-> + gLimChannelSwitch. + ch_center_freq_seg0 = + csa_params->channel - 2; + } + + } else { + session_entry-> + gLimChannelSwitch.ch_width = + CH_WIDTH_20MHZ; + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + } + + + } + if (csa_params->sec_chan_offset) { session_entry->gLimChannelSwitch.ch_width = CH_WIDTH_40MHZ; diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h index cd9d6a1a1bf3..42a5eab8e451 100644 --- a/core/mac/src/pe/lim/lim_utils.h +++ b/core/mac/src/pe/lim/lim_utils.h @@ -294,6 +294,59 @@ is_entering_mimo_ps(tSirMacHTMIMOPowerSaveState curState, return false; } +/** + * lim_select_cb_mode_for_sta() - return cb_mode based on current session + * @session_entry: Session entry + * @channel: channel + * @chan_bw: channel bandwidth + * + * Given a value of channel and bandwidth this API will return the value of + * cb_mode on basis of channel, bandwidth ht/vht capabilities + * + * Return: cb_mode + * + */ + +static inline int lim_select_cb_mode_for_sta(tpPESession session_entry, + uint8_t channel, uint8_t chan_bw) +{ + if (session_entry->vhtCapability && chan_bw) { + if (channel == 36 || channel == 52 || channel == 100 || + channel == 116 || channel == 149) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1; + } else if (channel == 40 || channel == 56 || channel == 104 || + channel == 120 || channel == 153) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW - 1; + } else if (channel == 44 || channel == 60 || channel == 108 || + channel == 124 || channel == 157) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH - 1; + } else if (channel == 48 || channel == 64 || channel == 112 || + channel == 128 || channel == 161) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH - 1; + } else if (channel == 165) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + } else if (session_entry->htSupportedChannelWidthSet) { + if (channel == 40 || channel == 48 || channel == 56 || + channel == 64 || channel == 104 || channel == 112 || + channel == 120 || channel == 128 || channel == 136 || + channel == 144 || channel == 153 || channel == 161) { + return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + } else if (channel == 36 || channel == 44 || channel == 52 || + channel == 60 || channel == 100 || + channel == 108 || channel == 116 || + channel == 124 || channel == 132 || + channel == 140 || channel == 149 || + channel == 157) { + return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + } else if (channel == 165) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + } + return PHY_SINGLE_CHANNEL_CENTERED; +} + + static inline int lim_select_cb_mode(tDphHashNode *pStaDs, tpPESession psessionEntry, uint8_t channel, uint8_t chan_bw) diff --git a/core/wma/inc/wma_if.h b/core/wma/inc/wma_if.h index 63dd5e3374bc..52e313908ff6 100644 --- a/core/wma/inc/wma_if.h +++ b/core/wma/inc/wma_if.h @@ -940,6 +940,7 @@ typedef struct CSAOffloadParams { uint8_t switchmode; uint8_t sec_chan_offset; uint8_t new_ch_width; + uint8_t new_op_class; uint8_t new_ch_freq_seg1; uint8_t new_ch_freq_seg2; uint32_t ies_present_flag; diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index ffe4771826b7..f8f2736e39d9 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -1492,6 +1492,7 @@ int wma_csa_offload_handler(void *handle, uint8_t *event, uint32_t len) (&csa_event->xcsa_ie[0]); csa_offload_event->channel = xcsa_ie->newchannel; csa_offload_event->switchmode = xcsa_ie->switchmode; + csa_offload_event->new_op_class = xcsa_ie->newClass; } else { WMA_LOGE("CSA Event error: No CSA IE present"); cdf_mem_free(csa_offload_event);