linux/drivers/net/wireless/ath/ath10k/txrx.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2005-2011 Atheros Communications Inc.
   3 * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18#include "core.h"
  19#include "txrx.h"
  20#include "htt.h"
  21#include "mac.h"
  22#include "debug.h"
  23
  24static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb)
  25{
  26        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
  27
  28        if (likely(!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)))
  29                return;
  30
  31        if (ath10k_mac_tx_frm_has_freq(ar))
  32                return;
  33
  34        /* If the original wait_for_completion() timed out before
  35         * {data,mgmt}_tx_completed() was called then we could complete
  36         * offchan_tx_completed for a different skb. Prevent this by using
  37         * offchan_tx_skb.
  38         */
  39        spin_lock_bh(&ar->data_lock);
  40        if (ar->offchan_tx_skb != skb) {
  41                ath10k_warn(ar, "completed old offchannel frame\n");
  42                goto out;
  43        }
  44
  45        complete(&ar->offchan_tx_completed);
  46        ar->offchan_tx_skb = NULL; /* just for sanity */
  47
  48        ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %pK\n", skb);
  49out:
  50        spin_unlock_bh(&ar->data_lock);
  51}
  52
  53int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
  54                         const struct htt_tx_done *tx_done)
  55{
  56        struct ath10k *ar = htt->ar;
  57        struct device *dev = ar->dev;
  58        struct ieee80211_tx_info *info;
  59        struct ieee80211_txq *txq;
  60        struct ath10k_skb_cb *skb_cb;
  61        struct ath10k_txq *artxq;
  62        struct sk_buff *msdu;
  63
  64        ath10k_dbg(ar, ATH10K_DBG_HTT,
  65                   "htt tx completion msdu_id %u status %d\n",
  66                   tx_done->msdu_id, tx_done->status);
  67
  68        if (tx_done->msdu_id >= htt->max_num_pending_tx) {
  69                ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
  70                            tx_done->msdu_id);
  71                return -EINVAL;
  72        }
  73
  74        spin_lock_bh(&htt->tx_lock);
  75        msdu = idr_find(&htt->pending_tx, tx_done->msdu_id);
  76        if (!msdu) {
  77                ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",
  78                            tx_done->msdu_id);
  79                spin_unlock_bh(&htt->tx_lock);
  80                return -ENOENT;
  81        }
  82
  83        skb_cb = ATH10K_SKB_CB(msdu);
  84        txq = skb_cb->txq;
  85
  86        if (txq) {
  87                artxq = (void *)txq->drv_priv;
  88                artxq->num_fw_queued--;
  89        }
  90
  91        ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
  92        ath10k_htt_tx_dec_pending(htt);
  93        if (htt->num_pending_tx == 0)
  94                wake_up(&htt->empty_tx_wq);
  95        spin_unlock_bh(&htt->tx_lock);
  96
  97        dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
  98
  99        ath10k_report_offchan_tx(htt->ar, msdu);
 100
 101        info = IEEE80211_SKB_CB(msdu);
 102        memset(&info->status, 0, sizeof(info->status));
 103        trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
 104
 105        if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
 106                ieee80211_free_txskb(htt->ar->hw, msdu);
 107                return 0;
 108        }
 109
 110        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 111                info->flags |= IEEE80211_TX_STAT_ACK;
 112
 113        if (tx_done->status == HTT_TX_COMPL_STATE_NOACK)
 114                info->flags &= ~IEEE80211_TX_STAT_ACK;
 115
 116        if ((tx_done->status == HTT_TX_COMPL_STATE_ACK) &&
 117            (info->flags & IEEE80211_TX_CTL_NO_ACK))
 118                info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
 119
 120        ieee80211_tx_status(htt->ar->hw, msdu);
 121        /* we do not own the msdu anymore */
 122
 123        return 0;
 124}
 125
 126struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
 127                                     const u8 *addr)
 128{
 129        struct ath10k_peer *peer;
 130
 131        lockdep_assert_held(&ar->data_lock);
 132
 133        list_for_each_entry(peer, &ar->peers, list) {
 134                if (peer->vdev_id != vdev_id)
 135                        continue;
 136                if (!ether_addr_equal(peer->addr, addr))
 137                        continue;
 138
 139                return peer;
 140        }
 141
 142        return NULL;
 143}
 144
 145struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id)
 146{
 147        struct ath10k_peer *peer;
 148
 149        lockdep_assert_held(&ar->data_lock);
 150
 151        list_for_each_entry(peer, &ar->peers, list)
 152                if (test_bit(peer_id, peer->peer_ids))
 153                        return peer;
 154
 155        return NULL;
 156}
 157
 158static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,
 159                                       const u8 *addr, bool expect_mapped)
 160{
 161        long time_left;
 162
 163        time_left = wait_event_timeout(ar->peer_mapping_wq, ({
 164                        bool mapped;
 165
 166                        spin_lock_bh(&ar->data_lock);
 167                        mapped = !!ath10k_peer_find(ar, vdev_id, addr);
 168                        spin_unlock_bh(&ar->data_lock);
 169
 170                        (mapped == expect_mapped ||
 171                         test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags));
 172                }), 3 * HZ);
 173
 174        if (time_left == 0)
 175                return -ETIMEDOUT;
 176
 177        return 0;
 178}
 179
 180int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, const u8 *addr)
 181{
 182        return ath10k_wait_for_peer_common(ar, vdev_id, addr, true);
 183}
 184
 185int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, const u8 *addr)
 186{
 187        return ath10k_wait_for_peer_common(ar, vdev_id, addr, false);
 188}
 189
 190void ath10k_peer_map_event(struct ath10k_htt *htt,
 191                           struct htt_peer_map_event *ev)
 192{
 193        struct ath10k *ar = htt->ar;
 194        struct ath10k_peer *peer;
 195
 196        if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) {
 197                ath10k_warn(ar,
 198                            "received htt peer map event with idx out of bounds: %hu\n",
 199                            ev->peer_id);
 200                return;
 201        }
 202
 203        spin_lock_bh(&ar->data_lock);
 204        peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr);
 205        if (!peer) {
 206                peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
 207                if (!peer)
 208                        goto exit;
 209
 210                peer->vdev_id = ev->vdev_id;
 211                ether_addr_copy(peer->addr, ev->addr);
 212                list_add(&peer->list, &ar->peers);
 213                wake_up(&ar->peer_mapping_wq);
 214        }
 215
 216        ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
 217                   ev->vdev_id, ev->addr, ev->peer_id);
 218
 219        WARN_ON(ar->peer_map[ev->peer_id] && (ar->peer_map[ev->peer_id] != peer));
 220        ar->peer_map[ev->peer_id] = peer;
 221        set_bit(ev->peer_id, peer->peer_ids);
 222exit:
 223        spin_unlock_bh(&ar->data_lock);
 224}
 225
 226void ath10k_peer_unmap_event(struct ath10k_htt *htt,
 227                             struct htt_peer_unmap_event *ev)
 228{
 229        struct ath10k *ar = htt->ar;
 230        struct ath10k_peer *peer;
 231
 232        if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) {
 233                ath10k_warn(ar,
 234                            "received htt peer unmap event with idx out of bounds: %hu\n",
 235                            ev->peer_id);
 236                return;
 237        }
 238
 239        spin_lock_bh(&ar->data_lock);
 240        peer = ath10k_peer_find_by_id(ar, ev->peer_id);
 241        if (!peer) {
 242                ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n",
 243                            ev->peer_id);
 244                goto exit;
 245        }
 246
 247        ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
 248                   peer->vdev_id, peer->addr, ev->peer_id);
 249
 250        ar->peer_map[ev->peer_id] = NULL;
 251        clear_bit(ev->peer_id, peer->peer_ids);
 252
 253        if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) {
 254                list_del(&peer->list);
 255                kfree(peer);
 256                wake_up(&ar->peer_mapping_wq);
 257        }
 258
 259exit:
 260        spin_unlock_bh(&ar->data_lock);
 261}
 262