Ver Fonte

qcacld-3.0: Support for variable number of tx power level stats

This is a qcacld-2.0 to qcacld-3.0 propagation.

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
Srinivas Girigowda há 8 anos atrás
pai
commit
ad874a8204

+ 24 - 21
core/hdd/src/wlan_hdd_stats.c

@@ -807,24 +807,19 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter,
 		return;
 
 	hdd_notice("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,
+	       " 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->onTimeHs20, pWifiRadioStat->numChannels,
+	       pWifiRadioStat->total_num_tx_power_levels);
 
 	/*
 	 * Allocate a size of 4096 for the Radio stats comprising
@@ -884,11 +879,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)) {
@@ -898,6 +889,18 @@ 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)) {
+			hdd_err("nla_put fail");
+			kfree_skb(vendor_event);
+			return;
+		}
+	}
+
 	if (pWifiRadioStat->numChannels) {
 		struct nlattr *chList;
 		struct nlattr *chInfo;

+ 5 - 0
core/mac/inc/sir_api.h

@@ -5034,6 +5034,11 @@ typedef struct {
 	 * (32 bits number accruing over time)
 	 */
 	uint32_t onTimeHs20;
+
+	/* tx time (in milliseconds) per TPC level (0.5 dBm) */
+	uint32_t total_num_tx_power_levels;
+	uint32_t *tx_time_per_power_level;
+
 	/* number of channels */
 	uint32_t numChannels;
 

+ 2 - 1
core/wma/inc/wma.h

@@ -1,4 +1,4 @@
-/*
+				/*
  * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
@@ -1608,6 +1608,7 @@ typedef struct {
 	bool sub_20_support;
 	tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb;
 	tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb;
+	tSirLLStatsResults *link_stats_results;
 } t_wma_handle, *tp_wma_handle;
 
 /**

+ 5 - 0
core/wma/src/wma_main.c

@@ -3536,6 +3536,11 @@ QDF_STATUS wma_close(void *cds_ctx)
 		wma_handle->pGetRssiReq = NULL;
 	}
 
+	if (wma_handle->link_stats_results) {
+		qdf_mem_free(wma_handle->link_stats_results);
+		wma_handle->link_stats_results = NULL;
+	}
+
 	wma_ndp_unregister_all_event_handlers(wma_handle);
 
 	if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,

+ 147 - 16
core/wma/src/wma_utils.c

@@ -609,6 +609,107 @@ 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 mac = cds_get_context(QDF_MODULE_ID_PE);
+
+	if (!mac) {
+		WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
+		return -EINVAL;
+	}
+
+	if (!mac->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_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",
+			__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 = qdf_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;
+		}
+	}
+	qdf_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
+	 */
+	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);
+	qdf_mem_free(wma_handle->link_stats_results);
+	rs_results->tx_time_per_power_level = NULL;
+	wma_handle->link_stats_results = NULL;
+
+	return 0;
+}
 
 /**
  * wma_unified_link_radio_stats_event_handler() - radio link stats event handler
@@ -622,15 +723,18 @@ static int wma_unified_link_radio_stats_event_handler(void *handle,
 						      uint8_t *cmd_param_info,
 						      uint32_t len)
 {
+	tp_wma_handle wma_handle = (tp_wma_handle) handle;
 	WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
 	wmi_radio_link_stats_event_fixed_param *fixed_param;
 	wmi_radio_link_stats *radio_stats;
 	wmi_channel_stats *channel_stats;
 	tSirLLStatsResults *link_stats_results;
 	uint8_t *results, *t_radio_stats, *t_channel_stats;
-	uint32_t next_res_offset, next_chan_offset, count;
+	uint32_t next_chan_offset, count;
 	size_t radio_stats_size, chan_stats_size;
 	size_t link_stats_results_size;
+	tSirWifiRadioStat *rs_results;
+	tSirWifiChannelStats *chn_results;
 
 	tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
 
@@ -672,15 +776,14 @@ static int wma_unified_link_radio_stats_event_handler(void *handle,
 	link_stats_results_size = sizeof(*link_stats_results) +
 				  radio_stats_size + (radio_stats->num_channels * chan_stats_size);
 
-	link_stats_results = qdf_mem_malloc(link_stats_results_size);
-	if (NULL == 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;
 	}
 
-	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);
@@ -696,6 +799,7 @@ static int wma_unified_link_radio_stats_event_handler(void *handle,
 		 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;
@@ -703,16 +807,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 = (uint8_t *) link_stats_results->results;
 	t_radio_stats = (uint8_t *) radio_stats;
 	t_channel_stats = (uint8_t *) channel_stats;
 
-	qdf_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++) {
@@ -726,21 +851,23 @@ static int wma_unified_link_radio_stats_event_handler(void *handle,
 			 channel_stats->cca_busy_time);
 		channel_stats++;
 
-		qdf_mem_copy(results + next_res_offset,
+		qdf_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,
 					     WMA_LINK_LAYER_STATS_RESULTS_RSP,
 					     link_stats_results);
-	qdf_mem_free(link_stats_results);
+	qdf_mem_free(wma_handle->link_stats_results);
+	wma_handle->link_stats_results = NULL;
 
 	return 0;
 }
@@ -771,6 +898,10 @@ void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)
 				WMI_RADIO_LINK_STATS_EVENTID,
 				wma_unified_link_radio_stats_event_handler,
 				WMA_RX_SERIALIZER_CTX);
+	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,
+			WMA_RX_SERIALIZER_CTX);
 
 	return;
 }