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
This commit is contained in:
Manishekar Chandrasekaran 2016-05-25 18:44:01 +05:30 • committed by Akash Patel
commit c67b2bb16c
3 changed files with 214 additions and 100 deletions

View file

@ -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);

View file

@ -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)
/**

View file

@ -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;
}
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;
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");
/* 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) {
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;
if (!hdd_ctxt->unsafe_channel_count) {
hdd_info("no unsafe channels - not restarting SAP");
return;
}
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;
}
/* 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.
*/
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;
}
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;
}