diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-02-14 08:49:48 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-02-15 01:49:02 -0500 |
commit | 9797febc4cc112869b19a110f70e0dedb1bb63d6 (patch) | |
tree | 71620df5981f1f1b9600c3002e4a6e4915385a1e /drivers/net/wireless | |
parent | 90046f509dca8e754b75aacb6ef7afa68b102c63 (diff) |
ath10k: implement sta_rc_update()
This allows dynamic changes of bandwidth/nss/smps,
e.g. via ht/vht operation mode change
notification.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 157 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 6 |
3 files changed, 175 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index fae53f909550..1fc26fe057e8 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -228,6 +228,18 @@ struct ath10k_peer { | |||
228 | struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; | 228 | struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; |
229 | }; | 229 | }; |
230 | 230 | ||
231 | struct ath10k_sta { | ||
232 | struct ath10k_vif *arvif; | ||
233 | |||
234 | /* the following are protected by ar->data_lock */ | ||
235 | u32 changed; /* IEEE80211_RC_* */ | ||
236 | u32 bw; | ||
237 | u32 nss; | ||
238 | u32 smps; | ||
239 | |||
240 | struct work_struct update_wk; | ||
241 | }; | ||
242 | |||
231 | #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) | 243 | #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) |
232 | 244 | ||
233 | struct ath10k_vif { | 245 | struct ath10k_vif { |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c2aaecb4c25b..e17f5d732b5a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -3104,6 +3104,69 @@ exit: | |||
3104 | return ret; | 3104 | return ret; |
3105 | } | 3105 | } |
3106 | 3106 | ||
3107 | static void ath10k_sta_rc_update_wk(struct work_struct *wk) | ||
3108 | { | ||
3109 | struct ath10k *ar; | ||
3110 | struct ath10k_vif *arvif; | ||
3111 | struct ath10k_sta *arsta; | ||
3112 | struct ieee80211_sta *sta; | ||
3113 | u32 changed, bw, nss, smps; | ||
3114 | int err; | ||
3115 | |||
3116 | arsta = container_of(wk, struct ath10k_sta, update_wk); | ||
3117 | sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); | ||
3118 | arvif = arsta->arvif; | ||
3119 | ar = arvif->ar; | ||
3120 | |||
3121 | spin_lock_bh(&ar->data_lock); | ||
3122 | |||
3123 | changed = arsta->changed; | ||
3124 | arsta->changed = 0; | ||
3125 | |||
3126 | bw = arsta->bw; | ||
3127 | nss = arsta->nss; | ||
3128 | smps = arsta->smps; | ||
3129 | |||
3130 | spin_unlock_bh(&ar->data_lock); | ||
3131 | |||
3132 | mutex_lock(&ar->conf_mutex); | ||
3133 | |||
3134 | if (changed & IEEE80211_RC_BW_CHANGED) { | ||
3135 | ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", | ||
3136 | sta->addr, bw); | ||
3137 | |||
3138 | err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, | ||
3139 | WMI_PEER_CHAN_WIDTH, bw); | ||
3140 | if (err) | ||
3141 | ath10k_warn("failed to update STA %pM peer bw %d: %d\n", | ||
3142 | sta->addr, bw, err); | ||
3143 | } | ||
3144 | |||
3145 | if (changed & IEEE80211_RC_NSS_CHANGED) { | ||
3146 | ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n", | ||
3147 | sta->addr, nss); | ||
3148 | |||
3149 | err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, | ||
3150 | WMI_PEER_NSS, nss); | ||
3151 | if (err) | ||
3152 | ath10k_warn("failed to update STA %pM nss %d: %d\n", | ||
3153 | sta->addr, nss, err); | ||
3154 | } | ||
3155 | |||
3156 | if (changed & IEEE80211_RC_SMPS_CHANGED) { | ||
3157 | ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n", | ||
3158 | sta->addr, smps); | ||
3159 | |||
3160 | err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, | ||
3161 | WMI_PEER_SMPS_STATE, smps); | ||
3162 | if (err) | ||
3163 | ath10k_warn("failed to update STA %pM smps %d: %d\n", | ||
3164 | sta->addr, smps, err); | ||
3165 | } | ||
3166 | |||
3167 | mutex_unlock(&ar->conf_mutex); | ||
3168 | } | ||
3169 | |||
3107 | static int ath10k_sta_state(struct ieee80211_hw *hw, | 3170 | static int ath10k_sta_state(struct ieee80211_hw *hw, |
3108 | struct ieee80211_vif *vif, | 3171 | struct ieee80211_vif *vif, |
3109 | struct ieee80211_sta *sta, | 3172 | struct ieee80211_sta *sta, |
@@ -3112,9 +3175,15 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, | |||
3112 | { | 3175 | { |
3113 | struct ath10k *ar = hw->priv; | 3176 | struct ath10k *ar = hw->priv; |
3114 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | 3177 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
3178 | struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; | ||
3115 | int max_num_peers; | 3179 | int max_num_peers; |
3116 | int ret = 0; | 3180 | int ret = 0; |
3117 | 3181 | ||
3182 | /* cancel must be done outside the mutex to avoid deadlock */ | ||
3183 | if ((old_state == IEEE80211_STA_NONE && | ||
3184 | new_state == IEEE80211_STA_NOTEXIST)) | ||
3185 | cancel_work_sync(&arsta->update_wk); | ||
3186 | |||
3118 | mutex_lock(&ar->conf_mutex); | 3187 | mutex_lock(&ar->conf_mutex); |
3119 | 3188 | ||
3120 | if (old_state == IEEE80211_STA_NOTEXIST && | 3189 | if (old_state == IEEE80211_STA_NOTEXIST && |
@@ -3139,6 +3208,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, | |||
3139 | "mac vdev %d peer create %pM (new sta) num_peers %d\n", | 3208 | "mac vdev %d peer create %pM (new sta) num_peers %d\n", |
3140 | arvif->vdev_id, sta->addr, ar->num_peers); | 3209 | arvif->vdev_id, sta->addr, ar->num_peers); |
3141 | 3210 | ||
3211 | memset(arsta, 0, sizeof(*arsta)); | ||
3212 | arsta->arvif = arvif; | ||
3213 | INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); | ||
3214 | |||
3142 | ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); | 3215 | ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); |
3143 | if (ret) | 3216 | if (ret) |
3144 | ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", | 3217 | ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", |
@@ -3905,6 +3978,88 @@ static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw, | |||
3905 | return; | 3978 | return; |
3906 | } | 3979 | } |
3907 | 3980 | ||
3981 | static void ath10k_sta_rc_update(struct ieee80211_hw *hw, | ||
3982 | struct ieee80211_vif *vif, | ||
3983 | struct ieee80211_sta *sta, | ||
3984 | u32 changed) | ||
3985 | { | ||
3986 | struct ath10k *ar = hw->priv; | ||
3987 | struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; | ||
3988 | u32 bw, smps; | ||
3989 | |||
3990 | spin_lock_bh(&ar->data_lock); | ||
3991 | |||
3992 | ath10k_dbg(ATH10K_DBG_MAC, | ||
3993 | "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", | ||
3994 | sta->addr, changed, sta->bandwidth, sta->rx_nss, | ||
3995 | sta->smps_mode); | ||
3996 | |||
3997 | if (changed & IEEE80211_RC_BW_CHANGED) { | ||
3998 | bw = WMI_PEER_CHWIDTH_20MHZ; | ||
3999 | |||
4000 | switch (sta->bandwidth) { | ||
4001 | case IEEE80211_STA_RX_BW_20: | ||
4002 | bw = WMI_PEER_CHWIDTH_20MHZ; | ||
4003 | break; | ||
4004 | case IEEE80211_STA_RX_BW_40: | ||
4005 | bw = WMI_PEER_CHWIDTH_40MHZ; | ||
4006 | break; | ||
4007 | case IEEE80211_STA_RX_BW_80: | ||
4008 | bw = WMI_PEER_CHWIDTH_80MHZ; | ||
4009 | break; | ||
4010 | case IEEE80211_STA_RX_BW_160: | ||
4011 | ath10k_warn("mac sta rc update for %pM: invalid bw %d\n", | ||
4012 | sta->addr, sta->bandwidth); | ||
4013 | bw = WMI_PEER_CHWIDTH_20MHZ; | ||
4014 | break; | ||
4015 | } | ||
4016 | |||
4017 | arsta->bw = bw; | ||
4018 | } | ||
4019 | |||
4020 | if (changed & IEEE80211_RC_NSS_CHANGED) | ||
4021 | arsta->nss = sta->rx_nss; | ||
4022 | |||
4023 | if (changed & IEEE80211_RC_SMPS_CHANGED) { | ||
4024 | smps = WMI_PEER_SMPS_PS_NONE; | ||
4025 | |||
4026 | switch (sta->smps_mode) { | ||
4027 | case IEEE80211_SMPS_AUTOMATIC: | ||
4028 | case IEEE80211_SMPS_OFF: | ||
4029 | smps = WMI_PEER_SMPS_PS_NONE; | ||
4030 | break; | ||
4031 | case IEEE80211_SMPS_STATIC: | ||
4032 | smps = WMI_PEER_SMPS_STATIC; | ||
4033 | break; | ||
4034 | case IEEE80211_SMPS_DYNAMIC: | ||
4035 | smps = WMI_PEER_SMPS_DYNAMIC; | ||
4036 | break; | ||
4037 | case IEEE80211_SMPS_NUM_MODES: | ||
4038 | ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n", | ||
4039 | sta->addr, sta->smps_mode); | ||
4040 | smps = WMI_PEER_SMPS_PS_NONE; | ||
4041 | break; | ||
4042 | } | ||
4043 | |||
4044 | arsta->smps = smps; | ||
4045 | } | ||
4046 | |||
4047 | if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { | ||
4048 | /* FIXME: Not implemented. Probably the only way to do it would | ||
4049 | * be to re-assoc the peer. */ | ||
4050 | changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED; | ||
4051 | ath10k_dbg(ATH10K_DBG_MAC, | ||
4052 | "mac sta rc update for %pM: changing supported rates not implemented\n", | ||
4053 | sta->addr); | ||
4054 | } | ||
4055 | |||
4056 | arsta->changed |= changed; | ||
4057 | |||
4058 | spin_unlock_bh(&ar->data_lock); | ||
4059 | |||
4060 | ieee80211_queue_work(hw, &arsta->update_wk); | ||
4061 | } | ||
4062 | |||
3908 | static const struct ieee80211_ops ath10k_ops = { | 4063 | static const struct ieee80211_ops ath10k_ops = { |
3909 | .tx = ath10k_tx, | 4064 | .tx = ath10k_tx, |
3910 | .start = ath10k_start, | 4065 | .start = ath10k_start, |
@@ -3929,6 +4084,7 @@ static const struct ieee80211_ops ath10k_ops = { | |||
3929 | .get_survey = ath10k_get_survey, | 4084 | .get_survey = ath10k_get_survey, |
3930 | .set_bitrate_mask = ath10k_set_bitrate_mask, | 4085 | .set_bitrate_mask = ath10k_set_bitrate_mask, |
3931 | .channel_switch_beacon = ath10k_channel_switch_beacon, | 4086 | .channel_switch_beacon = ath10k_channel_switch_beacon, |
4087 | .sta_rc_update = ath10k_sta_rc_update, | ||
3932 | #ifdef CONFIG_PM | 4088 | #ifdef CONFIG_PM |
3933 | .suspend = ath10k_suspend, | 4089 | .suspend = ath10k_suspend, |
3934 | .resume = ath10k_resume, | 4090 | .resume = ath10k_resume, |
@@ -4304,6 +4460,7 @@ int ath10k_mac_register(struct ath10k *ar) | |||
4304 | ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; | 4460 | ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; |
4305 | 4461 | ||
4306 | ar->hw->vif_data_size = sizeof(struct ath10k_vif); | 4462 | ar->hw->vif_data_size = sizeof(struct ath10k_vif); |
4463 | ar->hw->sta_data_size = sizeof(struct ath10k_sta); | ||
4307 | 4464 | ||
4308 | ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; | 4465 | ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; |
4309 | 4466 | ||
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index fc1093a51ab1..4fcc96aa9513 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h | |||
@@ -3876,6 +3876,12 @@ enum wmi_peer_smps_state { | |||
3876 | WMI_PEER_SMPS_DYNAMIC = 0x2 | 3876 | WMI_PEER_SMPS_DYNAMIC = 0x2 |
3877 | }; | 3877 | }; |
3878 | 3878 | ||
3879 | enum wmi_peer_chwidth { | ||
3880 | WMI_PEER_CHWIDTH_20MHZ = 0, | ||
3881 | WMI_PEER_CHWIDTH_40MHZ = 1, | ||
3882 | WMI_PEER_CHWIDTH_80MHZ = 2, | ||
3883 | }; | ||
3884 | |||
3879 | enum wmi_peer_param { | 3885 | enum wmi_peer_param { |
3880 | WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ | 3886 | WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ |
3881 | WMI_PEER_AMPDU = 0x2, | 3887 | WMI_PEER_AMPDU = 0x2, |