Browse Source

qcacld-3.0: Update linkspeed state to F/W for roaming dp part

To avoid unmeaningful roaming, when low RSSI trigger,
only roam when rx linkspeed is also bad.
Steps:
1. F/W indicates feature supported by:
	wmi_service_linkspeed_roam_trigger_support
2. App sets vdev rx link speed threshold by vendor cmd.
3. Bus_bw_work gets rx link speed from data path periodically.
4. If found rx link speed change from good to poor, or poor to good, send
	to F/W.
5. F/W low rssi roaming is triggered only when both RSSI and link speed are
	poor.

Change-Id: I2c2a22c1f24a730783ee09455f4d70b099d9bff1
CRs-Fixed: 3255036
Jianmin Zhu 2 years ago
parent
commit
71eb93c537

+ 15 - 0
components/dp/core/inc/wlan_dp_priv.h

@@ -252,9 +252,22 @@ struct wlan_dp_conn_info {
 	uint8_t is_authenticated;
 };
 
+/**
+ * struct link_monitoring - link speed monitoring related info
+ * @enabled: Is link speed monitoring feature enabled
+ * @rx_linkspeed_threshold: link speed good/bad threshold
+ * @is_link_speed_good: true means link speed good, false means bad
+ */
+struct link_monitoring {
+	uint8_t enabled;
+	uint32_t rx_linkspeed_threshold;
+	uint8_t is_rx_linkspeed_good;
+};
+
 /**
  * struct wlan_dp_intf - DP interface object related info
  * @dp_ctx: DP context reference
+ * @link_monitoring: Link monitoring related info
  * @mac_addr: Device MAC address
  * @device_mode: Device Mode
  * @intf_id: Interface ID
@@ -277,6 +290,8 @@ struct wlan_dp_conn_info {
 struct wlan_dp_intf {
 	struct wlan_dp_psoc_context *dp_ctx;
 
+	struct link_monitoring link_monitoring;
+
 	struct qdf_mac_addr mac_addr;
 
 	enum QDF_OPMODE device_mode;

+ 97 - 2
components/dp/core/src/wlan_dp_bus_bandwidth.c

@@ -39,6 +39,8 @@
 #include "wlan_mlme_ucfg_api.h"
 #include <i_qdf_net_stats.h>
 #include "wlan_dp_txrx.h"
+#include "cdp_txrx_host_stats.h"
+#include "wlan_cm_roam_api.h"
 
 #ifdef FEATURE_BUS_BANDWIDTH_MGR
 /**
@@ -1697,6 +1699,96 @@ dp_rx_check_qdisc_for_intf(struct wlan_dp_intf *dp_intf)
 }
 #endif
 
+#define NO_RX_PKT_LINK_SPEED_AGEOUT_COUNT 50
+static void
+dp_link_monitoring(struct wlan_dp_psoc_context *dp_ctx,
+		   struct wlan_dp_intf *dp_intf)
+{
+	struct cdp_peer_stats *peer_stats;
+	QDF_STATUS status;
+	ol_txrx_soc_handle soc;
+	struct wlan_objmgr_peer *bss_peer;
+	static uint32_t no_rx_times;
+	uint64_t  rx_packets;
+	uint32_t link_speed;
+	struct wlan_objmgr_psoc *psoc;
+	struct link_monitoring link_mon;
+
+	/*
+	 *  If throughput is high, link speed should be good,  don't check it
+	 *  to avoid performance penalty
+	 */
+	soc = cds_get_context(QDF_MODULE_ID_SOC);
+	if (cdp_get_bus_lvl_high(soc) == true)
+		return;
+
+	link_mon = dp_intf->link_monitoring;
+	if (!dp_ctx->dp_ops.link_monitoring_cb)
+		return;
+
+	psoc = dp_ctx->psoc;
+	/* If no rx packets received for N sec, set link speed to poor */
+	if (link_mon.is_rx_linkspeed_good) {
+		rx_packets = DP_BW_GET_DIFF(QDF_NET_DEV_STATS_RX_PKTS(&dp_intf->stats),
+					    dp_intf->prev_rx_packets);
+		if (!rx_packets)
+			no_rx_times++;
+		else
+			no_rx_times = 0;
+		if (no_rx_times >= NO_RX_PKT_LINK_SPEED_AGEOUT_COUNT) {
+			no_rx_times = 0;
+			dp_ctx->dp_ops.link_monitoring_cb(psoc,
+							  dp_intf->intf_id,
+							  false);
+			return;
+		}
+	}
+	/* Get rx link speed from dp peer */
+	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
+	if (!peer_stats)
+		return;
+	bss_peer = wlan_vdev_get_bsspeer(dp_intf->vdev);
+	if (!bss_peer) {
+		dp_debug("Invalid bss peer");
+		qdf_mem_free(peer_stats);
+		return;
+	}
+	status = cdp_host_get_peer_stats(soc, dp_intf->intf_id,
+					 bss_peer->macaddr,
+					 peer_stats);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(peer_stats);
+		return;
+	}
+	/* Convert rx linkspeed from kbps to mbps to compare with threshold */
+	link_speed = peer_stats->rx.last_rx_rate / 1000;
+
+	/*
+	 * When found current rx link speed becomes good(above threshold) or
+	 * poor, update to firmware.
+	 * If the current RX link speed is above the threshold, low rssi
+	 * roaming is not needed. If linkspeed_threshold is set to 0, the
+	 * firmware will not consider RX link speed in the roaming decision,
+	 * driver will send rx link speed poor state to firmware.
+	 */
+	if (!link_mon.rx_linkspeed_threshold) {
+		dp_ctx->dp_ops.link_monitoring_cb(psoc, dp_intf->intf_id,
+						  false);
+	} else if (link_speed > link_mon.rx_linkspeed_threshold &&
+	     !link_mon.is_rx_linkspeed_good) {
+		dp_ctx->dp_ops.link_monitoring_cb(psoc, dp_intf->intf_id,
+						  true);
+		link_mon.is_rx_linkspeed_good = true;
+	} else if (link_speed < link_mon.rx_linkspeed_threshold &&
+		   link_mon.is_rx_linkspeed_good) {
+		dp_ctx->dp_ops.link_monitoring_cb(psoc, dp_intf->intf_id,
+						  false);
+		link_mon.is_rx_linkspeed_good = false;
+	}
+
+	qdf_mem_free(peer_stats);
+}
+
 /**
  * __dp_bus_bw_work_handler() - Bus bandwidth work handler
  * @dp_ctx: handle to DP context
@@ -1770,10 +1862,12 @@ static void __dp_bus_bw_work_handler(struct wlan_dp_psoc_context *dp_ctx)
 			dp_intf->prev_tx_bytes);
 
 		if (dp_intf->device_mode == QDF_STA_MODE &&
-		    ucfg_cm_is_vdev_active(vdev))
+		    ucfg_cm_is_vdev_active(vdev)) {
 			dp_ctx->dp_ops.dp_send_mscs_action_frame(ctx,
 							dp_intf->intf_id);
-
+			if (dp_intf->link_monitoring.enabled)
+				dp_link_monitoring(dp_ctx, dp_intf);
+		}
 		if (dp_intf->device_mode == QDF_SAP_MODE ||
 		    dp_intf->device_mode == QDF_P2P_GO_MODE ||
 		    dp_intf->device_mode == QDF_NDI_MODE) {
@@ -1821,6 +1915,7 @@ static void __dp_bus_bw_work_handler(struct wlan_dp_psoc_context *dp_ctx)
 			QDF_NET_DEV_STATS_TX_BYTES(&dp_intf->stats);
 		qdf_spin_unlock_bh(&dp_ctx->bus_bw_lock);
 		connected = true;
+
 		dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
 	}
 

+ 4 - 0
components/dp/dispatcher/inc/wlan_dp_public_struct.h

@@ -587,6 +587,7 @@ union wlan_tp_data {
  * @os_if_dp_nud_stats_info: osif callback to print nud stats info
  * @dp_get_pause_map: Callback API to get pause map count
  * @dp_nud_failure_work: Callback API to handle NUD failuire work
+ * @link_monitoring_cb: Callback API to handle link speed change
  */
 struct wlan_dp_psoc_callbacks {
 	hdd_cb_handle callback_ctx;
@@ -666,6 +667,9 @@ struct wlan_dp_psoc_callbacks {
 	void (*os_if_dp_nud_stats_info)(struct wlan_objmgr_vdev *vdev);
 	uint32_t (*dp_get_pause_map)(hdd_cb_handle context, uint8_t vdev_id);
 	void (*dp_nud_failure_work)(hdd_cb_handle context, uint8_t vdev_id);
+	void (*link_monitoring_cb)(struct wlan_objmgr_psoc *psoc,
+				   uint8_t vdev_id,
+				   bool is_link_speed_good);
 };
 
 /**

+ 9 - 0
components/dp/dispatcher/inc/wlan_dp_ucfg_api.h

@@ -1222,4 +1222,13 @@ void ucfg_dp_event_eapol_log(qdf_nbuf_t nbuf, enum qdf_proto_dir dir);
 QDF_STATUS
 ucfg_dp_softap_inspect_dhcp_packet(struct wlan_objmgr_vdev *vdev,
 				   qdf_nbuf_t nbuf, enum qdf_proto_dir dir);
+
+void
+dp_ucfg_enable_link_monitoring(struct wlan_objmgr_psoc *psoc,
+			       struct wlan_objmgr_vdev *vdev,
+			       uint32_t threshold);
+
+void
+dp_ucfg_disable_link_monitoring(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev);
 #endif /* _WLAN_DP_UCFG_API_H_ */

+ 32 - 0
components/dp/dispatcher/src/wlan_dp_ucfg_api.c

@@ -1915,6 +1915,7 @@ void ucfg_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc,
 		cb_obj->os_if_dp_nud_stats_info;
 	dp_ctx->dp_ops.osif_dp_process_mic_error =
 		cb_obj->osif_dp_process_mic_error;
+	dp_ctx->dp_ops.link_monitoring_cb = cb_obj->link_monitoring_cb;
 	}
 
 void ucfg_dp_register_event_handler(struct wlan_objmgr_psoc *psoc,
@@ -2153,3 +2154,34 @@ ucfg_dp_softap_inspect_dhcp_packet(struct wlan_objmgr_vdev *vdev,
 
 	return dp_softap_inspect_dhcp_packet(dp_intf, nbuf, dir);
 }
+
+void
+dp_ucfg_enable_link_monitoring(struct wlan_objmgr_psoc *psoc,
+			       struct wlan_objmgr_vdev *vdev,
+			       uint32_t threshold)
+{
+	struct wlan_dp_intf *dp_intf;
+
+	dp_intf = dp_get_vdev_priv_obj(vdev);
+	if (unlikely(!dp_intf)) {
+		dp_err("DP interface not found");
+		return;
+	}
+	dp_intf->link_monitoring.rx_linkspeed_threshold = threshold;
+	dp_intf->link_monitoring.enabled = true;
+}
+
+void
+dp_ucfg_disable_link_monitoring(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_dp_intf *dp_intf;
+
+	dp_intf = dp_get_vdev_priv_obj(vdev);
+	if (unlikely(!dp_intf)) {
+		dp_err("DP interface not found");
+		return;
+	}
+	dp_intf->link_monitoring.enabled = false;
+	dp_intf->link_monitoring.rx_linkspeed_threshold = 0;
+}