diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 37766275dc16..c8f58ae4e560 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1642,6 +1642,7 @@ struct hdd_fw_ver_info { * @pdev: object manager pdev context * @iftype_data_2g: Interface data for 2g band * @iftype_data_5g: Interface data for 5g band + * @num_latency_critical_clients: Number of latency critical clients connected * @bus_bw_work: work for periodically computing DDR bus bandwidth requirements * @g_event_flags: a bitmap of hdd_driver_flags * @psoc_idle_timeout_work: delayed work for psoc idle shutdown @@ -1708,6 +1709,7 @@ struct hdd_context { int32_t oem_pid; #endif + qdf_atomic_t num_latency_critical_clients; /** Concurrency Parameters*/ uint32_t concurrency_mode; @@ -2537,6 +2539,54 @@ QDF_STATUS __wlan_hdd_validate_mac_address(struct qdf_mac_addr *mac_addr, */ bool hdd_is_any_adapter_connected(struct hdd_context *hdd_ctx); +/** + * hdd_add_latency_critical_client() - Add latency critical client + * @hdd_ctx: Global HDD context + * @phymode: the phymode of the connected adapter + * + * This function adds to the latency critical count if the present + * connection is also a latency critical one. + * + * Returns: None + */ +static inline void +hdd_add_latency_critical_client(struct hdd_context *hdd_ctx, + enum qca_wlan_802_11_mode phymode) +{ + switch (phymode) { + case QCA_WLAN_802_11_MODE_11A: + case QCA_WLAN_802_11_MODE_11G: + qdf_atomic_inc(&hdd_ctx->num_latency_critical_clients); + break; + default: + break; + } +} + +/** + * hdd_del_latency_critical_client() - Add tlatency critical client + * @hdd_ctx: Global HDD context + * @phymode: the phymode of the connected adapter + * + * This function removes from the latency critical count if the present + * connection is also a latency critical one. + * + * Returns: None + */ +static inline void +hdd_del_latency_critical_client(struct hdd_context *hdd_ctx, + enum qca_wlan_802_11_mode phymode) +{ + switch (phymode) { + case QCA_WLAN_802_11_MODE_11A: + case QCA_WLAN_802_11_MODE_11G: + qdf_atomic_dec(&hdd_ctx->num_latency_critical_clients); + break; + default: + break; + } +} + #ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH /** * hdd_bus_bw_compute_prev_txrx_stats() - get tx and rx stats diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index a5d197cebd5b..551d0f3e4434 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -1574,6 +1574,11 @@ static void hdd_send_association_event(struct net_device *dev, roam_info->tdls_prohibited, adapter->vdev); #endif + + hdd_add_latency_critical_client( + hdd_ctx, + hdd_convert_cfgdot11mode_to_80211mode( + sta_ctx->conn_info.dot11mode)); /* start timer in sta/p2p_cli */ hdd_bus_bw_compute_prev_txrx_stats(adapter); hdd_bus_bw_compute_timer_start(hdd_ctx); @@ -1613,6 +1618,10 @@ static void hdd_send_association_event(struct net_device *dev, false, adapter->vdev); + hdd_del_latency_critical_client( + hdd_ctx, + hdd_convert_cfgdot11mode_to_80211mode( + sta_ctx->conn_info.dot11mode)); /* stop timer in sta/p2p_cli */ hdd_bus_bw_compute_reset_prev_txrx_stats(adapter); hdd_bus_bw_compute_timer_try_stop(hdd_ctx); diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index c53e4b7557a2..42abedb23899 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -22977,6 +22977,37 @@ static int wlan_hdd_cfg80211_get_chainmask(struct wiphy *wiphy, return errno; } +enum qca_wlan_802_11_mode +hdd_convert_cfgdot11mode_to_80211mode(enum csr_cfgdot11mode mode) +{ + switch (mode) { + case eCSR_CFG_DOT11_MODE_11A: + return QCA_WLAN_802_11_MODE_11A; + case eCSR_CFG_DOT11_MODE_11B: + return QCA_WLAN_802_11_MODE_11B; + case eCSR_CFG_DOT11_MODE_11G: + return QCA_WLAN_802_11_MODE_11G; + case eCSR_CFG_DOT11_MODE_11N: + return QCA_WLAN_802_11_MODE_11N; + case eCSR_CFG_DOT11_MODE_11AC: + return QCA_WLAN_802_11_MODE_11AC; + case eCSR_CFG_DOT11_MODE_11G_ONLY: + return QCA_WLAN_802_11_MODE_11G; + case eCSR_CFG_DOT11_MODE_11N_ONLY: + return QCA_WLAN_802_11_MODE_11N; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + return QCA_WLAN_802_11_MODE_11AC; + case eCSR_CFG_DOT11_MODE_11AX: + return QCA_WLAN_802_11_MODE_11AX; + case eCSR_CFG_DOT11_MODE_11AX_ONLY: + return QCA_WLAN_802_11_MODE_11AX; + case eCSR_CFG_DOT11_MODE_ABG: + case eCSR_CFG_DOT11_MODE_AUTO: + default: + return QCA_WLAN_802_11_MODE_INVALID; + } +} + /** * struct cfg80211_ops - cfg80211_ops * diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index 8008466ad5a3..f20b99f8b4a6 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -816,4 +816,13 @@ void wlan_hdd_set_wlm_mode(struct hdd_context *hdd_ctx, uint16_t latency_level) } #endif +/** + * hdd_convert_cfgdot11mode_to_80211mode() - Function to convert cfg dot11 mode + * to 80211 mode + * @mode: cfg dot11 mode + * + * Return: 80211 mode + */ +enum qca_wlan_802_11_mode +hdd_convert_cfgdot11mode_to_80211mode(enum csr_cfgdot11mode mode); #endif diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index de55c7897107..34e6aecd74da 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -6243,6 +6243,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio } qdf_spinlock_create(&adapter->vdev_lock); + qdf_atomic_init(&hdd_ctx->num_latency_critical_clients); hdd_init_completion(adapter); INIT_WORK(&adapter->scan_block_work, wlan_hdd_cfg80211_scan_block_cb); @@ -8952,7 +8953,22 @@ static void hdd_pld_request_bus_bandwidth(struct hdd_context *hdd_ctx, hdd_ctx->cur_vote_level = next_vote_level; vote_level_change = true; - pld_request_bus_bandwidth(hdd_ctx->parent_dev, next_vote_level); + /* + * 11g/a clients are latency sensitive, and any delay in DDR + * access for fetching the packet can cause throughput drop. + * For 11g/a clients LOW voting level is not sufficient for + * peak throughput. Vote for higher DDR frequency if latency + * critical connections are present. + */ + if (hdd_ctx->config->enable_latency_crit_clients && + (next_vote_level == PLD_BUS_WIDTH_LOW || + next_vote_level == PLD_BUS_WIDTH_IDLE) && + qdf_atomic_read(&hdd_ctx->num_latency_critical_clients)) + pld_request_bus_bandwidth(hdd_ctx->parent_dev, + PLD_BUS_WIDTH_LOW_LATENCY); + else + pld_request_bus_bandwidth(hdd_ctx->parent_dev, + next_vote_level); if ((next_vote_level == PLD_BUS_WIDTH_LOW) || (next_vote_level == PLD_BUS_WIDTH_IDLE)) { @@ -14429,6 +14445,7 @@ exit: * connected */ if (!hdd_is_any_adapter_connected(hdd_ctx)) { + qdf_atomic_set(&hdd_ctx->num_latency_critical_clients, 0); hdd_ctx->cur_vote_level = PLD_BUS_WIDTH_NONE; pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_NONE); diff --git a/core/pld/inc/pld_common.h b/core/pld/inc/pld_common.h index 26803cf1a19a..4028a922548d 100644 --- a/core/pld/inc/pld_common.h +++ b/core/pld/inc/pld_common.h @@ -76,6 +76,7 @@ enum pld_bus_type { * @PLD_BUS_WIDTH_MEDIUM: vote for medium bus bandwidth * @PLD_BUS_WIDTH_HIGH: vote for high bus bandwidth * @PLD_BUS_WIDTH_VERY_HIGH: vote for very high bus bandwidth + * @PLD_BUS_WIDTH_LOW_LATENCY: vote for low latency bus bandwidth */ enum pld_bus_width_type { PLD_BUS_WIDTH_NONE, @@ -84,6 +85,7 @@ enum pld_bus_width_type { PLD_BUS_WIDTH_MEDIUM, PLD_BUS_WIDTH_HIGH, PLD_BUS_WIDTH_VERY_HIGH, + PLD_BUS_WIDTH_LOW_LATENCY, }; #define PLD_MAX_FILE_NAME NAME_MAX