diff --git a/components/dp/core/inc/wlan_dp_priv.h b/components/dp/core/inc/wlan_dp_priv.h index 317ac417dc..d2480e7546 100644 --- a/components/dp/core/inc/wlan_dp_priv.h +++ b/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; diff --git a/components/dp/core/src/wlan_dp_bus_bandwidth.c b/components/dp/core/src/wlan_dp_bus_bandwidth.c index 63ff5137b3..e48e66460a 100644 --- a/components/dp/core/src/wlan_dp_bus_bandwidth.c +++ b/components/dp/core/src/wlan_dp_bus_bandwidth.c @@ -39,6 +39,8 @@ #include "wlan_mlme_ucfg_api.h" #include #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); } diff --git a/components/dp/dispatcher/inc/wlan_dp_public_struct.h b/components/dp/dispatcher/inc/wlan_dp_public_struct.h index 7624cf9669..aad68b3113 100644 --- a/components/dp/dispatcher/inc/wlan_dp_public_struct.h +++ b/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); }; /** diff --git a/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h b/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h index 48c7f6d56b..f29e478555 100644 --- a/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h +++ b/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_ */ diff --git a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c index 78e14429ae..6159365c28 100644 --- a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c +++ b/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; +}