aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-02-14 08:49:48 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2014-02-15 01:49:02 -0500
commit9797febc4cc112869b19a110f70e0dedb1bb63d6 (patch)
tree71620df5981f1f1b9600c3002e4a6e4915385a1e /drivers/net/wireless
parent90046f509dca8e754b75aacb6ef7afa68b102c63 (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.h12
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c157
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h6
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
231struct 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
233struct ath10k_vif { 245struct 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
3107static 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
3107static int ath10k_sta_state(struct ieee80211_hw *hw, 3170static 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
3981static 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
3908static const struct ieee80211_ops ath10k_ops = { 4063static 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
3879enum wmi_peer_chwidth {
3880 WMI_PEER_CHWIDTH_20MHZ = 0,
3881 WMI_PEER_CHWIDTH_40MHZ = 1,
3882 WMI_PEER_CHWIDTH_80MHZ = 2,
3883};
3884
3879enum wmi_peer_param { 3885enum 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,