qcacld-3.0: Add support to handle updated link layer stats

Add support to parse and store additional link layer stats
included as part of radio stats and interface stats.

Change-Id: Idbefa508f5e79221c3d7598e6b120454b56e2423
CRs-Fixed: 2018087
diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c
index 99b2661..9e81a52 100644
--- a/core/hdd/src/wlan_hdd_stats.c
+++ b/core/hdd/src/wlan_hdd_stats.c
@@ -1016,7 +1016,8 @@
 		       " onTimeScan: %u onTimeNbd: %u"
 		       " onTimeGscan: %u onTimeRoamScan: %u"
 		       " onTimePnoScan: %u  onTimeHs20: %u"
-		       " numChannels: %u total_num_tx_pwr_levels: %u",
+		       " numChannels: %u total_num_tx_pwr_levels: %u"
+		       " on_time_host_scan: %u, on_time_lpi_scan: %u",
 		       pWifiRadioStat->radio, pWifiRadioStat->onTime,
 		       pWifiRadioStat->txTime, pWifiRadioStat->rxTime,
 		       pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd,
@@ -1024,7 +1025,9 @@
 		       pWifiRadioStat->onTimeRoamScan,
 		       pWifiRadioStat->onTimePnoScan,
 		       pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
-		       pWifiRadioStat->total_num_tx_power_levels);
+		       pWifiRadioStat->total_num_tx_power_levels,
+		       pWifiRadioStat->on_time_host_scan,
+		       pWifiRadioStat->on_time_lpi_scan);
 		pWifiRadioStat++;
 	}
 
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 2f7c0d6..94b4892 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -4823,6 +4823,9 @@
 	/* tx time (in milliseconds) per TPC level (0.5 dBm) */
 	uint32_t tx_time_per_tpc[MAX_TPC_LEVELS];
 
+	uint32_t on_time_host_scan;
+	uint32_t on_time_lpi_scan;
+
 	/* channel statistics tSirWifiChannelStats */
 	tSirWifiChannelStats *channels;
 } tSirWifiRadioStat, *tpSirWifiRadioStat;
@@ -4883,6 +4886,22 @@
 	tSirWifiRateStat rateStats[0];
 } tSirWifiPeerInfo, *tpSirWifiPeerInfo;
 
+/**
+ * struct wifi_iface_offload_stat - Wifi Iface offload statistics
+ * @type: type of offload stats (enum wmi_offload_stats_type)
+ * @rx_count: Number of (MSDUs) frames Received
+ * @drp_count: Number of frames Dropped
+ * @fwd_count:
+ *  Number of frames for which FW Responded (Valid for ARP and NS only).(or)
+ *  Number of frames forwarded to Host (Valid for stats type except ARP and NS).
+ */
+struct wifi_iface_offload_stat {
+	wmi_offload_stats_type type;
+	uint32_t rx_count;
+	uint32_t drp_count;
+	uint32_t fwd_count;
+};
+
 /* per access category statistics */
 typedef struct {
 	/* tSirWifiTrafficAc */
@@ -4981,8 +5000,23 @@
 	uint32_t rts_fail_cnt;
 	uint32_t ppdu_succ_cnt;
 	uint32_t ppdu_fail_cnt;
+
+	uint32_t tx_rts_succ_cnt;
+	uint32_t tx_rts_fail_cnt;
+	uint32_t tx_ppdu_succ_cnt;
+	uint32_t tx_ppdu_fail_cnt;
+	uint32_t connected_duration;
+	uint32_t disconnected_duration;
+	uint32_t rtt_ranging_duration;
+	uint32_t rtt_responder_duration;
+	uint32_t num_probes_tx;
+	uint32_t num_beacon_miss;
+
 	/* per ac data packet statistics */
 	tSirWifiWmmAcStat AccessclassStats[WIFI_AC_MAX];
+
+	uint32_t num_offload_stats;
+	struct wifi_iface_offload_stat offload_stat[WMI_OFFLOAD_STATS_TYPE_MAX];
 } tSirWifiIfaceStat, *tpSirWifiIfaceStat;
 
 /* Peer statistics - corresponding to 3rd most LSB in
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c
index 6aa09f0..4bf6922 100644
--- a/core/wma/src/wma_utils.c
+++ b/core/wma/src/wma_utils.c
@@ -1484,6 +1484,8 @@
 	WMA_LOGD("on_time_pno_scan: %u on_time_hs20: %u num_channels: %u",
 		radio_stats->on_time_pno_scan, radio_stats->on_time_hs20,
 		radio_stats->num_channels);
+	WMA_LOGD("on_time_host_scan: %u, on_time_lpi_scan: %u",
+		radio_stats->on_time_host_scan, radio_stats->on_time_lpi_scan);
 
 	link_stats_results->paramId = WMI_LINK_STATS_RADIO;
 	link_stats_results->rspId = fixed_param->request_id;
@@ -1519,6 +1521,8 @@
 	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->on_time_host_scan = radio_stats->on_time_host_scan;
+	rs_results->on_time_lpi_scan = radio_stats->on_time_lpi_scan;
 	rs_results->channels = NULL;
 
 	if (rs_results->numChannels) {
@@ -1891,12 +1895,14 @@
 	wmi_iface_link_stats_event_fixed_param *fixed_param;
 	wmi_iface_link_stats *link_stats;
 	wmi_wmm_ac_stats *ac_stats;
+	wmi_iface_offload_stats *offload_stats;
 	tSirLLStatsResults *link_stats_results;
-	uint8_t *results, *t_link_stats, *t_ac_stats;
-	uint32_t next_res_offset, next_ac_offset, count;
-	uint32_t roaming_offset, roaming_size;
+	uint8_t *results, *t_link_stats, *t_ac_stats, *t_offload_stats;
+	uint32_t next_res_offset, next_ac_offset, next_offload_offset, count;
+	uint32_t roaming_offset, size;
 	size_t link_stats_size, ac_stats_size, iface_info_size;
-	size_t link_stats_results_size;
+	size_t link_stats_results_size, offload_stats_size;
+	size_t total_ac_size, total_offload_size;
 
 	tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
 
@@ -1921,20 +1927,30 @@
 	 * wmi_iface_link_stats_event_fixed_param fixed_param;
 	 * wmi_iface_link_stats iface_link_stats;
 	 * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats)
+	 * fixed_param->num_offload_stats * size of(wmi_iface_offload_stats);
 	 */
 	fixed_param = param_tlvs->fixed_param;
 	link_stats = param_tlvs->iface_link_stats;
 	ac_stats = param_tlvs->ac;
+	offload_stats = param_tlvs->iface_offload_stats;
 
-	if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats)) {
+	if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats) ||
+	    (fixed_param->num_offload_stats && !offload_stats)) {
 		WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__);
 		return -EINVAL;
 	}
 
 	link_stats_size = sizeof(tSirWifiIfaceStat);
 	iface_info_size = sizeof(tSirWifiInterfaceInfo);
+
 	ac_stats_size = sizeof(tSirWifiWmmAcStat);
-	link_stats_results_size = sizeof(*link_stats_results) + link_stats_size;
+	offload_stats_size = sizeof(struct wifi_iface_offload_stat);
+
+	total_ac_size = ac_stats_size * WIFI_AC_MAX;
+	total_offload_size = offload_stats_size * WMI_OFFLOAD_STATS_TYPE_MAX +
+			      member_size(tSirWifiIfaceStat, num_offload_stats);
+
+	link_stats_results_size = sizeof(*link_stats_results) +	link_stats_size;
 
 	link_stats_results = qdf_mem_malloc(link_stats_results_size);
 	if (!link_stats_results) {
@@ -1952,23 +1968,34 @@
 	link_stats_results->peer_event_number = 0;
 	link_stats_results->moreResultToFollow = 0;
 
+	/* results is copied to tSirWifiIfaceStat in upper layer
+	 *   tSirWifiIfaceStat
+	 *    - tSirWifiInterfaceInfo (all fields except roaming is
+	 *                             filled by host in the upper layer)
+	 *    - various members of tSirWifiIfaceStat (from wmi_iface_link_stats)
+	 *    - ACs information (from wmi_wmm_ac_stats)
+	 *    - num_offload_stats (from fixed param)
+	 *    - offload stats (from wmi_iface_offload_stats)
+	 */
+
 	results = (uint8_t *) link_stats_results->results;
 	t_link_stats = (uint8_t *) link_stats;
 	t_ac_stats = (uint8_t *) ac_stats;
+	t_offload_stats = (uint8_t *) offload_stats;
 
 	/* Copy roaming state */
 	roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming);
-	roaming_size = member_size(tSirWifiInterfaceInfo, roaming);
+	size = member_size(tSirWifiInterfaceInfo, roaming);
 
-	qdf_mem_copy(results + roaming_offset, &link_stats->roam_state,
-		     roaming_size);
+	qdf_mem_copy(results + roaming_offset, &link_stats->roam_state, size);
 
-	qdf_mem_copy(results + iface_info_size,
+	next_res_offset = iface_info_size;
+	qdf_mem_copy(results + next_res_offset,
 		     t_link_stats + WMI_TLV_HDR_SIZE,
 		     link_stats_size - iface_info_size -
-		     WIFI_AC_MAX * ac_stats_size);
+		     total_ac_size - total_offload_size);
 
-	next_res_offset = link_stats_size - WIFI_AC_MAX * ac_stats_size;
+	next_res_offset = link_stats_size - total_ac_size - total_offload_size;
 	next_ac_offset = WMI_TLV_HDR_SIZE;
 
 	for (count = 0; count < link_stats->num_ac; count++) {
@@ -1980,6 +2007,23 @@
 		next_ac_offset += sizeof(*ac_stats);
 	}
 
+	next_res_offset = link_stats_size - total_offload_size;
+	/* copy num_offload_stats into result */
+	size =  member_size(tSirWifiIfaceStat, num_offload_stats);
+	qdf_mem_copy(results + next_res_offset, &fixed_param->num_offload_stats,
+		     size);
+
+	next_res_offset += size;
+	next_offload_offset = WMI_TLV_HDR_SIZE;
+
+	for (count = 0; count < fixed_param->num_offload_stats; count++) {
+		qdf_mem_copy(results + next_res_offset,
+			     t_offload_stats + next_offload_offset,
+			     offload_stats_size);
+		next_res_offset += offload_stats_size;
+		next_offload_offset += sizeof(*offload_stats);
+	}
+
 	/* call hdd callback with Link Layer Statistics
 	 * vdev_id/ifacId in link_stats_results will be
 	 * used to retrieve the correct HDD context