diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index e2d944e57e11..485d01930bc7 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -309,15 +309,8 @@ * threads will be serialized. */ -struct linkspeedContext { - struct completion completion; - hdd_adapter_t *pAdapter; - unsigned int magic; -}; - extern spinlock_t hdd_context_lock; -#define LINK_CONTEXT_MAGIC 0x4C494E4B /* LINKSPEED */ #define BPF_CONTEXT_MAGIC 0x4575354 /* BPF */ /* MAX OS Q block time value in msec @@ -962,8 +955,9 @@ struct hdd_adapter_s { struct net_device_stats stats; /** HDD statistics*/ hdd_stats_t hdd_stats; - /** linkspeed statistics */ - tSirLinkSpeedInfo ls_stats; + + /* estimated link speed */ + uint32_t estimated_linkspeed; uint8_t sessionId; diff --git a/core/hdd/inc/wlan_hdd_wext.h b/core/hdd/inc/wlan_hdd_wext.h index de41c5c3d199..9f386f2c5f19 100644 --- a/core/hdd/inc/wlan_hdd_wext.h +++ b/core/hdd/inc/wlan_hdd_wext.h @@ -355,8 +355,20 @@ extern int hdd_priv_get_data(struct iw_point *p_priv_data, extern void *mem_alloc_copy_from_user_helper(const void *wrqu_data, size_t len); -extern QDF_STATUS wlan_hdd_get_linkspeed_for_peermac(hdd_adapter_t *pAdapter, - struct qdf_mac_addr mac_address); +/** + * wlan_hdd_get_linkspeed_for_peermac() - Get link speed for a peer + * @adapter: adapter upon which the peer is active + * @mac_address: MAC address of the peer + * @linkspeed: pointer to memory where returned link speed is to be placed + * + * This function will send a query to SME for the linkspeed of the + * given peer, and then wait for the callback to be invoked. + * + * Return: 0 if linkspeed data is available, negative errno otherwise + */ +int wlan_hdd_get_linkspeed_for_peermac(hdd_adapter_t *adapter, + struct qdf_mac_addr *mac_address, + uint32_t *linkspeed); void hdd_clear_roam_profile_ie(hdd_adapter_t *pAdapter); uint8_t *wlan_hdd_get_vendor_oui_ie_ptr(uint8_t *oui, uint8_t oui_size, diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 40a948f3d83b..c93a7df19407 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -5153,15 +5153,13 @@ int __iw_get_softap_linkspeed(struct net_device *dev, hdd_err("Invalid peer macaddress"); return -EINVAL; } - status = wlan_hdd_get_linkspeed_for_peermac(pHostapdAdapter, - macAddress); - if (!QDF_IS_STATUS_SUCCESS(status)) { + rc = wlan_hdd_get_linkspeed_for_peermac(pHostapdAdapter, &macAddress, + &link_speed); + if (!rc) { hdd_err("Unable to retrieve SME linkspeed"); - return -EINVAL; + return rc; } - link_speed = pHostapdAdapter->ls_stats.estLinkSpeed; - /* linkspeed in units of 500 kbps */ link_speed = link_speed / 500; wrqu->data.length = len; diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 2594aa144526..3b132f3cc5aa 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -1874,127 +1874,92 @@ QDF_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, int8_t *snr) return QDF_STATUS_SUCCESS; } -/** - * hdd_get_link_speed_cb() - Get link speed callback function - * @pLinkSpeed: pointer to the link speed record - * @pContext: pointer to the user context passed to SME - * - * This function is passed as the callback function to - * sme_get_link_speed() by wlan_hdd_get_linkspeed_for_peermac(). By - * agreement a &struct linkspeedContext is passed as @pContext. If - * the context is valid, then the contents of @pLinkSpeed are copied - * into the adapter record referenced by @pContext where they can be - * subsequently retrieved. If the context is invalid, then this - * function does nothing since it is assumed the caller has already - * timed-out and destroyed the context. - * - * Return: None. - */ +struct linkspeed_priv { + tSirLinkSpeedInfo linkspeed_info; +}; + static void -hdd_get_link_speed_cb(tSirLinkSpeedInfo *pLinkSpeed, void *pContext) +hdd_get_link_speed_cb(tSirLinkSpeedInfo *linkspeed_info, void *context) { - struct linkspeedContext *pLinkSpeedContext; - hdd_adapter_t *pAdapter; + struct hdd_request *request; + struct linkspeed_priv *priv; - if ((NULL == pLinkSpeed) || (NULL == pContext)) { - hdd_err("Bad param, pLinkSpeed [%p] pContext [%p]", - pLinkSpeed, pContext); - return; - } - spin_lock(&hdd_context_lock); - pLinkSpeedContext = pContext; - pAdapter = pLinkSpeedContext->pAdapter; - - /* there is a race condition that exists between this callback - * function and the caller since the caller could time out either - * before or while this code is executing. we use a spinlock to - * serialize these actions - */ - - if ((NULL == pAdapter) || - (LINK_CONTEXT_MAGIC != pLinkSpeedContext->magic)) { - /* the caller presumably timed out so there is nothing - * we can do - */ - spin_unlock(&hdd_context_lock); - hdd_warn("Invalid context, pAdapter [%p] magic [%08x]", - pAdapter, pLinkSpeedContext->magic); + if (!linkspeed_info) { + hdd_err("NULL linkspeed"); return; } - /* context is valid so caller is still waiting */ + request = hdd_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } - /* paranoia: invalidate the magic */ - pLinkSpeedContext->magic = 0; - - /* copy over the stats. do so as a struct copy */ - pAdapter->ls_stats = *pLinkSpeed; - - /* notify the caller */ - complete(&pLinkSpeedContext->completion); - - /* serialization is complete */ - spin_unlock(&hdd_context_lock); + priv = hdd_request_priv(request); + priv->linkspeed_info = *linkspeed_info; + hdd_request_complete(request); + hdd_request_put(request); } -/** - * wlan_hdd_get_linkspeed_for_peermac() - Get link speed for a peer - * @pAdapter: adapter upon which the peer is active - * @macAddress: MAC address of the peer - * - * This function will send a query to SME for the linkspeed of the - * given peer, and then wait for the callback to be invoked. - * - * Return: QDF_STATUS_SUCCESS if linkspeed data is available, - * otherwise a QDF_STATUS_E_** error. - */ -QDF_STATUS wlan_hdd_get_linkspeed_for_peermac(hdd_adapter_t *pAdapter, - struct qdf_mac_addr macAddress) { +int wlan_hdd_get_linkspeed_for_peermac(hdd_adapter_t *adapter, + struct qdf_mac_addr *mac_address, + uint32_t *linkspeed) +{ + int ret; QDF_STATUS status; - unsigned long rc; - static struct linkspeedContext context; - tSirLinkSpeedInfo linkspeed_req; + void *cookie; + tSirLinkSpeedInfo *linkspeed_info; + struct hdd_request *request; + struct linkspeed_priv *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; - if (NULL == pAdapter) { - hdd_err("pAdapter is NULL"); - return QDF_STATUS_E_FAULT; + if ((!adapter) || (!linkspeed)) { + hdd_err("NULL argument"); + return -EINVAL; } - init_completion(&context.completion); - context.pAdapter = pAdapter; - context.magic = LINK_CONTEXT_MAGIC; - qdf_copy_macaddr(&linkspeed_req.peer_macaddr, &macAddress); - status = sme_get_link_speed(WLAN_HDD_GET_HAL_CTX(pAdapter), - &linkspeed_req, - &context, hdd_get_link_speed_cb); - if (QDF_STATUS_SUCCESS != status) { + request = hdd_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + ret = -ENOMEM; + goto return_cached_value; + } + + cookie = hdd_request_cookie(request); + priv = hdd_request_priv(request); + + linkspeed_info = &priv->linkspeed_info; + qdf_copy_macaddr(&linkspeed_info->peer_macaddr, mac_address); + status = sme_get_link_speed(WLAN_HDD_GET_HAL_CTX(adapter), + linkspeed_info, + cookie, hdd_get_link_speed_cb); + if (QDF_IS_STATUS_ERROR(status)) { hdd_err("Unable to retrieve statistics for link speed"); - } else { - rc = wait_for_completion_timeout - (&context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); - if (!rc) { - hdd_err("SME timed out while retrieving link speed"); - } + ret = qdf_status_to_os_return(status); + goto cleanup; } + ret = hdd_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving link speed"); + goto cleanup; + } + adapter->estimated_linkspeed = linkspeed_info->estLinkSpeed; - /* either we never sent a request, we sent a request and - * received a response or we sent a request and timed out. if - * we never sent a request or if we sent a request and got a - * response, we want to clear the magic out of paranoia. if - * we timed out there is a race condition such that the - * callback function could be executing at the same time we - * are. of primary concern is if the callback function had - * already verified the "magic" but had not yet set the - * completion variable when a timeout occurred. we serialize - * these activities by invalidating the magic while holding a - * shared spinlock which will cause us to block if the - * callback is currently executing +cleanup: + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. */ - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); - return QDF_STATUS_SUCCESS; + hdd_request_put(request); + +return_cached_value: + *linkspeed = adapter->estimated_linkspeed; + + return ret; } /** @@ -2031,17 +1996,16 @@ int wlan_hdd_get_link_speed(hdd_adapter_t *sta_adapter, uint32_t *link_speed) /* we are not connected so we don't have a classAstats */ *link_speed = 0; } else { - QDF_STATUS status; struct qdf_mac_addr bssid; qdf_copy_macaddr(&bssid, &hdd_stactx->conn_info.bssId); - status = wlan_hdd_get_linkspeed_for_peermac(sta_adapter, bssid); - if (!QDF_IS_STATUS_SUCCESS(status)) { + ret = wlan_hdd_get_linkspeed_for_peermac(sta_adapter, &bssid, + link_speed); + if (ret) { hdd_err("Unable to retrieve SME linkspeed"); - return -EINVAL; + return ret; } - *link_speed = sta_adapter->ls_stats.estLinkSpeed; /* linkspeed in units of 500 kbps */ *link_speed = (*link_speed) / 500; }