diff --git a/os_if/linux/cp_stats/inc/wlan_cfg80211_mc_cp_stats.h b/os_if/linux/cp_stats/inc/wlan_cfg80211_mc_cp_stats.h index c2770a69d5..40fcd481ee 100644 --- a/os_if/linux/cp_stats/inc/wlan_cfg80211_mc_cp_stats.h +++ b/os_if/linux/cp_stats/inc/wlan_cfg80211_mc_cp_stats.h @@ -57,48 +57,39 @@ int wlan_cfg80211_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, * wlan_cfg80211_mc_cp_stats_get_station_stats() - API to get station * statistics to firmware * @vdev: Pointer to vdev - * @info: pointer to object to populate with station stats + * @errno: error type in case of failure * - * Call of this API must call wlan_cfg80211_mc_cp_stats_put_station_stats + * Call of this API must call wlan_cfg80211_mc_cp_stats_free_stats_event * API when done with information provided by info. - * Return: 0 on success, negative value on failure + * Return: stats buffer on success, Null on failure */ -int wlan_cfg80211_mc_cp_stats_get_station_stats( - struct wlan_objmgr_vdev *vdev, - struct stats_event *info); +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev, + int *errno); /** - * wlan_cfg80211_mc_cp_stats_put_station_stats() - API to release station + * wlan_cfg80211_mc_cp_stats_free_stats_event() - API to release station * statistics buffer * @vdev: Pointer to vdev * @info: pointer to object to populate with station stats * * Return: None */ -void wlan_cfg80211_mc_cp_stats_put_station_stats(struct stats_event *info); +void wlan_cfg80211_mc_cp_stats_free_stats_event(struct stats_event *info); /** * wlan_cfg80211_mc_cp_stats_get_peer_rssi() - API to fetch peer rssi * @vdev: Pointer to vdev * @macaddress: mac address - * @rssi_info: stats structure within which rssi info will be populated + * @errno: error type in case of failure * - * Call of this API must call wlan_cfg80211_mc_cp_stats_put_peer_rssi + * Call of this API must call wlan_cfg80211_mc_cp_stats_free_stats_event * API when done with information provided by rssi_info. - * Return: 0 on success, negative value on failure + * Return: stats buffer on success, Null on failure */ -int wlan_cfg80211_mc_cp_stats_get_peer_rssi(struct wlan_objmgr_vdev *vdev, - uint8_t *macaddress, - struct stats_event *rssi_info); - -/** - * wlan_cfg80211_mc_cp_stats_put_peer_rssi() - API to free rssi_info after user - * or caller is done with the buffer/information - * @rssi_info: structure which needs to be freed - * - * Return: None - */ -void wlan_cfg80211_mc_cp_stats_put_peer_rssi(struct stats_event *rssi_info); +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_peer_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddress, int *errno); #endif /* QCA_SUPPORT_CP_STATS */ #endif /* __WLAN_CFG80211_MC_CP_STATS_H__ */ diff --git a/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c b/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c index f0fdceaa0b..6d0b3192f7 100644 --- a/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c +++ b/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c @@ -32,6 +32,27 @@ /* max time in ms, caller may wait for stats request get serviced */ #define CP_STATS_WAIT_TIME_STAT 800 +/** + * wlan_cfg80211_mc_cp_stats_dealloc() - callback to free priv + * allocations for stats + * @priv: Pointer to priv data statucture + * + * Return: None + */ +static void wlan_cfg80211_mc_cp_stats_dealloc(void *priv) +{ + struct stats_event *stats = priv; + + if (!stats) + return; + + qdf_mem_free(stats->pdev_stats); + qdf_mem_free(stats->peer_stats); + qdf_mem_free(stats->cca_stats); + qdf_mem_free(stats->vdev_summary_stats); + qdf_mem_free(stats->vdev_chain_rssi); +} + /** * wlan_cfg80211_mc_cp_stats_send_wake_lock_stats() - API to send wakelock stats * @wiphy: wiphy pointer @@ -280,7 +301,7 @@ peer_is_null: /** * get_peer_rssi_cb() - get_peer_rssi_cb callback function - * @mac_addr: mac address + * @ev: peer stats buffer * @cookie: a cookie for the request context * * Return: None @@ -289,6 +310,7 @@ static void get_peer_rssi_cb(struct stats_event *ev, void *cookie) { struct stats_event *priv; struct osif_request *request; + uint32_t rssi_size; request = osif_request_get(cookie); if (!request) { @@ -298,31 +320,55 @@ static void get_peer_rssi_cb(struct stats_event *ev, void *cookie) } priv = osif_request_priv(request); - *priv = *ev; + rssi_size = sizeof(*ev->peer_stats) * ev->num_peer_stats; + if (rssi_size == 0) { + cfg80211_err("Invalid rssi stats"); + goto get_peer_rssi_cb_fail; + } + + priv->peer_stats = qdf_mem_malloc(rssi_size); + if (!priv->peer_stats) { + cfg80211_err("allocation failed"); + goto get_peer_rssi_cb_fail; + } + + priv->num_peer_stats = ev->num_peer_stats; + qdf_mem_copy(priv->peer_stats, ev->peer_stats, rssi_size); + +get_peer_rssi_cb_fail: osif_request_complete(request); osif_request_put(request); } -int wlan_cfg80211_mc_cp_stats_get_peer_rssi(struct wlan_objmgr_vdev *vdev, - uint8_t *mac_addr, - struct stats_event *rssi_info) +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_peer_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + int *errno) { - int ret = 0; void *cookie; QDF_STATUS status; - struct stats_event *priv; + struct stats_event *priv, *out; struct request_info info = {0}; struct osif_request *request = NULL; static const struct osif_request_params params = { .priv_size = sizeof(*priv), .timeout_ms = CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_cp_stats_dealloc, }; - qdf_mem_zero(rssi_info, sizeof(*rssi_info)); + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + cfg80211_err("allocation failed"); + *errno = -ENOMEM; + return NULL; + } + request = osif_request_alloc(¶ms); if (!request) { cfg80211_err("Request allocation failure, return cached value"); - return -EINVAL; + *errno = -ENOMEM; + qdf_mem_free(out); + return NULL; } cookie = osif_request_cookie(request); @@ -336,75 +382,118 @@ int wlan_cfg80211_mc_cp_stats_get_peer_rssi(struct wlan_objmgr_vdev *vdev, &info); if (QDF_IS_STATUS_ERROR(status)) { cfg80211_err("stats req failed: %d", status); - ret = qdf_status_to_os_return(status); - } else { - ret = osif_request_wait_for_response(request); - if (ret) { - cfg80211_err("wait failed or timed out ret: %d", ret); - } else { - *rssi_info = *priv; - } + *errno = qdf_status_to_os_return(status); + goto get_peer_rssi_fail; } - /* - * 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. - */ - if (request) - osif_request_put(request); + *errno = osif_request_wait_for_response(request); + if (*errno) { + cfg80211_err("wait failed or timed out ret: %d", *errno); + goto get_peer_rssi_fail; + } - return ret; -} + if (!priv->peer_stats || priv->num_peer_stats == 0) { + cfg80211_err("Invalid peer stats, count %d, data %pK", + priv->num_peer_stats, priv->peer_stats); + *errno = -EINVAL; + goto get_peer_rssi_fail; + } + out->num_peer_stats = priv->num_peer_stats; + out->peer_stats = priv->peer_stats; + priv->peer_stats = NULL; + osif_request_put(request); -void wlan_cfg80211_mc_cp_stats_put_peer_rssi(struct stats_event *rssi_info) -{ - ucfg_mc_cp_stats_free_stats_resources(rssi_info); + return out; + +get_peer_rssi_fail: + osif_request_put(request); + wlan_cfg80211_mc_cp_stats_free_stats_event(out); + + return NULL; } /** * get_station_stats_cb() - get_station_stats_cb callback function + * @ev: station stats buffer * @cookie: a cookie for the request context * * Return: None */ -static void get_station_stats_cb(struct stats_event *station_info, void *cookie) +static void get_station_stats_cb(struct stats_event *ev, void *cookie) { struct stats_event *priv; struct osif_request *request; + uint32_t summary_size, rssi_size; request = osif_request_get(cookie); if (!request) { cfg80211_err("Obsolete request"); - ucfg_mc_cp_stats_free_stats_resources(station_info); return; } + priv = osif_request_priv(request); - *priv = *station_info; + summary_size = sizeof(*ev->vdev_summary_stats) * ev->num_summary_stats; + rssi_size = sizeof(*ev->vdev_chain_rssi) * ev->num_chain_rssi_stats; + if (summary_size == 0 || rssi_size == 0) { + cfg80211_err("Invalid stats, summary size %d rssi size %d", + summary_size, rssi_size); + goto station_stats_cb_fail; + } + + priv->vdev_summary_stats = qdf_mem_malloc(summary_size); + if (!priv->vdev_summary_stats) { + cfg80211_err("memory allocation failed"); + goto station_stats_cb_fail; + } + + priv->vdev_chain_rssi = qdf_mem_malloc(rssi_size); + if (!priv->vdev_chain_rssi) { + cfg80211_err("memory allocation failed"); + goto station_stats_cb_fail; + } + + priv->num_summary_stats = ev->num_summary_stats; + priv->num_chain_rssi_stats = ev->num_chain_rssi_stats; + priv->tx_rate = ev->tx_rate; + priv->tx_rate_flags = ev->tx_rate_flags; + qdf_mem_copy(priv->vdev_chain_rssi, ev->vdev_chain_rssi, rssi_size); + qdf_mem_copy(priv->vdev_summary_stats, ev->vdev_summary_stats, + summary_size); + +station_stats_cb_fail: osif_request_complete(request); osif_request_put(request); } -int wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev, - struct stats_event *out) +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev, + int *errno) { - int ret; void *cookie; QDF_STATUS status; - struct stats_event *priv; + struct stats_event *priv, *out; struct wlan_objmgr_peer *peer; struct osif_request *request; struct request_info info = {0}; static const struct osif_request_params params = { .priv_size = sizeof(*priv), .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_cp_stats_dealloc, }; - qdf_mem_zero(out, sizeof(*out)); + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + cfg80211_err("allocation failed"); + *errno = -ENOMEM; + return NULL; + } + request = osif_request_alloc(¶ms); if (!request) { cfg80211_err("Request allocation failure, return cached value"); - return -EINVAL; + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; } cookie = osif_request_cookie(request); @@ -415,37 +504,63 @@ int wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev, info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); peer = wlan_vdev_get_bsspeer(vdev); if (!peer) { - ret = -EINVAL; - goto peer_is_null; + cfg80211_err("peer is null"); + *errno = -EINVAL; + goto get_station_stats_fail; } qdf_mem_copy(info.peer_mac_addr, peer->macaddr, WLAN_MACADDR_LEN); status = ucfg_mc_cp_stats_send_stats_request(vdev, TYPE_STATION_STATS, &info); if (QDF_IS_STATUS_ERROR(status)) { - cfg80211_err("wlan_mc_cp_stats_send_stats_request status: %d", - status); - ret = qdf_status_to_os_return(status); - } else { - ret = osif_request_wait_for_response(request); - if (ret) - cfg80211_err("wait failed or timed out ret: %d", ret); - else - *out = *priv; + cfg80211_err("Failed to send stats request status: %d", status); + *errno = qdf_status_to_os_return(status); + goto get_station_stats_fail; } -peer_is_null: - /* - * 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. - */ + *errno = osif_request_wait_for_response(request); + if (*errno) { + cfg80211_err("wait failed or timed out ret: %d", *errno); + goto get_station_stats_fail; + } + + if (!priv->vdev_summary_stats || !priv->vdev_chain_rssi || + priv->num_summary_stats == 0 || priv->num_chain_rssi_stats == 0) { + cfg80211_err("Invalid stats, summary %d:%pK, rssi %d:%pK", + priv->num_summary_stats, priv->vdev_summary_stats, + priv->num_chain_rssi_stats, priv->vdev_chain_rssi); + *errno = -EINVAL; + goto get_station_stats_fail; + } + + out->tx_rate = priv->tx_rate; + out->tx_rate_flags = priv->tx_rate_flags; + out->num_summary_stats = priv->num_summary_stats; + out->num_chain_rssi_stats = priv->num_chain_rssi_stats; + out->vdev_summary_stats = priv->vdev_summary_stats; + priv->vdev_summary_stats = NULL; + out->vdev_chain_rssi = priv->vdev_chain_rssi; + priv->vdev_chain_rssi = NULL; osif_request_put(request); - return ret; + return out; + +get_station_stats_fail: + osif_request_put(request); + wlan_cfg80211_mc_cp_stats_free_stats_event(out); + + return NULL; } -void wlan_cfg80211_mc_cp_stats_put_station_stats(struct stats_event *info) +void wlan_cfg80211_mc_cp_stats_free_stats_event(struct stats_event *stats) { - ucfg_mc_cp_stats_free_stats_resources(info); + if (!stats) + return; + + qdf_mem_free(stats->pdev_stats); + qdf_mem_free(stats->peer_stats); + qdf_mem_free(stats->cca_stats); + qdf_mem_free(stats->vdev_summary_stats); + qdf_mem_free(stats->vdev_chain_rssi); + qdf_mem_free(stats); } diff --git a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c index 6b8d928c5a..cf51fcebed 100644 --- a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c +++ b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c @@ -207,8 +207,8 @@ tgt_mc_cp_stats_prepare_raw_peer_rssi(struct wlan_objmgr_psoc *psoc, end: if (ev.peer_stats) get_peer_rssi_cb(&ev, last_req->cookie); - else - ucfg_mc_cp_stats_free_stats_resources(&ev); + + ucfg_mc_cp_stats_free_stats_resources(&ev); if (vdev) wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); @@ -576,8 +576,8 @@ tgt_mc_cp_stats_prepare_n_send_raw_station_stats(struct wlan_objmgr_psoc *psoc, end: if (info.vdev_summary_stats && info.vdev_chain_rssi) get_station_stats_cb(&info, last_req->cookie); - else - ucfg_mc_cp_stats_free_stats_resources(&info); + + ucfg_mc_cp_stats_free_stats_resources(&info); if (peer) wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); diff --git a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c index 12c4e14f44..847193e7cf 100644 --- a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c +++ b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c @@ -541,6 +541,9 @@ QDF_STATUS ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc *psoc, void ucfg_mc_cp_stats_free_stats_resources(struct stats_event *ev) { + if (!ev) + return; + qdf_mem_free(ev->pdev_stats); qdf_mem_free(ev->peer_stats); qdf_mem_free(ev->cca_stats);