diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2013-09-13 08:16:56 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2013-09-16 12:47:46 -0400 |
commit | ed54388a38d817dce7fe22e7dc80fc13b1a6838e (patch) | |
tree | 8af974a287b4ed329f511725b87a62265d362763 | |
parent | 12acbc43c1c302022984bf0af89ac5f0a24b133a (diff) |
ath10k: improve beacon submission latency
The patch prevents beacon misses in some case of
heavy load on a system.
If a beacon can't be transmitted directly from an
SWBA event it will be left in arvif->beacon and
transmission will be retried once TX credits
become available.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 74 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 3 |
4 files changed, 71 insertions, 14 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c953a3317d7b..14b7d3de6883 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -204,6 +204,7 @@ struct ath10k_vif { | |||
204 | enum wmi_vdev_subtype vdev_subtype; | 204 | enum wmi_vdev_subtype vdev_subtype; |
205 | u32 beacon_interval; | 205 | u32 beacon_interval; |
206 | u32 dtim_period; | 206 | u32 dtim_period; |
207 | struct sk_buff *beacon; | ||
207 | 208 | ||
208 | struct ath10k *ar; | 209 | struct ath10k *ar; |
209 | struct ieee80211_vif *vif; | 210 | struct ieee80211_vif *vif; |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8b9fb660519b..6c3e9d1f80d9 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -2075,6 +2075,13 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, | |||
2075 | 2075 | ||
2076 | mutex_lock(&ar->conf_mutex); | 2076 | mutex_lock(&ar->conf_mutex); |
2077 | 2077 | ||
2078 | spin_lock_bh(&ar->data_lock); | ||
2079 | if (arvif->beacon) { | ||
2080 | dev_kfree_skb_any(arvif->beacon); | ||
2081 | arvif->beacon = NULL; | ||
2082 | } | ||
2083 | spin_unlock_bh(&ar->data_lock); | ||
2084 | |||
2078 | ar->free_vdev_map |= 1 << (arvif->vdev_id); | 2085 | ar->free_vdev_map |= 1 << (arvif->vdev_id); |
2079 | 2086 | ||
2080 | if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { | 2087 | if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ff407c2f1d2b..9152daea9d96 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c | |||
@@ -120,8 +120,53 @@ err_pull: | |||
120 | return ret; | 120 | return ret; |
121 | } | 121 | } |
122 | 122 | ||
123 | static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) | ||
124 | { | ||
125 | struct wmi_bcn_tx_arg arg = {0}; | ||
126 | int ret; | ||
127 | |||
128 | lockdep_assert_held(&arvif->ar->data_lock); | ||
129 | |||
130 | if (arvif->beacon == NULL) | ||
131 | return; | ||
132 | |||
133 | arg.vdev_id = arvif->vdev_id; | ||
134 | arg.tx_rate = 0; | ||
135 | arg.tx_power = 0; | ||
136 | arg.bcn = arvif->beacon->data; | ||
137 | arg.bcn_len = arvif->beacon->len; | ||
138 | |||
139 | ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg); | ||
140 | if (ret) | ||
141 | return; | ||
142 | |||
143 | dev_kfree_skb_any(arvif->beacon); | ||
144 | arvif->beacon = NULL; | ||
145 | } | ||
146 | |||
147 | static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, | ||
148 | struct ieee80211_vif *vif) | ||
149 | { | ||
150 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | ||
151 | |||
152 | ath10k_wmi_tx_beacon_nowait(arvif); | ||
153 | } | ||
154 | |||
155 | static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar) | ||
156 | { | ||
157 | spin_lock_bh(&ar->data_lock); | ||
158 | ieee80211_iterate_active_interfaces_atomic(ar->hw, | ||
159 | IEEE80211_IFACE_ITER_NORMAL, | ||
160 | ath10k_wmi_tx_beacons_iter, | ||
161 | NULL); | ||
162 | spin_unlock_bh(&ar->data_lock); | ||
163 | } | ||
164 | |||
123 | static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar) | 165 | static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar) |
124 | { | 166 | { |
167 | /* try to send pending beacons first. they take priority */ | ||
168 | ath10k_wmi_tx_beacons_nowait(ar); | ||
169 | |||
125 | wake_up(&ar->wmi.tx_credits_wq); | 170 | wake_up(&ar->wmi.tx_credits_wq); |
126 | } | 171 | } |
127 | 172 | ||
@@ -131,6 +176,9 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, | |||
131 | int ret = -EINVAL; | 176 | int ret = -EINVAL; |
132 | 177 | ||
133 | wait_event_timeout(ar->wmi.tx_credits_wq, ({ | 178 | wait_event_timeout(ar->wmi.tx_credits_wq, ({ |
179 | /* try to send pending beacons first. they take priority */ | ||
180 | ath10k_wmi_tx_beacons_nowait(ar); | ||
181 | |||
134 | ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id); | 182 | ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id); |
135 | (ret != -EAGAIN); | 183 | (ret != -EAGAIN); |
136 | }), 3*HZ); | 184 | }), 3*HZ); |
@@ -760,10 +808,8 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) | |||
760 | int i = -1; | 808 | int i = -1; |
761 | struct wmi_bcn_info *bcn_info; | 809 | struct wmi_bcn_info *bcn_info; |
762 | struct ath10k_vif *arvif; | 810 | struct ath10k_vif *arvif; |
763 | struct wmi_bcn_tx_arg arg; | ||
764 | struct sk_buff *bcn; | 811 | struct sk_buff *bcn; |
765 | int vdev_id = 0; | 812 | int vdev_id = 0; |
766 | int ret; | ||
767 | 813 | ||
768 | ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n"); | 814 | ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n"); |
769 | 815 | ||
@@ -820,17 +866,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) | |||
820 | ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); | 866 | ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); |
821 | ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); | 867 | ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); |
822 | 868 | ||
823 | arg.vdev_id = arvif->vdev_id; | 869 | spin_lock_bh(&ar->data_lock); |
824 | arg.tx_rate = 0; | 870 | if (arvif->beacon) { |
825 | arg.tx_power = 0; | 871 | ath10k_warn("SWBA overrun on vdev %d\n", |
826 | arg.bcn = bcn->data; | 872 | arvif->vdev_id); |
827 | arg.bcn_len = bcn->len; | 873 | dev_kfree_skb_any(arvif->beacon); |
874 | } | ||
828 | 875 | ||
829 | ret = ath10k_wmi_beacon_send(ar, &arg); | 876 | arvif->beacon = bcn; |
830 | if (ret) | ||
831 | ath10k_warn("could not send beacon (%d)\n", ret); | ||
832 | 877 | ||
833 | dev_kfree_skb_any(bcn); | 878 | ath10k_wmi_tx_beacon_nowait(arvif); |
879 | spin_unlock_bh(&ar->data_lock); | ||
834 | } | 880 | } |
835 | } | 881 | } |
836 | 882 | ||
@@ -1181,6 +1227,7 @@ static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) | |||
1181 | * thus can't be defered to a worker thread */ | 1227 | * thus can't be defered to a worker thread */ |
1182 | switch (event_id) { | 1228 | switch (event_id) { |
1183 | case WMI_MGMT_RX_EVENTID: | 1229 | case WMI_MGMT_RX_EVENTID: |
1230 | case WMI_HOST_SWBA_EVENTID: | ||
1184 | ath10k_wmi_event_process(ar, skb); | 1231 | ath10k_wmi_event_process(ar, skb); |
1185 | return; | 1232 | return; |
1186 | default: | 1233 | default: |
@@ -2138,7 +2185,8 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, | |||
2138 | return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID); | 2185 | return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID); |
2139 | } | 2186 | } |
2140 | 2187 | ||
2141 | int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg) | 2188 | int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, |
2189 | const struct wmi_bcn_tx_arg *arg) | ||
2142 | { | 2190 | { |
2143 | struct wmi_bcn_tx_cmd *cmd; | 2191 | struct wmi_bcn_tx_cmd *cmd; |
2144 | struct sk_buff *skb; | 2192 | struct sk_buff *skb; |
@@ -2154,7 +2202,7 @@ int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg) | |||
2154 | cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); | 2202 | cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); |
2155 | memcpy(cmd->bcn, arg->bcn, arg->bcn_len); | 2203 | memcpy(cmd->bcn, arg->bcn, arg->bcn_len); |
2156 | 2204 | ||
2157 | return ath10k_wmi_cmd_send(ar, skb, WMI_BCN_TX_CMDID); | 2205 | return ath10k_wmi_cmd_send_nowait(ar, skb, WMI_BCN_TX_CMDID); |
2158 | } | 2206 | } |
2159 | 2207 | ||
2160 | static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, | 2208 | static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index ab46582d4eaa..b100431f2241 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h | |||
@@ -3110,7 +3110,8 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, | |||
3110 | enum wmi_ap_ps_peer_param param_id, u32 value); | 3110 | enum wmi_ap_ps_peer_param param_id, u32 value); |
3111 | int ath10k_wmi_scan_chan_list(struct ath10k *ar, | 3111 | int ath10k_wmi_scan_chan_list(struct ath10k *ar, |
3112 | const struct wmi_scan_chan_list_arg *arg); | 3112 | const struct wmi_scan_chan_list_arg *arg); |
3113 | int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg); | 3113 | int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, |
3114 | const struct wmi_bcn_tx_arg *arg); | ||
3114 | int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, | 3115 | int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, |
3115 | const struct wmi_pdev_set_wmm_params_arg *arg); | 3116 | const struct wmi_pdev_set_wmm_params_arg *arg); |
3116 | int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); | 3117 | int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); |