diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/txrx.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/txrx.c | 81 |
1 files changed, 54 insertions, 27 deletions
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index d4986f626c35..493bfb410aff 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2011-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. */ #include "core.h" @@ -45,7 +35,7 @@ static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb) complete(&ar->offchan_tx_completed); ar->offchan_tx_skb = NULL; /* just for sanity */ - ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %pK\n", skb); + ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb); out: spin_unlock_bh(&ar->data_lock); } @@ -53,6 +43,7 @@ out: int ath10k_txrx_tx_unref(struct ath10k_htt *htt, const struct htt_tx_done *tx_done) { + struct ieee80211_tx_status status; struct ath10k *ar = htt->ar; struct device *dev = ar->dev; struct ieee80211_tx_info *info; @@ -60,6 +51,7 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct ath10k_skb_cb *skb_cb; struct ath10k_txq *artxq; struct sk_buff *msdu; + u8 flags; ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u status %d\n", @@ -88,36 +80,68 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, artxq->num_fw_queued--; } + flags = skb_cb->flags; ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); ath10k_htt_tx_dec_pending(htt); - if (htt->num_pending_tx == 0) - wake_up(&htt->empty_tx_wq); spin_unlock_bh(&htt->tx_lock); - dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); + rcu_read_lock(); + if (txq && txq->sta && skb_cb->airtime_est) + ieee80211_sta_register_airtime(txq->sta, txq->tid, + skb_cb->airtime_est, 0); + rcu_read_unlock(); + + if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL) + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); ath10k_report_offchan_tx(htt->ar, msdu); info = IEEE80211_SKB_CB(msdu); memset(&info->status, 0, sizeof(info->status)); - trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); + info->status.rates[0].idx = -1; - if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) { - ieee80211_free_txskb(htt->ar->hw, msdu); - return 0; - } + trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + !(flags & ATH10K_SKB_F_NOACK_TID)) info->flags |= IEEE80211_TX_STAT_ACK; if (tx_done->status == HTT_TX_COMPL_STATE_NOACK) info->flags &= ~IEEE80211_TX_STAT_ACK; if ((tx_done->status == HTT_TX_COMPL_STATE_ACK) && - (info->flags & IEEE80211_TX_CTL_NO_ACK)) + ((info->flags & IEEE80211_TX_CTL_NO_ACK) || + (flags & ATH10K_SKB_F_NOACK_TID))) info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - ieee80211_tx_status(htt->ar->hw, msdu); + if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) { + if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || + (flags & ATH10K_SKB_F_NOACK_TID)) + info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + info->flags &= ~IEEE80211_TX_STAT_ACK; + } + + if (tx_done->status == HTT_TX_COMPL_STATE_ACK && + tx_done->ack_rssi != ATH10K_INVALID_RSSI) { + info->status.ack_signal = ATH10K_DEFAULT_NOISE_FLOOR + + tx_done->ack_rssi; + info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; + } + + memset(&status, 0, sizeof(status)); + status.skb = msdu; + status.info = info; + + rcu_read_lock(); + + if (txq) + status.sta = txq->sta; + + ieee80211_tx_status_ext(htt->ar->hw, &status); + + rcu_read_unlock(); + /* we do not own the msdu anymore */ return 0; @@ -146,6 +170,9 @@ struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) { struct ath10k_peer *peer; + if (peer_id >= BITS_PER_TYPE(peer->peer_ids)) + return NULL; + lockdep_assert_held(&ar->data_lock); list_for_each_entry(peer, &ar->peers, list) @@ -195,7 +222,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt, if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) { ath10k_warn(ar, - "received htt peer map event with idx out of bounds: %hu\n", + "received htt peer map event with idx out of bounds: %u\n", ev->peer_id); return; } @@ -231,7 +258,7 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt, if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) { ath10k_warn(ar, - "received htt peer unmap event with idx out of bounds: %hu\n", + "received htt peer unmap event with idx out of bounds: %u\n", ev->peer_id); return; } |
