qcacld-3.0: Add support of request peer stats info(part 1)
qcacld-2.0 to qcacld-3.0 propagation
FW has limitation to support old WMI_REQUEST_STATS_CMDID and
WMI_UPDATE_STATS_EVENTID interface on AP vDev. FW suggest to use new
WMI_REQUEST_PEER_STATS_INFO_CMDID and WMI_PEER_STATS_INFO_EVENTID to
get tx/rx rate.
This checkin is about WMA layer which process SME message to get peer
stats info and WMI event WMI_PEER_STATS_INFO_EVENTID which send from
firmware as response to WMI_REQUEST_PEER_STATS_INFO_CMDID. There are
also updates using old WMI_REQUEST_STATS_CMDID to get peer stats.
Change-Id: I964520dc44c112875434771154f55f4746298308
CRs-Fixed: 2046459
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c
index 910ae89..1f7e307 100644
--- a/core/wma/src/wma_utils.c
+++ b/core/wma/src/wma_utils.c
@@ -2703,6 +2703,111 @@
}
/**
+ * wma_handle_sta_peer_info() - handle peer information in
+ * peer stats
+ * @num_peer_stats: peer number
+ * @peer_stats: peer stats received from firmware
+ * @peer_macaddr: the specified mac address
+ * @sapaddr: sap mac address
+ *
+ * This function will send eWNI_SME_GET_PEER_INFO_IND
+ * to sme with stations' information
+ *
+ */
+static void wma_handle_sta_peer_info(uint32_t num_peer_stats,
+ wmi_peer_stats *peer_stats,
+ struct qdf_mac_addr peer_macaddr,
+ uint8_t *sapaddr)
+{
+ QDF_STATUS qdf_status;
+ wmi_mac_addr temp_addr;
+ struct sir_peer_info_resp *peer_info;
+ struct scheduler_msg sme_msg = {0};
+ uint32_t i;
+ uint32_t j = 0;
+
+ if (!qdf_is_macaddr_broadcast(&peer_macaddr)) {
+ WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_macaddr.bytes, &temp_addr);
+ for (i = 0; i < num_peer_stats; i++) {
+ if ((((temp_addr.mac_addr47to32) & 0x0000ffff) ==
+ ((peer_stats->peer_macaddr.mac_addr47to32) &
+ 0x0000ffff))
+ && (temp_addr.mac_addr31to0 ==
+ peer_stats->peer_macaddr.mac_addr31to0)) {
+
+ break;
+ }
+ peer_stats = peer_stats + 1;
+ }
+ peer_info = qdf_mem_malloc(sizeof(*peer_info) +
+ sizeof(peer_info->info[0]));
+ if (NULL == peer_info) {
+ WMA_LOGE("%s: Memory allocation failed.", __func__);
+ return;
+ }
+ if (i < num_peer_stats) {
+ peer_info->count = 1;
+ WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
+ peer_info->info[0].peer_macaddr.bytes);
+ peer_info->info[0].rssi = peer_stats->peer_rssi;
+ peer_info->info[0].tx_rate = peer_stats->peer_tx_rate;
+ peer_info->info[0].rx_rate = peer_stats->peer_rx_rate;
+ WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d",
+ __func__,
+ peer_info->info[0].peer_macaddr.bytes,
+ peer_stats->peer_rssi,
+ peer_stats->peer_tx_rate,
+ peer_stats->peer_rx_rate);
+ } else {
+ WMA_LOGE("%s: no match mac address", __func__);
+ peer_info->count = 0;
+ }
+ } else {
+ peer_info = qdf_mem_malloc(sizeof(*peer_info) +
+ num_peer_stats * sizeof(peer_info->info[0]));
+ if (NULL == peer_info) {
+ WMA_LOGE("%s: Memory allocation failed.", __func__);
+ return;
+ }
+ peer_info->count = num_peer_stats;
+
+ for (i = 0; i < num_peer_stats; i++) {
+ WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
+ peer_info->info[j].peer_macaddr.bytes);
+ peer_info->info[j].rssi = peer_stats->peer_rssi;
+ peer_info->info[j].tx_rate = peer_stats->peer_tx_rate;
+ peer_info->info[j].rx_rate = peer_stats->peer_rx_rate;
+ WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d",
+ __func__,
+ peer_info->info[j].peer_macaddr.bytes,
+ peer_stats->peer_rssi,
+ peer_stats->peer_tx_rate,
+ peer_stats->peer_rx_rate);
+ if (!qdf_mem_cmp(peer_info->info[j].peer_macaddr.bytes,
+ sapaddr, QDF_MAC_ADDR_SIZE)) {
+ peer_info->count = peer_info->count - 1;
+ } else {
+ j++;
+ }
+ peer_stats = peer_stats + 1;
+ }
+ WMA_LOGD("WDA send peer num %d", peer_info->count);
+ }
+
+ sme_msg.type = eWNI_SME_GET_PEER_INFO_IND;
+ sme_msg.bodyptr = peer_info;
+ sme_msg.bodyval = 0;
+
+ qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
+ if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+ WMA_LOGE("%s: Fail to post get rssi msg", __func__);
+ qdf_mem_free(peer_info);
+ }
+
+ return;
+}
+
+/**
* wma_stats_event_handler() - stats event handler
* @handle: wma handle
* @cmd_param_info: data from event
@@ -2751,10 +2856,17 @@
}
if (event->num_peer_stats > 0) {
- for (i = 0; i < event->num_peer_stats; i++) {
- peer_stats = (wmi_peer_stats *) temp;
- wma_update_peer_stats(wma, peer_stats);
- temp += sizeof(wmi_peer_stats);
+ if (wma->get_sta_peer_info == true) {
+ wma_handle_sta_peer_info(event->num_peer_stats,
+ (wmi_peer_stats *)temp,
+ wma->peer_macaddr,
+ wma->myaddr);
+ } else {
+ for (i = 0; i < event->num_peer_stats; i++) {
+ peer_stats = (wmi_peer_stats *) temp;
+ wma_update_peer_stats(wma, peer_stats);
+ temp += sizeof(wmi_peer_stats);
+ }
}
}
@@ -2816,6 +2928,210 @@
}
/**
+ * wma_fill_peer_info() - fill SIR peer info from WMI peer info struct
+ * @wma: wma interface
+ * @stats_info: WMI peer info pointer
+ * @peer_info: SIR peer info pointer
+ *
+ * This function will fill SIR peer info from WMI peer info struct
+ *
+ * Return: None
+ */
+static void wma_fill_peer_info(tp_wma_handle wma,
+ wmi_peer_stats_info *stats_info,
+ struct sir_peer_info_ext *peer_info)
+{
+ peer_info->tx_packets = stats_info->tx_packets.low_32;
+ peer_info->tx_bytes = stats_info->tx_bytes.high_32;
+ peer_info->tx_bytes <<= 32;
+ peer_info->tx_bytes += stats_info->tx_bytes.low_32;
+ peer_info->rx_packets = stats_info->rx_packets.low_32;
+ peer_info->rx_bytes = stats_info->rx_bytes.high_32;
+ peer_info->rx_bytes <<= 32;
+ peer_info->rx_bytes += stats_info->rx_bytes.low_32;
+ peer_info->tx_retries = stats_info->tx_retries;
+ peer_info->tx_failed = stats_info->tx_failed;
+ peer_info->rssi = stats_info->peer_rssi;
+ peer_info->tx_rate = stats_info->last_tx_bitrate_kbps;
+ peer_info->tx_rate_code = stats_info->last_tx_rate_code;
+ peer_info->rx_rate = stats_info->last_rx_bitrate_kbps;
+ peer_info->rx_rate_code = stats_info->last_rx_rate_code;
+}
+
+/**
+ * wma_peer_info_ext_rsp() - process peer ext info ext
+ * @handle: wma interface
+ * @buf: wmi event buf pointer
+ *
+ * This function will send eWNI_SME_GET_PEER_INFO_EXT_IND to SME
+ *
+ * Return: 0 on success, error code otherwise
+ */
+static QDF_STATUS wma_peer_info_ext_rsp(tp_wma_handle wma, u_int8_t *buf)
+{
+ wmi_peer_stats_info_event_fixed_param *event;
+ wmi_peer_stats_info *stats_info;
+ struct sir_peer_info_ext_resp *resp;
+ struct sir_peer_info_ext *peer_info;
+ struct scheduler_msg sme_msg = {0};
+ int i, j = 0;
+ QDF_STATUS qdf_status;
+
+ event = (wmi_peer_stats_info_event_fixed_param *)buf;
+ stats_info = (wmi_peer_stats_info *)(buf +
+ sizeof(wmi_peer_stats_info_event_fixed_param));
+
+ if (wma->get_one_peer_info) {
+ resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
+ sizeof(resp->info[0]));
+ if (!resp) {
+ WMA_LOGE(FL("resp allocation failed."));
+ return QDF_STATUS_E_NOMEM;
+ }
+ resp->count = 0;
+ peer_info = &resp->info[0];
+ for (i = 0; i < event->num_peers; i++) {
+ WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
+ peer_info->peer_macaddr.bytes);
+
+ if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes,
+ wma->peer_macaddr.bytes,
+ QDF_MAC_ADDR_SIZE)) {
+ wma_fill_peer_info(wma, stats_info, peer_info);
+ resp->count++;
+ break;
+ }
+
+ stats_info = stats_info + 1;
+ }
+ } else {
+ resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
+ event->num_peers * sizeof(resp->info[0]));
+ if (!resp) {
+ WMA_LOGE(FL("resp allocation failed."));
+ return QDF_STATUS_E_NOMEM;
+ }
+ resp->count = event->num_peers;
+ for (i = 0; i < event->num_peers; i++) {
+ peer_info = &resp->info[j];
+ WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
+ peer_info->peer_macaddr.bytes);
+
+ if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes,
+ wma->myaddr, QDF_MAC_ADDR_SIZE)) {
+ resp->count = resp->count - 1;
+ } else {
+ wma_fill_peer_info(wma, stats_info, peer_info);
+ j++;
+ }
+ stats_info = stats_info + 1;
+ }
+ }
+
+ sme_msg.type = eWNI_SME_GET_PEER_INFO_EXT_IND;
+ sme_msg.bodyptr = resp;
+ sme_msg.bodyval = 0;
+
+ qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
+ if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+ WMA_LOGE("%s: Fail to post get peer info msg", __func__);
+ qdf_mem_free(resp);
+ }
+
+ return qdf_status;
+}
+
+/**
+ * dump_peer_stats_info() - dump wmi peer info struct
+ * @event: wmi peer info fixed param pointer
+ * @peer_stats: wmi peer stats info pointer
+ *
+ * This function will dump wmi peer info struct
+ *
+ * Return: None
+ */
+static void dump_peer_stats_info(wmi_peer_stats_info_event_fixed_param *event,
+ wmi_peer_stats_info *peer_stats)
+{
+ int i;
+ wmi_peer_stats_info *stats = peer_stats;
+ u_int8_t mac[6];
+
+ WMA_LOGI("%s vdev_id %d, num_peers %d more_data %d",
+ __func__, event->vdev_id,
+ event->num_peers, event->more_data);
+
+ for (i = 0; i < event->num_peers; i++) {
+ WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats->peer_macaddr, mac);
+ WMA_LOGI("%s mac %pM", __func__, mac);
+ WMA_LOGI("%s tx_bytes %d %d tx_packets %d %d",
+ __func__,
+ stats->tx_bytes.low_32,
+ stats->tx_bytes.high_32,
+ stats->tx_packets.low_32,
+ stats->tx_packets.high_32);
+ WMA_LOGI("%s rx_bytes %d %d rx_packets %d %d",
+ __func__,
+ stats->rx_bytes.low_32,
+ stats->rx_bytes.high_32,
+ stats->rx_packets.low_32,
+ stats->rx_packets.high_32);
+ WMA_LOGI("%s tx_retries %d tx_failed %d",
+ __func__, stats->tx_retries, stats->tx_failed);
+ WMA_LOGI("%s tx_rate_code %x rx_rate_code %x",
+ __func__,
+ stats->last_tx_rate_code,
+ stats->last_rx_rate_code);
+ WMA_LOGI("%s tx_rate %x rx_rate %x",
+ __func__,
+ stats->last_tx_bitrate_kbps,
+ stats->last_rx_bitrate_kbps);
+ WMA_LOGI("%s peer_rssi %d", __func__, stats->peer_rssi);
+ stats++;
+ }
+}
+
+int wma_peer_info_event_handler(void *handle, u_int8_t *cmd_param_info,
+ u_int32_t len)
+{
+ tp_wma_handle wma = (tp_wma_handle) handle;
+ WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
+ wmi_peer_stats_info_event_fixed_param *event;
+ u_int32_t buf_size;
+ u_int8_t *buf;
+
+ param_buf =
+ (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)cmd_param_info;
+ if (!param_buf) {
+ WMA_LOGA("%s: Invalid stats event", __func__);
+ return -EINVAL;
+ }
+
+ WMA_LOGI("%s Recv WMI_PEER_STATS_INFO_EVENTID", __func__);
+ event = param_buf->fixed_param;
+ buf_size = sizeof(wmi_peer_stats_info_event_fixed_param) +
+ sizeof(wmi_peer_stats_info) * event->num_peers;
+ buf = qdf_mem_malloc(buf_size);
+ if (!buf) {
+ WMA_LOGE("%s: Failed alloc memory for buf", __func__);
+ return -ENOMEM;
+ }
+
+ qdf_mem_copy(buf, param_buf->fixed_param,
+ sizeof(wmi_peer_stats_info_event_fixed_param));
+ qdf_mem_copy((buf + sizeof(wmi_peer_stats_info_event_fixed_param)),
+ param_buf->peer_stats_info,
+ sizeof(wmi_peer_stats_info) * event->num_peers);
+ WMA_LOGI("%s dump peer stats info", __func__);
+ dump_peer_stats_info(event, param_buf->peer_stats_info);
+
+ wma_peer_info_ext_rsp(wma, buf);
+ qdf_mem_free(buf);
+
+ return 0;
+}
+
+/**
* wma_send_link_speed() - send link speed to SME
* @link_speed: link speed
*
@@ -3315,6 +3631,7 @@
node->stats_rsp = NULL;
}
node->stats_rsp = pGetPEStatsRspParams;
+ wma_handle->get_sta_peer_info = false;
WMA_LOGD("stats_rsp allocated: %p, sta_id: %d, mask: %d, vdev_id: %d",
node->stats_rsp, node->stats_rsp->staId,
node->stats_rsp->statsMask, get_stats_param->sessionId);