18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include "mt7603.h" 48c2ecf20Sopenharmony_ci#include "mac.h" 58c2ecf20Sopenharmony_ci#include "../dma.h" 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_cistatic int 88c2ecf20Sopenharmony_cimt7603_init_tx_queue(struct mt7603_dev *dev, int qid, int idx, int n_desc) 98c2ecf20Sopenharmony_ci{ 108c2ecf20Sopenharmony_ci struct mt76_queue *hwq; 118c2ecf20Sopenharmony_ci int err; 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL); 148c2ecf20Sopenharmony_ci if (!hwq) 158c2ecf20Sopenharmony_ci return -ENOMEM; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE); 188c2ecf20Sopenharmony_ci if (err < 0) 198c2ecf20Sopenharmony_ci return err; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci dev->mt76.q_tx[qid] = hwq; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci mt7603_irq_enable(dev, MT_INT_TX_DONE(idx)); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return 0; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void 298c2ecf20Sopenharmony_cimt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci static const u8 tid_to_ac[8] = { 328c2ecf20Sopenharmony_ci IEEE80211_AC_BE, 338c2ecf20Sopenharmony_ci IEEE80211_AC_BK, 348c2ecf20Sopenharmony_ci IEEE80211_AC_BK, 358c2ecf20Sopenharmony_ci IEEE80211_AC_BE, 368c2ecf20Sopenharmony_ci IEEE80211_AC_VI, 378c2ecf20Sopenharmony_ci IEEE80211_AC_VI, 388c2ecf20Sopenharmony_ci IEEE80211_AC_VO, 398c2ecf20Sopenharmony_ci IEEE80211_AC_VO 408c2ecf20Sopenharmony_ci }; 418c2ecf20Sopenharmony_ci __le32 *txd = (__le32 *)skb->data; 428c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 438c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 448c2ecf20Sopenharmony_ci struct mt7603_sta *msta; 458c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 468c2ecf20Sopenharmony_ci void *priv; 478c2ecf20Sopenharmony_ci int idx; 488c2ecf20Sopenharmony_ci u32 val; 498c2ecf20Sopenharmony_ci u8 tid = 0; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (skb->len < MT_TXD_SIZE + sizeof(struct ieee80211_hdr)) 528c2ecf20Sopenharmony_ci goto free; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci val = le32_to_cpu(txd[1]); 558c2ecf20Sopenharmony_ci idx = FIELD_GET(MT_TXD1_WLAN_IDX, val); 568c2ecf20Sopenharmony_ci skb->priority = FIELD_GET(MT_TXD1_TID, val); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (idx >= MT7603_WTBL_STA - 1) 598c2ecf20Sopenharmony_ci goto free; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[idx]); 628c2ecf20Sopenharmony_ci if (!wcid) 638c2ecf20Sopenharmony_ci goto free; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci priv = msta = container_of(wcid, struct mt7603_sta, wcid); 668c2ecf20Sopenharmony_ci val = le32_to_cpu(txd[0]); 678c2ecf20Sopenharmony_ci val &= ~(MT_TXD0_P_IDX | MT_TXD0_Q_IDX); 688c2ecf20Sopenharmony_ci val |= FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_HW_QUEUE_MGMT); 698c2ecf20Sopenharmony_ci txd[0] = cpu_to_le32(val); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci sta = container_of(priv, struct ieee80211_sta, drv_priv); 728c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; 738c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 748c2ecf20Sopenharmony_ci tid = *ieee80211_get_qos_ctl(hdr) & 758c2ecf20Sopenharmony_ci IEEE80211_QOS_CTL_TAG1D_MASK; 768c2ecf20Sopenharmony_ci skb_set_queue_mapping(skb, tid_to_ac[tid]); 778c2ecf20Sopenharmony_ci ieee80211_sta_set_buffered(sta, tid, true); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci spin_lock_bh(&dev->ps_lock); 808c2ecf20Sopenharmony_ci __skb_queue_tail(&msta->psq, skb); 818c2ecf20Sopenharmony_ci if (skb_queue_len(&msta->psq) >= 64) { 828c2ecf20Sopenharmony_ci skb = __skb_dequeue(&msta->psq); 838c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->ps_lock); 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cifree: 898c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_civoid mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, 938c2ecf20Sopenharmony_ci struct sk_buff *skb) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); 968c2ecf20Sopenharmony_ci __le32 *rxd = (__le32 *)skb->data; 978c2ecf20Sopenharmony_ci __le32 *end = (__le32 *)&skb->data[skb->len]; 988c2ecf20Sopenharmony_ci enum rx_pkt_type type; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (q == MT_RXQ_MCU) { 1038c2ecf20Sopenharmony_ci if (type == PKT_TYPE_RX_EVENT) 1048c2ecf20Sopenharmony_ci mt76_mcu_rx_event(&dev->mt76, skb); 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci mt7603_rx_loopback_skb(dev, skb); 1078c2ecf20Sopenharmony_ci return; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci switch (type) { 1118c2ecf20Sopenharmony_ci case PKT_TYPE_TXS: 1128c2ecf20Sopenharmony_ci for (rxd++; rxd + 5 <= end; rxd += 5) 1138c2ecf20Sopenharmony_ci mt7603_mac_add_txs(dev, rxd); 1148c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci case PKT_TYPE_RX_EVENT: 1178c2ecf20Sopenharmony_ci mt76_mcu_rx_event(&dev->mt76, skb); 1188c2ecf20Sopenharmony_ci return; 1198c2ecf20Sopenharmony_ci case PKT_TYPE_NORMAL: 1208c2ecf20Sopenharmony_ci if (mt7603_mac_fill_rx(dev, skb) == 0) { 1218c2ecf20Sopenharmony_ci mt76_rx(&dev->mt76, q, skb); 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci fallthrough; 1258c2ecf20Sopenharmony_ci default: 1268c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int 1328c2ecf20Sopenharmony_cimt7603_init_rx_queue(struct mt7603_dev *dev, struct mt76_queue *q, 1338c2ecf20Sopenharmony_ci int idx, int n_desc, int bufsize) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci int err; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci err = mt76_queue_alloc(dev, q, idx, n_desc, bufsize, 1388c2ecf20Sopenharmony_ci MT_RX_RING_BASE); 1398c2ecf20Sopenharmony_ci if (err < 0) 1408c2ecf20Sopenharmony_ci return err; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci mt7603_irq_enable(dev, MT_INT_RX_DONE(idx)); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int mt7603_poll_tx(struct napi_struct *napi, int budget) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct mt7603_dev *dev; 1508c2ecf20Sopenharmony_ci int i; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci dev = container_of(napi, struct mt7603_dev, mt76.tx_napi); 1538c2ecf20Sopenharmony_ci dev->tx_dma_check = 0; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci for (i = MT_TXQ_MCU; i >= 0; i--) 1568c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, i, false); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (napi_complete_done(napi, 0)) 1598c2ecf20Sopenharmony_ci mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci for (i = MT_TXQ_MCU; i >= 0; i--) 1628c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, i, false); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci mt7603_mac_sta_poll(dev); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci mt76_worker_schedule(&dev->mt76.tx_worker); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciint mt7603_dma_init(struct mt7603_dev *dev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci static const u8 wmm_queue_map[] = { 1748c2ecf20Sopenharmony_ci [IEEE80211_AC_BK] = 0, 1758c2ecf20Sopenharmony_ci [IEEE80211_AC_BE] = 1, 1768c2ecf20Sopenharmony_ci [IEEE80211_AC_VI] = 2, 1778c2ecf20Sopenharmony_ci [IEEE80211_AC_VO] = 3, 1788c2ecf20Sopenharmony_ci }; 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci int i; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci mt76_dma_attach(&dev->mt76); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, 1858c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_DMA_EN | 1868c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_EN | 1878c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | 1888c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); 1918c2ecf20Sopenharmony_ci mt7603_pse_client_reset(dev); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { 1948c2ecf20Sopenharmony_ci ret = mt7603_init_tx_queue(dev, i, wmm_queue_map[i], 1958c2ecf20Sopenharmony_ci MT7603_TX_RING_SIZE); 1968c2ecf20Sopenharmony_ci if (ret) 1978c2ecf20Sopenharmony_ci return ret; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci ret = mt7603_init_tx_queue(dev, MT_TXQ_PSD, 2018c2ecf20Sopenharmony_ci MT_TX_HW_QUEUE_MGMT, MT7603_PSD_RING_SIZE); 2028c2ecf20Sopenharmony_ci if (ret) 2038c2ecf20Sopenharmony_ci return ret; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ret = mt7603_init_tx_queue(dev, MT_TXQ_MCU, 2068c2ecf20Sopenharmony_ci MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE); 2078c2ecf20Sopenharmony_ci if (ret) 2088c2ecf20Sopenharmony_ci return ret; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci ret = mt7603_init_tx_queue(dev, MT_TXQ_BEACON, 2118c2ecf20Sopenharmony_ci MT_TX_HW_QUEUE_BCN, MT_MCU_RING_SIZE); 2128c2ecf20Sopenharmony_ci if (ret) 2138c2ecf20Sopenharmony_ci return ret; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = mt7603_init_tx_queue(dev, MT_TXQ_CAB, 2168c2ecf20Sopenharmony_ci MT_TX_HW_QUEUE_BMC, MT_MCU_RING_SIZE); 2178c2ecf20Sopenharmony_ci if (ret) 2188c2ecf20Sopenharmony_ci return ret; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, 2218c2ecf20Sopenharmony_ci MT7603_MCU_RX_RING_SIZE, MT_RX_BUF_SIZE); 2228c2ecf20Sopenharmony_ci if (ret) 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, 2268c2ecf20Sopenharmony_ci MT7603_RX_RING_SIZE, MT_RX_BUF_SIZE); 2278c2ecf20Sopenharmony_ci if (ret) 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci mt76_wr(dev, MT_DELAY_INT_CFG, 0); 2318c2ecf20Sopenharmony_ci ret = mt76_init_queues(dev); 2328c2ecf20Sopenharmony_ci if (ret) 2338c2ecf20Sopenharmony_ci return ret; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi, 2368c2ecf20Sopenharmony_ci mt7603_poll_tx, NAPI_POLL_WEIGHT); 2378c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_civoid mt7603_dma_cleanup(struct mt7603_dev *dev) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, 2458c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_DMA_EN | 2468c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_EN | 2478c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci mt76_dma_cleanup(&dev->mt76); 2508c2ecf20Sopenharmony_ci} 251