diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f660553c6c48..7762061a1944 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -799,6 +799,17 @@ static void ath10k_core_restart(struct work_struct *work) mutex_unlock(&ar->conf_mutex); } +static void ath10k_core_init_max_sta_count(struct ath10k *ar) +{ + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + ar->max_num_peers = TARGET_10X_NUM_PEERS; + ar->max_num_stations = TARGET_10X_NUM_STATIONS; + } else { + ar->max_num_peers = TARGET_NUM_PEERS; + ar->max_num_stations = TARGET_NUM_STATIONS; + } +} + int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) { int status; @@ -1035,6 +1046,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar) return ret; } + ath10k_core_init_max_sta_count(ar); + mutex_lock(&ar->conf_mutex); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 0a0182107dc9..4a294987736c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -566,6 +566,10 @@ struct ath10k { /* protected by conf_mutex */ int num_peers; + int num_stations; + + int max_num_peers; + int max_num_stations; struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index ff831ca507f7..c096d00aab97 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -123,7 +123,7 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -135,7 +135,8 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->fw_version_minor, ar->fw_version_release, ar->fw_version_build, - ath10k_cal_mode_str(ar->cal_mode)); + ath10k_cal_mode_str(ar->cal_mode), + ar->max_num_stations); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", config_enabled(CONFIG_ATH10K_DEBUG), config_enabled(CONFIG_ATH10K_DEBUGFS), diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 392c2501d0a1..dfedfd0e0f34 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr { #define TARGET_DMA_BURST_SIZE 0 #define TARGET_MAC_AGGR_DELIM 0 #define TARGET_AST_SKID_LIMIT 16 -#define TARGET_NUM_PEERS 16 +#define TARGET_NUM_STATIONS 16 +#define TARGET_NUM_PEERS ((TARGET_NUM_STATIONS) + \ + (TARGET_NUM_VDEVS)) #define TARGET_NUM_OFFLOAD_PEERS 0 #define TARGET_NUM_OFFLOAD_REORDER_BUFS 0 #define TARGET_NUM_PEER_KEYS 2 -#define TARGET_NUM_TIDS (2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS))) +#define TARGET_NUM_TIDS ((TARGET_NUM_PEERS) * 2) #define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_RX_TIMEOUT_LO_PRI 100 @@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr { #define TARGET_10X_DMA_BURST_SIZE 0 #define TARGET_10X_MAC_AGGR_DELIM 0 #define TARGET_10X_AST_SKID_LIMIT 16 -#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS)) -#define TARGET_10X_NUM_PEERS_MAX 128 +#define TARGET_10X_NUM_STATIONS 128 +#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \ + (TARGET_10X_NUM_VDEVS)) #define TARGET_10X_NUM_OFFLOAD_PEERS 0 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0 #define TARGET_10X_NUM_PEER_KEYS 2 -#define TARGET_10X_NUM_TIDS 256 +#define TARGET_10X_NUM_TIDS_MAX 256 +#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \ + (TARGET_10X_NUM_PEERS) * 2) #define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_10X_RX_TIMEOUT_LO_PRI 100 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index bb138ceca2b9..e475cc4095b6 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -355,6 +355,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) lockdep_assert_held(&ar->conf_mutex); + if (ar->num_peers >= ar->max_num_peers) + return -ENOBUFS; + ret = ath10k_wmi_peer_create(ar, vdev_id, addr); if (ret) { ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n", @@ -500,6 +503,7 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar) spin_unlock_bh(&ar->data_lock); ar->num_peers = 0; + ar->num_stations = 0; } /************************/ @@ -3596,6 +3600,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) mutex_unlock(&ar->conf_mutex); } +static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + + lockdep_assert_held(&ar->conf_mutex); + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP && + arvif->vdev_type != WMI_VDEV_TYPE_IBSS) + return 0; + + if (ar->num_stations >= ar->max_num_stations) + return -ENOBUFS; + + ar->num_stations++; + + return 0; +} + +static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + + lockdep_assert_held(&ar->conf_mutex); + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP && + arvif->vdev_type != WMI_VDEV_TYPE_IBSS) + return; + + ar->num_stations--; +} + static int ath10k_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -3605,7 +3640,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; - int max_num_peers; int ret = 0; if (old_state == IEEE80211_STA_NOTEXIST && @@ -3627,26 +3661,24 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, /* * New station addition. */ - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1; - else - max_num_peers = TARGET_NUM_PEERS; + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n", + arvif->vdev_id, sta->addr, + ar->num_stations + 1, ar->max_num_stations, + ar->num_peers + 1, ar->max_num_peers); - if (ar->num_peers >= max_num_peers) { - ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n", - ar->num_peers, max_num_peers); - ret = -ENOBUFS; + ret = ath10k_mac_inc_num_stations(arvif); + if (ret) { + ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n", + ar->max_num_stations); goto exit; } - ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac vdev %d peer create %pM (new sta) num_peers %d\n", - arvif->vdev_id, sta->addr, ar->num_peers); - ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); if (ret) { ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", sta->addr, arvif->vdev_id, ret); + ath10k_mac_dec_num_stations(arvif); goto exit; } @@ -3659,6 +3691,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arvif->vdev_id, ret); WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id, sta->addr)); + ath10k_mac_dec_num_stations(arvif); goto exit; } @@ -3689,6 +3722,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", sta->addr, arvif->vdev_id, ret); + ath10k_mac_dec_num_stations(arvif); } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP || diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7dd7c78ec195..23fee9a0530a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3181,7 +3181,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) u32 len, val; config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); - config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS); + config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS); config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS); config.num_offload_reorder_bufs =