diff options
| author | Justin Shen <chias@qca.qualcomm.com> | 2014-09-11 14:52:55 +0800 |
|---|---|---|
| committer | AnjaneeDevi Kapparapu <c_akappa@qti.qualcomm.com> | 2014-10-07 17:38:29 +0530 |
| commit | ca349a9ac565a5e84ba262ab6addc486d66529a9 (patch) | |
| tree | 453cab6299caf6071d12f90509564e86caad1a90 | |
| parent | 6c7164b5d477a521c3e7c40556cf31f768106e17 (diff) | |
qcacld: add remain-on-channel queue scenario code
We hit the case one interface issued p2p_find but other interface is
during connection in progress. This RoC would get failed. And then
no more RoC got triggered. The host driver should enqueue this RoC
as request once the driver is temporarily busy. Then execute this RoC
after driver becomes free later.
Change-Id: Ie3d8b9d54b7c5a7d70b3995fc7e87f79ba338e92
CRs-Fixed: 715957
| -rw-r--r-- | CORE/HDD/inc/wlan_hdd_cfg80211.h | 4 | ||||
| -rw-r--r-- | CORE/HDD/inc/wlan_hdd_main.h | 12 | ||||
| -rw-r--r-- | CORE/HDD/inc/wlan_hdd_p2p.h | 5 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_assoc.c | 59 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_cfg80211.c | 11 | ||||
| -rwxr-xr-x | CORE/HDD/src/wlan_hdd_main.c | 12 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_p2p.c | 291 |
7 files changed, 286 insertions, 108 deletions
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h index 3500f087efa7..a9a9726ab88c 100644 --- a/CORE/HDD/inc/wlan_hdd_cfg80211.h +++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h @@ -905,8 +905,8 @@ void wlan_hdd_linux_reg_notifier(struct wiphy *wiphy, struct regulatory_request int wlan_hdd_linux_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); #endif -extern v_VOID_t hdd_connSetConnectionState( hdd_station_ctx_t *pHddStaCtx, - eConnectionState connState ); +extern v_VOID_t hdd_connSetConnectionState(hdd_adapter_t *pAdapter, + eConnectionState connState); VOS_STATUS wlan_hdd_validate_operation_channel(hdd_adapter_t *pAdapter,int channel); #ifdef FEATURE_WLAN_TDLS int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy, diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h index 6c1ea806df98..6e91a699a298 100644 --- a/CORE/HDD/inc/wlan_hdd_main.h +++ b/CORE/HDD/inc/wlan_hdd_main.h @@ -600,6 +600,14 @@ typedef struct hdd_remain_on_chan_ctx v_BOOL_t hdd_remain_on_chan_cancel_in_progress; }hdd_remain_on_chan_ctx_t; +/* RoC Request entry */ +typedef struct hdd_roc_req +{ + hdd_list_node_t node; /* MUST be first element */ + hdd_adapter_t *pAdapter; + hdd_remain_on_chan_ctx_t *pRemainChanCtx; +}hdd_roc_req_t; + typedef enum{ HDD_IDLE, HDD_PD_REQ_ACK_PENDING, @@ -1491,6 +1499,10 @@ struct hdd_context_s /* Time since boot up to WiFi turn ON (in micro seconds) */ v_U64_t wifi_turn_on_time_since_boot; + + /* RoC request queue and work */ + struct work_struct rocReqWork; + hdd_list_t hdd_roc_req_q; }; /*--------------------------------------------------------------------------- diff --git a/CORE/HDD/inc/wlan_hdd_p2p.h b/CORE/HDD/inc/wlan_hdd_p2p.h index a4ffe7fed916..4318ebfe7017 100644 --- a/CORE/HDD/inc/wlan_hdd_p2p.h +++ b/CORE/HDD/inc/wlan_hdd_p2p.h @@ -184,4 +184,9 @@ int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev ); void wlan_hdd_cleanup_remain_on_channel_ctx(hdd_adapter_t *pAdapter); +/* Max entry for RoC request */ +#define MAX_ROC_REQ_QUEUE_ENTRY 10 + +void hdd_roc_req_work(struct work_struct *work); + #endif // __P2P_H diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c index 0429e185cf19..f01b496f4935 100644 --- a/CORE/HDD/src/wlan_hdd_assoc.c +++ b/CORE/HDD/src/wlan_hdd_assoc.c @@ -136,14 +136,33 @@ static eHalStatus hdd_RoamSetKeyCompleteHandler( hdd_adapter_t *pAdapter, eRoamCmdStatus roamStatus, eCsrRoamResult roamResult ); -v_VOID_t hdd_connSetConnectionState( hdd_station_ctx_t *pHddStaCtx, - eConnectionState connState ) +v_VOID_t hdd_connSetAuthenticated( hdd_adapter_t *pAdapter, v_U8_t authState ) { - // save the new connection state + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* save the new connection state */ + hddLog(LOG1, FL("Authenticated state Changed from oldState:%d to State:%d"), + pHddStaCtx->conn_info.uIsAuthenticated, authState); + pHddStaCtx->conn_info.uIsAuthenticated = authState; + + /* Check is pending ROC request or not when auth state changed */ + schedule_work(&pHddCtx->rocReqWork); +} + +v_VOID_t hdd_connSetConnectionState( hdd_adapter_t *pAdapter, + eConnectionState connState ) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* save the new connection state */ hddLog(LOG1, FL("ConnectionState Changed from oldState:%d to State:%d"), pHddStaCtx->conn_info.connState,connState); pHddStaCtx->conn_info.connState = connState; + /* Check is pending ROC request or not when connection state changed */ + schedule_work(&pHddCtx->rocReqWork); } // returns FALSE if not connected. @@ -909,7 +928,8 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Set HDD connState to eConnectionState_Disconnecting", __func__); - hdd_connSetConnectionState( pHddStaCtx, eConnectionState_Disconnecting ); + hdd_connSetConnectionState(pAdapter, + eConnectionState_Disconnecting); } /* If only STA mode is on */ @@ -1034,7 +1054,8 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Set HDD connState to eConnectionState_NotConnected", __func__); - hdd_connSetConnectionState( pHddStaCtx, eConnectionState_NotConnected ); + hdd_connSetConnectionState(pAdapter, + eConnectionState_NotConnected); #ifdef WLAN_FEATURE_GTK_OFFLOAD if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) @@ -1252,7 +1273,7 @@ static VOS_STATUS hdd_roamRegisterSTA( hdd_adapter_t *pAdapter, #endif ); - pHddStaCtx->conn_info.uIsAuthenticated = VOS_TRUE; + hdd_connSetAuthenticated(pAdapter, VOS_TRUE); } else { @@ -1267,7 +1288,7 @@ static VOS_STATUS hdd_roamRegisterSTA( hdd_adapter_t *pAdapter, VOS_FALSE #endif ); - pHddStaCtx->conn_info.uIsAuthenticated = VOS_FALSE; + hdd_connSetAuthenticated(pAdapter, VOS_FALSE); } return( vosStatus ); } @@ -1407,7 +1428,8 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Set HDD connState to eConnectionState_Associated", __func__); - hdd_connSetConnectionState( pHddStaCtx, eConnectionState_Associated ); + hdd_connSetConnectionState(pAdapter, + eConnectionState_Associated); } // Save the connection info from CSR... @@ -1707,7 +1729,7 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs VOS_FALSE #endif ); - pHddStaCtx->conn_info.uIsAuthenticated = VOS_FALSE; + hdd_connSetAuthenticated(pAdapter, VOS_FALSE); } else { @@ -1723,7 +1745,7 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs VOS_FALSE #endif ); - pHddStaCtx->conn_info.uIsAuthenticated = VOS_TRUE; + hdd_connSetAuthenticated(pAdapter, VOS_TRUE); } if ( VOS_IS_STATUS_SUCCESS( vosStatus ) ) @@ -1776,7 +1798,8 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Set HDD connState to eConnectionState_NotConnected", __func__); - hdd_connSetConnectionState( pHddStaCtx, eConnectionState_NotConnected); + hdd_connSetConnectionState(pAdapter, + eConnectionState_NotConnected); } if((pHddCtx->concurrency_mode <= 1) && (pHddCtx->no_of_open_sessions[WLAN_HDD_INFRA_STATION] <=1)) @@ -1954,8 +1977,8 @@ static void hdd_RoamIbssIndicationHandler( hdd_adapter_t *pAdapter, VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Set HDD connState to eConnectionState_IbssDisconnected", __func__); - hdd_connSetConnectionState( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), - eConnectionState_IbssDisconnected ); + hdd_connSetConnectionState(pAdapter, + eConnectionState_IbssDisconnected); /* Notify wmm */ hdd_wmm_connect(pAdapter, pRoamInfo, eCSR_BSS_TYPE_IBSS); pHddCtx->sta_to_adapter[IBSS_BROADCAST_STAID] = pAdapter; @@ -2125,7 +2148,8 @@ static eHalStatus roamIbssConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo "Set HDD connState to eConnectionState_IbssConnected", __func__); // Set the internal connection state to show 'IBSS Connected' (IBSS with a partner stations)... - hdd_connSetConnectionState( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), eConnectionState_IbssConnected ); + hdd_connSetConnectionState(pAdapter, + eConnectionState_IbssConnected); // Save the connection info from CSR... hdd_connSaveConnectInfo( pAdapter, pRoamInfo, eCSR_BSS_TYPE_IBSS ); @@ -2227,7 +2251,7 @@ static eHalStatus hdd_RoamSetKeyCompleteHandler( hdd_adapter_t *pAdapter, tCsrRo VOS_FALSE #endif ); - pHddStaCtx->conn_info.uIsAuthenticated = VOS_TRUE; + hdd_connSetAuthenticated(pAdapter, VOS_TRUE); if ( ( eCSR_ROAM_RESULT_AUTHENTICATED == roamResult ) && (pRoamInfo != NULL) && !pRoamInfo->fAuthRequired ) { @@ -2247,7 +2271,7 @@ static eHalStatus hdd_RoamSetKeyCompleteHandler( hdd_adapter_t *pAdapter, tCsrRo #endif ); - pHddStaCtx->conn_info.uIsAuthenticated = VOS_TRUE; + hdd_connSetAuthenticated(pAdapter, VOS_TRUE); if (pHddCtx->cfg_ini->enablePowersaveOffload && ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || @@ -2451,7 +2475,8 @@ static eHalStatus roamRoamConnectStatusUpdateHandler( hdd_adapter_t *pAdapter, t VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Set HDD connState to eConnectionState_NotConnected", __func__); - hdd_connSetConnectionState( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), eConnectionState_NotConnected ); + hdd_connSetConnectionState(pAdapter, + eConnectionState_NotConnected); // Send the bssid address to the wext. hdd_SendAssociationEvent(pAdapter->dev, pRoamInfo); diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c index 01065dbbd495..790b023afa21 100644 --- a/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -9575,8 +9575,8 @@ int wlan_hdd_cfg80211_connect_start( hdd_adapter_t *pAdapter, VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Set HDD connState to eConnectionState_Connecting", __func__); - hdd_connSetConnectionState(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), - eConnectionState_Connecting); + hdd_connSetConnectionState(pAdapter, + eConnectionState_Connecting); } /* After 8-way handshake supplicant should give the scan command @@ -9605,8 +9605,8 @@ int wlan_hdd_cfg80211_connect_start( hdd_adapter_t *pAdapter, hddLog(VOS_TRACE_LEVEL_ERROR, "%s: sme_RoamConnect (session %d) failed with " "status %d. -> NotConnected", __func__, pAdapter->sessionId, status); /* change back to NotAssociated */ - hdd_connSetConnectionState(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), - eConnectionState_NotConnected); + hdd_connSetConnectionState(pAdapter, + eConnectionState_NotConnected); } pRoamProfile->ChannelInfo.ChannelList = NULL; @@ -10539,7 +10539,8 @@ int wlan_hdd_disconnect( hdd_adapter_t *pAdapter, u16 reason ) disconnected: VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, FL("Set HDD connState to eConnectionState_NotConnected")); - pHddStaCtx->conn_info.connState = eConnectionState_NotConnected; + hdd_connSetConnectionState(pAdapter, + eConnectionState_NotConnected); return 0; } diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c index 29eadca58d09..4dc3511a3048 100755 --- a/CORE/HDD/src/wlan_hdd_main.c +++ b/CORE/HDD/src/wlan_hdd_main.c @@ -10868,6 +10868,10 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) __func__); } + /* Free up RoC request queue and flush workqueue */ + vos_flush_work(&pHddCtx->rocReqWork); + hdd_list_destroy(&pHddCtx->hdd_roc_req_q); + free_hdd_ctx: /* FTM mode, WIPHY did not registered If un-register here, system crash will happen */ @@ -12231,6 +12235,14 @@ int hdd_wlan_startup(struct device *dev, v_VOID_t *hif_sc) pHddCtx->target_hw_name); #endif + /* Initialize the RoC Request queue and work. */ + hdd_list_init((&pHddCtx->hdd_roc_req_q), MAX_ROC_REQ_QUEUE_ENTRY); +#ifdef CONFIG_CNSS + cnss_init_work(&pHddCtx->rocReqWork, hdd_roc_req_work); +#else + INIT_WORK(&pHddCtx->rocReqWork, hdd_roc_req_work); +#endif + complete(&wlan_start_comp); goto success; diff --git a/CORE/HDD/src/wlan_hdd_p2p.c b/CORE/HDD/src/wlan_hdd_p2p.c index 92b33b103db9..a76e8dbb8452 100644 --- a/CORE/HDD/src/wlan_hdd_p2p.c +++ b/CORE/HDD/src/wlan_hdd_p2p.c @@ -496,17 +496,9 @@ void wlan_hdd_remain_on_chan_timeout(void *data) } -static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, - struct net_device *dev, - struct ieee80211_channel *chan, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) - enum nl80211_channel_type channel_type, -#endif - unsigned int duration, u64 *cookie, - rem_on_channel_request_type_t request_type ) +static int wlan_hdd_execute_remain_on_channel(hdd_adapter_t *pAdapter, + hdd_remain_on_chan_ctx_t *pRemainChanCtx) { - hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); - hdd_remain_on_chan_ctx_t *pRemainChanCtx; hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter ); VOS_STATUS vos_status = VOS_STATUS_E_FAILURE; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter ); @@ -514,74 +506,7 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, hdd_adapter_t *pAdapter_temp; VOS_STATUS status; v_BOOL_t isGoPresent = VOS_FALSE; - - hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d", - __func__,pAdapter->device_mode); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) - hddLog( LOG1, - "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d", - chan->hw_value, chan->center_freq, channel_type, duration ); -#else - hddLog( LOG1, - "chan(hw_val)0x%x chan(centerfreq) %d, duration %d", - chan->hw_value, chan->center_freq, duration ); -#endif - //Cancel existing remain On Channel if any - wlan_hdd_cancel_existing_remain_on_channel(pAdapter); - - /* When P2P-GO and if we are trying to unload the driver then - * wlan driver is keep on receiving the remain on channel command - * and which is resulting in crash. So not allowing any remain on - * channel request when Load/Unload is in progress*/ - if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadInProgress || - ((hdd_context_t*)pAdapter->pHddCtx)->isUnloadInProgress || - hdd_isConnectionInProgress((hdd_context_t *)pAdapter->pHddCtx)) - { - hddLog( LOGE, - "%s: Wlan Load/Unload or Connection is in progress", __func__); - return -EBUSY; - } - - if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s:LOGP in Progress. Ignore!!!", __func__); - return -EAGAIN; - } - pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) ); - if( NULL == pRemainChanCtx ) - { - hddLog(VOS_TRACE_LEVEL_FATAL, - "%s: Not able to allocate memory for Channel context", - __func__); - return -ENOMEM; - } - - vos_mem_copy( &pRemainChanCtx->chan, chan, - sizeof(struct ieee80211_channel) ); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) - pRemainChanCtx->chan_type = channel_type; -#endif - pRemainChanCtx->duration = duration; - pRemainChanCtx->p2pRemOnChanTimeStamp = vos_timer_get_system_time(); - pRemainChanCtx->dev = dev; - *cookie = (uintptr_t) pRemainChanCtx; - pRemainChanCtx->cookie = *cookie; - pRemainChanCtx->rem_on_chan_request = request_type; - - mutex_lock(&cfgState->remain_on_chan_ctx_lock); - cfgState->remain_on_chan_ctx = pRemainChanCtx; - pAdapter->is_roc_inprogress = TRUE; - mutex_unlock(&cfgState->remain_on_chan_ctx_lock); - - cfgState->current_freq = chan->center_freq; - - pRemainChanCtx->action_pkt_buff.freq = 0; - pRemainChanCtx->action_pkt_buff.frame_ptr = NULL; - pRemainChanCtx->action_pkt_buff.frame_length = 0; - pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = FALSE; + unsigned int duration; /* Initialize Remain on chan timer */ vos_status = vos_timer_init(&pRemainChanCtx->hdd_remain_on_chan_timer, @@ -596,6 +521,8 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, mutex_lock(&cfgState->remain_on_chan_ctx_lock); cfgState->remain_on_chan_ctx = pRemainChanCtx; + cfgState->current_freq = pRemainChanCtx->chan.center_freq; + pAdapter->is_roc_inprogress = TRUE; mutex_unlock(&cfgState->remain_on_chan_ctx_lock); status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); @@ -611,6 +538,7 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, } //Extending duration for proactive extension logic for RoC + duration = pRemainChanCtx->duration; if (isGoPresent == VOS_TRUE) duration = P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT * duration; else @@ -631,12 +559,12 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, sme_RemainOnChannel( WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId, - chan->hw_value, duration, + pRemainChanCtx->chan.hw_value, duration, wlan_hdd_remain_on_channel_callback, pAdapter, - (tANI_U8)(request_type == REMAIN_ON_CHANNEL_REQUEST)? TRUE:FALSE); + (tANI_U8)(pRemainChanCtx->rem_on_chan_request + == REMAIN_ON_CHANNEL_REQUEST)? TRUE:FALSE); - if( REMAIN_ON_CHANNEL_REQUEST == request_type) - { + if (REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request) { sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId, (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 ); @@ -654,7 +582,7 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, #else (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, #endif - chan->hw_value, duration, + pRemainChanCtx->chan.hw_value, duration, wlan_hdd_remain_on_channel_callback, pAdapter)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, @@ -693,7 +621,182 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, } return 0; +} +static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) + enum nl80211_channel_type channel_type, +#endif + unsigned int duration, u64 *cookie, + rem_on_channel_request_type_t request_type ) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter ); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + v_BOOL_t isBusy = VOS_FALSE; + v_SIZE_t size = 0; + hdd_roc_req_t* phdd_roc_req; + VOS_STATUS status; + + hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d", + __func__, pAdapter->device_mode); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) + hddLog( LOG1, + "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d", + chan->hw_value, chan->center_freq, channel_type, duration ); +#else + hddLog( LOG1, + "chan(hw_val)0x%x chan(centerfreq) %d, duration %d", + chan->hw_value, chan->center_freq, duration ); +#endif + + /* + * When P2P-GO and if we are trying to unload the driver then + * wlan driver is keep on receiving the remain on channel command + * and which is resulting in crash. So not allowing any remain on + * channel requets when Load/Unload is in progress + */ + if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadInProgress || + ((hdd_context_t*)pAdapter->pHddCtx)->isUnloadInProgress) { + hddLog( LOGE, + "%s: Wlan Load/Unload is in progress", __func__); + return -EBUSY; + } + + if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:LOGP in Progress. Ignore!!!", __func__); + return -EAGAIN; + } + + if (hdd_isConnectionInProgress((hdd_context_t *)pAdapter->pHddCtx)) { + hddLog( LOGE, + "%s: Connection is in progress", __func__); + isBusy = VOS_TRUE; + } + + pRemainChanCtx = vos_mem_malloc(sizeof(hdd_remain_on_chan_ctx_t)); + if (NULL == pRemainChanCtx) { + hddLog(VOS_TRACE_LEVEL_FATAL, + "%s: Not able to allocate memory for Channel context", + __func__); + return -ENOMEM; + } + + vos_mem_copy(&pRemainChanCtx->chan, chan, + sizeof(struct ieee80211_channel)); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) + pRemainChanCtx->chan_type = channel_type; +#endif + pRemainChanCtx->duration = duration; + pRemainChanCtx->p2pRemOnChanTimeStamp = vos_timer_get_system_time(); + pRemainChanCtx->dev = dev; + *cookie = (uintptr_t) pRemainChanCtx; + pRemainChanCtx->cookie = *cookie; + pRemainChanCtx->rem_on_chan_request = request_type; + + pRemainChanCtx->action_pkt_buff.freq = 0; + pRemainChanCtx->action_pkt_buff.frame_ptr = NULL; + pRemainChanCtx->action_pkt_buff.frame_length = 0; + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = FALSE; + + /* Check roc_req_Q has pendding RoC Request or not */ + hdd_list_size(&(pHddCtx->hdd_roc_req_q), &size); + + if ((isBusy == VOS_FALSE) && (!size)) { + + /* Media is free and no RoC request is in queue, execute directly */ + wlan_hdd_execute_remain_on_channel(pAdapter, pRemainChanCtx); + + return 0; + } else { + + /* + * "Driver is busy" OR "there is already RoC request inside the queue" + * so enqueue this RoC Request for execute RoC sequently in the future. + */ + + phdd_roc_req = vos_mem_malloc(sizeof(hdd_roc_req_t)); + + if (NULL == phdd_roc_req) { + hddLog(VOS_TRACE_LEVEL_FATAL, + "%s: Not able to allocate memory for roc req context", + __func__); + return -ENOMEM; + } + + phdd_roc_req->pAdapter = pAdapter; + phdd_roc_req->pRemainChanCtx = pRemainChanCtx; + + /* Enqueue this RoC request */ + spin_lock(&pHddCtx->hdd_roc_req_q.lock); + status = hdd_list_insert_back(&pHddCtx->hdd_roc_req_q, + &phdd_roc_req->node); + spin_unlock(&pHddCtx->hdd_roc_req_q.lock); + + if (VOS_STATUS_SUCCESS != status) { + hddLog(VOS_TRACE_LEVEL_FATAL, + "%s: Not able to enqueue RoC Req context", + __func__); + vos_mem_free(phdd_roc_req); + return -ENOMEM; + } + } + + /* + * if driver is free and there is RoC request in the queue then + * schedule the RoC work directly. + */ + if (isBusy == VOS_FALSE) { + schedule_work(&pHddCtx->rocReqWork); + } + + return 0; +} + +void hdd_roc_req_work(struct work_struct *work) +{ + VOS_STATUS status; + hdd_roc_req_t *hdd_roc_req; + hdd_context_t *pHddCtx = + container_of(work, hdd_context_t, rocReqWork); + + hddLog(LOG1, FL("RoC request timeout")); + + if (list_empty(&pHddCtx->hdd_roc_req_q.anchor)) { + return; + } + + /* If driver is busy then we can't run RoC */ + if (pHddCtx->isLoadInProgress || pHddCtx->isUnloadInProgress || + hdd_isConnectionInProgress(pHddCtx)) { + hddLog( LOGE, + "%s: Wlan Load/Unload or Connection is in progress", __func__); + return; + } + + if (pHddCtx->isLogpInProgress) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:LOGP in Progress. Ignore!!!", __func__); + return; + } + + while (!list_empty(&pHddCtx->hdd_roc_req_q.anchor)) { + /* go to process this RoC request */ + spin_lock(&pHddCtx->hdd_roc_req_q.lock); + status = hdd_list_remove_front(&pHddCtx->hdd_roc_req_q, + (hdd_list_node_t**) &hdd_roc_req); + spin_unlock(&pHddCtx->hdd_roc_req_q.lock); + if (status == VOS_STATUS_SUCCESS) { + wlan_hdd_execute_remain_on_channel(hdd_roc_req->pAdapter, + hdd_roc_req->pRemainChanCtx); + vos_mem_free(hdd_roc_req); + } + } } int __wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy, @@ -873,8 +976,10 @@ int __wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy, hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter ); int status; unsigned long rc; + hdd_list_node_t *tmp, *q; + hdd_roc_req_t *curr_roc_req; - hddLog( LOG1, "Cancel remain on channel req"); + hddLog( LOG1, "Cancel remain on channel"); status = wlan_hdd_validate_context(pHddCtx); @@ -884,6 +989,24 @@ int __wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy, "%s: HDD context is not valid", __func__); return status; } + + /* Remove RoC request inside queue */ + spin_lock(&pHddCtx->hdd_roc_req_q.lock); + list_for_each_safe(tmp, q, &pHddCtx->hdd_roc_req_q.anchor) { + curr_roc_req = list_entry(tmp, hdd_roc_req_t, node); + if ((uintptr_t)curr_roc_req->pRemainChanCtx == cookie) { + status = hdd_list_remove_node(&pHddCtx->hdd_roc_req_q, + (hdd_list_node_t*)curr_roc_req); + spin_unlock(&pHddCtx->hdd_roc_req_q.lock); + if (status == VOS_STATUS_SUCCESS) { + vos_mem_free(curr_roc_req->pRemainChanCtx); + vos_mem_free(curr_roc_req); + } + return 0; + } + } + spin_unlock(&pHddCtx->hdd_roc_req_q.lock); + /* FIXME cancel currently running remain on chan. * Need to check cookie and cancel accordingly */ |
