diff options
| author | Srinivas Girigowda <sgirigow@qca.qualcomm.com> | 2016-04-12 17:27:10 -0700 |
|---|---|---|
| committer | Anjaneedevi Kapparapu <akappa@codeaurora.org> | 2016-04-14 14:14:26 +0530 |
| commit | dc6b41a65500dfcffed86d54741012ebe4d2af3f (patch) | |
| tree | 8cfec1f57d9a80c9886be4d834d1875a690faa76 | |
| parent | f55bfffa5d19706bdca5d9b32440734d6468f6fc (diff) | |
qcacld-2.0: Support for variable number of tx power level stats
Currently, firmware sends static 64 number of tx power level stats.
This is not scalable, hence add the support to send variable number
of tx power level stats.
Change is, firmware sends a separate WMI event with tx power level stats
indicating the total/num tx power levels and offset in the event
followed by the TLV. Host driver radio stats event processing is complete
only after receiving the tx power level stats.
Change-Id: Icd2c3958e09b2ce60f61e902d3f2da8b97acb013
CRs-Fixed: 992365
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_cfg80211.c | 50 | ||||
| -rw-r--r-- | CORE/MAC/inc/sirApi.h | 7 | ||||
| -rw-r--r-- | CORE/SERVICES/WMA/wma.c | 176 | ||||
| -rw-r--r-- | CORE/SERVICES/WMA/wma.h | 1 |
4 files changed, 185 insertions, 49 deletions
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c index a0f54175ab9b..c5f1dac727aa 100644 --- a/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -5929,27 +5929,20 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, if (0 != status) return; - hddLog(VOS_TRACE_LEVEL_INFO, + hddLog(LOG1, "LL_STATS_RADIO" - " number of radios = %u" - " radio is %d onTime is %u" - " txTime is %u rxTime is %u" - " onTimeScan is %u onTimeNbd is %u" - " onTimeGscan is %u onTimeRoamScan is %u" - " onTimePnoScan is %u onTimeHs20 is %u" - " numChannels is %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); + " 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); /* * Allocate a size of 4096 for the Radio stats comprising @@ -6011,11 +6004,7 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, pWifiRadioStat->onTimeHs20) || nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS, - MAX_TPC_LEVELS) || - nla_put(vendor_event, - QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL, - sizeof(u32) * MAX_TPC_LEVELS, - pWifiRadioStat->tx_time_per_tpc) || + pWifiRadioStat->total_num_tx_power_levels) || nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS, pWifiRadioStat->numChannels)) { @@ -6025,6 +6014,17 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, 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)) { + hddLog(LOGE, FL("ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL put fail")); + kfree_skb(vendor_event); + return; + } + } + if (pWifiRadioStat->numChannels) { struct nlattr *chList; diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h index 50b652975a1f..2852e00e9179 100644 --- a/CORE/MAC/inc/sirApi.h +++ b/CORE/MAC/inc/sirApi.h @@ -5875,12 +5875,13 @@ typedef struct * (32 bits number accruing over time) */ tANI_U32 onTimeHs20; - /* number of channels */ - tANI_U32 numChannels; /** tx time (in milliseconds) per TPC level (0.5 dBm) */ - uint32_t tx_time_per_tpc[MAX_TPC_LEVELS]; + uint32_t total_num_tx_power_levels; + uint32_t *tx_time_per_power_level; + /* number of channels */ + tANI_U32 numChannels; /* channel statistics tSirWifiChannelStats */ tSirWifiChannelStats channels[0]; } tSirWifiRadioStat, *tpSirWifiRadioStat; diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c index db507abcc699..34a2cdb4aa1e 100644 --- a/CORE/SERVICES/WMA/wma.c +++ b/CORE/SERVICES/WMA/wma.c @@ -4436,8 +4436,7 @@ static int wma_unified_link_iface_stats_event_handler(void *handle, return -ENOMEM; } - WMA_LOGD("Interface stats from FW event buf"); - WMA_LOGD("Fixed Param:"); + WMA_LOGD("Interface stats Fixed Param:"); WMA_LOGD("request_id %u vdev_id %u", fixed_param->request_id,fixed_param->vdev_id); @@ -4671,6 +4670,110 @@ static int wma_unified_link_peer_stats_event_handler(void *handle, return 0; } +/** + * wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats + * @handle: WMI handle + * @cmd_param_info: command param info + * @len: Length of @cmd_param_info + * + * This is the WMI event handler function to receive radio stats tx + * power level stats. + * + * Return: 0 on success, error number otherwise. +*/ +static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_tx_power_level_stats_evt_fixed_param *fixed_param; + uint8_t *tx_power_level_values; + tSirLLStatsResults *link_stats_results; + tSirWifiRadioStat *rs_results; + + tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(VOS_MODULE_ID_PE, + wma_handle->vos_context); + + if (!pMac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!pMac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *)cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid tx power level stats event", __func__); + return -EINVAL; + } + + fixed_param = param_tlvs->fixed_param; + if (!fixed_param) { + WMA_LOGA("%s: Invalid param_tlvs for Radio tx_power level Stats", __func__); + return -EINVAL; + } + + link_stats_results = wma_handle->link_stats_results; + rs_results = (tSirWifiRadioStat *) &link_stats_results->results[0]; + tx_power_level_values = (uint8 *) 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", + __func__, fixed_param->total_num_tx_power_levels, + fixed_param->num_tx_power_levels, + fixed_param->power_level_offset); + + rs_results->total_num_tx_power_levels = + fixed_param->total_num_tx_power_levels; + if (!rs_results->total_num_tx_power_levels) + goto post_stats; + + if (!rs_results->tx_time_per_power_level) { + rs_results->tx_time_per_power_level = vos_mem_malloc( + sizeof(uint32_t) * + rs_results->total_num_tx_power_levels); + if (!rs_results->tx_time_per_power_level) { + WMA_LOGA("%s: Mem alloc failed for tx power level stats", __func__); + /* In error case, atleast send the radio stats without + * tx_power_level stats */ + rs_results->total_num_tx_power_levels = 0; + goto post_stats; + } + } + vos_mem_copy(&rs_results->tx_time_per_power_level[fixed_param->power_level_offset], + 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)) + link_stats_results->moreResultToFollow = 0; + + WMA_LOGD("%s: moreResultToFollow: %u", + __func__, link_stats_results->moreResultToFollow); + + /* If still data to receive, return from here */ + if (link_stats_results->moreResultToFollow) + return 0; + +post_stats: + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd, + WDA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results); + WMA_LOGD("%s: Radio Stats event posted to HDD", __func__); + vos_mem_free(rs_results->tx_time_per_power_level); + vos_mem_free(wma_handle->link_stats_results); + rs_results->tx_time_per_power_level = NULL; + wma_handle->link_stats_results = NULL; + + return 0; +} + + static int wma_unified_link_radio_stats_event_handler(void *handle, u_int8_t *cmd_param_info, u_int32_t len) { @@ -4680,8 +4783,10 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, wmi_radio_link_stats *radio_stats; wmi_channel_stats *channel_stats; tSirLLStatsResults *link_stats_results; - u_int8_t *results, *t_radio_stats, *t_channel_stats; - u_int32_t next_res_offset, next_chan_offset, count; + tSirWifiRadioStat *rs_results; + tSirWifiChannelStats *chn_results; + uint8_t *results, *t_radio_stats, *t_channel_stats; + uint32_t next_chan_offset, count; size_t radio_stats_size, chan_stats_size; size_t link_stats_results_size; @@ -4698,7 +4803,6 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, 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__); @@ -4727,15 +4831,14 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, radio_stats_size + (radio_stats->num_channels * chan_stats_size); - link_stats_results = vos_mem_malloc(link_stats_results_size); - if (NULL == link_stats_results ) { + wma_handle->link_stats_results = vos_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; } - WMA_LOGD("Radio stats from FW event buf"); - WMA_LOGD("Fixed Param:"); + WMA_LOGD("Radio Stats Fixed Param:"); WMA_LOGD("request_id %u num_radio %u more_radio_events %u", fixed_param->request_id, fixed_param->num_radio, fixed_param->more_radio_events); @@ -4753,6 +4856,7 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, radio_stats->on_time_hs20, radio_stats->num_channels); + link_stats_results = wma_handle->link_stats_results; vos_mem_zero(link_stats_results, link_stats_results_size); link_stats_results->paramId = WMI_LINK_STATS_RADIO; @@ -4760,16 +4864,37 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, link_stats_results->ifaceId = 0; link_stats_results->num_radio = fixed_param->num_radio; link_stats_results->peer_event_number = 0; + + /* + * Backward compatibility: + * There are firmware(s) which will send Radio stats only with + * more_radio_events set to 0 and firmware which sends Radio stats + * followed by tx_power level stats with more_radio_events set to 1. + * if more_radio_events is set to 1, buffer the radio stats and + * wait for tx_power_level stats. + */ link_stats_results->moreResultToFollow = fixed_param->more_radio_events; results = (u_int8_t *)link_stats_results->results; t_radio_stats = (u_int8_t *)radio_stats; t_channel_stats = (u_int8_t *)channel_stats; - vos_mem_copy(results, t_radio_stats + WMI_TLV_HDR_SIZE, - radio_stats_size); - - next_res_offset = radio_stats_size; + rs_results = (tSirWifiRadioStat *) &results[0]; + rs_results->radio = radio_stats->radio_id; + rs_results->onTime = radio_stats->on_time; + rs_results->txTime = radio_stats->tx_time; + rs_results->rxTime = radio_stats->rx_time; + rs_results->onTimeScan = radio_stats->on_time_scan; + rs_results->onTimeNbd = radio_stats->on_time_nbd; + rs_results->onTimeGscan = radio_stats->on_time_gscan; + rs_results->onTimeRoamScan = radio_stats->on_time_roam_scan; + rs_results->onTimePnoScan = radio_stats->on_time_pno_scan; + rs_results->onTimeHs20 = radio_stats->on_time_hs20; + rs_results->total_num_tx_power_levels = 0; + rs_results->tx_time_per_power_level = NULL; + rs_results->numChannels = radio_stats->num_channels; + + 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++) { @@ -4781,22 +4906,23 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, channel_stats->cca_busy_time); channel_stats++; - vos_mem_copy(results + next_res_offset, + vos_mem_copy(chn_results, t_channel_stats + next_chan_offset, chan_stats_size); - next_res_offset += chan_stats_size; + chn_results++; next_chan_offset += sizeof(*channel_stats); } - /* call hdd callback with Link Layer Statistics - * vdev_id/ifacId in link_stats_results will be - * used to retrieve the correct HDD context - */ + if (link_stats_results->moreResultToFollow) { + /* More results coming, don't post yet */ + return 0; + } + pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd, WDA_LINK_LAYER_STATS_RESULTS_RSP, link_stats_results); - WMA_LOGD("%s: Radio Stats event posted to HDD", __func__); - vos_mem_free(link_stats_results); + vos_mem_free(wma_handle->link_stats_results); + wma_handle->link_stats_results = NULL; return 0; } @@ -6321,6 +6447,9 @@ wma_register_ll_stats_event_handler(tp_wma_handle wma_handle) wmi_unified_register_event_handler(wma_handle->wmi_handle, WMI_RADIO_LINK_STATS_EVENTID, wma_unified_link_radio_stats_event_handler); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID, + wma_unified_radio_tx_power_level_stats_event_handler); return; } @@ -31938,6 +32067,11 @@ VOS_STATUS wma_close(v_VOID_t *vos_ctx) WMA_LOGD("%s: Event log list freed", __func__); } + if (wma_handle->link_stats_results) { + vos_mem_free(wma_handle->link_stats_results); + wma_handle->link_stats_results = NULL; + } + /* Free wow pattern cache */ for (ptrn_id = 0; ptrn_id < wma_handle->wlan_resource_config.num_wow_filters; ptrn_id++) diff --git a/CORE/SERVICES/WMA/wma.h b/CORE/SERVICES/WMA/wma.h index 3add5cf8275e..3c10af968e35 100644 --- a/CORE/SERVICES/WMA/wma.h +++ b/CORE/SERVICES/WMA/wma.h @@ -864,6 +864,7 @@ typedef struct wma_handle { /* NAN datapath support enabled in firmware */ bool nan_datapath_enabled; + tSirLLStatsResults *link_stats_results; }t_wma_handle, *tp_wma_handle; struct wma_target_cap { |
