Browse Source

qcacmn: Add umac implementation of getting peer rssi

Add changes to support get peer rssi from within cp_stats
component.

Change-Id: I68c9c7e23dd14b515a71080b1b5fe3af15651ef9
CRs-Fixed: 2222777
Naveen Rawat 7 years ago
parent
commit
34e15c4636

+ 12 - 0
qdf/inc/qdf_util.h

@@ -105,6 +105,18 @@ typedef __qdf_wait_queue_head_t qdf_wait_queue_head_t;
  */
 #define QDF_MIN(_x, _y) (((_x) < (_y)) ? (_x) : (_y))
 
+/**
+ * QDF_IS_ADDR_BROADCAST - is mac address broadcast mac address
+ * @_a: pointer to mac address
+ */
+#define QDF_IS_ADDR_BROADCAST(_a)  \
+	((_a)[0] == 0xff &&        \
+	 (_a)[1] == 0xff &&        \
+	 (_a)[2] == 0xff &&        \
+	 (_a)[3] == 0xff &&        \
+	 (_a)[4] == 0xff &&        \
+	 (_a)[5] == 0xff)
+
 /**
  * qdf_status_to_os_return - returns the status to OS.
  * @status: enum QDF_STATUS

+ 26 - 3
umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h

@@ -41,14 +41,16 @@
 #include "qdf_event.h"
 
 /**
- * enum stats_req_type: enum indicating bit position of various stats type in
+ * enum stats_req_type - enum indicating bit position of various stats type in
  * request map
  * @TYPE_CONNECTION_TX_POWER: tx power was requested
  * @TYPE_STATION_STATS: station stats was requested
+ * @TYPE_PEER_STATS: peer stats was requested
  */
 enum stats_req_type {
 	TYPE_CONNECTION_TX_POWER = 0,
 	TYPE_STATION_STATS,
+	TYPE_PEER_STATS,
 	TYPE_MAX,
 };
 
@@ -92,6 +94,8 @@ struct wake_lock_stats {
 	uint32_t scan_11d;
 };
 
+struct stats_event;
+
 /**
  * struct request_info: details of each request
  * @cookie: identifier for os_if request
@@ -104,6 +108,7 @@ struct request_info {
 	void *cookie;
 	union {
 		void (*get_tx_power_cb)(int tx_power, void *cookie);
+		void (*get_peer_rssi_cb)(struct stats_event *ev, void *cookie);
 	} u;
 	uint32_t vdev_id;
 	uint32_t pdev_id;
@@ -146,14 +151,32 @@ struct vdev_mc_cp_stats {
 	struct wake_lock_stats wow_stats;
 };
 
+/**
+ * struct peer_mc_cp_stats - peer specific stats
+ * @tx_rate: tx rate
+ * @rx_rate: rx rate
+ * @peer_rssi: rssi
+ * @peer_macaddr: mac address
+ */
+struct peer_mc_cp_stats {
+	uint32_t tx_rate;
+	uint32_t rx_rate;
+	uint32_t peer_rssi;
+	uint8_t peer_macaddr[WLAN_MACADDR_LEN];
+};
+
 /**
  * struct stats_event - parameters populated by stats event
- * @num_pdev_stats: number of pdev stats
- * @pdev_stats: array of per pdev stats (index = pdev_id)
+ * @num_pdev_stats: num pdev stats
+ * @pdev_stats: if populated array indicating pdev stats (index = pdev_id)
+ * @num_peer_stats: num peer stats
+ * @peer_stats: if populated array indicating peer stats
  */
 struct stats_event {
 	uint32_t num_pdev_stats;
 	struct pdev_mc_cp_stats *pdev_stats;
+	uint32_t num_peer_stats;
+	struct peer_mc_cp_stats *peer_stats;
 };
 
 #endif /* CONFIG_MCL */

+ 1 - 1
umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h

@@ -177,4 +177,4 @@ QDF_STATUS ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc *psoc,
 					    struct request_info *info);
 
 #endif /* QCA_SUPPORT_CP_STATS */
-#endif /* __WLAN_CP_STATS_UCFG_API_H__ */
+#endif /* __WLAN_CP_STATS_MC_UCFG_API_H__ */

+ 217 - 3
umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c

