aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-01-23 06:48:21 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2014-01-24 03:23:37 -0500
commit748afc4735361e21ad655c0dc021ea3aaeeb3efd (patch)
tree950155c5fdf8671375d4e0af21c7857645b5ee83
parentc2df44b39b31a730a89b13f7be90860d93d1f9d8 (diff)
ath10k: implement and use new beacon method
Until now ath10k used a copy-by-value beacon submission. The new method passes a DMA address via WMI command only. This command contains additional metadata that fixes AP behaviour with regard to powersave buffering. This also fixes strange bug when multicast traffic would freeze TX indefinitely. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h7
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c10
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c71
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h21
4 files changed, 85 insertions, 24 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8b145209d37d..c0b00e1f7562 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -73,6 +73,11 @@ struct ath10k_skb_cb {
73 u8 frag_len; 73 u8 frag_len;
74 u8 pad_len; 74 u8 pad_len;
75 } __packed htt; 75 } __packed htt;
76
77 struct {
78 bool dtim_zero;
79 bool deliver_cab;
80 } bcn;
76} __packed; 81} __packed;
77 82
78static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) 83static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
@@ -234,6 +239,8 @@ struct ath10k_vif {
234 u32 beacon_interval; 239 u32 beacon_interval;
235 u32 dtim_period; 240 u32 dtim_period;
236 struct sk_buff *beacon; 241 struct sk_buff *beacon;
242 /* protected by data_lock */
243 bool beacon_sent;
237 244
238 struct ath10k *ar; 245 struct ath10k *ar;
239 struct ieee80211_vif *vif; 246 struct ieee80211_vif *vif;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 4bf5f19602e4..bb1c8397c0d3 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -837,6 +837,16 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
837 arvif->is_started = false; 837 arvif->is_started = false;
838 arvif->is_up = false; 838 arvif->is_up = false;
839 839
840 spin_lock_bh(&arvif->ar->data_lock);
841 if (arvif->beacon) {
842 ath10k_skb_unmap(arvif->ar->dev, arvif->beacon);
843 dev_kfree_skb_any(arvif->beacon);
844
845 arvif->beacon = NULL;
846 arvif->beacon_sent = false;
847 }
848 spin_unlock_bh(&arvif->ar->data_lock);
849
840 return; 850 return;
841 } 851 }
842 852
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index a1ec5d0fb0ef..bd01f0a7dafb 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -561,7 +561,6 @@ err_pull:
561 561
562static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) 562static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
563{ 563{
564 struct wmi_bcn_tx_arg arg = {0};
565 int ret; 564 int ret;
566 565
567 lockdep_assert_held(&arvif->ar->data_lock); 566 lockdep_assert_held(&arvif->ar->data_lock);
@@ -569,18 +568,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
569 if (arvif->beacon == NULL) 568 if (arvif->beacon == NULL)
570 return; 569 return;
571 570
572 arg.vdev_id = arvif->vdev_id; 571 if (arvif->beacon_sent)
573 arg.tx_rate = 0; 572 return;
574 arg.tx_power = 0;
575 arg.bcn = arvif->beacon->data;
576 arg.bcn_len = arvif->beacon->len;
577 573
578 ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg); 574 ret = ath10k_wmi_beacon_send_ref_nowait(arvif);
579 if (ret) 575 if (ret)
580 return; 576 return;
581 577
582 dev_kfree_skb_any(arvif->beacon); 578 /* We need to retain the arvif->beacon reference for DMA unmapping and
583 arvif->beacon = NULL; 579 * freeing the skbuff later. */
580 arvif->beacon_sent = true;
584} 581}
585 582
586static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, 583static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
@@ -1237,6 +1234,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
1237 tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); 1234 tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
1238 memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); 1235 memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
1239 1236
1237 if (tim->dtim_count == 0) {
1238 ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
1239
1240 if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1)
1241 ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
1242 }
1243
1240 ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", 1244 ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
1241 tim->dtim_count, tim->dtim_period, 1245 tim->dtim_count, tim->dtim_period,
1242 tim->bitmap_ctrl, pvm_len); 1246 tim->bitmap_ctrl, pvm_len);
@@ -1427,13 +1431,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
1427 ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); 1431 ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
1428 1432
1429 spin_lock_bh(&ar->data_lock); 1433 spin_lock_bh(&ar->data_lock);
1434
1430 if (arvif->beacon) { 1435 if (arvif->beacon) {
1431 ath10k_warn("SWBA overrun on vdev %d\n", 1436 if (!arvif->beacon_sent)
1432 arvif->vdev_id); 1437 ath10k_warn("SWBA overrun on vdev %d\n",
1438 arvif->vdev_id);
1439
1440 ath10k_skb_unmap(ar->dev, arvif->beacon);
1433 dev_kfree_skb_any(arvif->beacon); 1441 dev_kfree_skb_any(arvif->beacon);
1434 } 1442 }
1435 1443
1444 ath10k_skb_map(ar->dev, bcn);
1445
1436 arvif->beacon = bcn; 1446 arvif->beacon = bcn;
1447 arvif->beacon_sent = false;
1437 1448
1438 ath10k_wmi_tx_beacon_nowait(arvif); 1449 ath10k_wmi_tx_beacon_nowait(arvif);
1439 spin_unlock_bh(&ar->data_lock); 1450 spin_unlock_bh(&ar->data_lock);
@@ -3442,25 +3453,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
3442 return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); 3453 return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
3443} 3454}
3444 3455
3445int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, 3456/* This function assumes the beacon is already DMA mapped */
3446 const struct wmi_bcn_tx_arg *arg) 3457int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
3447{ 3458{
3448 struct wmi_bcn_tx_cmd *cmd; 3459 struct wmi_bcn_tx_ref_cmd *cmd;
3449 struct sk_buff *skb; 3460 struct sk_buff *skb;
3461 struct sk_buff *beacon = arvif->beacon;
3462 struct ath10k *ar = arvif->ar;
3463 struct ieee80211_hdr *hdr;
3450 int ret; 3464 int ret;
3465 u16 fc;
3451 3466
3452 skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); 3467 skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
3453 if (!skb) 3468 if (!skb)
3454 return -ENOMEM; 3469 return -ENOMEM;
3455 3470
3456 cmd = (struct wmi_bcn_tx_cmd *)skb->data; 3471 hdr = (struct ieee80211_hdr *)beacon->data;
3457 cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id); 3472 fc = le16_to_cpu(hdr->frame_control);
3458 cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate); 3473
3459 cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); 3474 cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data;
3460 cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); 3475 cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
3461 memcpy(cmd->bcn, arg->bcn, arg->bcn_len); 3476 cmd->data_len = __cpu_to_le32(beacon->len);
3477 cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr);
3478 cmd->msdu_id = 0;
3479 cmd->frame_control = __cpu_to_le32(fc);
3480 cmd->flags = 0;
3481
3482 if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
3483 cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
3484
3485 if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab)
3486 cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
3487
3488 ret = ath10k_wmi_cmd_send_nowait(ar, skb,
3489 ar->wmi.cmd->pdev_send_bcn_cmdid);
3462 3490
3463 ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid);
3464 if (ret) 3491 if (ret)
3465 dev_kfree_skb(skb); 3492 dev_kfree_skb(skb);
3466 3493
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 9dc90c5dd0e4..9d9a81bfbb36 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -3403,6 +3403,24 @@ struct wmi_bcn_tx_arg {
3403 const void *bcn; 3403 const void *bcn;
3404}; 3404};
3405 3405
3406enum wmi_bcn_tx_ref_flags {
3407 WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1,
3408 WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
3409};
3410
3411struct wmi_bcn_tx_ref_cmd {
3412 __le32 vdev_id;
3413 __le32 data_len;
3414 /* physical address of the frame - dma pointer */
3415 __le32 data_ptr;
3416 /* id for host to track */
3417 __le32 msdu_id;
3418 /* frame ctrl to setup PPDU desc */
3419 __le32 frame_control;
3420 /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
3421 __le32 flags;
3422} __packed;
3423
3406/* Beacon filter */ 3424/* Beacon filter */
3407#define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ 3425#define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */
3408#define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ 3426#define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */
@@ -4223,8 +4241,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
4223 enum wmi_ap_ps_peer_param param_id, u32 value); 4241 enum wmi_ap_ps_peer_param param_id, u32 value);
4224int ath10k_wmi_scan_chan_list(struct ath10k *ar, 4242int ath10k_wmi_scan_chan_list(struct ath10k *ar,
4225 const struct wmi_scan_chan_list_arg *arg); 4243 const struct wmi_scan_chan_list_arg *arg);
4226int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, 4244int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
4227 const struct wmi_bcn_tx_arg *arg);
4228int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, 4245int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
4229 const struct wmi_pdev_set_wmm_params_arg *arg); 4246 const struct wmi_pdev_set_wmm_params_arg *arg);
4230int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); 4247int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);