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