diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-01-23 06:48:21 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-01-24 03:23:37 -0500 |
commit | 748afc4735361e21ad655c0dc021ea3aaeeb3efd (patch) | |
tree | 950155c5fdf8671375d4e0af21c7857645b5ee83 /drivers/net/wireless/ath/ath10k/wmi.c | |
parent | c2df44b39b31a730a89b13f7be90860d93d1f9d8 (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>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/wmi.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 71 |
1 files changed, 49 insertions, 22 deletions
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 | ||
562 | static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) | 562 | static 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 | ||
586 | static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, | 583 | static 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 | ||
3445 | int 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) | 3457 | int 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 | ||