xref: /freebsd/sys/contrib/dev/rtw88/tx.c (revision a0ccc12f6882a886d89ae279c541b2c2b62c6aca)
12774f206SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
22774f206SBjoern A. Zeeb /* Copyright(c) 2018-2019  Realtek Corporation
32774f206SBjoern A. Zeeb  */
42774f206SBjoern A. Zeeb 
52774f206SBjoern A. Zeeb #include "main.h"
62774f206SBjoern A. Zeeb #include "tx.h"
72774f206SBjoern A. Zeeb #include "fw.h"
82774f206SBjoern A. Zeeb #include "ps.h"
92774f206SBjoern A. Zeeb #include "debug.h"
102774f206SBjoern A. Zeeb 
112774f206SBjoern A. Zeeb static
122774f206SBjoern A. Zeeb void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
132774f206SBjoern A. Zeeb 		  struct sk_buff *skb)
142774f206SBjoern A. Zeeb {
152774f206SBjoern A. Zeeb 	struct ieee80211_hdr *hdr;
162774f206SBjoern A. Zeeb 	struct rtw_vif *rtwvif;
172774f206SBjoern A. Zeeb 
182774f206SBjoern A. Zeeb 	hdr = (struct ieee80211_hdr *)skb->data;
192774f206SBjoern A. Zeeb 
202774f206SBjoern A. Zeeb 	if (!ieee80211_is_data(hdr->frame_control))
212774f206SBjoern A. Zeeb 		return;
222774f206SBjoern A. Zeeb 
232774f206SBjoern A. Zeeb 	if (!is_broadcast_ether_addr(hdr->addr1) &&
242774f206SBjoern A. Zeeb 	    !is_multicast_ether_addr(hdr->addr1)) {
252774f206SBjoern A. Zeeb 		rtwdev->stats.tx_unicast += skb->len;
262774f206SBjoern A. Zeeb 		rtwdev->stats.tx_cnt++;
272774f206SBjoern A. Zeeb 		if (vif) {
282774f206SBjoern A. Zeeb 			rtwvif = (struct rtw_vif *)vif->drv_priv;
292774f206SBjoern A. Zeeb 			rtwvif->stats.tx_unicast += skb->len;
302774f206SBjoern A. Zeeb 			rtwvif->stats.tx_cnt++;
312774f206SBjoern A. Zeeb 		}
322774f206SBjoern A. Zeeb 	}
332774f206SBjoern A. Zeeb }
342774f206SBjoern A. Zeeb 
35*a0ccc12fSBjoern A. Zeeb void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev,
36*a0ccc12fSBjoern A. Zeeb 			 struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb)
372774f206SBjoern A. Zeeb {
3890aac0d8SBjoern A. Zeeb 	struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data;
3990aac0d8SBjoern A. Zeeb 	bool more_data = false;
402774f206SBjoern A. Zeeb 
4190aac0d8SBjoern A. Zeeb 	if (pkt_info->qsel == TX_DESC_QSEL_HIGH)
4290aac0d8SBjoern A. Zeeb 		more_data = true;
4390aac0d8SBjoern A. Zeeb 
4490aac0d8SBjoern A. Zeeb 	tx_desc->w0 = le32_encode_bits(pkt_info->tx_pkt_size, RTW_TX_DESC_W0_TXPKTSIZE) |
4590aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->offset, RTW_TX_DESC_W0_OFFSET) |
4690aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->bmc, RTW_TX_DESC_W0_BMC) |
4790aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->ls, RTW_TX_DESC_W0_LS) |
4890aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->dis_qselseq, RTW_TX_DESC_W0_DISQSELSEQ);
4990aac0d8SBjoern A. Zeeb 
50*a0ccc12fSBjoern A. Zeeb 	tx_desc->w1 = le32_encode_bits(pkt_info->mac_id, RTW_TX_DESC_W1_MACID) |
51*a0ccc12fSBjoern A. Zeeb 		      le32_encode_bits(pkt_info->qsel, RTW_TX_DESC_W1_QSEL) |
5290aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->rate_id, RTW_TX_DESC_W1_RATE_ID) |
5390aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->sec_type, RTW_TX_DESC_W1_SEC_TYPE) |
5490aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET) |
5590aac0d8SBjoern A. Zeeb 		      le32_encode_bits(more_data, RTW_TX_DESC_W1_MORE_DATA);
5690aac0d8SBjoern A. Zeeb 
5790aac0d8SBjoern A. Zeeb 	tx_desc->w2 = le32_encode_bits(pkt_info->ampdu_en, RTW_TX_DESC_W2_AGG_EN) |
5890aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->report, RTW_TX_DESC_W2_SPE_RPT) |
5990aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->ampdu_density, RTW_TX_DESC_W2_AMPDU_DEN) |
6090aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->bt_null, RTW_TX_DESC_W2_BT_NULL);
6190aac0d8SBjoern A. Zeeb 
6290aac0d8SBjoern A. Zeeb 	tx_desc->w3 = le32_encode_bits(pkt_info->hw_ssn_sel, RTW_TX_DESC_W3_HW_SSN_SEL) |
6390aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->use_rate, RTW_TX_DESC_W3_USE_RATE) |
6490aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->dis_rate_fallback, RTW_TX_DESC_W3_DISDATAFB) |
6590aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->rts, RTW_TX_DESC_W3_USE_RTS) |
6690aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->nav_use_hdr, RTW_TX_DESC_W3_NAVUSEHDR) |
6790aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->ampdu_factor, RTW_TX_DESC_W3_MAX_AGG_NUM);
6890aac0d8SBjoern A. Zeeb 
6990aac0d8SBjoern A. Zeeb 	tx_desc->w4 = le32_encode_bits(pkt_info->rate, RTW_TX_DESC_W4_DATARATE);
7090aac0d8SBjoern A. Zeeb 
71*a0ccc12fSBjoern A. Zeeb 	if (rtwdev->chip->old_datarate_fb_limit)
72*a0ccc12fSBjoern A. Zeeb 		tx_desc->w4 |= le32_encode_bits(0x1f, RTW_TX_DESC_W4_DATARATE_FB_LIMIT);
73*a0ccc12fSBjoern A. Zeeb 
7490aac0d8SBjoern A. Zeeb 	tx_desc->w5 = le32_encode_bits(pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) |
7590aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) |
7690aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) |
7790aac0d8SBjoern A. Zeeb 		      le32_encode_bits(pkt_info->stbc, RTW_TX_DESC_W5_DATA_STBC);
7890aac0d8SBjoern A. Zeeb 
7990aac0d8SBjoern A. Zeeb 	tx_desc->w6 = le32_encode_bits(pkt_info->sn, RTW_TX_DESC_W6_SW_DEFINE);
8090aac0d8SBjoern A. Zeeb 
8190aac0d8SBjoern A. Zeeb 	tx_desc->w8 = le32_encode_bits(pkt_info->en_hwseq, RTW_TX_DESC_W8_EN_HWSEQ);
8290aac0d8SBjoern A. Zeeb 
8390aac0d8SBjoern A. Zeeb 	tx_desc->w9 = le32_encode_bits(pkt_info->seq, RTW_TX_DESC_W9_SW_SEQ);
8490aac0d8SBjoern A. Zeeb 
852774f206SBjoern A. Zeeb 	if (pkt_info->rts) {
8690aac0d8SBjoern A. Zeeb 		tx_desc->w4 |= le32_encode_bits(DESC_RATE24M, RTW_TX_DESC_W4_RTSRATE);
8790aac0d8SBjoern A. Zeeb 		tx_desc->w5 |= le32_encode_bits(1, RTW_TX_DESC_W5_DATA_RTS_SHORT);
882774f206SBjoern A. Zeeb 	}
8990aac0d8SBjoern A. Zeeb 
9090aac0d8SBjoern A. Zeeb 	if (pkt_info->tim_offset)
9190aac0d8SBjoern A. Zeeb 		tx_desc->w9 |= le32_encode_bits(1, RTW_TX_DESC_W9_TIM_EN) |
9290aac0d8SBjoern A. Zeeb 			       le32_encode_bits(pkt_info->tim_offset, RTW_TX_DESC_W9_TIM_OFFSET);
932774f206SBjoern A. Zeeb }
942774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_tx_fill_tx_desc);
952774f206SBjoern A. Zeeb 
962774f206SBjoern A. Zeeb static u8 get_tx_ampdu_factor(struct ieee80211_sta *sta)
972774f206SBjoern A. Zeeb {
986cf748adSBjoern A. Zeeb 	u8 exp = sta->deflink.ht_cap.ampdu_factor;
992774f206SBjoern A. Zeeb 
1002774f206SBjoern A. Zeeb 	/* the least ampdu factor is 8K, and the value in the tx desc is the
1012774f206SBjoern A. Zeeb 	 * max aggregation num, which represents val * 2 packets can be
1022774f206SBjoern A. Zeeb 	 * aggregated in an AMPDU, so here we should use 8/2=4 as the base
1032774f206SBjoern A. Zeeb 	 */
1042774f206SBjoern A. Zeeb 	return (BIT(2) << exp) - 1;
1052774f206SBjoern A. Zeeb }
1062774f206SBjoern A. Zeeb 
1072774f206SBjoern A. Zeeb static u8 get_tx_ampdu_density(struct ieee80211_sta *sta)
1082774f206SBjoern A. Zeeb {
1096cf748adSBjoern A. Zeeb 	return sta->deflink.ht_cap.ampdu_density;
1102774f206SBjoern A. Zeeb }
1112774f206SBjoern A. Zeeb 
1122774f206SBjoern A. Zeeb static u8 get_highest_ht_tx_rate(struct rtw_dev *rtwdev,
1132774f206SBjoern A. Zeeb 				 struct ieee80211_sta *sta)
1142774f206SBjoern A. Zeeb {
1152774f206SBjoern A. Zeeb 	u8 rate;
1162774f206SBjoern A. Zeeb 
1176cf748adSBjoern A. Zeeb 	if (rtwdev->hal.rf_type == RF_2T2R && sta->deflink.ht_cap.mcs.rx_mask[1] != 0)
1182774f206SBjoern A. Zeeb 		rate = DESC_RATEMCS15;
1192774f206SBjoern A. Zeeb 	else
1202774f206SBjoern A. Zeeb 		rate = DESC_RATEMCS7;
1212774f206SBjoern A. Zeeb 
1222774f206SBjoern A. Zeeb 	return rate;
1232774f206SBjoern A. Zeeb }
1242774f206SBjoern A. Zeeb 
1252774f206SBjoern A. Zeeb static u8 get_highest_vht_tx_rate(struct rtw_dev *rtwdev,
1262774f206SBjoern A. Zeeb 				  struct ieee80211_sta *sta)
1272774f206SBjoern A. Zeeb {
1282774f206SBjoern A. Zeeb 	struct rtw_efuse *efuse = &rtwdev->efuse;
1292774f206SBjoern A. Zeeb 	u8 rate;
1302774f206SBjoern A. Zeeb 	u16 tx_mcs_map;
1312774f206SBjoern A. Zeeb 
1326cf748adSBjoern A. Zeeb 	tx_mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.tx_mcs_map);
1332774f206SBjoern A. Zeeb 	if (efuse->hw_cap.nss == 1) {
1342774f206SBjoern A. Zeeb 		switch (tx_mcs_map & 0x3) {
1352774f206SBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_7:
1362774f206SBjoern A. Zeeb 			rate = DESC_RATEVHT1SS_MCS7;
1372774f206SBjoern A. Zeeb 			break;
1382774f206SBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_8:
1392774f206SBjoern A. Zeeb 			rate = DESC_RATEVHT1SS_MCS8;
1402774f206SBjoern A. Zeeb 			break;
1412774f206SBjoern A. Zeeb 		default:
1422774f206SBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_9:
1432774f206SBjoern A. Zeeb 			rate = DESC_RATEVHT1SS_MCS9;
1442774f206SBjoern A. Zeeb 			break;
1452774f206SBjoern A. Zeeb 		}
1462774f206SBjoern A. Zeeb 	} else if (efuse->hw_cap.nss >= 2) {
1472774f206SBjoern A. Zeeb 		switch ((tx_mcs_map & 0xc) >> 2) {
1482774f206SBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_7:
1492774f206SBjoern A. Zeeb 			rate = DESC_RATEVHT2SS_MCS7;
1502774f206SBjoern A. Zeeb 			break;
1512774f206SBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_8:
1522774f206SBjoern A. Zeeb 			rate = DESC_RATEVHT2SS_MCS8;
1532774f206SBjoern A. Zeeb 			break;
1542774f206SBjoern A. Zeeb 		default:
1552774f206SBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_9:
1562774f206SBjoern A. Zeeb 			rate = DESC_RATEVHT2SS_MCS9;
1572774f206SBjoern A. Zeeb 			break;
1582774f206SBjoern A. Zeeb 		}
1592774f206SBjoern A. Zeeb 	} else {
1602774f206SBjoern A. Zeeb 		rate = DESC_RATEVHT1SS_MCS9;
1612774f206SBjoern A. Zeeb 	}
1622774f206SBjoern A. Zeeb 
1632774f206SBjoern A. Zeeb 	return rate;
1642774f206SBjoern A. Zeeb }
1652774f206SBjoern A. Zeeb 
1662774f206SBjoern A. Zeeb static void rtw_tx_report_enable(struct rtw_dev *rtwdev,
1672774f206SBjoern A. Zeeb 				 struct rtw_tx_pkt_info *pkt_info)
1682774f206SBjoern A. Zeeb {
1692774f206SBjoern A. Zeeb 	struct rtw_tx_report *tx_report = &rtwdev->tx_report;
1702774f206SBjoern A. Zeeb 
1712774f206SBjoern A. Zeeb 	/* [11:8], reserved, fills with zero
1722774f206SBjoern A. Zeeb 	 * [7:2],  tx report sequence number
1732774f206SBjoern A. Zeeb 	 * [1:0],  firmware use, fills with zero
1742774f206SBjoern A. Zeeb 	 */
1752774f206SBjoern A. Zeeb 	pkt_info->sn = (atomic_inc_return(&tx_report->sn) << 2) & 0xfc;
1762774f206SBjoern A. Zeeb 	pkt_info->report = true;
1772774f206SBjoern A. Zeeb }
1782774f206SBjoern A. Zeeb 
1792774f206SBjoern A. Zeeb void rtw_tx_report_purge_timer(struct timer_list *t)
1802774f206SBjoern A. Zeeb {
1812774f206SBjoern A. Zeeb 	struct rtw_dev *rtwdev = from_timer(rtwdev, t, tx_report.purge_timer);
1822774f206SBjoern A. Zeeb 	struct rtw_tx_report *tx_report = &rtwdev->tx_report;
1832774f206SBjoern A. Zeeb 	unsigned long flags;
1842774f206SBjoern A. Zeeb 
185e140d551SBjoern A. Zeeb #if defined(__linux__)
1862774f206SBjoern A. Zeeb 	if (skb_queue_len(&tx_report->queue) == 0)
1872774f206SBjoern A. Zeeb 		return;
1882774f206SBjoern A. Zeeb 
1892774f206SBjoern A. Zeeb 	rtw_warn(rtwdev, "failed to get tx report from firmware\n");
1902774f206SBjoern A. Zeeb 
1912774f206SBjoern A. Zeeb 	spin_lock_irqsave(&tx_report->q_lock, flags);
1922774f206SBjoern A. Zeeb 	skb_queue_purge(&tx_report->queue);
1932774f206SBjoern A. Zeeb 	spin_unlock_irqrestore(&tx_report->q_lock, flags);
194e140d551SBjoern A. Zeeb #elif defined(__FreeBSD__)
195e140d551SBjoern A. Zeeb 	uint32_t qlen;
196e140d551SBjoern A. Zeeb 
197e140d551SBjoern A. Zeeb 	spin_lock_irqsave(&tx_report->q_lock, flags);
198e140d551SBjoern A. Zeeb 	qlen = skb_queue_len(&tx_report->queue);
199e140d551SBjoern A. Zeeb 	if (qlen > 0)
200e140d551SBjoern A. Zeeb 		skb_queue_purge(&tx_report->queue);
201e140d551SBjoern A. Zeeb 	spin_unlock_irqrestore(&tx_report->q_lock, flags);
202e140d551SBjoern A. Zeeb 
203e140d551SBjoern A. Zeeb 	/*
204e140d551SBjoern A. Zeeb 	 * XXX while there could be a new enqueue in the queue
205e140d551SBjoern A. Zeeb 	 * simply not yet processed given the timer is updated without
206e140d551SBjoern A. Zeeb 	 * locks after enqueue in rtw_tx_report_enqueue(), the numbers
207e140d551SBjoern A. Zeeb 	 * seen can be in the 100s.  We revert to rtw_dbg from
208e140d551SBjoern A. Zeeb 	 * Linux git 584dce175f0461d5d9d63952a1e7955678c91086 .
209e140d551SBjoern A. Zeeb 	 */
210e140d551SBjoern A. Zeeb 	rtw_dbg(rtwdev, RTW_DBG_TX, "failed to get tx report from firmware: "
211e140d551SBjoern A. Zeeb 	    "txreport qlen %u\n", qlen);
212e140d551SBjoern A. Zeeb #endif
2132774f206SBjoern A. Zeeb }
2142774f206SBjoern A. Zeeb 
2152774f206SBjoern A. Zeeb void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn)
2162774f206SBjoern A. Zeeb {
2172774f206SBjoern A. Zeeb 	struct rtw_tx_report *tx_report = &rtwdev->tx_report;
2182774f206SBjoern A. Zeeb 	unsigned long flags;
2192774f206SBjoern A. Zeeb 	u8 *drv_data;
2202774f206SBjoern A. Zeeb 
2212774f206SBjoern A. Zeeb 	/* pass sn to tx report handler through driver data */
2222774f206SBjoern A. Zeeb 	drv_data = (u8 *)IEEE80211_SKB_CB(skb)->status.status_driver_data;
2232774f206SBjoern A. Zeeb 	*drv_data = sn;
2242774f206SBjoern A. Zeeb 
2252774f206SBjoern A. Zeeb 	spin_lock_irqsave(&tx_report->q_lock, flags);
2262774f206SBjoern A. Zeeb 	__skb_queue_tail(&tx_report->queue, skb);
2272774f206SBjoern A. Zeeb 	spin_unlock_irqrestore(&tx_report->q_lock, flags);
2282774f206SBjoern A. Zeeb 
2292774f206SBjoern A. Zeeb 	mod_timer(&tx_report->purge_timer, jiffies + RTW_TX_PROBE_TIMEOUT);
2302774f206SBjoern A. Zeeb }
2312774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_tx_report_enqueue);
2322774f206SBjoern A. Zeeb 
2332774f206SBjoern A. Zeeb static void rtw_tx_report_tx_status(struct rtw_dev *rtwdev,
2342774f206SBjoern A. Zeeb 				    struct sk_buff *skb, bool acked)
2352774f206SBjoern A. Zeeb {
2362774f206SBjoern A. Zeeb 	struct ieee80211_tx_info *info;
2372774f206SBjoern A. Zeeb 
2382774f206SBjoern A. Zeeb 	info = IEEE80211_SKB_CB(skb);
2392774f206SBjoern A. Zeeb 	ieee80211_tx_info_clear_status(info);
2402774f206SBjoern A. Zeeb 	if (acked)
2412774f206SBjoern A. Zeeb 		info->flags |= IEEE80211_TX_STAT_ACK;
2422774f206SBjoern A. Zeeb 	else
2432774f206SBjoern A. Zeeb 		info->flags &= ~IEEE80211_TX_STAT_ACK;
2442774f206SBjoern A. Zeeb 
2452774f206SBjoern A. Zeeb 	ieee80211_tx_status_irqsafe(rtwdev->hw, skb);
2462774f206SBjoern A. Zeeb }
2472774f206SBjoern A. Zeeb 
2482774f206SBjoern A. Zeeb void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src)
2492774f206SBjoern A. Zeeb {
2502774f206SBjoern A. Zeeb 	struct rtw_tx_report *tx_report = &rtwdev->tx_report;
2512774f206SBjoern A. Zeeb 	struct rtw_c2h_cmd *c2h;
2522774f206SBjoern A. Zeeb 	struct sk_buff *cur, *tmp;
2532774f206SBjoern A. Zeeb 	unsigned long flags;
2542774f206SBjoern A. Zeeb 	u8 sn, st;
2552774f206SBjoern A. Zeeb 	u8 *n;
2562774f206SBjoern A. Zeeb 
2572774f206SBjoern A. Zeeb 	c2h = get_c2h_from_skb(skb);
2582774f206SBjoern A. Zeeb 
2592774f206SBjoern A. Zeeb 	if (src == C2H_CCX_TX_RPT) {
2602774f206SBjoern A. Zeeb 		sn = GET_CCX_REPORT_SEQNUM_V0(c2h->payload);
2612774f206SBjoern A. Zeeb 		st = GET_CCX_REPORT_STATUS_V0(c2h->payload);
2622774f206SBjoern A. Zeeb 	} else {
2632774f206SBjoern A. Zeeb 		sn = GET_CCX_REPORT_SEQNUM_V1(c2h->payload);
2642774f206SBjoern A. Zeeb 		st = GET_CCX_REPORT_STATUS_V1(c2h->payload);
2652774f206SBjoern A. Zeeb 	}
2662774f206SBjoern A. Zeeb 
2672774f206SBjoern A. Zeeb 	spin_lock_irqsave(&tx_report->q_lock, flags);
2682774f206SBjoern A. Zeeb 	skb_queue_walk_safe(&tx_report->queue, cur, tmp) {
2692774f206SBjoern A. Zeeb 		n = (u8 *)IEEE80211_SKB_CB(cur)->status.status_driver_data;
2702774f206SBjoern A. Zeeb 		if (*n == sn) {
2712774f206SBjoern A. Zeeb 			__skb_unlink(cur, &tx_report->queue);
2722774f206SBjoern A. Zeeb 			rtw_tx_report_tx_status(rtwdev, cur, st == 0);
2732774f206SBjoern A. Zeeb 			break;
2742774f206SBjoern A. Zeeb 		}
2752774f206SBjoern A. Zeeb 	}
2762774f206SBjoern A. Zeeb 	spin_unlock_irqrestore(&tx_report->q_lock, flags);
2772774f206SBjoern A. Zeeb }
2782774f206SBjoern A. Zeeb 
2792774f206SBjoern A. Zeeb static u8 rtw_get_mgmt_rate(struct rtw_dev *rtwdev, struct sk_buff *skb,
2802774f206SBjoern A. Zeeb 			    u8 lowest_rate, bool ignore_rate)
2812774f206SBjoern A. Zeeb {
2822774f206SBjoern A. Zeeb 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
2832774f206SBjoern A. Zeeb 	struct ieee80211_vif *vif = tx_info->control.vif;
2842774f206SBjoern A. Zeeb 	bool force_lowest = test_bit(RTW_FLAG_FORCE_LOWEST_RATE, rtwdev->flags);
2852774f206SBjoern A. Zeeb 
2862774f206SBjoern A. Zeeb 	if (!vif || !vif->bss_conf.basic_rates || ignore_rate || force_lowest)
2872774f206SBjoern A. Zeeb 		return lowest_rate;
2882774f206SBjoern A. Zeeb 
2892774f206SBjoern A. Zeeb 	return __ffs(vif->bss_conf.basic_rates) + lowest_rate;
2902774f206SBjoern A. Zeeb }
2912774f206SBjoern A. Zeeb 
2922774f206SBjoern A. Zeeb static void rtw_tx_pkt_info_update_rate(struct rtw_dev *rtwdev,
2932774f206SBjoern A. Zeeb 					struct rtw_tx_pkt_info *pkt_info,
2942774f206SBjoern A. Zeeb 					struct sk_buff *skb,
2952774f206SBjoern A. Zeeb 					bool ignore_rate)
2962774f206SBjoern A. Zeeb {
2972774f206SBjoern A. Zeeb 	if (rtwdev->hal.current_band_type == RTW_BAND_2G) {
2982774f206SBjoern A. Zeeb 		pkt_info->rate_id = RTW_RATEID_B_20M;
2992774f206SBjoern A. Zeeb 		pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, DESC_RATE1M,
3002774f206SBjoern A. Zeeb 						   ignore_rate);
3012774f206SBjoern A. Zeeb 	} else {
3022774f206SBjoern A. Zeeb 		pkt_info->rate_id = RTW_RATEID_G;
3032774f206SBjoern A. Zeeb 		pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, DESC_RATE6M,
3042774f206SBjoern A. Zeeb 						   ignore_rate);
3052774f206SBjoern A. Zeeb 	}
3062774f206SBjoern A. Zeeb 
3072774f206SBjoern A. Zeeb 	pkt_info->use_rate = true;
3082774f206SBjoern A. Zeeb 	pkt_info->dis_rate_fallback = true;
3092774f206SBjoern A. Zeeb }
3102774f206SBjoern A. Zeeb 
3112774f206SBjoern A. Zeeb static void rtw_tx_pkt_info_update_sec(struct rtw_dev *rtwdev,
3122774f206SBjoern A. Zeeb 				       struct rtw_tx_pkt_info *pkt_info,
3132774f206SBjoern A. Zeeb 				       struct sk_buff *skb)
3142774f206SBjoern A. Zeeb {
3152774f206SBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3162774f206SBjoern A. Zeeb 	u8 sec_type = 0;
3172774f206SBjoern A. Zeeb 
3182774f206SBjoern A. Zeeb 	if (info && info->control.hw_key) {
3192774f206SBjoern A. Zeeb 		struct ieee80211_key_conf *key = info->control.hw_key;
3202774f206SBjoern A. Zeeb 
3212774f206SBjoern A. Zeeb 		switch (key->cipher) {
3222774f206SBjoern A. Zeeb 		case WLAN_CIPHER_SUITE_WEP40:
3232774f206SBjoern A. Zeeb 		case WLAN_CIPHER_SUITE_WEP104:
3242774f206SBjoern A. Zeeb 		case WLAN_CIPHER_SUITE_TKIP:
3252774f206SBjoern A. Zeeb 			sec_type = 0x01;
3262774f206SBjoern A. Zeeb 			break;
3272774f206SBjoern A. Zeeb 		case WLAN_CIPHER_SUITE_CCMP:
3282774f206SBjoern A. Zeeb 			sec_type = 0x03;
3292774f206SBjoern A. Zeeb 			break;
3302774f206SBjoern A. Zeeb 		default:
3312774f206SBjoern A. Zeeb 			break;
3322774f206SBjoern A. Zeeb 		}
3332774f206SBjoern A. Zeeb 	}
3342774f206SBjoern A. Zeeb 
3352774f206SBjoern A. Zeeb 	pkt_info->sec_type = sec_type;
3362774f206SBjoern A. Zeeb }
3372774f206SBjoern A. Zeeb 
3382774f206SBjoern A. Zeeb static void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev,
3392774f206SBjoern A. Zeeb 					struct rtw_tx_pkt_info *pkt_info,
3402774f206SBjoern A. Zeeb 					struct ieee80211_sta *sta,
3412774f206SBjoern A. Zeeb 					struct sk_buff *skb)
3422774f206SBjoern A. Zeeb {
3432774f206SBjoern A. Zeeb 	rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, false);
3442774f206SBjoern A. Zeeb 	pkt_info->dis_qselseq = true;
3452774f206SBjoern A. Zeeb 	pkt_info->en_hwseq = true;
3462774f206SBjoern A. Zeeb 	pkt_info->hw_ssn_sel = 0;
3472774f206SBjoern A. Zeeb 	/* TODO: need to change hw port and hw ssn sel for multiple vifs */
3482774f206SBjoern A. Zeeb }
3492774f206SBjoern A. Zeeb 
3502774f206SBjoern A. Zeeb static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev,
3512774f206SBjoern A. Zeeb 					struct rtw_tx_pkt_info *pkt_info,
3522774f206SBjoern A. Zeeb 					struct ieee80211_sta *sta,
3532774f206SBjoern A. Zeeb 					struct sk_buff *skb)
3542774f206SBjoern A. Zeeb {
3552774f206SBjoern A. Zeeb 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
3562774f206SBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3572774f206SBjoern A. Zeeb 	struct ieee80211_hw *hw = rtwdev->hw;
3582774f206SBjoern A. Zeeb 	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
3592774f206SBjoern A. Zeeb 	struct rtw_sta_info *si;
3602774f206SBjoern A. Zeeb 	u8 fix_rate;
3612774f206SBjoern A. Zeeb 	u16 seq;
3622774f206SBjoern A. Zeeb 	u8 ampdu_factor = 0;
3632774f206SBjoern A. Zeeb 	u8 ampdu_density = 0;
3642774f206SBjoern A. Zeeb 	bool ampdu_en = false;
3652774f206SBjoern A. Zeeb 	u8 rate = DESC_RATE6M;
3662774f206SBjoern A. Zeeb 	u8 rate_id = 6;
3672774f206SBjoern A. Zeeb 	u8 bw = RTW_CHANNEL_WIDTH_20;
3682774f206SBjoern A. Zeeb 	bool stbc = false;
3692774f206SBjoern A. Zeeb 	bool ldpc = false;
3702774f206SBjoern A. Zeeb 
3712774f206SBjoern A. Zeeb 	seq = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
3722774f206SBjoern A. Zeeb 
3732774f206SBjoern A. Zeeb 	/* for broadcast/multicast, use default values */
3742774f206SBjoern A. Zeeb 	if (!sta)
3752774f206SBjoern A. Zeeb 		goto out;
3762774f206SBjoern A. Zeeb 
3772774f206SBjoern A. Zeeb 	if (info->flags & IEEE80211_TX_CTL_AMPDU) {
3782774f206SBjoern A. Zeeb 		ampdu_en = true;
3792774f206SBjoern A. Zeeb 		ampdu_factor = get_tx_ampdu_factor(sta);
3802774f206SBjoern A. Zeeb 		ampdu_density = get_tx_ampdu_density(sta);
3812774f206SBjoern A. Zeeb 	}
3822774f206SBjoern A. Zeeb 
3832774f206SBjoern A. Zeeb 	if (info->control.use_rts || skb->len > hw->wiphy->rts_threshold)
3842774f206SBjoern A. Zeeb 		pkt_info->rts = true;
3852774f206SBjoern A. Zeeb 
3866cf748adSBjoern A. Zeeb 	if (sta->deflink.vht_cap.vht_supported)
3872774f206SBjoern A. Zeeb 		rate = get_highest_vht_tx_rate(rtwdev, sta);
3886cf748adSBjoern A. Zeeb 	else if (sta->deflink.ht_cap.ht_supported)
3892774f206SBjoern A. Zeeb 		rate = get_highest_ht_tx_rate(rtwdev, sta);
3906cf748adSBjoern A. Zeeb 	else if (sta->deflink.supp_rates[0] <= 0xf)
3912774f206SBjoern A. Zeeb 		rate = DESC_RATE11M;
3922774f206SBjoern A. Zeeb 	else
3932774f206SBjoern A. Zeeb 		rate = DESC_RATE54M;
3942774f206SBjoern A. Zeeb 
3952774f206SBjoern A. Zeeb 	si = (struct rtw_sta_info *)sta->drv_priv;
3962774f206SBjoern A. Zeeb 
3972774f206SBjoern A. Zeeb 	bw = si->bw_mode;
3982774f206SBjoern A. Zeeb 	rate_id = si->rate_id;
3999c951734SBjoern A. Zeeb 	stbc = rtwdev->hal.txrx_1ss ? false : si->stbc_en;
4002774f206SBjoern A. Zeeb 	ldpc = si->ldpc_en;
4012774f206SBjoern A. Zeeb 
4022774f206SBjoern A. Zeeb out:
4032774f206SBjoern A. Zeeb 	pkt_info->seq = seq;
4042774f206SBjoern A. Zeeb 	pkt_info->ampdu_factor = ampdu_factor;
4052774f206SBjoern A. Zeeb 	pkt_info->ampdu_density = ampdu_density;
4062774f206SBjoern A. Zeeb 	pkt_info->ampdu_en = ampdu_en;
4072774f206SBjoern A. Zeeb 	pkt_info->rate = rate;
4082774f206SBjoern A. Zeeb 	pkt_info->rate_id = rate_id;
4092774f206SBjoern A. Zeeb 	pkt_info->bw = bw;
4102774f206SBjoern A. Zeeb 	pkt_info->stbc = stbc;
4112774f206SBjoern A. Zeeb 	pkt_info->ldpc = ldpc;
4122774f206SBjoern A. Zeeb 
4132774f206SBjoern A. Zeeb 	fix_rate = dm_info->fix_rate;
4142774f206SBjoern A. Zeeb 	if (fix_rate < DESC_RATE_MAX) {
4152774f206SBjoern A. Zeeb 		pkt_info->rate = fix_rate;
4162774f206SBjoern A. Zeeb 		pkt_info->dis_rate_fallback = true;
4172774f206SBjoern A. Zeeb 		pkt_info->use_rate = true;
4182774f206SBjoern A. Zeeb 	}
4192774f206SBjoern A. Zeeb }
4202774f206SBjoern A. Zeeb 
4212774f206SBjoern A. Zeeb void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev,
4222774f206SBjoern A. Zeeb 			    struct rtw_tx_pkt_info *pkt_info,
4232774f206SBjoern A. Zeeb 			    struct ieee80211_sta *sta,
4242774f206SBjoern A. Zeeb 			    struct sk_buff *skb)
4252774f206SBjoern A. Zeeb {
42690aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
4272774f206SBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
4282774f206SBjoern A. Zeeb 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
429*a0ccc12fSBjoern A. Zeeb 	struct ieee80211_vif *vif = info->control.vif;
4302774f206SBjoern A. Zeeb 	struct rtw_sta_info *si;
431*a0ccc12fSBjoern A. Zeeb 	struct rtw_vif *rtwvif;
4322774f206SBjoern A. Zeeb 	__le16 fc = hdr->frame_control;
4332774f206SBjoern A. Zeeb 	bool bmc;
4342774f206SBjoern A. Zeeb 
4352774f206SBjoern A. Zeeb 	if (sta) {
4362774f206SBjoern A. Zeeb 		si = (struct rtw_sta_info *)sta->drv_priv;
437*a0ccc12fSBjoern A. Zeeb 		pkt_info->mac_id = si->mac_id;
438*a0ccc12fSBjoern A. Zeeb 	} else if (vif) {
439*a0ccc12fSBjoern A. Zeeb 		rtwvif = (struct rtw_vif *)vif->drv_priv;
440*a0ccc12fSBjoern A. Zeeb 		pkt_info->mac_id = rtwvif->mac_id;
4412774f206SBjoern A. Zeeb 	}
4422774f206SBjoern A. Zeeb 
4432774f206SBjoern A. Zeeb 	if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc))
4442774f206SBjoern A. Zeeb 		rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb);
4452774f206SBjoern A. Zeeb 	else if (ieee80211_is_data(fc))
4462774f206SBjoern A. Zeeb 		rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb);
4472774f206SBjoern A. Zeeb 
4482774f206SBjoern A. Zeeb 	bmc = is_broadcast_ether_addr(hdr->addr1) ||
4492774f206SBjoern A. Zeeb 	      is_multicast_ether_addr(hdr->addr1);
4502774f206SBjoern A. Zeeb 
4512774f206SBjoern A. Zeeb 	if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
4522774f206SBjoern A. Zeeb 		rtw_tx_report_enable(rtwdev, pkt_info);
4532774f206SBjoern A. Zeeb 
4542774f206SBjoern A. Zeeb 	pkt_info->bmc = bmc;
4552774f206SBjoern A. Zeeb 	rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb);
4562774f206SBjoern A. Zeeb 	pkt_info->tx_pkt_size = skb->len;
4572774f206SBjoern A. Zeeb 	pkt_info->offset = chip->tx_pkt_desc_sz;
4582774f206SBjoern A. Zeeb 	pkt_info->qsel = skb->priority;
4592774f206SBjoern A. Zeeb 	pkt_info->ls = true;
4602774f206SBjoern A. Zeeb 
4612774f206SBjoern A. Zeeb 	/* maybe merge with tx status ? */
4622774f206SBjoern A. Zeeb 	rtw_tx_stats(rtwdev, vif, skb);
4632774f206SBjoern A. Zeeb }
4642774f206SBjoern A. Zeeb 
4652774f206SBjoern A. Zeeb void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev,
4662774f206SBjoern A. Zeeb 				      struct rtw_tx_pkt_info *pkt_info,
4672774f206SBjoern A. Zeeb 				      struct sk_buff *skb,
4682774f206SBjoern A. Zeeb 				      enum rtw_rsvd_packet_type type)
4692774f206SBjoern A. Zeeb {
47090aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
4712774f206SBjoern A. Zeeb 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
4722774f206SBjoern A. Zeeb 	bool bmc;
4732774f206SBjoern A. Zeeb 
4742774f206SBjoern A. Zeeb 	/* A beacon or dummy reserved page packet indicates that it is the first
4752774f206SBjoern A. Zeeb 	 * reserved page, and the qsel of it will be set in each hci.
4762774f206SBjoern A. Zeeb 	 */
4772774f206SBjoern A. Zeeb 	if (type != RSVD_BEACON && type != RSVD_DUMMY)
4782774f206SBjoern A. Zeeb 		pkt_info->qsel = TX_DESC_QSEL_MGMT;
4792774f206SBjoern A. Zeeb 
4802774f206SBjoern A. Zeeb 	rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, true);
4812774f206SBjoern A. Zeeb 
4822774f206SBjoern A. Zeeb 	bmc = is_broadcast_ether_addr(hdr->addr1) ||
4832774f206SBjoern A. Zeeb 	      is_multicast_ether_addr(hdr->addr1);
4842774f206SBjoern A. Zeeb 	pkt_info->bmc = bmc;
4852774f206SBjoern A. Zeeb 	pkt_info->tx_pkt_size = skb->len;
4862774f206SBjoern A. Zeeb 	pkt_info->offset = chip->tx_pkt_desc_sz;
4872774f206SBjoern A. Zeeb 	pkt_info->ls = true;
4882774f206SBjoern A. Zeeb 	if (type == RSVD_PS_POLL) {
4892774f206SBjoern A. Zeeb 		pkt_info->nav_use_hdr = true;
4902774f206SBjoern A. Zeeb 	} else {
4912774f206SBjoern A. Zeeb 		pkt_info->dis_qselseq = true;
4922774f206SBjoern A. Zeeb 		pkt_info->en_hwseq = true;
4932774f206SBjoern A. Zeeb 		pkt_info->hw_ssn_sel = 0;
4942774f206SBjoern A. Zeeb 	}
4952774f206SBjoern A. Zeeb 	if (type == RSVD_QOS_NULL)
4962774f206SBjoern A. Zeeb 		pkt_info->bt_null = true;
4972774f206SBjoern A. Zeeb 
4989c951734SBjoern A. Zeeb 	if (type == RSVD_BEACON) {
4999c951734SBjoern A. Zeeb 		struct rtw_rsvd_page *rsvd_pkt;
5009c951734SBjoern A. Zeeb 		int hdr_len;
5019c951734SBjoern A. Zeeb 
5029c951734SBjoern A. Zeeb 		rsvd_pkt = list_first_entry_or_null(&rtwdev->rsvd_page_list,
5039c951734SBjoern A. Zeeb 						    struct rtw_rsvd_page,
5049c951734SBjoern A. Zeeb 						    build_list);
5059c951734SBjoern A. Zeeb 		if (rsvd_pkt && rsvd_pkt->tim_offset != 0) {
5069c951734SBjoern A. Zeeb 			hdr_len = sizeof(struct ieee80211_hdr_3addr);
5079c951734SBjoern A. Zeeb 			pkt_info->tim_offset = rsvd_pkt->tim_offset - hdr_len;
5089c951734SBjoern A. Zeeb 		}
5099c951734SBjoern A. Zeeb 	}
5109c951734SBjoern A. Zeeb 
5112774f206SBjoern A. Zeeb 	rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb);
5122774f206SBjoern A. Zeeb 
5132774f206SBjoern A. Zeeb 	/* TODO: need to change hw port and hw ssn sel for multiple vifs */
5142774f206SBjoern A. Zeeb }
5152774f206SBjoern A. Zeeb 
5162774f206SBjoern A. Zeeb struct sk_buff *
5172774f206SBjoern A. Zeeb rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev,
5182774f206SBjoern A. Zeeb 				struct rtw_tx_pkt_info *pkt_info,
5192774f206SBjoern A. Zeeb 				u8 *buf, u32 size)
5202774f206SBjoern A. Zeeb {
52190aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
5222774f206SBjoern A. Zeeb 	struct sk_buff *skb;
5232774f206SBjoern A. Zeeb 	u32 tx_pkt_desc_sz;
5242774f206SBjoern A. Zeeb 	u32 length;
5252774f206SBjoern A. Zeeb 
5262774f206SBjoern A. Zeeb 	tx_pkt_desc_sz = chip->tx_pkt_desc_sz;
5272774f206SBjoern A. Zeeb 	length = size + tx_pkt_desc_sz;
5282774f206SBjoern A. Zeeb 	skb = dev_alloc_skb(length);
5292774f206SBjoern A. Zeeb 	if (!skb) {
5302774f206SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to alloc write data rsvd page skb\n");
5312774f206SBjoern A. Zeeb 		return NULL;
5322774f206SBjoern A. Zeeb 	}
5332774f206SBjoern A. Zeeb 
5342774f206SBjoern A. Zeeb 	skb_reserve(skb, tx_pkt_desc_sz);
5352774f206SBjoern A. Zeeb 	skb_put_data(skb, buf, size);
5362774f206SBjoern A. Zeeb 	rtw_tx_rsvd_page_pkt_info_update(rtwdev, pkt_info, skb, RSVD_BEACON);
5372774f206SBjoern A. Zeeb 
5382774f206SBjoern A. Zeeb 	return skb;
5392774f206SBjoern A. Zeeb }
5402774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_tx_write_data_rsvd_page_get);
5412774f206SBjoern A. Zeeb 
5422774f206SBjoern A. Zeeb struct sk_buff *
5432774f206SBjoern A. Zeeb rtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev,
5442774f206SBjoern A. Zeeb 			  struct rtw_tx_pkt_info *pkt_info,
5452774f206SBjoern A. Zeeb 			  u8 *buf, u32 size)
5462774f206SBjoern A. Zeeb {
54790aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
5482774f206SBjoern A. Zeeb 	struct sk_buff *skb;
5492774f206SBjoern A. Zeeb 	u32 tx_pkt_desc_sz;
5502774f206SBjoern A. Zeeb 	u32 length;
5512774f206SBjoern A. Zeeb 
5522774f206SBjoern A. Zeeb 	tx_pkt_desc_sz = chip->tx_pkt_desc_sz;
5532774f206SBjoern A. Zeeb 	length = size + tx_pkt_desc_sz;
5542774f206SBjoern A. Zeeb 	skb = dev_alloc_skb(length);
5552774f206SBjoern A. Zeeb 	if (!skb) {
5562774f206SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to alloc write data h2c skb\n");
5572774f206SBjoern A. Zeeb 		return NULL;
5582774f206SBjoern A. Zeeb 	}
5592774f206SBjoern A. Zeeb 
5602774f206SBjoern A. Zeeb 	skb_reserve(skb, tx_pkt_desc_sz);
5612774f206SBjoern A. Zeeb 	skb_put_data(skb, buf, size);
5622774f206SBjoern A. Zeeb 	pkt_info->tx_pkt_size = size;
5632774f206SBjoern A. Zeeb 
5642774f206SBjoern A. Zeeb 	return skb;
5652774f206SBjoern A. Zeeb }
5662774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_tx_write_data_h2c_get);
5672774f206SBjoern A. Zeeb 
5682774f206SBjoern A. Zeeb void rtw_tx(struct rtw_dev *rtwdev,
5692774f206SBjoern A. Zeeb 	    struct ieee80211_tx_control *control,
5702774f206SBjoern A. Zeeb 	    struct sk_buff *skb)
5712774f206SBjoern A. Zeeb {
5722774f206SBjoern A. Zeeb 	struct rtw_tx_pkt_info pkt_info = {0};
5732774f206SBjoern A. Zeeb 	int ret;
5742774f206SBjoern A. Zeeb 
5752774f206SBjoern A. Zeeb 	rtw_tx_pkt_info_update(rtwdev, &pkt_info, control->sta, skb);
5762774f206SBjoern A. Zeeb 	ret = rtw_hci_tx_write(rtwdev, &pkt_info, skb);
5772774f206SBjoern A. Zeeb 	if (ret) {
578e140d551SBjoern A. Zeeb #if defined(__linux__)
5792774f206SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to write TX skb to HCI\n");
580e140d551SBjoern A. Zeeb #elif defined(__FreeBSD__)
581e140d551SBjoern A. Zeeb 		rtw_err(rtwdev, "%s: failed to write TX skb to HCI: %d\n", __func__, ret);
582e140d551SBjoern A. Zeeb #endif
5832774f206SBjoern A. Zeeb 		goto out;
5842774f206SBjoern A. Zeeb 	}
5852774f206SBjoern A. Zeeb 
5862774f206SBjoern A. Zeeb 	rtw_hci_tx_kick_off(rtwdev);
5872774f206SBjoern A. Zeeb 
5882774f206SBjoern A. Zeeb 	return;
5892774f206SBjoern A. Zeeb 
5902774f206SBjoern A. Zeeb out:
5912774f206SBjoern A. Zeeb 	ieee80211_free_txskb(rtwdev->hw, skb);
5922774f206SBjoern A. Zeeb }
5932774f206SBjoern A. Zeeb 
5942774f206SBjoern A. Zeeb static void rtw_txq_check_agg(struct rtw_dev *rtwdev,
5952774f206SBjoern A. Zeeb 			      struct rtw_txq *rtwtxq,
5962774f206SBjoern A. Zeeb 			      struct sk_buff *skb)
5972774f206SBjoern A. Zeeb {
5982774f206SBjoern A. Zeeb 	struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
5992774f206SBjoern A. Zeeb 	struct ieee80211_tx_info *info;
6002774f206SBjoern A. Zeeb 	struct rtw_sta_info *si;
6012774f206SBjoern A. Zeeb 
6022774f206SBjoern A. Zeeb 	if (test_bit(RTW_TXQ_AMPDU, &rtwtxq->flags)) {
6032774f206SBjoern A. Zeeb 		info = IEEE80211_SKB_CB(skb);
6042774f206SBjoern A. Zeeb 		info->flags |= IEEE80211_TX_CTL_AMPDU;
6052774f206SBjoern A. Zeeb 		return;
6062774f206SBjoern A. Zeeb 	}
6072774f206SBjoern A. Zeeb 
6082774f206SBjoern A. Zeeb 	if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
6092774f206SBjoern A. Zeeb 		return;
6102774f206SBjoern A. Zeeb 
6112774f206SBjoern A. Zeeb 	if (test_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags))
6122774f206SBjoern A. Zeeb 		return;
6132774f206SBjoern A. Zeeb 
6142774f206SBjoern A. Zeeb 	if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
6152774f206SBjoern A. Zeeb 		return;
6162774f206SBjoern A. Zeeb 
6172774f206SBjoern A. Zeeb 	if (!txq->sta)
6182774f206SBjoern A. Zeeb 		return;
6192774f206SBjoern A. Zeeb 
6202774f206SBjoern A. Zeeb 	si = (struct rtw_sta_info *)txq->sta->drv_priv;
6212774f206SBjoern A. Zeeb 	set_bit(txq->tid, si->tid_ba);
6222774f206SBjoern A. Zeeb 
6232774f206SBjoern A. Zeeb 	ieee80211_queue_work(rtwdev->hw, &rtwdev->ba_work);
6242774f206SBjoern A. Zeeb }
6252774f206SBjoern A. Zeeb 
6262774f206SBjoern A. Zeeb static int rtw_txq_push_skb(struct rtw_dev *rtwdev,
6272774f206SBjoern A. Zeeb 			    struct rtw_txq *rtwtxq,
6282774f206SBjoern A. Zeeb 			    struct sk_buff *skb)
6292774f206SBjoern A. Zeeb {
6302774f206SBjoern A. Zeeb 	struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
6312774f206SBjoern A. Zeeb 	struct rtw_tx_pkt_info pkt_info = {0};
6322774f206SBjoern A. Zeeb 	int ret;
6332774f206SBjoern A. Zeeb 
6342774f206SBjoern A. Zeeb 	rtw_txq_check_agg(rtwdev, rtwtxq, skb);
6352774f206SBjoern A. Zeeb 
6362774f206SBjoern A. Zeeb 	rtw_tx_pkt_info_update(rtwdev, &pkt_info, txq->sta, skb);
6372774f206SBjoern A. Zeeb 	ret = rtw_hci_tx_write(rtwdev, &pkt_info, skb);
6382774f206SBjoern A. Zeeb 	if (ret) {
639e140d551SBjoern A. Zeeb #if defined(__linux__)
6402774f206SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to write TX skb to HCI\n");
641e140d551SBjoern A. Zeeb #elif defined(__FreeBSD__)
642e140d551SBjoern A. Zeeb 		rtw_err(rtwdev, "%s: failed to write TX skb to HCI: %d\n", __func__, ret);
643e140d551SBjoern A. Zeeb #endif
6442774f206SBjoern A. Zeeb 		return ret;
6452774f206SBjoern A. Zeeb 	}
6462774f206SBjoern A. Zeeb 	return 0;
6472774f206SBjoern A. Zeeb }
6482774f206SBjoern A. Zeeb 
6492774f206SBjoern A. Zeeb static struct sk_buff *rtw_txq_dequeue(struct rtw_dev *rtwdev,
6502774f206SBjoern A. Zeeb 				       struct rtw_txq *rtwtxq)
6512774f206SBjoern A. Zeeb {
6522774f206SBjoern A. Zeeb 	struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
6532774f206SBjoern A. Zeeb 	struct sk_buff *skb;
6542774f206SBjoern A. Zeeb 
6552774f206SBjoern A. Zeeb 	skb = ieee80211_tx_dequeue(rtwdev->hw, txq);
6562774f206SBjoern A. Zeeb 	if (!skb)
6572774f206SBjoern A. Zeeb 		return NULL;
6582774f206SBjoern A. Zeeb 
6592774f206SBjoern A. Zeeb 	return skb;
6602774f206SBjoern A. Zeeb }
6612774f206SBjoern A. Zeeb 
6622774f206SBjoern A. Zeeb static void rtw_txq_push(struct rtw_dev *rtwdev,
6632774f206SBjoern A. Zeeb 			 struct rtw_txq *rtwtxq,
6642774f206SBjoern A. Zeeb 			 unsigned long frames)
6652774f206SBjoern A. Zeeb {
6662774f206SBjoern A. Zeeb 	struct sk_buff *skb;
6672774f206SBjoern A. Zeeb 	int ret;
6682774f206SBjoern A. Zeeb 	int i;
6692774f206SBjoern A. Zeeb 
6702774f206SBjoern A. Zeeb 	rcu_read_lock();
6712774f206SBjoern A. Zeeb 
6722774f206SBjoern A. Zeeb 	for (i = 0; i < frames; i++) {
6732774f206SBjoern A. Zeeb 		skb = rtw_txq_dequeue(rtwdev, rtwtxq);
6742774f206SBjoern A. Zeeb 		if (!skb)
6752774f206SBjoern A. Zeeb 			break;
6762774f206SBjoern A. Zeeb 
6772774f206SBjoern A. Zeeb 		ret = rtw_txq_push_skb(rtwdev, rtwtxq, skb);
6782774f206SBjoern A. Zeeb 		if (ret) {
679728afa88SBjoern A. Zeeb #if defined(__FreeBSD__)
680728afa88SBjoern A. Zeeb 			dev_kfree_skb_any(skb);
681728afa88SBjoern A. Zeeb 			rtw_err(rtwdev, "failed to push skb, ret %d\n", ret);
682728afa88SBjoern A. Zeeb #else
6832774f206SBjoern A. Zeeb 			rtw_err(rtwdev, "failed to pusk skb, ret %d\n", ret);
684728afa88SBjoern A. Zeeb #endif
6852774f206SBjoern A. Zeeb 			break;
6862774f206SBjoern A. Zeeb 		}
6872774f206SBjoern A. Zeeb 	}
6882774f206SBjoern A. Zeeb 
6892774f206SBjoern A. Zeeb 	rcu_read_unlock();
6902774f206SBjoern A. Zeeb }
6912774f206SBjoern A. Zeeb 
69290aac0d8SBjoern A. Zeeb void __rtw_tx_work(struct rtw_dev *rtwdev)
6932774f206SBjoern A. Zeeb {
6942774f206SBjoern A. Zeeb 	struct rtw_txq *rtwtxq, *tmp;
6952774f206SBjoern A. Zeeb 
6962774f206SBjoern A. Zeeb 	spin_lock_bh(&rtwdev->txq_lock);
6972774f206SBjoern A. Zeeb 
6982774f206SBjoern A. Zeeb 	list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) {
6992774f206SBjoern A. Zeeb 		struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
7002774f206SBjoern A. Zeeb 		unsigned long frame_cnt;
7012774f206SBjoern A. Zeeb 
70211c53278SBjoern A. Zeeb 		ieee80211_txq_get_depth(txq, &frame_cnt, NULL);
7032774f206SBjoern A. Zeeb 		rtw_txq_push(rtwdev, rtwtxq, frame_cnt);
7042774f206SBjoern A. Zeeb 
7052774f206SBjoern A. Zeeb 		list_del_init(&rtwtxq->list);
7062774f206SBjoern A. Zeeb 	}
7072774f206SBjoern A. Zeeb 
7082774f206SBjoern A. Zeeb 	rtw_hci_tx_kick_off(rtwdev);
7092774f206SBjoern A. Zeeb 
7102774f206SBjoern A. Zeeb 	spin_unlock_bh(&rtwdev->txq_lock);
7112774f206SBjoern A. Zeeb }
7122774f206SBjoern A. Zeeb 
71390aac0d8SBjoern A. Zeeb void rtw_tx_work(struct work_struct *w)
71490aac0d8SBjoern A. Zeeb {
71590aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work);
71690aac0d8SBjoern A. Zeeb 
71790aac0d8SBjoern A. Zeeb 	__rtw_tx_work(rtwdev);
71890aac0d8SBjoern A. Zeeb }
71990aac0d8SBjoern A. Zeeb 
7202774f206SBjoern A. Zeeb void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq)
7212774f206SBjoern A. Zeeb {
7222774f206SBjoern A. Zeeb 	struct rtw_txq *rtwtxq;
7232774f206SBjoern A. Zeeb 
7242774f206SBjoern A. Zeeb 	if (!txq)
7252774f206SBjoern A. Zeeb 		return;
7262774f206SBjoern A. Zeeb 
7272774f206SBjoern A. Zeeb 	rtwtxq = (struct rtw_txq *)txq->drv_priv;
7282774f206SBjoern A. Zeeb 	INIT_LIST_HEAD(&rtwtxq->list);
7292774f206SBjoern A. Zeeb }
7302774f206SBjoern A. Zeeb 
7312774f206SBjoern A. Zeeb void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq)
7322774f206SBjoern A. Zeeb {
7332774f206SBjoern A. Zeeb 	struct rtw_txq *rtwtxq;
7342774f206SBjoern A. Zeeb 
7352774f206SBjoern A. Zeeb 	if (!txq)
7362774f206SBjoern A. Zeeb 		return;
7372774f206SBjoern A. Zeeb 
7382774f206SBjoern A. Zeeb 	rtwtxq = (struct rtw_txq *)txq->drv_priv;
7392774f206SBjoern A. Zeeb 	spin_lock_bh(&rtwdev->txq_lock);
7402774f206SBjoern A. Zeeb 	if (!list_empty(&rtwtxq->list))
7412774f206SBjoern A. Zeeb 		list_del_init(&rtwtxq->list);
7422774f206SBjoern A. Zeeb 	spin_unlock_bh(&rtwdev->txq_lock);
7432774f206SBjoern A. Zeeb }
74490aac0d8SBjoern A. Zeeb 
74590aac0d8SBjoern A. Zeeb static const enum rtw_tx_queue_type ac_to_hwq[] = {
74690aac0d8SBjoern A. Zeeb 	[IEEE80211_AC_VO] = RTW_TX_QUEUE_VO,
74790aac0d8SBjoern A. Zeeb 	[IEEE80211_AC_VI] = RTW_TX_QUEUE_VI,
74890aac0d8SBjoern A. Zeeb 	[IEEE80211_AC_BE] = RTW_TX_QUEUE_BE,
74990aac0d8SBjoern A. Zeeb 	[IEEE80211_AC_BK] = RTW_TX_QUEUE_BK,
75090aac0d8SBjoern A. Zeeb };
75190aac0d8SBjoern A. Zeeb 
75290aac0d8SBjoern A. Zeeb #if defined(__linux__)
75390aac0d8SBjoern A. Zeeb static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS);
75490aac0d8SBjoern A. Zeeb #elif defined(__FreeBSD__)
75590aac0d8SBjoern A. Zeeb rtw88_static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS);
75690aac0d8SBjoern A. Zeeb #endif
75790aac0d8SBjoern A. Zeeb 
75890aac0d8SBjoern A. Zeeb enum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac)
75990aac0d8SBjoern A. Zeeb {
76090aac0d8SBjoern A. Zeeb 	if (WARN_ON(unlikely(ac >= IEEE80211_NUM_ACS)))
76190aac0d8SBjoern A. Zeeb 		return RTW_TX_QUEUE_BE;
76290aac0d8SBjoern A. Zeeb 
76390aac0d8SBjoern A. Zeeb 	return ac_to_hwq[ac];
76490aac0d8SBjoern A. Zeeb }
76590aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_tx_ac_to_hwq);
76690aac0d8SBjoern A. Zeeb 
76790aac0d8SBjoern A. Zeeb enum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb)
76890aac0d8SBjoern A. Zeeb {
76990aac0d8SBjoern A. Zeeb 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
77090aac0d8SBjoern A. Zeeb 	__le16 fc = hdr->frame_control;
77190aac0d8SBjoern A. Zeeb 	u8 q_mapping = skb_get_queue_mapping(skb);
77290aac0d8SBjoern A. Zeeb 	enum rtw_tx_queue_type queue;
77390aac0d8SBjoern A. Zeeb 
77490aac0d8SBjoern A. Zeeb 	if (unlikely(ieee80211_is_beacon(fc)))
77590aac0d8SBjoern A. Zeeb 		queue = RTW_TX_QUEUE_BCN;
77690aac0d8SBjoern A. Zeeb 	else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
77790aac0d8SBjoern A. Zeeb 		queue = RTW_TX_QUEUE_MGMT;
77890aac0d8SBjoern A. Zeeb 	else if (is_broadcast_ether_addr(hdr->addr1) ||
77990aac0d8SBjoern A. Zeeb 		 is_multicast_ether_addr(hdr->addr1))
78090aac0d8SBjoern A. Zeeb 		queue = RTW_TX_QUEUE_HI0;
78190aac0d8SBjoern A. Zeeb 	else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq)))
78290aac0d8SBjoern A. Zeeb 		queue = ac_to_hwq[IEEE80211_AC_BE];
78390aac0d8SBjoern A. Zeeb 	else
78490aac0d8SBjoern A. Zeeb 		queue = ac_to_hwq[q_mapping];
78590aac0d8SBjoern A. Zeeb 
78690aac0d8SBjoern A. Zeeb 	return queue;
78790aac0d8SBjoern A. Zeeb }
78890aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_tx_queue_mapping);
789