qcacld-3.0: Fix radio_stats to handle num_radios more than 1
In case of multiple radio, driver need to wait until it receives
all the radios stats and tx power levels stats and then
post the radio stats to user space.
Change-Id: I6e4f9ac8f0d2950551301589dfd8332e8c349605
CRs-Fixed: 992365
diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c
index 777f1e0..b635702 100644
--- a/core/hdd/src/wlan_hdd_stats.c
+++ b/core/hdd/src/wlan_hdd_stats.c
@@ -776,6 +776,180 @@
}
/**
+ * hdd_llstats_radio_fill_channels() - radio stats fill channels
+ * @adapter: Pointer to device adapter
+ * @radiostat: Pointer to stats data
+ * @vendor_event: vendor event
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int hdd_llstats_radio_fill_channels(hdd_adapter_t *adapter,
+ tSirWifiRadioStat *radiostat,
+ struct sk_buff *vendor_event)
+{
+ tSirWifiChannelStats *channel_stats;
+ struct nlattr *chlist;
+ struct nlattr *chinfo;
+ int i;
+
+ chlist = nla_nest_start(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
+ if (chlist == NULL) {
+ hdd_err("nla_nest_start failed");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < radiostat->numChannels; i++) {
+ channel_stats = (tSirWifiChannelStats *) ((uint8_t *)
+ radiostat->channels +
+ (i * sizeof(tSirWifiChannelStats)));
+
+ chinfo = nla_nest_start(vendor_event, i);
+ if (chinfo == NULL) {
+ hdd_err("nla_nest_start failed");
+ return -EINVAL;
+ }
+
+ if (nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
+ channel_stats->channel.width) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
+ channel_stats->channel.centerFreq) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
+ channel_stats->channel.centerFreq0) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
+ channel_stats->channel.centerFreq1) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
+ channel_stats->onTime) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
+ channel_stats->ccaBusyTime)) {
+ hdd_err("nla_put failed");
+ return -EINVAL;
+ }
+ nla_nest_end(vendor_event, chinfo);
+ }
+ nla_nest_end(vendor_event, chlist);
+
+ return 0;
+}
+
+/**
+ * hdd_llstats_post_radio_stats() - post radio stats
+ * @adapter: Pointer to device adapter
+ * @more_data: More data
+ * @radiostat: Pointer to stats data
+ * @num_radio: Number of radios
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int hdd_llstats_post_radio_stats(hdd_adapter_t *adapter,
+ u32 more_data,
+ tSirWifiRadioStat *radiostat,
+ u32 num_radio)
+{
+ struct sk_buff *vendor_event;
+ hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ int ret;
+
+ /*
+ * Allocate a size of 4096 for the Radio stats comprising
+ * sizeof (tSirWifiRadioStat) + numChannels * sizeof
+ * (tSirWifiChannelStats).Each channel data is put with an
+ * NL attribute.The size of 4096 is considered assuming that
+ * number of channels shall not exceed beyond 60 with the
+ * sizeof (tSirWifiChannelStats) being 24 bytes.
+ */
+
+ vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(
+ hdd_ctx->wiphy,
+ LL_STATS_EVENT_BUF_SIZE);
+
+ if (!vendor_event) {
+ hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
+ return -ENOMEM;
+ }
+
+ if (nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
+ more_data) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
+ num_radio) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
+ radiostat->radio) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
+ radiostat->onTime) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
+ radiostat->txTime) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
+ radiostat->rxTime) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
+ radiostat->onTimeScan) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
+ radiostat->onTimeNbd) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
+ radiostat->onTimeGscan) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
+ radiostat->onTimeRoamScan) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
+ radiostat->onTimePnoScan) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
+ radiostat->onTimeHs20) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
+ radiostat->total_num_tx_power_levels) ||
+ nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
+ radiostat->numChannels)) {
+ hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
+ goto failure;
+ }
+
+ if (radiostat->total_num_tx_power_levels) {
+ if (nla_put(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
+ sizeof(u32) *
+ radiostat->total_num_tx_power_levels,
+ radiostat->tx_time_per_power_level)) {
+ hdd_err("nla_put fail");
+ goto failure;
+ }
+ }
+
+ if (radiostat->numChannels) {
+ ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
+ vendor_event);
+ if (ret)
+ goto failure;
+ }
+
+ cfg80211_vendor_cmd_reply(vendor_event);
+ return 0;
+
+failure:
+ kfree_skb(vendor_event);
+ return -EINVAL;
+}
+
+/**
* hdd_link_layer_process_radio_stats() - This function is called after
* @pAdapter: Pointer to device adapter
* @more_data: More data
@@ -793,170 +967,45 @@
tpSirWifiRadioStat pData,
u32 num_radio)
{
- int status, i;
- tpSirWifiRadioStat pWifiRadioStat;
- tpSirWifiChannelStats pWifiChannelStats;
- struct sk_buff *vendor_event;
+ int status, i, nr, ret;
+ tSirWifiRadioStat *pWifiRadioStat = pData;
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
ENTER();
- pWifiRadioStat = pData;
status = wlan_hdd_validate_context(pHddCtx);
if (0 != status)
return;
- hdd_notice("LL_STATS_RADIO"
- " number of radios: %u radio: %d onTime: %u"
- " txTime: %u rxTime: %u onTimeScan: %u onTimeNbd: %u"
- " onTimeGscan: %u onTimeRoamScan: %u"
- " onTimePnoScan: %u onTimeHs20: %u"
- " numChannels: %u total_num_tx_power_levels: %u",
- num_radio, pWifiRadioStat->radio,
- pWifiRadioStat->onTime, pWifiRadioStat->txTime,
- pWifiRadioStat->rxTime, pWifiRadioStat->onTimeScan,
- pWifiRadioStat->onTimeNbd, pWifiRadioStat->onTimeGscan,
- pWifiRadioStat->onTimeRoamScan,
- pWifiRadioStat->onTimePnoScan,
- pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
- pWifiRadioStat->total_num_tx_power_levels);
+ hdd_notice("LL_STATS_RADIO: number of radios: %u", num_radio);
- /*
- * Allocate a size of 4096 for the Radio stats comprising
- * sizeof (tSirWifiRadioStat) + numChannels * sizeof
- * (tSirWifiChannelStats).Each channel data is put with an
- * NL attribute.The size of 4096 is considered assuming that
- * number of channels shall not exceed beyond 60 with the
- * sizeof (tSirWifiChannelStats) being 24 bytes.
- */
-
- vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
- LL_STATS_EVENT_BUF_SIZE);
-
- if (!vendor_event) {
- hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
- return;
+ for (i = 0; i < num_radio; i++) {
+ hdd_notice("LL_STATS_RADIO"
+ " radio: %u onTime: %u txTime: %u rxTime: %u"
+ " onTimeScan: %u onTimeNbd: %u"
+ " onTimeGscan: %u onTimeRoamScan: %u"
+ " onTimePnoScan: %u onTimeHs20: %u"
+ " numChannels: %u total_num_tx_pwr_levels: %u",
+ pWifiRadioStat->radio, pWifiRadioStat->onTime,
+ pWifiRadioStat->txTime, pWifiRadioStat->rxTime,
+ pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd,
+ pWifiRadioStat->onTimeGscan,
+ pWifiRadioStat->onTimeRoamScan,
+ pWifiRadioStat->onTimePnoScan,
+ pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
+ pWifiRadioStat->total_num_tx_power_levels);
+ pWifiRadioStat++;
}
- if (nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
- more_data) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
- num_radio) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
- pWifiRadioStat->radio) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
- pWifiRadioStat->onTime) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
- pWifiRadioStat->txTime) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
- pWifiRadioStat->rxTime) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
- pWifiRadioStat->onTimeScan) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
- pWifiRadioStat->onTimeNbd) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
- pWifiRadioStat->onTimeGscan) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
- pWifiRadioStat->onTimeRoamScan) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
- pWifiRadioStat->onTimePnoScan) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
- pWifiRadioStat->onTimeHs20) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
- pWifiRadioStat->total_num_tx_power_levels) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
- pWifiRadioStat->numChannels)) {
- hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
-
- kfree_skb(vendor_event);
- return;
- }
-
- if (pWifiRadioStat->total_num_tx_power_levels) {
- if (nla_put(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
- sizeof(u32) *
- pWifiRadioStat->total_num_tx_power_levels,
- pWifiRadioStat->tx_time_per_power_level)) {
- hdd_err("nla_put fail");
- kfree_skb(vendor_event);
+ pWifiRadioStat = pData;
+ for (nr = 0; nr < num_radio; nr++) {
+ ret = hdd_llstats_post_radio_stats(pAdapter, more_data,
+ pWifiRadioStat, num_radio);
+ if (ret)
return;
- }
+
+ pWifiRadioStat++;
}
-
- if (pWifiRadioStat->numChannels) {
- struct nlattr *chList;
- struct nlattr *chInfo;
-
- chList = nla_nest_start(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
- if (chList == NULL) {
- hdd_err("nla_nest_start failed");
- kfree_skb(vendor_event);
- return;
- }
-
- for (i = 0; i < pWifiRadioStat->numChannels; i++) {
- pWifiChannelStats = (tpSirWifiChannelStats) ((uint8_t *)
- pWifiRadioStat->
- channels +
- (i *
- sizeof
- (tSirWifiChannelStats)));
-
- chInfo = nla_nest_start(vendor_event, i);
- if (chInfo == NULL) {
- hdd_err("nla_nest_start failed");
- kfree_skb(vendor_event);
- return;
- }
-
- if (nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
- pWifiChannelStats->channel.width) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
- pWifiChannelStats->channel.centerFreq) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
- pWifiChannelStats->channel.
- centerFreq0) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
- pWifiChannelStats->channel.
- centerFreq1) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
- pWifiChannelStats->onTime) ||
- nla_put_u32(vendor_event,
- QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
- pWifiChannelStats->ccaBusyTime)) {
- hdd_err("nla_put failed");
- kfree_skb(vendor_event);
- return;
- }
- nla_nest_end(vendor_event, chInfo);
- }
- nla_nest_end(vendor_event, chList);
- }
- cfg80211_vendor_cmd_reply(vendor_event);
EXIT();
return;
}
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 8ab3e32..5f98bcc 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -5046,7 +5046,7 @@
uint32_t tx_time_per_tpc[MAX_TPC_LEVELS];
/* channel statistics tSirWifiChannelStats */
- tSirWifiChannelStats channels[0];
+ tSirWifiChannelStats *channels;
} tSirWifiRadioStat, *tpSirWifiRadioStat;
/* per rate statistics */
@@ -5238,6 +5238,7 @@
uint8_t ifaceId;
uint32_t rspId;
uint32_t moreResultToFollow;
+ uint32_t nr_received;
union {
uint32_t num_peers;
uint32_t num_radio;
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index c8a6c6b..aeeb71b 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -2031,6 +2031,7 @@
wma_handle->enable_mc_list = cds_cfg->enable_mc_list;
wma_handle->bpf_packet_filter_enable =
cds_cfg->bpf_packet_filter_enable;
+ wma_handle->link_stats_results = NULL;
#ifdef FEATURE_WLAN_RA_FILTERING
wma_handle->IsRArateLimitEnabled = cds_cfg->is_ra_ratelimit_enabled;
wma_handle->RArateLimitInterval = cds_cfg->ra_ratelimit_interval;
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c
index 8c28ae1..f527385 100644
--- a/core/wma/src/wma_utils.c
+++ b/core/wma/src/wma_utils.c
@@ -610,6 +610,41 @@
}
/**
+ * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory
+ * @handle: WMI handle
+ *
+ * Return: 0 on success, error number otherwise.
+ */
+static int wma_unified_radio_tx_mem_free(void *handle)
+{
+ tp_wma_handle wma_handle = (tp_wma_handle) handle;
+ tSirWifiRadioStat *rs_results;
+ uint32_t i = 0;
+
+ if (!wma_handle->link_stats_results)
+ return 0;
+
+ rs_results = (tSirWifiRadioStat *)&wma_handle->link_stats_results->results[0];
+ for (i = 0; i < wma_handle->link_stats_results->num_radio; i++) {
+ rs_results += i;
+ if (rs_results->tx_time_per_power_level) {
+ qdf_mem_free(rs_results->tx_time_per_power_level);
+ rs_results->tx_time_per_power_level = NULL;
+ }
+
+ if (rs_results->channels) {
+ qdf_mem_free(rs_results->channels);
+ rs_results->channels = NULL;
+ }
+ }
+
+ qdf_mem_free(wma_handle->link_stats_results);
+ wma_handle->link_stats_results = NULL;
+
+ return 0;
+}
+
+/**
* wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats
* @handle: WMI handle
* @cmd_param_info: command param info
@@ -660,18 +695,21 @@
return -EINVAL;
}
- rs_results = (tSirWifiRadioStat *) &link_stats_results->results[0];
- tx_power_level_values = (uint8_t *) param_tlvs->tx_time_per_power_level;
-
- WMA_LOGD("%s: total_num_tx_power_levels: %u num_tx_power_levels: %u power_level_offset: %u",
+ WMA_LOGD("%s: tot_num_tx_pwr_lvls: %u num_tx_pwr_lvls: %u pwr_lvl_offset: %u radio_id: %u",
__func__, fixed_param->total_num_tx_power_levels,
fixed_param->num_tx_power_levels,
- fixed_param->power_level_offset);
+ fixed_param->power_level_offset,
+ fixed_param->radio_id);
+
+ rs_results = (tSirWifiRadioStat *) &link_stats_results->results[0] + fixed_param->radio_id;
+ tx_power_level_values = (uint8_t *) param_tlvs->tx_time_per_power_level;
rs_results->total_num_tx_power_levels =
fixed_param->total_num_tx_power_levels;
- if (!rs_results->total_num_tx_power_levels)
+ if (!rs_results->total_num_tx_power_levels) {
+ link_stats_results->nr_received++;
goto post_stats;
+ }
if (!rs_results->tx_time_per_power_level) {
rs_results->tx_time_per_power_level = qdf_mem_malloc(
@@ -682,6 +720,7 @@
/* In error case, atleast send the radio stats without
* tx_power_level stats */
rs_results->total_num_tx_power_levels = 0;
+ link_stats_results->nr_received++;
goto post_stats;
}
}
@@ -689,17 +728,26 @@
tx_power_level_values,
sizeof(uint32_t) * fixed_param->num_tx_power_levels);
if (rs_results->total_num_tx_power_levels ==
- (fixed_param->num_tx_power_levels + fixed_param->power_level_offset))
+ (fixed_param->num_tx_power_levels + fixed_param->power_level_offset)) {
link_stats_results->moreResultToFollow = 0;
+ link_stats_results->nr_received++;
+ }
- WMA_LOGD("%s: moreResultToFollow: %u",
- __func__, link_stats_results->moreResultToFollow);
+ WMA_LOGD("%s: moreResultToFollow: %u nr: %u nr_received: %u",
+ __func__, link_stats_results->moreResultToFollow,
+ link_stats_results->num_radio,
+ link_stats_results->nr_received);
/* If still data to receive, return from here */
if (link_stats_results->moreResultToFollow)
return 0;
post_stats:
+ if (link_stats_results->num_radio != link_stats_results->nr_received) {
+ /* Not received all radio stats yet, don't post yet */
+ return 0;
+ }
+
/* call hdd callback with Link Layer Statistics
* vdev_id/ifacId in link_stats_results will be
* used to retrieve the correct HDD context
@@ -707,11 +755,7 @@
mac->sme.pLinkLayerStatsIndCallback(mac->hHdd,
WMA_LINK_LAYER_STATS_RESULTS_RSP,
link_stats_results);
- WMA_LOGD("%s: Radio Stats event posted to HDD", __func__);
- qdf_mem_free(rs_results->tx_time_per_power_level);
- rs_results->tx_time_per_power_level = NULL;
- qdf_mem_free(wma_handle->link_stats_results);
- wma_handle->link_stats_results = NULL;
+ wma_unified_radio_tx_mem_free(handle);
return 0;
}
@@ -753,7 +797,6 @@
return -EINVAL;
}
- WMA_LOGD("%s: Posting Radio Stats event to HDD", __func__);
param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
if (!param_tlvs) {
WMA_LOGA("%s: Invalid stats event", __func__);
@@ -779,23 +822,26 @@
radio_stats_size = sizeof(tSirWifiRadioStat);
chan_stats_size = sizeof(tSirWifiChannelStats);
link_stats_results_size = sizeof(*link_stats_results) +
- radio_stats_size + (radio_stats->num_channels * chan_stats_size);
+ fixed_param->num_radio * radio_stats_size;
- wma_handle->link_stats_results = qdf_mem_malloc(link_stats_results_size);
- if (NULL == wma_handle->link_stats_results) {
- WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
- __func__, link_stats_results_size);
- return -ENOMEM;
+ if (!wma_handle->link_stats_results) {
+ wma_handle->link_stats_results = qdf_mem_malloc(link_stats_results_size);
+ if (NULL == wma_handle->link_stats_results) {
+ WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
+ __func__, link_stats_results_size);
+ return -ENOMEM;
+ }
}
+ link_stats_results = wma_handle->link_stats_results;
WMA_LOGD("Radio stats Fixed Param:");
- WMA_LOGD("request_id %u num_radio %u more_radio_events %u",
+ WMA_LOGD("req_id: %u num_radio: %u more_radio_events: %u",
fixed_param->request_id, fixed_param->num_radio,
fixed_param->more_radio_events);
- WMA_LOGD("Radio Info: radio_id %u on_time %u tx_time %u rx_time %u on_time_scan %u "
- "on_time_nbd %u on_time_gscan %u on_time_roam_scan %u "
- "on_time_pno_scan %u on_time_hs20 %u num_channels %u",
+ WMA_LOGD("Radio Info: radio_id: %u on_time: %u tx_time: %u rx_time: %u on_time_scan: %u "
+ "on_time_nbd: %u on_time_gscan: %u on_time_roam_scan: %u "
+ "on_time_pno_scan: %u on_time_hs20: %u num_channels: %u",
radio_stats->radio_id, radio_stats->on_time,
radio_stats->tx_time, radio_stats->rx_time,
radio_stats->on_time_scan, radio_stats->on_time_nbd,
@@ -804,9 +850,6 @@
radio_stats->on_time_pno_scan,
radio_stats->on_time_hs20, radio_stats->num_channels);
- link_stats_results = wma_handle->link_stats_results;
- qdf_mem_zero(link_stats_results, link_stats_results_size);
-
link_stats_results->paramId = WMI_LINK_STATS_RADIO;
link_stats_results->rspId = fixed_param->request_id;
link_stats_results->ifaceId = 0;
@@ -827,7 +870,7 @@
t_radio_stats = (uint8_t *) radio_stats;
t_channel_stats = (uint8_t *) channel_stats;
- rs_results = (tSirWifiRadioStat *) &results[0];
+ rs_results = (tSirWifiRadioStat *) &results[0] + radio_stats->radio_id;
rs_results->radio = radio_stats->radio_id;
rs_results->onTime = radio_stats->on_time;
rs_results->txTime = radio_stats->tx_time;
@@ -841,38 +884,57 @@
rs_results->total_num_tx_power_levels = 0;
rs_results->tx_time_per_power_level = NULL;
rs_results->numChannels = radio_stats->num_channels;
+ rs_results->channels = NULL;
- chn_results = (tSirWifiChannelStats *) &rs_results->channels[0];
- next_chan_offset = WMI_TLV_HDR_SIZE;
- WMA_LOGD("Channel Stats Info");
- for (count = 0; count < radio_stats->num_channels; count++) {
- WMA_LOGD("channel_width %u center_freq %u center_freq0 %u "
- "center_freq1 %u radio_awake_time %u cca_busy_time %u",
- channel_stats->channel_width,
- channel_stats->center_freq,
- channel_stats->center_freq0,
- channel_stats->center_freq1,
- channel_stats->radio_awake_time,
- channel_stats->cca_busy_time);
- channel_stats++;
+ if (rs_results->numChannels) {
+ rs_results->channels = (tSirWifiChannelStats *) qdf_mem_malloc(
+ radio_stats->num_channels *
+ chan_stats_size);
+ if (rs_results->channels == NULL) {
+ WMA_LOGD("%s: could not allocate mem for channel stats (size=%zu)",
+ __func__, radio_stats->num_channels * chan_stats_size);
+ wma_unified_radio_tx_mem_free(handle);
+ return -ENOMEM;
+ }
- qdf_mem_copy(chn_results,
- t_channel_stats + next_chan_offset,
- chan_stats_size);
- chn_results++;
- next_chan_offset += sizeof(*channel_stats);
+ chn_results = (tSirWifiChannelStats *) &rs_results->channels[0];
+ next_chan_offset = WMI_TLV_HDR_SIZE;
+ WMA_LOGD("Channel Stats Info");
+ for (count = 0; count < radio_stats->num_channels; count++) {
+ WMA_LOGD("channel_width %u center_freq %u center_freq0 %u "
+ "center_freq1 %u radio_awake_time %u cca_busy_time %u",
+ channel_stats->channel_width,
+ channel_stats->center_freq,
+ channel_stats->center_freq0,
+ channel_stats->center_freq1,
+ channel_stats->radio_awake_time,
+ channel_stats->cca_busy_time);
+ channel_stats++;
+
+ qdf_mem_copy(chn_results,
+ t_channel_stats + next_chan_offset,
+ chan_stats_size);
+ chn_results++;
+ next_chan_offset += sizeof(*channel_stats);
+ }
}
if (link_stats_results->moreResultToFollow) {
/* More results coming, don't post yet */
return 0;
+ } else {
+ link_stats_results->nr_received++;
+ }
+
+ if (link_stats_results->num_radio != link_stats_results->nr_received) {
+ /* Not received all radio stats yet, don't post yet */
+ return 0;
}
pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
WMA_LINK_LAYER_STATS_RESULTS_RSP,
link_stats_results);
- qdf_mem_free(wma_handle->link_stats_results);
- wma_handle->link_stats_results = NULL;
+ wma_unified_radio_tx_mem_free(handle);
return 0;
}