linux/drivers/net/wireless/ti/wl18xx/tx.c
<<
>>
Prefs
   1/*
   2 * This file is part of wl18xx
   3 *
   4 * Copyright (C) 2011 Texas Instruments Inc.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  18 * 02110-1301 USA
  19 *
  20 */
  21
  22#include "../wlcore/wlcore.h"
  23#include "../wlcore/cmd.h"
  24#include "../wlcore/debug.h"
  25#include "../wlcore/acx.h"
  26#include "../wlcore/tx.h"
  27
  28#include "wl18xx.h"
  29#include "tx.h"
  30
  31static
  32void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
  33                             u8 band, struct ieee80211_tx_rate *rate, u8 hlid)
  34{
  35        u8 fw_rate = wl->links[hlid].fw_rate_idx;
  36
  37        if (fw_rate > CONF_HW_RATE_INDEX_MAX) {
  38                wl1271_error("last Tx rate invalid: %d", fw_rate);
  39                rate->idx = 0;
  40                rate->flags = 0;
  41                return;
  42        }
  43
  44        if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) {
  45                rate->idx = fw_rate;
  46                if (band == NL80211_BAND_5GHZ)
  47                        rate->idx -= CONF_HW_RATE_INDEX_6MBPS;
  48                rate->flags = 0;
  49        } else {
  50                rate->flags = IEEE80211_TX_RC_MCS;
  51                rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0;
  52
  53                /* SGI modifier is counted as a separate rate */
  54                if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI)
  55                        (rate->idx)--;
  56                if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI)
  57                        (rate->idx)--;
  58
  59                /* this also covers the 40Mhz SGI case (= MCS15) */
  60                if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI ||
  61                    fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI)
  62                        rate->flags |= IEEE80211_TX_RC_SHORT_GI;
  63
  64                if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) {
  65                        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
  66                        if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
  67                            wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
  68                                /* adjustment needed for range 0-7 */
  69                                rate->idx -= 8;
  70                                rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
  71                        }
  72                }
  73        }
  74}
  75
  76static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
  77{
  78        struct ieee80211_tx_info *info;
  79        struct sk_buff *skb;
  80        int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK;
  81        bool tx_success;
  82        struct wl1271_tx_hw_descr *tx_desc;
  83
  84        /* check for id legality */
  85        if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
  86                wl1271_warning("illegal id in tx completion: %d", id);
  87                return;
  88        }
  89
  90        /* a zero bit indicates Tx success */
  91        tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
  92
  93        skb = wl->tx_frames[id];
  94        info = IEEE80211_SKB_CB(skb);
  95        tx_desc = (struct wl1271_tx_hw_descr *)skb->data;
  96
  97        if (wl12xx_is_dummy_packet(wl, skb)) {
  98                wl1271_free_tx_id(wl, id);
  99                return;
 100        }
 101
 102        /* update the TX status info */
 103        if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
 104                info->flags |= IEEE80211_TX_STAT_ACK;
 105        /*
 106         * first pass info->control.vif while it's valid, and then fill out
 107         * the info->status structures
 108         */
 109        wl18xx_get_last_tx_rate(wl, info->control.vif,
 110                                info->band,
 111                                &info->status.rates[0],
 112                                tx_desc->hlid);
 113
 114        info->status.rates[0].count = 1; /* no data about retries */
 115        info->status.ack_signal = -1;
 116
 117        if (!tx_success)
 118                wl->stats.retry_count++;
 119
 120        /*
 121         * TODO: update sequence number for encryption? seems to be
 122         * unsupported for now. needed for recovery with encryption.
 123         */
 124
 125        /* remove private header from packet */
 126        skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
 127
 128        /* remove TKIP header space if present */
 129        if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
 130            info->control.hw_key &&
 131            info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
 132                int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 133                memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, hdrlen);
 134                skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
 135        }
 136
 137        wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p success %d",
 138                     id, skb, tx_success);
 139
 140        /* return the packet to the stack */
 141        skb_queue_tail(&wl->deferred_tx_queue, skb);
 142        queue_work(wl->freezable_wq, &wl->netstack_work);
 143        wl1271_free_tx_id(wl, id);
 144}
 145
 146void wl18xx_tx_immediate_complete(struct wl1271 *wl)
 147{
 148        struct wl18xx_fw_status_priv *status_priv =
 149                (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
 150        struct wl18xx_priv *priv = wl->priv;
 151        u8 i, hlid;
 152
 153        /* nothing to do here */
 154        if (priv->last_fw_rls_idx == status_priv->fw_release_idx)
 155                return;
 156
 157        /* update rates per link */
 158        hlid = wl->fw_status->counters.hlid;
 159
 160        if (hlid < WLCORE_MAX_LINKS) {
 161                wl->links[hlid].fw_rate_idx =
 162                                wl->fw_status->counters.tx_last_rate;
 163                wl->links[hlid].fw_rate_mbps =
 164                                wl->fw_status->counters.tx_last_rate_mbps;
 165        }
 166
 167        /* freed Tx descriptors */
 168        wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d",
 169                     priv->last_fw_rls_idx, status_priv->fw_release_idx);
 170
 171        if (status_priv->fw_release_idx >= WL18XX_FW_MAX_TX_STATUS_DESC) {
 172                wl1271_error("invalid desc release index %d",
 173                             status_priv->fw_release_idx);
 174                WARN_ON(1);
 175                return;
 176        }
 177
 178        for (i = priv->last_fw_rls_idx;
 179             i != status_priv->fw_release_idx;
 180             i = (i + 1) % WL18XX_FW_MAX_TX_STATUS_DESC) {
 181                wl18xx_tx_complete_packet(wl,
 182                        status_priv->released_tx_desc[i]);
 183
 184                wl->tx_results_count++;
 185        }
 186
 187        priv->last_fw_rls_idx = status_priv->fw_release_idx;
 188}
 189