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