Commit cfd1061e authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: fix station count enforcement

The number of peers isn't directly translatable to
the number of stations because ath10k needs to
reserve a few extra peers for special cases like
multi-vif concurrency.

The previous limit was 126 and 15 stations in AP
mode for 10.x and main firmware branches
respectively. The limit is now 128 and 16 which
was the original intention.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 292a753d
...@@ -799,6 +799,17 @@ static void ath10k_core_restart(struct work_struct *work) ...@@ -799,6 +799,17 @@ static void ath10k_core_restart(struct work_struct *work)
mutex_unlock(&ar->conf_mutex); 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 ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
{ {
int status; int status;
...@@ -1035,6 +1046,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ...@@ -1035,6 +1046,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
return ret; return ret;
} }
ath10k_core_init_max_sta_count(ar);
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
......
...@@ -566,6 +566,10 @@ struct ath10k { ...@@ -566,6 +566,10 @@ struct ath10k {
/* protected by conf_mutex */ /* protected by conf_mutex */
int num_peers; int num_peers;
int num_stations;
int max_num_peers;
int max_num_stations;
struct work_struct offchan_tx_work; struct work_struct offchan_tx_work;
struct sk_buff_head offchan_tx_queue; struct sk_buff_head offchan_tx_queue;
......
...@@ -123,7 +123,7 @@ EXPORT_SYMBOL(ath10k_info); ...@@ -123,7 +123,7 @@ EXPORT_SYMBOL(ath10k_info);
void ath10k_print_driver_info(struct ath10k *ar) 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->hw_params.name,
ar->target_version, ar->target_version,
ar->chip_id, ar->chip_id,
...@@ -135,7 +135,8 @@ void ath10k_print_driver_info(struct ath10k *ar) ...@@ -135,7 +135,8 @@ void ath10k_print_driver_info(struct ath10k *ar)
ar->fw_version_minor, ar->fw_version_minor,
ar->fw_version_release, ar->fw_version_release,
ar->fw_version_build, 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", ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
config_enabled(CONFIG_ATH10K_DEBUG), config_enabled(CONFIG_ATH10K_DEBUG),
config_enabled(CONFIG_ATH10K_DEBUGFS), config_enabled(CONFIG_ATH10K_DEBUGFS),
......
...@@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr { ...@@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr {
#define TARGET_DMA_BURST_SIZE 0 #define TARGET_DMA_BURST_SIZE 0
#define TARGET_MAC_AGGR_DELIM 0 #define TARGET_MAC_AGGR_DELIM 0
#define TARGET_AST_SKID_LIMIT 16 #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_PEERS 0
#define TARGET_NUM_OFFLOAD_REORDER_BUFS 0 #define TARGET_NUM_OFFLOAD_REORDER_BUFS 0
#define TARGET_NUM_PEER_KEYS 2 #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_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_RX_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 #define TARGET_RX_TIMEOUT_LO_PRI 100
...@@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr { ...@@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr {
#define TARGET_10X_DMA_BURST_SIZE 0 #define TARGET_10X_DMA_BURST_SIZE 0
#define TARGET_10X_MAC_AGGR_DELIM 0 #define TARGET_10X_MAC_AGGR_DELIM 0
#define TARGET_10X_AST_SKID_LIMIT 16 #define TARGET_10X_AST_SKID_LIMIT 16
#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS)) #define TARGET_10X_NUM_STATIONS 128
#define TARGET_10X_NUM_PEERS_MAX 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_PEERS 0
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
#define TARGET_10X_NUM_PEER_KEYS 2 #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_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_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#define TARGET_10X_RX_TIMEOUT_LO_PRI 100 #define TARGET_10X_RX_TIMEOUT_LO_PRI 100
......
...@@ -355,6 +355,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) ...@@ -355,6 +355,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
lockdep_assert_held(&ar->conf_mutex); 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); ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n", 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) ...@@ -500,6 +503,7 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
ar->num_peers = 0; ar->num_peers = 0;
ar->num_stations = 0;
} }
/************************/ /************************/
...@@ -3596,6 +3600,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) ...@@ -3596,6 +3600,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_unlock(&ar->conf_mutex); 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, static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
...@@ -3605,7 +3640,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ...@@ -3605,7 +3640,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
int max_num_peers;
int ret = 0; int ret = 0;
if (old_state == IEEE80211_STA_NOTEXIST && if (old_state == IEEE80211_STA_NOTEXIST &&
...@@ -3627,26 +3661,24 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ...@@ -3627,26 +3661,24 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/* /*
* New station addition. * New station addition.
*/ */
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) ath10k_dbg(ar, ATH10K_DBG_MAC,
max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1; "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
else arvif->vdev_id, sta->addr,
max_num_peers = TARGET_NUM_PEERS; ar->num_stations + 1, ar->max_num_stations,
ar->num_peers + 1, ar->max_num_peers);
if (ar->num_peers >= max_num_peers) { ret = ath10k_mac_inc_num_stations(arvif);
ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n", if (ret) {
ar->num_peers, max_num_peers); ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n",
ret = -ENOBUFS; ar->max_num_stations);
goto exit; 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); ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
sta->addr, arvif->vdev_id, ret); sta->addr, arvif->vdev_id, ret);
ath10k_mac_dec_num_stations(arvif);
goto exit; goto exit;
} }
...@@ -3659,6 +3691,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ...@@ -3659,6 +3691,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
arvif->vdev_id, ret); arvif->vdev_id, ret);
WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id, WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
sta->addr)); sta->addr));
ath10k_mac_dec_num_stations(arvif);
goto exit; goto exit;
} }
...@@ -3689,6 +3722,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ...@@ -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", ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
sta->addr, arvif->vdev_id, ret); sta->addr, arvif->vdev_id, ret);
ath10k_mac_dec_num_stations(arvif);
} else if (old_state == IEEE80211_STA_AUTH && } else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_ASSOC &&
(vif->type == NL80211_IFTYPE_AP || (vif->type == NL80211_IFTYPE_AP ||
......
...@@ -3181,7 +3181,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) ...@@ -3181,7 +3181,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
u32 len, val; u32 len, val;
config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); 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_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS);
config.num_offload_reorder_bufs = config.num_offload_reorder_bufs =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment