18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of wl18xx 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "../wlcore/wlcore.h" 98c2ecf20Sopenharmony_ci#include "../wlcore/cmd.h" 108c2ecf20Sopenharmony_ci#include "../wlcore/debug.h" 118c2ecf20Sopenharmony_ci#include "../wlcore/acx.h" 128c2ecf20Sopenharmony_ci#include "../wlcore/tx.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "wl18xx.h" 158c2ecf20Sopenharmony_ci#include "tx.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic 188c2ecf20Sopenharmony_civoid wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, 198c2ecf20Sopenharmony_ci u8 band, struct ieee80211_tx_rate *rate, u8 hlid) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci u8 fw_rate = wl->links[hlid].fw_rate_idx; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (fw_rate > CONF_HW_RATE_INDEX_MAX) { 248c2ecf20Sopenharmony_ci wl1271_error("last Tx rate invalid: %d", fw_rate); 258c2ecf20Sopenharmony_ci rate->idx = 0; 268c2ecf20Sopenharmony_ci rate->flags = 0; 278c2ecf20Sopenharmony_ci return; 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) { 318c2ecf20Sopenharmony_ci rate->idx = fw_rate; 328c2ecf20Sopenharmony_ci if (band == NL80211_BAND_5GHZ) 338c2ecf20Sopenharmony_ci rate->idx -= CONF_HW_RATE_INDEX_6MBPS; 348c2ecf20Sopenharmony_ci rate->flags = 0; 358c2ecf20Sopenharmony_ci } else { 368c2ecf20Sopenharmony_ci rate->flags = IEEE80211_TX_RC_MCS; 378c2ecf20Sopenharmony_ci rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* SGI modifier is counted as a separate rate */ 408c2ecf20Sopenharmony_ci if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI) 418c2ecf20Sopenharmony_ci (rate->idx)--; 428c2ecf20Sopenharmony_ci if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) 438c2ecf20Sopenharmony_ci (rate->idx)--; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* this also covers the 40Mhz SGI case (= MCS15) */ 468c2ecf20Sopenharmony_ci if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI || 478c2ecf20Sopenharmony_ci fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) 488c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_SHORT_GI; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) { 518c2ecf20Sopenharmony_ci struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 528c2ecf20Sopenharmony_ci if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || 538c2ecf20Sopenharmony_ci wlvif->channel_type == NL80211_CHAN_HT40PLUS) { 548c2ecf20Sopenharmony_ci /* adjustment needed for range 0-7 */ 558c2ecf20Sopenharmony_ci rate->idx -= 8; 568c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 658c2ecf20Sopenharmony_ci struct sk_buff *skb; 668c2ecf20Sopenharmony_ci int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK; 678c2ecf20Sopenharmony_ci bool tx_success; 688c2ecf20Sopenharmony_ci struct wl1271_tx_hw_descr *tx_desc; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* check for id legality */ 718c2ecf20Sopenharmony_ci if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) { 728c2ecf20Sopenharmony_ci wl1271_warning("illegal id in tx completion: %d", id); 738c2ecf20Sopenharmony_ci return; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* a zero bit indicates Tx success */ 778c2ecf20Sopenharmony_ci tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX)); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci skb = wl->tx_frames[id]; 808c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 818c2ecf20Sopenharmony_ci tx_desc = (struct wl1271_tx_hw_descr *)skb->data; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (wl12xx_is_dummy_packet(wl, skb)) { 848c2ecf20Sopenharmony_ci wl1271_free_tx_id(wl, id); 858c2ecf20Sopenharmony_ci return; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* update the TX status info */ 898c2ecf20Sopenharmony_ci if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) 908c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * first pass info->control.vif while it's valid, and then fill out 938c2ecf20Sopenharmony_ci * the info->status structures 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci wl18xx_get_last_tx_rate(wl, info->control.vif, 968c2ecf20Sopenharmony_ci info->band, 978c2ecf20Sopenharmony_ci &info->status.rates[0], 988c2ecf20Sopenharmony_ci tx_desc->hlid); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci info->status.rates[0].count = 1; /* no data about retries */ 1018c2ecf20Sopenharmony_ci info->status.ack_signal = -1; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (!tx_success) 1048c2ecf20Sopenharmony_ci wl->stats.retry_count++; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * TODO: update sequence number for encryption? seems to be 1088c2ecf20Sopenharmony_ci * unsupported for now. needed for recovery with encryption. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* remove private header from packet */ 1128c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* remove TKIP header space if present */ 1158c2ecf20Sopenharmony_ci if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && 1168c2ecf20Sopenharmony_ci info->control.hw_key && 1178c2ecf20Sopenharmony_ci info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 1188c2ecf20Sopenharmony_ci int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 1198c2ecf20Sopenharmony_ci memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, hdrlen); 1208c2ecf20Sopenharmony_ci skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p success %d", 1248c2ecf20Sopenharmony_ci id, skb, tx_success); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* return the packet to the stack */ 1278c2ecf20Sopenharmony_ci skb_queue_tail(&wl->deferred_tx_queue, skb); 1288c2ecf20Sopenharmony_ci queue_work(wl->freezable_wq, &wl->netstack_work); 1298c2ecf20Sopenharmony_ci wl1271_free_tx_id(wl, id); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_civoid wl18xx_tx_immediate_complete(struct wl1271 *wl) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct wl18xx_fw_status_priv *status_priv = 1358c2ecf20Sopenharmony_ci (struct wl18xx_fw_status_priv *)wl->fw_status->priv; 1368c2ecf20Sopenharmony_ci struct wl18xx_priv *priv = wl->priv; 1378c2ecf20Sopenharmony_ci u8 i, hlid; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* nothing to do here */ 1408c2ecf20Sopenharmony_ci if (priv->last_fw_rls_idx == status_priv->fw_release_idx) 1418c2ecf20Sopenharmony_ci return; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* update rates per link */ 1448c2ecf20Sopenharmony_ci hlid = wl->fw_status->counters.hlid; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (hlid < WLCORE_MAX_LINKS) { 1478c2ecf20Sopenharmony_ci wl->links[hlid].fw_rate_idx = 1488c2ecf20Sopenharmony_ci wl->fw_status->counters.tx_last_rate; 1498c2ecf20Sopenharmony_ci wl->links[hlid].fw_rate_mbps = 1508c2ecf20Sopenharmony_ci wl->fw_status->counters.tx_last_rate_mbps; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* freed Tx descriptors */ 1548c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d", 1558c2ecf20Sopenharmony_ci priv->last_fw_rls_idx, status_priv->fw_release_idx); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (status_priv->fw_release_idx >= WL18XX_FW_MAX_TX_STATUS_DESC) { 1588c2ecf20Sopenharmony_ci wl1271_error("invalid desc release index %d", 1598c2ecf20Sopenharmony_ci status_priv->fw_release_idx); 1608c2ecf20Sopenharmony_ci WARN_ON(1); 1618c2ecf20Sopenharmony_ci return; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci for (i = priv->last_fw_rls_idx; 1658c2ecf20Sopenharmony_ci i != status_priv->fw_release_idx; 1668c2ecf20Sopenharmony_ci i = (i + 1) % WL18XX_FW_MAX_TX_STATUS_DESC) { 1678c2ecf20Sopenharmony_ci wl18xx_tx_complete_packet(wl, 1688c2ecf20Sopenharmony_ci status_priv->released_tx_desc[i]); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci wl->tx_results_count++; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci priv->last_fw_rls_idx = status_priv->fw_release_idx; 1748c2ecf20Sopenharmony_ci} 175