Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ath10k: fix offchannel tx failure when no ath10k_mac_tx_frm_has_freq

Offchannel management frames were failing:

[18099.253732] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3780
[18102.293686] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3780
[18105.333653] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3780
[18108.373712] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3780
[18111.413687] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e36c0
[18114.453726] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3f00
[18117.493773] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e36c0
[18120.533631] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3f00

This bug appears to have been added between 4.0 (which works for us),
and 4.4, which does not work.

I think this is because the tx-offchannel logic gets in a loop when
ath10k_mac_tx_frm_has_freq(ar) is false, so pkt is never actually
sent to the firmware for transmit.

This patch fixes the problem on 4.9 for me, and now HS20 clients
can work again with my firmware.

Antonio: tested with 10.4-3.5.3-00057 on QCA4019 and QCA9888

Signed-off-by: Ben Greear <greearb@candelatech.com>
Tested-by: Antonio Quartulli <antonio.quartulli@kaiwoo.ai>
[kvalo@codeaurora.org: improve commit log, remove unneeded parenthesis]
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>

authored by

Ben Greear and committed by
Kalle Valo
cc6df017 cd486e62

+11 -11
+11 -11
drivers/net/wireless/ath/ath10k/mac.c
··· 3708 3708 struct ieee80211_vif *vif, 3709 3709 enum ath10k_hw_txrx_mode txmode, 3710 3710 enum ath10k_mac_tx_path txpath, 3711 - struct sk_buff *skb) 3711 + struct sk_buff *skb, bool noque_offchan) 3712 3712 { 3713 3713 struct ieee80211_hw *hw = ar->hw; 3714 3714 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ··· 3738 3738 } 3739 3739 } 3740 3740 3741 - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { 3741 + if (!noque_offchan && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { 3742 3742 if (!ath10k_mac_tx_frm_has_freq(ar)) { 3743 - ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %pK\n", 3744 - skb); 3743 + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac queued offchannel skb %pK len %d\n", 3744 + skb, skb->len); 3745 3745 3746 3746 skb_queue_tail(&ar->offchan_tx_queue, skb); 3747 3747 ieee80211_queue_work(hw, &ar->offchan_tx_work); ··· 3803 3803 3804 3804 mutex_lock(&ar->conf_mutex); 3805 3805 3806 - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK\n", 3807 - skb); 3806 + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK len %d\n", 3807 + skb, skb->len); 3808 3808 3809 3809 hdr = (struct ieee80211_hdr *)skb->data; 3810 3810 peer_addr = ieee80211_get_DA(hdr); ··· 3850 3850 txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); 3851 3851 txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode); 3852 3852 3853 - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); 3853 + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, true); 3854 3854 if (ret) { 3855 3855 ath10k_warn(ar, "failed to transmit offchannel frame: %d\n", 3856 3856 ret); ··· 3860 3860 time_left = 3861 3861 wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); 3862 3862 if (time_left == 0) 3863 - ath10k_warn(ar, "timed out waiting for offchannel skb %pK\n", 3864 - skb); 3863 + ath10k_warn(ar, "timed out waiting for offchannel skb %pK, len: %d\n", 3864 + skb, skb->len); 3865 3865 3866 3866 if (!peer && tmp_peer_created) { 3867 3867 ret = ath10k_peer_delete(ar, vdev_id, peer_addr); ··· 4097 4097 spin_unlock_bh(&ar->htt.tx_lock); 4098 4098 } 4099 4099 4100 - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); 4100 + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); 4101 4101 if (unlikely(ret)) { 4102 4102 ath10k_warn(ar, "failed to push frame: %d\n", ret); 4103 4103 ··· 4378 4378 spin_unlock_bh(&ar->htt.tx_lock); 4379 4379 } 4380 4380 4381 - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); 4381 + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); 4382 4382 if (ret) { 4383 4383 ath10k_warn(ar, "failed to transmit frame: %d\n", ret); 4384 4384 if (is_htt) {