162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file is part of wl18xx 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "../wlcore/wlcore.h" 962306a36Sopenharmony_ci#include "../wlcore/cmd.h" 1062306a36Sopenharmony_ci#include "../wlcore/debug.h" 1162306a36Sopenharmony_ci#include "../wlcore/acx.h" 1262306a36Sopenharmony_ci#include "../wlcore/tx.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "wl18xx.h" 1562306a36Sopenharmony_ci#include "tx.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic 1862306a36Sopenharmony_civoid wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, 1962306a36Sopenharmony_ci u8 band, struct ieee80211_tx_rate *rate, u8 hlid) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci u8 fw_rate = wl->links[hlid].fw_rate_idx; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (fw_rate > CONF_HW_RATE_INDEX_MAX) { 2462306a36Sopenharmony_ci wl1271_error("last Tx rate invalid: %d", fw_rate); 2562306a36Sopenharmony_ci rate->idx = 0; 2662306a36Sopenharmony_ci rate->flags = 0; 2762306a36Sopenharmony_ci return; 2862306a36Sopenharmony_ci } 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) { 3162306a36Sopenharmony_ci rate->idx = fw_rate; 3262306a36Sopenharmony_ci if (band == NL80211_BAND_5GHZ) 3362306a36Sopenharmony_ci rate->idx -= CONF_HW_RATE_INDEX_6MBPS; 3462306a36Sopenharmony_ci rate->flags = 0; 3562306a36Sopenharmony_ci } else { 3662306a36Sopenharmony_ci rate->flags = IEEE80211_TX_RC_MCS; 3762306a36Sopenharmony_ci rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* SGI modifier is counted as a separate rate */ 4062306a36Sopenharmony_ci if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI) 4162306a36Sopenharmony_ci (rate->idx)--; 4262306a36Sopenharmony_ci if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) 4362306a36Sopenharmony_ci (rate->idx)--; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* this also covers the 40Mhz SGI case (= MCS15) */ 4662306a36Sopenharmony_ci if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI || 4762306a36Sopenharmony_ci fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) 4862306a36Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_SHORT_GI; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) { 5162306a36Sopenharmony_ci struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 5262306a36Sopenharmony_ci if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || 5362306a36Sopenharmony_ci wlvif->channel_type == NL80211_CHAN_HT40PLUS) { 5462306a36Sopenharmony_ci /* adjustment needed for range 0-7 */ 5562306a36Sopenharmony_ci rate->idx -= 8; 5662306a36Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct ieee80211_tx_info *info; 6562306a36Sopenharmony_ci struct sk_buff *skb; 6662306a36Sopenharmony_ci int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK; 6762306a36Sopenharmony_ci bool tx_success; 6862306a36Sopenharmony_ci struct wl1271_tx_hw_descr *tx_desc; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* check for id legality */ 7162306a36Sopenharmony_ci if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) { 7262306a36Sopenharmony_ci wl1271_warning("illegal id in tx completion: %d", id); 7362306a36Sopenharmony_ci return; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* a zero bit indicates Tx success */ 7762306a36Sopenharmony_ci tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX)); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci skb = wl->tx_frames[id]; 8062306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 8162306a36Sopenharmony_ci tx_desc = (struct wl1271_tx_hw_descr *)skb->data; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (wl12xx_is_dummy_packet(wl, skb)) { 8462306a36Sopenharmony_ci wl1271_free_tx_id(wl, id); 8562306a36Sopenharmony_ci return; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* update the TX status info */ 8962306a36Sopenharmony_ci if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) 9062306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * first pass info->control.vif while it's valid, and then fill out 9362306a36Sopenharmony_ci * the info->status structures 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci wl18xx_get_last_tx_rate(wl, info->control.vif, 9662306a36Sopenharmony_ci info->band, 9762306a36Sopenharmony_ci &info->status.rates[0], 9862306a36Sopenharmony_ci tx_desc->hlid); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci info->status.rates[0].count = 1; /* no data about retries */ 10162306a36Sopenharmony_ci info->status.ack_signal = -1; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (!tx_success) 10462306a36Sopenharmony_ci wl->stats.retry_count++; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* 10762306a36Sopenharmony_ci * TODO: update sequence number for encryption? seems to be 10862306a36Sopenharmony_ci * unsupported for now. needed for recovery with encryption. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* remove private header from packet */ 11262306a36Sopenharmony_ci skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* remove TKIP header space if present */ 11562306a36Sopenharmony_ci if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && 11662306a36Sopenharmony_ci info->control.hw_key && 11762306a36Sopenharmony_ci info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 11862306a36Sopenharmony_ci int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 11962306a36Sopenharmony_ci memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, hdrlen); 12062306a36Sopenharmony_ci skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p success %d", 12462306a36Sopenharmony_ci id, skb, tx_success); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* return the packet to the stack */ 12762306a36Sopenharmony_ci skb_queue_tail(&wl->deferred_tx_queue, skb); 12862306a36Sopenharmony_ci queue_work(wl->freezable_wq, &wl->netstack_work); 12962306a36Sopenharmony_ci wl1271_free_tx_id(wl, id); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_civoid wl18xx_tx_immediate_complete(struct wl1271 *wl) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct wl18xx_fw_status_priv *status_priv = 13562306a36Sopenharmony_ci (struct wl18xx_fw_status_priv *)wl->fw_status->priv; 13662306a36Sopenharmony_ci struct wl18xx_priv *priv = wl->priv; 13762306a36Sopenharmony_ci u8 i, hlid; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* nothing to do here */ 14062306a36Sopenharmony_ci if (priv->last_fw_rls_idx == status_priv->fw_release_idx) 14162306a36Sopenharmony_ci return; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* update rates per link */ 14462306a36Sopenharmony_ci hlid = wl->fw_status->counters.hlid; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (hlid < WLCORE_MAX_LINKS) { 14762306a36Sopenharmony_ci wl->links[hlid].fw_rate_idx = 14862306a36Sopenharmony_ci wl->fw_status->counters.tx_last_rate; 14962306a36Sopenharmony_ci wl->links[hlid].fw_rate_mbps = 15062306a36Sopenharmony_ci wl->fw_status->counters.tx_last_rate_mbps; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* freed Tx descriptors */ 15462306a36Sopenharmony_ci wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d", 15562306a36Sopenharmony_ci priv->last_fw_rls_idx, status_priv->fw_release_idx); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (status_priv->fw_release_idx >= WL18XX_FW_MAX_TX_STATUS_DESC) { 15862306a36Sopenharmony_ci wl1271_error("invalid desc release index %d", 15962306a36Sopenharmony_ci status_priv->fw_release_idx); 16062306a36Sopenharmony_ci WARN_ON(1); 16162306a36Sopenharmony_ci return; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci for (i = priv->last_fw_rls_idx; 16562306a36Sopenharmony_ci i != status_priv->fw_release_idx; 16662306a36Sopenharmony_ci i = (i + 1) % WL18XX_FW_MAX_TX_STATUS_DESC) { 16762306a36Sopenharmony_ci wl18xx_tx_complete_packet(wl, 16862306a36Sopenharmony_ci status_priv->released_tx_desc[i]); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci wl->tx_results_count++; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci priv->last_fw_rls_idx = status_priv->fw_release_idx; 17462306a36Sopenharmony_ci} 175