@@ -107,8 +107,220 @@ static void tgt_mc_cp_stats_extract_tx_power(struct wlan_objmgr_psoc *psoc,
 end:
 	if (vdev)
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
-	qdf_mem_free(ev->pdev_stats);
-	ev->pdev_stats = NULL;
+}
+
+static void peer_rssi_iterator(struct wlan_objmgr_pdev *pdev,
+			       void *peer, void *arg)
+{
+	struct stats_event *ev;
+	struct peer_mc_cp_stats *peer_mc_stats;
+	struct peer_cp_stats *peer_cp_stats_priv;
+
+	if (WLAN_PEER_SELF == wlan_peer_get_peer_type(peer)) {
+		cp_stats_err("ignore self peer: %pM",
+			     wlan_peer_get_macaddr(peer));
+		return;
+	}
+
+	peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer);
+	if (!peer_cp_stats_priv) {
+		cp_stats_err("peer cp stats object is null");
+		return;
+	}
+
+	wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
+	peer_mc_stats = peer_cp_stats_priv->peer_stats;
+	ev = arg;
+	ev->peer_stats[ev->num_peer_stats] = *peer_mc_stats;
+	ev->num_peer_stats++;
+	wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
+}
+
+static void
+tgt_mc_cp_stats_prepare_raw_peer_rssi(struct wlan_objmgr_psoc *psoc,
+				      struct request_info *last_req)
+{
+	uint8_t *mac_addr;
+	uint16_t peer_count;
+	struct stats_event ev = {0};
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_peer *peer = NULL;
+	struct peer_mc_cp_stats *peer_mc_stats;
+	struct peer_cp_stats *peer_cp_stats_priv;
+	void (*get_peer_rssi_cb)(struct stats_event *ev, void *cookie);
+
+	get_peer_rssi_cb = last_req->u.get_peer_rssi_cb;
+	if (!get_peer_rssi_cb) {
+		cp_stats_err("get_peer_rssi_cb is null");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req->vdev_id,
+						    WLAN_CP_STATS_ID);
+	if (!vdev) {
+		cp_stats_err("vdev is null");
+		goto end;
+	}
+
+	mac_addr = last_req->peer_mac_addr;
+	if (QDF_IS_ADDR_BROADCAST(mac_addr)) {
+		pdev = wlan_vdev_get_pdev(vdev);
+		peer_count = wlan_pdev_get_peer_count(pdev);
+		ev.peer_stats = qdf_mem_malloc(sizeof(*ev.peer_stats) *
+								peer_count);
+		if (!ev.peer_stats) {
+			cp_stats_err("malloc failed");
+			goto end;
+		}
+
+		wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_PEER_OP,
+						  peer_rssi_iterator, &ev,
+						  true, WLAN_CP_STATS_ID);
+	} else {
+		peer = wlan_objmgr_get_peer(psoc, mac_addr, WLAN_CP_STATS_ID);
+		if (!peer) {
+			cp_stats_err("peer[%pM] is null", mac_addr);
+			goto end;
+		}
+
+		peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer);
+		if (!peer_cp_stats_priv) {
+			cp_stats_err("peer cp stats object is null");
+			goto end;
+		}
+
+		ev.peer_stats = qdf_mem_malloc(sizeof(*ev.peer_stats));
+		if (!ev.peer_stats) {
+			cp_stats_err("malloc failed");
+			goto end;
+		}
+
+		ev.num_peer_stats = 1;
+		wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
+		peer_mc_stats = peer_cp_stats_priv->peer_stats;
+		*ev.peer_stats = *peer_mc_stats;
+		wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
+	}
+
+	get_peer_rssi_cb(&ev, last_req->cookie);
+	return;
+end:
+	if (vdev)
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
+	if (peer)
+		wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
+	ucfg_mc_cp_stats_free_stats_event(&ev);
+}
+
+static QDF_STATUS
+tgt_mc_cp_stats_update_peer_stats(struct wlan_objmgr_psoc *psoc,
+				  struct peer_mc_cp_stats *peer_stats)
+{
+	uint8_t *peer_mac_addr;
+	struct wlan_objmgr_peer *peer;
+	struct peer_mc_cp_stats *peer_mc_stats;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct peer_cp_stats *peer_cp_stats_priv;
+
+	if (!peer_stats)
+		return QDF_STATUS_E_INVAL;
+
+	peer_mac_addr = peer_stats->peer_macaddr;
+	peer = wlan_objmgr_get_peer(psoc, peer_mac_addr,
+				    WLAN_CP_STATS_ID);
+	if (!peer) {
+		cp_stats_err("peer is null");
+		return QDF_STATUS_E_EXISTS;
+	}
+
+	peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer);
+	if (!peer_cp_stats_priv) {
+		cp_stats_err("peer_cp_stats_priv is null");
+		status = QDF_STATUS_E_EXISTS;
+		goto end;
+	}
+
+	wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
+	peer_mc_stats = peer_cp_stats_priv->peer_stats;
+	qdf_mem_copy(peer_mc_stats->peer_macaddr,
+		     peer_stats->peer_macaddr,
+		     WLAN_MACADDR_LEN);
+	if (peer_stats->tx_rate)
+		peer_mc_stats->tx_rate = peer_stats->tx_rate;
+	if (peer_stats->rx_rate)
+		peer_mc_stats->rx_rate = peer_stats->rx_rate;
+	if (peer_stats->peer_rssi)
+		peer_mc_stats->peer_rssi = peer_stats->peer_rssi;
+
+	cp_stats_debug("peer_mac=%pM, tx_rate=%u, rx_rate=%u, peer_rssi=%u",
+		       peer_mc_stats->peer_macaddr, peer_mc_stats->tx_rate,
+		       peer_mc_stats->rx_rate, peer_mc_stats->peer_rssi);
+	wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
+
+end:
+	if (peer)
+		wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
+
+	return status;
+}
+
+static void tgt_mc_cp_stats_extract_peer_stats(struct wlan_objmgr_psoc *psoc,
+					       struct stats_event *ev,
+					       bool is_station_stats)
+{
+	uint32_t i;
+	QDF_STATUS status;
+	struct request_info last_req = {0};
+	uint32_t selected;
+
+	if (!ev->peer_stats) {
+		cp_stats_err("no peer stats");
+		return;
+	}
+
+	if (is_station_stats)
+		status = ucfg_mc_cp_stats_get_pending_req(psoc,
+							  TYPE_STATION_STATS,
+							  &last_req);
+	else
+		status = ucfg_mc_cp_stats_get_pending_req(psoc,
+							  TYPE_PEER_STATS,
+							  &last_req);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed");
+		return;
+	}
+
+	selected = ev->num_peer_stats;
+	for (i = 0; i < ev->num_peer_stats; i++) {
+		status = tgt_mc_cp_stats_update_peer_stats(psoc,
+							   &ev->peer_stats[i]);
+		if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) &&
+		    !qdf_mem_cmp(ev->peer_stats[i].peer_macaddr,
+				 last_req.peer_mac_addr,
+				 WLAN_MACADDR_LEN)) {
+			/* mac is specified, but failed to update the peer */
+			if (QDF_IS_STATUS_ERROR(status))
+				return;
+
+			selected = i;
+		}
+	}
+
+	/* no matched peer */
+	if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) &&
+	    selected == ev->num_peer_stats) {
+		cp_stats_err("peer not found stats");
+		return;
+	}
+
+	if (is_station_stats)
+		return;
+
+	tgt_mc_cp_stats_prepare_raw_peer_rssi(psoc, &last_req);
+	ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_PEER_STATS);
 }
 
 QDF_STATUS tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc,
@@ -117,6 +329,8 @@ QDF_STATUS tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc,
 	if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_CONNECTION_TX_POWER))
 		tgt_mc_cp_stats_extract_tx_power(psoc, ev, false);
 
+	if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_PEER_STATS))
+		tgt_mc_cp_stats_extract_peer_stats(psoc, ev, false);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -144,7 +358,7 @@ QDF_STATUS tgt_send_mc_cp_stats_req(struct wlan_objmgr_psoc *psoc,
 	struct wlan_lmac_if_cp_stats_tx_ops *tx_ops;
 
 	tx_ops = target_if_cp_stats_get_tx_ops(psoc);
-	if (!tx_ops) {
+	if (!tx_ops || !tx_ops->send_req_stats) {
 		cp_stats_err("could not get tx_ops");
 		return QDF_STATUS_E_NULL_VALUE;
 	}