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
This commit is contained in:
Jianmin Zhu
2022-08-10 19:10:40 +08:00
committed by Madan Koyyalamudi
parent c4459eb18e
commit 71eb93c537
5 changed files with 157 additions and 2 deletions

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
};
/**

View File

@@ -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_ */

View File

@@ -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;
}