162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2018-2019 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "main.h" 662306a36Sopenharmony_ci#include "tx.h" 762306a36Sopenharmony_ci#include "fw.h" 862306a36Sopenharmony_ci#include "ps.h" 962306a36Sopenharmony_ci#include "debug.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic 1262306a36Sopenharmony_civoid rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 1362306a36Sopenharmony_ci struct sk_buff *skb) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 1662306a36Sopenharmony_ci struct rtw_vif *rtwvif; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control)) 2162306a36Sopenharmony_ci return; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (!is_broadcast_ether_addr(hdr->addr1) && 2462306a36Sopenharmony_ci !is_multicast_ether_addr(hdr->addr1)) { 2562306a36Sopenharmony_ci rtwdev->stats.tx_unicast += skb->len; 2662306a36Sopenharmony_ci rtwdev->stats.tx_cnt++; 2762306a36Sopenharmony_ci if (vif) { 2862306a36Sopenharmony_ci rtwvif = (struct rtw_vif *)vif->drv_priv; 2962306a36Sopenharmony_ci rtwvif->stats.tx_unicast += skb->len; 3062306a36Sopenharmony_ci rtwvif->stats.tx_cnt++; 3162306a36Sopenharmony_ci } 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_civoid rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; 3862306a36Sopenharmony_ci bool more_data = false; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (pkt_info->qsel == TX_DESC_QSEL_HIGH) 4162306a36Sopenharmony_ci more_data = true; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci tx_desc->w0 = le32_encode_bits(pkt_info->tx_pkt_size, RTW_TX_DESC_W0_TXPKTSIZE) | 4462306a36Sopenharmony_ci le32_encode_bits(pkt_info->offset, RTW_TX_DESC_W0_OFFSET) | 4562306a36Sopenharmony_ci le32_encode_bits(pkt_info->bmc, RTW_TX_DESC_W0_BMC) | 4662306a36Sopenharmony_ci le32_encode_bits(pkt_info->ls, RTW_TX_DESC_W0_LS) | 4762306a36Sopenharmony_ci le32_encode_bits(pkt_info->dis_qselseq, RTW_TX_DESC_W0_DISQSELSEQ); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci tx_desc->w1 = le32_encode_bits(pkt_info->qsel, RTW_TX_DESC_W1_QSEL) | 5062306a36Sopenharmony_ci le32_encode_bits(pkt_info->rate_id, RTW_TX_DESC_W1_RATE_ID) | 5162306a36Sopenharmony_ci le32_encode_bits(pkt_info->sec_type, RTW_TX_DESC_W1_SEC_TYPE) | 5262306a36Sopenharmony_ci le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET) | 5362306a36Sopenharmony_ci le32_encode_bits(more_data, RTW_TX_DESC_W1_MORE_DATA); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci tx_desc->w2 = le32_encode_bits(pkt_info->ampdu_en, RTW_TX_DESC_W2_AGG_EN) | 5662306a36Sopenharmony_ci le32_encode_bits(pkt_info->report, RTW_TX_DESC_W2_SPE_RPT) | 5762306a36Sopenharmony_ci le32_encode_bits(pkt_info->ampdu_density, RTW_TX_DESC_W2_AMPDU_DEN) | 5862306a36Sopenharmony_ci le32_encode_bits(pkt_info->bt_null, RTW_TX_DESC_W2_BT_NULL); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci tx_desc->w3 = le32_encode_bits(pkt_info->hw_ssn_sel, RTW_TX_DESC_W3_HW_SSN_SEL) | 6162306a36Sopenharmony_ci le32_encode_bits(pkt_info->use_rate, RTW_TX_DESC_W3_USE_RATE) | 6262306a36Sopenharmony_ci le32_encode_bits(pkt_info->dis_rate_fallback, RTW_TX_DESC_W3_DISDATAFB) | 6362306a36Sopenharmony_ci le32_encode_bits(pkt_info->rts, RTW_TX_DESC_W3_USE_RTS) | 6462306a36Sopenharmony_ci le32_encode_bits(pkt_info->nav_use_hdr, RTW_TX_DESC_W3_NAVUSEHDR) | 6562306a36Sopenharmony_ci le32_encode_bits(pkt_info->ampdu_factor, RTW_TX_DESC_W3_MAX_AGG_NUM); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci tx_desc->w4 = le32_encode_bits(pkt_info->rate, RTW_TX_DESC_W4_DATARATE); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci tx_desc->w5 = le32_encode_bits(pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) | 7062306a36Sopenharmony_ci le32_encode_bits(pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) | 7162306a36Sopenharmony_ci le32_encode_bits(pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) | 7262306a36Sopenharmony_ci le32_encode_bits(pkt_info->stbc, RTW_TX_DESC_W5_DATA_STBC); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci tx_desc->w6 = le32_encode_bits(pkt_info->sn, RTW_TX_DESC_W6_SW_DEFINE); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci tx_desc->w8 = le32_encode_bits(pkt_info->en_hwseq, RTW_TX_DESC_W8_EN_HWSEQ); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci tx_desc->w9 = le32_encode_bits(pkt_info->seq, RTW_TX_DESC_W9_SW_SEQ); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (pkt_info->rts) { 8162306a36Sopenharmony_ci tx_desc->w4 |= le32_encode_bits(DESC_RATE24M, RTW_TX_DESC_W4_RTSRATE); 8262306a36Sopenharmony_ci tx_desc->w5 |= le32_encode_bits(1, RTW_TX_DESC_W5_DATA_RTS_SHORT); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (pkt_info->tim_offset) 8662306a36Sopenharmony_ci tx_desc->w9 |= le32_encode_bits(1, RTW_TX_DESC_W9_TIM_EN) | 8762306a36Sopenharmony_ci le32_encode_bits(pkt_info->tim_offset, RTW_TX_DESC_W9_TIM_OFFSET); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_tx_fill_tx_desc); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic u8 get_tx_ampdu_factor(struct ieee80211_sta *sta) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci u8 exp = sta->deflink.ht_cap.ampdu_factor; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* the least ampdu factor is 8K, and the value in the tx desc is the 9662306a36Sopenharmony_ci * max aggregation num, which represents val * 2 packets can be 9762306a36Sopenharmony_ci * aggregated in an AMPDU, so here we should use 8/2=4 as the base 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci return (BIT(2) << exp) - 1; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic u8 get_tx_ampdu_density(struct ieee80211_sta *sta) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return sta->deflink.ht_cap.ampdu_density; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic u8 get_highest_ht_tx_rate(struct rtw_dev *rtwdev, 10862306a36Sopenharmony_ci struct ieee80211_sta *sta) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci u8 rate; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (rtwdev->hal.rf_type == RF_2T2R && sta->deflink.ht_cap.mcs.rx_mask[1] != 0) 11362306a36Sopenharmony_ci rate = DESC_RATEMCS15; 11462306a36Sopenharmony_ci else 11562306a36Sopenharmony_ci rate = DESC_RATEMCS7; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return rate; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic u8 get_highest_vht_tx_rate(struct rtw_dev *rtwdev, 12162306a36Sopenharmony_ci struct ieee80211_sta *sta) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct rtw_efuse *efuse = &rtwdev->efuse; 12462306a36Sopenharmony_ci u8 rate; 12562306a36Sopenharmony_ci u16 tx_mcs_map; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci tx_mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.tx_mcs_map); 12862306a36Sopenharmony_ci if (efuse->hw_cap.nss == 1) { 12962306a36Sopenharmony_ci switch (tx_mcs_map & 0x3) { 13062306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_7: 13162306a36Sopenharmony_ci rate = DESC_RATEVHT1SS_MCS7; 13262306a36Sopenharmony_ci break; 13362306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_8: 13462306a36Sopenharmony_ci rate = DESC_RATEVHT1SS_MCS8; 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci default: 13762306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_9: 13862306a36Sopenharmony_ci rate = DESC_RATEVHT1SS_MCS9; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci } else if (efuse->hw_cap.nss >= 2) { 14262306a36Sopenharmony_ci switch ((tx_mcs_map & 0xc) >> 2) { 14362306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_7: 14462306a36Sopenharmony_ci rate = DESC_RATEVHT2SS_MCS7; 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_8: 14762306a36Sopenharmony_ci rate = DESC_RATEVHT2SS_MCS8; 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci default: 15062306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_9: 15162306a36Sopenharmony_ci rate = DESC_RATEVHT2SS_MCS9; 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci } else { 15562306a36Sopenharmony_ci rate = DESC_RATEVHT1SS_MCS9; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return rate; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void rtw_tx_report_enable(struct rtw_dev *rtwdev, 16262306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct rtw_tx_report *tx_report = &rtwdev->tx_report; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* [11:8], reserved, fills with zero 16762306a36Sopenharmony_ci * [7:2], tx report sequence number 16862306a36Sopenharmony_ci * [1:0], firmware use, fills with zero 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci pkt_info->sn = (atomic_inc_return(&tx_report->sn) << 2) & 0xfc; 17162306a36Sopenharmony_ci pkt_info->report = true; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_civoid rtw_tx_report_purge_timer(struct timer_list *t) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct rtw_dev *rtwdev = from_timer(rtwdev, t, tx_report.purge_timer); 17762306a36Sopenharmony_ci struct rtw_tx_report *tx_report = &rtwdev->tx_report; 17862306a36Sopenharmony_ci unsigned long flags; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (skb_queue_len(&tx_report->queue) == 0) 18162306a36Sopenharmony_ci return; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci rtw_warn(rtwdev, "failed to get tx report from firmware\n"); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci spin_lock_irqsave(&tx_report->q_lock, flags); 18662306a36Sopenharmony_ci skb_queue_purge(&tx_report->queue); 18762306a36Sopenharmony_ci spin_unlock_irqrestore(&tx_report->q_lock, flags); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_civoid rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct rtw_tx_report *tx_report = &rtwdev->tx_report; 19362306a36Sopenharmony_ci unsigned long flags; 19462306a36Sopenharmony_ci u8 *drv_data; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* pass sn to tx report handler through driver data */ 19762306a36Sopenharmony_ci drv_data = (u8 *)IEEE80211_SKB_CB(skb)->status.status_driver_data; 19862306a36Sopenharmony_ci *drv_data = sn; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci spin_lock_irqsave(&tx_report->q_lock, flags); 20162306a36Sopenharmony_ci __skb_queue_tail(&tx_report->queue, skb); 20262306a36Sopenharmony_ci spin_unlock_irqrestore(&tx_report->q_lock, flags); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci mod_timer(&tx_report->purge_timer, jiffies + RTW_TX_PROBE_TIMEOUT); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_tx_report_enqueue); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void rtw_tx_report_tx_status(struct rtw_dev *rtwdev, 20962306a36Sopenharmony_ci struct sk_buff *skb, bool acked) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct ieee80211_tx_info *info; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 21462306a36Sopenharmony_ci ieee80211_tx_info_clear_status(info); 21562306a36Sopenharmony_ci if (acked) 21662306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 21762306a36Sopenharmony_ci else 21862306a36Sopenharmony_ci info->flags &= ~IEEE80211_TX_STAT_ACK; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ieee80211_tx_status_irqsafe(rtwdev->hw, skb); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_civoid rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct rtw_tx_report *tx_report = &rtwdev->tx_report; 22662306a36Sopenharmony_ci struct rtw_c2h_cmd *c2h; 22762306a36Sopenharmony_ci struct sk_buff *cur, *tmp; 22862306a36Sopenharmony_ci unsigned long flags; 22962306a36Sopenharmony_ci u8 sn, st; 23062306a36Sopenharmony_ci u8 *n; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci c2h = get_c2h_from_skb(skb); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (src == C2H_CCX_TX_RPT) { 23562306a36Sopenharmony_ci sn = GET_CCX_REPORT_SEQNUM_V0(c2h->payload); 23662306a36Sopenharmony_ci st = GET_CCX_REPORT_STATUS_V0(c2h->payload); 23762306a36Sopenharmony_ci } else { 23862306a36Sopenharmony_ci sn = GET_CCX_REPORT_SEQNUM_V1(c2h->payload); 23962306a36Sopenharmony_ci st = GET_CCX_REPORT_STATUS_V1(c2h->payload); 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci spin_lock_irqsave(&tx_report->q_lock, flags); 24362306a36Sopenharmony_ci skb_queue_walk_safe(&tx_report->queue, cur, tmp) { 24462306a36Sopenharmony_ci n = (u8 *)IEEE80211_SKB_CB(cur)->status.status_driver_data; 24562306a36Sopenharmony_ci if (*n == sn) { 24662306a36Sopenharmony_ci __skb_unlink(cur, &tx_report->queue); 24762306a36Sopenharmony_ci rtw_tx_report_tx_status(rtwdev, cur, st == 0); 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci spin_unlock_irqrestore(&tx_report->q_lock, flags); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic u8 rtw_get_mgmt_rate(struct rtw_dev *rtwdev, struct sk_buff *skb, 25562306a36Sopenharmony_ci u8 lowest_rate, bool ignore_rate) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 25862306a36Sopenharmony_ci struct ieee80211_vif *vif = tx_info->control.vif; 25962306a36Sopenharmony_ci bool force_lowest = test_bit(RTW_FLAG_FORCE_LOWEST_RATE, rtwdev->flags); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (!vif || !vif->bss_conf.basic_rates || ignore_rate || force_lowest) 26262306a36Sopenharmony_ci return lowest_rate; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return __ffs(vif->bss_conf.basic_rates) + lowest_rate; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic void rtw_tx_pkt_info_update_rate(struct rtw_dev *rtwdev, 26862306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 26962306a36Sopenharmony_ci struct sk_buff *skb, 27062306a36Sopenharmony_ci bool ignore_rate) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci if (rtwdev->hal.current_band_type == RTW_BAND_2G) { 27362306a36Sopenharmony_ci pkt_info->rate_id = RTW_RATEID_B_20M; 27462306a36Sopenharmony_ci pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, DESC_RATE1M, 27562306a36Sopenharmony_ci ignore_rate); 27662306a36Sopenharmony_ci } else { 27762306a36Sopenharmony_ci pkt_info->rate_id = RTW_RATEID_G; 27862306a36Sopenharmony_ci pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, DESC_RATE6M, 27962306a36Sopenharmony_ci ignore_rate); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci pkt_info->use_rate = true; 28362306a36Sopenharmony_ci pkt_info->dis_rate_fallback = true; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void rtw_tx_pkt_info_update_sec(struct rtw_dev *rtwdev, 28762306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 28862306a36Sopenharmony_ci struct sk_buff *skb) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 29162306a36Sopenharmony_ci u8 sec_type = 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (info && info->control.hw_key) { 29462306a36Sopenharmony_ci struct ieee80211_key_conf *key = info->control.hw_key; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci switch (key->cipher) { 29762306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 29862306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 29962306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 30062306a36Sopenharmony_ci sec_type = 0x01; 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 30362306a36Sopenharmony_ci sec_type = 0x03; 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci default: 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci pkt_info->sec_type = sec_type; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev, 31462306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 31562306a36Sopenharmony_ci struct ieee80211_sta *sta, 31662306a36Sopenharmony_ci struct sk_buff *skb) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, false); 31962306a36Sopenharmony_ci pkt_info->dis_qselseq = true; 32062306a36Sopenharmony_ci pkt_info->en_hwseq = true; 32162306a36Sopenharmony_ci pkt_info->hw_ssn_sel = 0; 32262306a36Sopenharmony_ci /* TODO: need to change hw port and hw ssn sel for multiple vifs */ 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev, 32662306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 32762306a36Sopenharmony_ci struct ieee80211_sta *sta, 32862306a36Sopenharmony_ci struct sk_buff *skb) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 33162306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 33262306a36Sopenharmony_ci struct ieee80211_hw *hw = rtwdev->hw; 33362306a36Sopenharmony_ci struct rtw_dm_info *dm_info = &rtwdev->dm_info; 33462306a36Sopenharmony_ci struct rtw_sta_info *si; 33562306a36Sopenharmony_ci u8 fix_rate; 33662306a36Sopenharmony_ci u16 seq; 33762306a36Sopenharmony_ci u8 ampdu_factor = 0; 33862306a36Sopenharmony_ci u8 ampdu_density = 0; 33962306a36Sopenharmony_ci bool ampdu_en = false; 34062306a36Sopenharmony_ci u8 rate = DESC_RATE6M; 34162306a36Sopenharmony_ci u8 rate_id = 6; 34262306a36Sopenharmony_ci u8 bw = RTW_CHANNEL_WIDTH_20; 34362306a36Sopenharmony_ci bool stbc = false; 34462306a36Sopenharmony_ci bool ldpc = false; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci seq = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* for broadcast/multicast, use default values */ 34962306a36Sopenharmony_ci if (!sta) 35062306a36Sopenharmony_ci goto out; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_AMPDU) { 35362306a36Sopenharmony_ci ampdu_en = true; 35462306a36Sopenharmony_ci ampdu_factor = get_tx_ampdu_factor(sta); 35562306a36Sopenharmony_ci ampdu_density = get_tx_ampdu_density(sta); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (info->control.use_rts || skb->len > hw->wiphy->rts_threshold) 35962306a36Sopenharmony_ci pkt_info->rts = true; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported) 36262306a36Sopenharmony_ci rate = get_highest_vht_tx_rate(rtwdev, sta); 36362306a36Sopenharmony_ci else if (sta->deflink.ht_cap.ht_supported) 36462306a36Sopenharmony_ci rate = get_highest_ht_tx_rate(rtwdev, sta); 36562306a36Sopenharmony_ci else if (sta->deflink.supp_rates[0] <= 0xf) 36662306a36Sopenharmony_ci rate = DESC_RATE11M; 36762306a36Sopenharmony_ci else 36862306a36Sopenharmony_ci rate = DESC_RATE54M; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci si = (struct rtw_sta_info *)sta->drv_priv; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci bw = si->bw_mode; 37362306a36Sopenharmony_ci rate_id = si->rate_id; 37462306a36Sopenharmony_ci stbc = rtwdev->hal.txrx_1ss ? false : si->stbc_en; 37562306a36Sopenharmony_ci ldpc = si->ldpc_en; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciout: 37862306a36Sopenharmony_ci pkt_info->seq = seq; 37962306a36Sopenharmony_ci pkt_info->ampdu_factor = ampdu_factor; 38062306a36Sopenharmony_ci pkt_info->ampdu_density = ampdu_density; 38162306a36Sopenharmony_ci pkt_info->ampdu_en = ampdu_en; 38262306a36Sopenharmony_ci pkt_info->rate = rate; 38362306a36Sopenharmony_ci pkt_info->rate_id = rate_id; 38462306a36Sopenharmony_ci pkt_info->bw = bw; 38562306a36Sopenharmony_ci pkt_info->stbc = stbc; 38662306a36Sopenharmony_ci pkt_info->ldpc = ldpc; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci fix_rate = dm_info->fix_rate; 38962306a36Sopenharmony_ci if (fix_rate < DESC_RATE_MAX) { 39062306a36Sopenharmony_ci pkt_info->rate = fix_rate; 39162306a36Sopenharmony_ci pkt_info->dis_rate_fallback = true; 39262306a36Sopenharmony_ci pkt_info->use_rate = true; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_civoid rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, 39762306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 39862306a36Sopenharmony_ci struct ieee80211_sta *sta, 39962306a36Sopenharmony_ci struct sk_buff *skb) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 40262306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 40362306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 40462306a36Sopenharmony_ci struct rtw_sta_info *si; 40562306a36Sopenharmony_ci struct ieee80211_vif *vif = NULL; 40662306a36Sopenharmony_ci __le16 fc = hdr->frame_control; 40762306a36Sopenharmony_ci bool bmc; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (sta) { 41062306a36Sopenharmony_ci si = (struct rtw_sta_info *)sta->drv_priv; 41162306a36Sopenharmony_ci vif = si->vif; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) 41562306a36Sopenharmony_ci rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); 41662306a36Sopenharmony_ci else if (ieee80211_is_data(fc)) 41762306a36Sopenharmony_ci rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci bmc = is_broadcast_ether_addr(hdr->addr1) || 42062306a36Sopenharmony_ci is_multicast_ether_addr(hdr->addr1); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) 42362306a36Sopenharmony_ci rtw_tx_report_enable(rtwdev, pkt_info); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci pkt_info->bmc = bmc; 42662306a36Sopenharmony_ci rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); 42762306a36Sopenharmony_ci pkt_info->tx_pkt_size = skb->len; 42862306a36Sopenharmony_ci pkt_info->offset = chip->tx_pkt_desc_sz; 42962306a36Sopenharmony_ci pkt_info->qsel = skb->priority; 43062306a36Sopenharmony_ci pkt_info->ls = true; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* maybe merge with tx status ? */ 43362306a36Sopenharmony_ci rtw_tx_stats(rtwdev, vif, skb); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_civoid rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, 43762306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 43862306a36Sopenharmony_ci struct sk_buff *skb, 43962306a36Sopenharmony_ci enum rtw_rsvd_packet_type type) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 44262306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 44362306a36Sopenharmony_ci bool bmc; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* A beacon or dummy reserved page packet indicates that it is the first 44662306a36Sopenharmony_ci * reserved page, and the qsel of it will be set in each hci. 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_ci if (type != RSVD_BEACON && type != RSVD_DUMMY) 44962306a36Sopenharmony_ci pkt_info->qsel = TX_DESC_QSEL_MGMT; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, true); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci bmc = is_broadcast_ether_addr(hdr->addr1) || 45462306a36Sopenharmony_ci is_multicast_ether_addr(hdr->addr1); 45562306a36Sopenharmony_ci pkt_info->bmc = bmc; 45662306a36Sopenharmony_ci pkt_info->tx_pkt_size = skb->len; 45762306a36Sopenharmony_ci pkt_info->offset = chip->tx_pkt_desc_sz; 45862306a36Sopenharmony_ci pkt_info->ls = true; 45962306a36Sopenharmony_ci if (type == RSVD_PS_POLL) { 46062306a36Sopenharmony_ci pkt_info->nav_use_hdr = true; 46162306a36Sopenharmony_ci } else { 46262306a36Sopenharmony_ci pkt_info->dis_qselseq = true; 46362306a36Sopenharmony_ci pkt_info->en_hwseq = true; 46462306a36Sopenharmony_ci pkt_info->hw_ssn_sel = 0; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci if (type == RSVD_QOS_NULL) 46762306a36Sopenharmony_ci pkt_info->bt_null = true; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (type == RSVD_BEACON) { 47062306a36Sopenharmony_ci struct rtw_rsvd_page *rsvd_pkt; 47162306a36Sopenharmony_ci int hdr_len; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci rsvd_pkt = list_first_entry_or_null(&rtwdev->rsvd_page_list, 47462306a36Sopenharmony_ci struct rtw_rsvd_page, 47562306a36Sopenharmony_ci build_list); 47662306a36Sopenharmony_ci if (rsvd_pkt && rsvd_pkt->tim_offset != 0) { 47762306a36Sopenharmony_ci hdr_len = sizeof(struct ieee80211_hdr_3addr); 47862306a36Sopenharmony_ci pkt_info->tim_offset = rsvd_pkt->tim_offset - hdr_len; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* TODO: need to change hw port and hw ssn sel for multiple vifs */ 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistruct sk_buff * 48862306a36Sopenharmony_cirtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev, 48962306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 49062306a36Sopenharmony_ci u8 *buf, u32 size) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 49362306a36Sopenharmony_ci struct sk_buff *skb; 49462306a36Sopenharmony_ci u32 tx_pkt_desc_sz; 49562306a36Sopenharmony_ci u32 length; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci tx_pkt_desc_sz = chip->tx_pkt_desc_sz; 49862306a36Sopenharmony_ci length = size + tx_pkt_desc_sz; 49962306a36Sopenharmony_ci skb = dev_alloc_skb(length); 50062306a36Sopenharmony_ci if (!skb) { 50162306a36Sopenharmony_ci rtw_err(rtwdev, "failed to alloc write data rsvd page skb\n"); 50262306a36Sopenharmony_ci return NULL; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci skb_reserve(skb, tx_pkt_desc_sz); 50662306a36Sopenharmony_ci skb_put_data(skb, buf, size); 50762306a36Sopenharmony_ci rtw_tx_rsvd_page_pkt_info_update(rtwdev, pkt_info, skb, RSVD_BEACON); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci return skb; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_tx_write_data_rsvd_page_get); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistruct sk_buff * 51462306a36Sopenharmony_cirtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev, 51562306a36Sopenharmony_ci struct rtw_tx_pkt_info *pkt_info, 51662306a36Sopenharmony_ci u8 *buf, u32 size) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 51962306a36Sopenharmony_ci struct sk_buff *skb; 52062306a36Sopenharmony_ci u32 tx_pkt_desc_sz; 52162306a36Sopenharmony_ci u32 length; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci tx_pkt_desc_sz = chip->tx_pkt_desc_sz; 52462306a36Sopenharmony_ci length = size + tx_pkt_desc_sz; 52562306a36Sopenharmony_ci skb = dev_alloc_skb(length); 52662306a36Sopenharmony_ci if (!skb) { 52762306a36Sopenharmony_ci rtw_err(rtwdev, "failed to alloc write data h2c skb\n"); 52862306a36Sopenharmony_ci return NULL; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci skb_reserve(skb, tx_pkt_desc_sz); 53262306a36Sopenharmony_ci skb_put_data(skb, buf, size); 53362306a36Sopenharmony_ci pkt_info->tx_pkt_size = size; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return skb; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_tx_write_data_h2c_get); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_civoid rtw_tx(struct rtw_dev *rtwdev, 54062306a36Sopenharmony_ci struct ieee80211_tx_control *control, 54162306a36Sopenharmony_ci struct sk_buff *skb) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct rtw_tx_pkt_info pkt_info = {0}; 54462306a36Sopenharmony_ci int ret; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci rtw_tx_pkt_info_update(rtwdev, &pkt_info, control->sta, skb); 54762306a36Sopenharmony_ci ret = rtw_hci_tx_write(rtwdev, &pkt_info, skb); 54862306a36Sopenharmony_ci if (ret) { 54962306a36Sopenharmony_ci rtw_err(rtwdev, "failed to write TX skb to HCI\n"); 55062306a36Sopenharmony_ci goto out; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci rtw_hci_tx_kick_off(rtwdev); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ciout: 55862306a36Sopenharmony_ci ieee80211_free_txskb(rtwdev->hw, skb); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic void rtw_txq_check_agg(struct rtw_dev *rtwdev, 56262306a36Sopenharmony_ci struct rtw_txq *rtwtxq, 56362306a36Sopenharmony_ci struct sk_buff *skb) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); 56662306a36Sopenharmony_ci struct ieee80211_tx_info *info; 56762306a36Sopenharmony_ci struct rtw_sta_info *si; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (test_bit(RTW_TXQ_AMPDU, &rtwtxq->flags)) { 57062306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 57162306a36Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_AMPDU; 57262306a36Sopenharmony_ci return; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) 57662306a36Sopenharmony_ci return; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (test_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags)) 57962306a36Sopenharmony_ci return; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) 58262306a36Sopenharmony_ci return; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (!txq->sta) 58562306a36Sopenharmony_ci return; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci si = (struct rtw_sta_info *)txq->sta->drv_priv; 58862306a36Sopenharmony_ci set_bit(txq->tid, si->tid_ba); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci ieee80211_queue_work(rtwdev->hw, &rtwdev->ba_work); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic int rtw_txq_push_skb(struct rtw_dev *rtwdev, 59462306a36Sopenharmony_ci struct rtw_txq *rtwtxq, 59562306a36Sopenharmony_ci struct sk_buff *skb) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); 59862306a36Sopenharmony_ci struct rtw_tx_pkt_info pkt_info = {0}; 59962306a36Sopenharmony_ci int ret; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci rtw_txq_check_agg(rtwdev, rtwtxq, skb); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci rtw_tx_pkt_info_update(rtwdev, &pkt_info, txq->sta, skb); 60462306a36Sopenharmony_ci ret = rtw_hci_tx_write(rtwdev, &pkt_info, skb); 60562306a36Sopenharmony_ci if (ret) { 60662306a36Sopenharmony_ci rtw_err(rtwdev, "failed to write TX skb to HCI\n"); 60762306a36Sopenharmony_ci return ret; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci return 0; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic struct sk_buff *rtw_txq_dequeue(struct rtw_dev *rtwdev, 61362306a36Sopenharmony_ci struct rtw_txq *rtwtxq) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); 61662306a36Sopenharmony_ci struct sk_buff *skb; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci skb = ieee80211_tx_dequeue(rtwdev->hw, txq); 61962306a36Sopenharmony_ci if (!skb) 62062306a36Sopenharmony_ci return NULL; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return skb; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void rtw_txq_push(struct rtw_dev *rtwdev, 62662306a36Sopenharmony_ci struct rtw_txq *rtwtxq, 62762306a36Sopenharmony_ci unsigned long frames) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct sk_buff *skb; 63062306a36Sopenharmony_ci int ret; 63162306a36Sopenharmony_ci int i; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci rcu_read_lock(); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci for (i = 0; i < frames; i++) { 63662306a36Sopenharmony_ci skb = rtw_txq_dequeue(rtwdev, rtwtxq); 63762306a36Sopenharmony_ci if (!skb) 63862306a36Sopenharmony_ci break; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ret = rtw_txq_push_skb(rtwdev, rtwtxq, skb); 64162306a36Sopenharmony_ci if (ret) { 64262306a36Sopenharmony_ci rtw_err(rtwdev, "failed to pusk skb, ret %d\n", ret); 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci rcu_read_unlock(); 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_civoid __rtw_tx_work(struct rtw_dev *rtwdev) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct rtw_txq *rtwtxq, *tmp; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci spin_lock_bh(&rtwdev->txq_lock); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) { 65762306a36Sopenharmony_ci struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); 65862306a36Sopenharmony_ci unsigned long frame_cnt; 65962306a36Sopenharmony_ci unsigned long byte_cnt; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); 66262306a36Sopenharmony_ci rtw_txq_push(rtwdev, rtwtxq, frame_cnt); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci list_del_init(&rtwtxq->list); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci rtw_hci_tx_kick_off(rtwdev); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci spin_unlock_bh(&rtwdev->txq_lock); 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_civoid rtw_tx_work(struct work_struct *w) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci __rtw_tx_work(rtwdev); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_civoid rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct rtw_txq *rtwtxq; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (!txq) 68462306a36Sopenharmony_ci return; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci rtwtxq = (struct rtw_txq *)txq->drv_priv; 68762306a36Sopenharmony_ci INIT_LIST_HEAD(&rtwtxq->list); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_civoid rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct rtw_txq *rtwtxq; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (!txq) 69562306a36Sopenharmony_ci return; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci rtwtxq = (struct rtw_txq *)txq->drv_priv; 69862306a36Sopenharmony_ci spin_lock_bh(&rtwdev->txq_lock); 69962306a36Sopenharmony_ci if (!list_empty(&rtwtxq->list)) 70062306a36Sopenharmony_ci list_del_init(&rtwtxq->list); 70162306a36Sopenharmony_ci spin_unlock_bh(&rtwdev->txq_lock); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic const enum rtw_tx_queue_type ac_to_hwq[] = { 70562306a36Sopenharmony_ci [IEEE80211_AC_VO] = RTW_TX_QUEUE_VO, 70662306a36Sopenharmony_ci [IEEE80211_AC_VI] = RTW_TX_QUEUE_VI, 70762306a36Sopenharmony_ci [IEEE80211_AC_BE] = RTW_TX_QUEUE_BE, 70862306a36Sopenharmony_ci [IEEE80211_AC_BK] = RTW_TX_QUEUE_BK, 70962306a36Sopenharmony_ci}; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cienum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci if (WARN_ON(unlikely(ac >= IEEE80211_NUM_ACS))) 71662306a36Sopenharmony_ci return RTW_TX_QUEUE_BE; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return ac_to_hwq[ac]; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_tx_ac_to_hwq); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cienum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 72562306a36Sopenharmony_ci __le16 fc = hdr->frame_control; 72662306a36Sopenharmony_ci u8 q_mapping = skb_get_queue_mapping(skb); 72762306a36Sopenharmony_ci enum rtw_tx_queue_type queue; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (unlikely(ieee80211_is_beacon(fc))) 73062306a36Sopenharmony_ci queue = RTW_TX_QUEUE_BCN; 73162306a36Sopenharmony_ci else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) 73262306a36Sopenharmony_ci queue = RTW_TX_QUEUE_MGMT; 73362306a36Sopenharmony_ci else if (is_broadcast_ether_addr(hdr->addr1) || 73462306a36Sopenharmony_ci is_multicast_ether_addr(hdr->addr1)) 73562306a36Sopenharmony_ci queue = RTW_TX_QUEUE_HI0; 73662306a36Sopenharmony_ci else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq))) 73762306a36Sopenharmony_ci queue = ac_to_hwq[IEEE80211_AC_BE]; 73862306a36Sopenharmony_ci else 73962306a36Sopenharmony_ci queue = ac_to_hwq[q_mapping]; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return queue; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_tx_queue_mapping); 744