18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 48c2ecf20Sopenharmony_ci * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/irq.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "mt76x02.h" 118c2ecf20Sopenharmony_ci#include "mt76x02_mcu.h" 128c2ecf20Sopenharmony_ci#include "trace.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic void mt76x02_pre_tbtt_tasklet(unsigned long arg) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = (struct mt76x02_dev *)arg; 178c2ecf20Sopenharmony_ci struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD]; 188c2ecf20Sopenharmony_ci struct beacon_bc_data data = {}; 198c2ecf20Sopenharmony_ci struct sk_buff *skb; 208c2ecf20Sopenharmony_ci int i; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci if (mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL) 238c2ecf20Sopenharmony_ci return; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci mt76x02_resync_beacon_timer(dev); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* Prevent corrupt transmissions during update */ 288c2ecf20Sopenharmony_ci mt76_set(dev, MT_BCN_BYPASS_MASK, 0xffff); 298c2ecf20Sopenharmony_ci dev->beacon_data_count = 0; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), 328c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 338c2ecf20Sopenharmony_ci mt76x02_update_beacon_iter, dev); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci mt76_wr(dev, MT_BCN_BYPASS_MASK, 368c2ecf20Sopenharmony_ci 0xff00 | ~(0xff00 >> dev->beacon_data_count)); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci mt76_csa_check(&dev->mt76); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (dev->mt76.csa_complete) 418c2ecf20Sopenharmony_ci return; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci mt76x02_enqueue_buffered_bc(dev, &data, 8); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (!skb_queue_len(&data.q)) 468c2ecf20Sopenharmony_ci return; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data.tail); i++) { 498c2ecf20Sopenharmony_ci if (!data.tail[i]) 508c2ecf20Sopenharmony_ci continue; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci mt76_skb_set_moredata(data.tail[i], false); 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci spin_lock_bh(&q->lock); 568c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&data.q)) != NULL) { 578c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 588c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 598c2ecf20Sopenharmony_ci struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, &mvif->group_wcid, 628c2ecf20Sopenharmony_ci NULL); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci spin_unlock_bh(&q->lock); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void mt76x02e_pre_tbtt_enable(struct mt76x02_dev *dev, bool en) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci if (en) 708c2ecf20Sopenharmony_ci tasklet_enable(&dev->mt76.pre_tbtt_tasklet); 718c2ecf20Sopenharmony_ci else 728c2ecf20Sopenharmony_ci tasklet_disable(&dev->mt76.pre_tbtt_tasklet); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void mt76x02e_beacon_enable(struct mt76x02_dev *dev, bool en) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en); 788c2ecf20Sopenharmony_ci if (en) 798c2ecf20Sopenharmony_ci mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_civoid mt76x02e_init_beacon_config(struct mt76x02_dev *dev) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci static const struct mt76x02_beacon_ops beacon_ops = { 878c2ecf20Sopenharmony_ci .nslots = 8, 888c2ecf20Sopenharmony_ci .slot_size = 1024, 898c2ecf20Sopenharmony_ci .pre_tbtt_enable = mt76x02e_pre_tbtt_enable, 908c2ecf20Sopenharmony_ci .beacon_enable = mt76x02e_beacon_enable, 918c2ecf20Sopenharmony_ci }; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci dev->beacon_ops = &beacon_ops; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Fire a pre-TBTT interrupt 8 ms before TBTT */ 968c2ecf20Sopenharmony_ci mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, 978c2ecf20Sopenharmony_ci 8 << 4); 988c2ecf20Sopenharmony_ci mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, 998c2ecf20Sopenharmony_ci MT_DFS_GP_INTERVAL); 1008c2ecf20Sopenharmony_ci mt76_wr(dev, MT_INT_TIMER_EN, 0); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci mt76x02_init_beacon_config(dev); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02e_init_beacon_config); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int 1078c2ecf20Sopenharmony_cimt76x02_init_tx_queue(struct mt76x02_dev *dev, int qid, int idx, int n_desc) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct mt76_queue *hwq; 1108c2ecf20Sopenharmony_ci int err; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL); 1138c2ecf20Sopenharmony_ci if (!hwq) 1148c2ecf20Sopenharmony_ci return -ENOMEM; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE); 1178c2ecf20Sopenharmony_ci if (err < 0) 1188c2ecf20Sopenharmony_ci return err; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci dev->mt76.q_tx[qid] = hwq; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx)); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int 1288c2ecf20Sopenharmony_cimt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q, 1298c2ecf20Sopenharmony_ci int idx, int n_desc, int bufsize) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci int err; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci err = mt76_queue_alloc(dev, q, idx, n_desc, bufsize, 1348c2ecf20Sopenharmony_ci MT_RX_RING_BASE); 1358c2ecf20Sopenharmony_ci if (err < 0) 1368c2ecf20Sopenharmony_ci return err; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci mt76x02_irq_enable(dev, MT_INT_RX_DONE(idx)); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct mt76x02_tx_status stat; 1468c2ecf20Sopenharmony_ci u8 update = 1; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci while (kfifo_get(&dev->txstatus_fifo, &stat)) 1498c2ecf20Sopenharmony_ci mt76x02_send_tx_status(dev, &stat, &update); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void mt76x02_tx_worker(struct mt76_worker *w) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct mt76x02_dev *dev; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci dev = container_of(w, struct mt76x02_dev, mt76.tx_worker); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci mt76x02_mac_poll_tx_status(dev, false); 1598c2ecf20Sopenharmony_ci mt76x02_process_tx_status_fifo(dev); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci mt76_txq_schedule_all(&dev->mphy); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int mt76x02_poll_tx(struct napi_struct *napi, int budget) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = container_of(napi, struct mt76x02_dev, 1678c2ecf20Sopenharmony_ci mt76.tx_napi); 1688c2ecf20Sopenharmony_ci int i; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci mt76x02_mac_poll_tx_status(dev, false); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci for (i = MT_TXQ_MCU; i >= 0; i--) 1738c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, i, false); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (napi_complete_done(napi, 0)) 1768c2ecf20Sopenharmony_ci mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci for (i = MT_TXQ_MCU; i >= 0; i--) 1798c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, i, false); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci mt76_worker_schedule(&dev->mt76.tx_worker); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciint mt76x02_dma_init(struct mt76x02_dev *dev) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct mt76_txwi_cache __maybe_unused *t; 1898c2ecf20Sopenharmony_ci int i, ret, fifo_size; 1908c2ecf20Sopenharmony_ci struct mt76_queue *q; 1918c2ecf20Sopenharmony_ci void *status_fifo; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status)); 1968c2ecf20Sopenharmony_ci status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); 1978c2ecf20Sopenharmony_ci if (!status_fifo) 1988c2ecf20Sopenharmony_ci return -ENOMEM; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci dev->mt76.tx_worker.fn = mt76x02_tx_worker; 2018c2ecf20Sopenharmony_ci tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet, 2028c2ecf20Sopenharmony_ci (unsigned long)dev); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci spin_lock_init(&dev->txstatus_fifo_lock); 2058c2ecf20Sopenharmony_ci kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci mt76_dma_attach(&dev->mt76); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 2128c2ecf20Sopenharmony_ci ret = mt76x02_init_tx_queue(dev, i, mt76_ac_to_hwq(i), 2138c2ecf20Sopenharmony_ci MT76x02_TX_RING_SIZE); 2148c2ecf20Sopenharmony_ci if (ret) 2158c2ecf20Sopenharmony_ci return ret; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ret = mt76x02_init_tx_queue(dev, MT_TXQ_PSD, 2198c2ecf20Sopenharmony_ci MT_TX_HW_QUEUE_MGMT, MT76x02_PSD_RING_SIZE); 2208c2ecf20Sopenharmony_ci if (ret) 2218c2ecf20Sopenharmony_ci return ret; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ret = mt76x02_init_tx_queue(dev, MT_TXQ_MCU, 2248c2ecf20Sopenharmony_ci MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE); 2258c2ecf20Sopenharmony_ci if (ret) 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ret = mt76x02_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, 2298c2ecf20Sopenharmony_ci MT_MCU_RING_SIZE, MT_RX_BUF_SIZE); 2308c2ecf20Sopenharmony_ci if (ret) 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci q = &dev->mt76.q_rx[MT_RXQ_MAIN]; 2348c2ecf20Sopenharmony_ci q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi); 2358c2ecf20Sopenharmony_ci ret = mt76x02_init_rx_queue(dev, q, 0, MT76X02_RX_RING_SIZE, 2368c2ecf20Sopenharmony_ci MT_RX_BUF_SIZE); 2378c2ecf20Sopenharmony_ci if (ret) 2388c2ecf20Sopenharmony_ci return ret; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci ret = mt76_init_queues(dev); 2418c2ecf20Sopenharmony_ci if (ret) 2428c2ecf20Sopenharmony_ci return ret; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi, 2458c2ecf20Sopenharmony_ci mt76x02_poll_tx, NAPI_POLL_WEIGHT); 2468c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_dma_init); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_civoid mt76x02_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct mt76x02_dev *dev; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci dev = container_of(mdev, struct mt76x02_dev, mt76); 2578c2ecf20Sopenharmony_ci mt76x02_irq_enable(dev, MT_INT_RX_DONE(q)); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_rx_poll_complete); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ciirqreturn_t mt76x02_irq_handler(int irq, void *dev_instance) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = dev_instance; 2648c2ecf20Sopenharmony_ci u32 intr, mask; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci intr = mt76_rr(dev, MT_INT_SOURCE_CSR); 2678c2ecf20Sopenharmony_ci intr &= dev->mt76.mmio.irqmask; 2688c2ecf20Sopenharmony_ci mt76_wr(dev, MT_INT_SOURCE_CSR, intr); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) 2718c2ecf20Sopenharmony_ci return IRQ_NONE; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci mask = intr & (MT_INT_RX_DONE_ALL | MT_INT_GPTIMER); 2768c2ecf20Sopenharmony_ci if (intr & (MT_INT_TX_DONE_ALL | MT_INT_TX_STAT)) 2778c2ecf20Sopenharmony_ci mask |= MT_INT_TX_DONE_ALL; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci mt76x02_irq_disable(dev, mask); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (intr & MT_INT_RX_DONE(0)) 2828c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[0]); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (intr & MT_INT_RX_DONE(1)) 2858c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[1]); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (intr & MT_INT_PRE_TBTT) 2888c2ecf20Sopenharmony_ci tasklet_schedule(&dev->mt76.pre_tbtt_tasklet); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* send buffered multicast frames now */ 2918c2ecf20Sopenharmony_ci if (intr & MT_INT_TBTT) { 2928c2ecf20Sopenharmony_ci if (dev->mt76.csa_complete) 2938c2ecf20Sopenharmony_ci mt76_csa_finish(&dev->mt76); 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci mt76_queue_kick(dev, dev->mt76.q_tx[MT_TXQ_PSD]); 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (intr & MT_INT_TX_STAT) 2998c2ecf20Sopenharmony_ci mt76x02_mac_poll_tx_status(dev, true); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (intr & (MT_INT_TX_STAT | MT_INT_TX_DONE_ALL)) 3028c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (intr & MT_INT_GPTIMER) 3058c2ecf20Sopenharmony_ci tasklet_schedule(&dev->dfs_pd.dfs_tasklet); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_irq_handler); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic void mt76x02_dma_enable(struct mt76x02_dev *dev) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci u32 val; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); 3168c2ecf20Sopenharmony_ci mt76x02_wait_for_wpdma(&dev->mt76, 1000); 3178c2ecf20Sopenharmony_ci usleep_range(50, 100); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) | 3208c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_DMA_EN | 3218c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_EN; 3228c2ecf20Sopenharmony_ci mt76_set(dev, MT_WPDMA_GLO_CFG, val); 3238c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, 3248c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_civoid mt76x02_dma_disable(struct mt76x02_dev *dev) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | 3328c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_BIG_ENDIAN | 3338c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_HDR_SEG_LEN; 3348c2ecf20Sopenharmony_ci val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE; 3358c2ecf20Sopenharmony_ci mt76_wr(dev, MT_WPDMA_GLO_CFG, val); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_dma_disable); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_civoid mt76x02_mac_start(struct mt76x02_dev *dev) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci mt76x02_mac_reset_counters(dev); 3428c2ecf20Sopenharmony_ci mt76x02_dma_enable(dev); 3438c2ecf20Sopenharmony_ci mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); 3448c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MAC_SYS_CTRL, 3458c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_ENABLE_TX | 3468c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_ENABLE_RX); 3478c2ecf20Sopenharmony_ci mt76x02_irq_enable(dev, 3488c2ecf20Sopenharmony_ci MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | 3498c2ecf20Sopenharmony_ci MT_INT_TX_STAT); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_mac_start); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic bool mt76x02_tx_hang(struct mt76x02_dev *dev) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci u32 dma_idx, prev_dma_idx; 3568c2ecf20Sopenharmony_ci struct mt76_queue *q; 3578c2ecf20Sopenharmony_ci int i; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 3608c2ecf20Sopenharmony_ci q = dev->mt76.q_tx[i]; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (!q->queued) 3638c2ecf20Sopenharmony_ci continue; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci prev_dma_idx = dev->mt76.tx_dma_idx[i]; 3668c2ecf20Sopenharmony_ci dma_idx = readl(&q->regs->dma_idx); 3678c2ecf20Sopenharmony_ci dev->mt76.tx_dma_idx[i] = dma_idx; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (prev_dma_idx == dma_idx) 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return i < 4; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void mt76x02_key_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 3778c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 3788c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key, void *data) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = hw->priv; 3818c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (!sta) 3848c2ecf20Sopenharmony_ci return; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci wcid = (struct mt76_wcid *)sta->drv_priv; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (wcid->hw_key_idx != key->keyidx || wcid->sw_iv) 3898c2ecf20Sopenharmony_ci return; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci mt76x02_mac_wcid_sync_pn(dev, wcid->idx, key); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void mt76x02_reset_state(struct mt76x02_dev *dev) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci int i; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci lockdep_assert_held(&dev->mt76.mutex); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci rcu_read_lock(); 4038c2ecf20Sopenharmony_ci ieee80211_iter_keys_rcu(dev->mt76.hw, NULL, mt76x02_key_sync, NULL); 4048c2ecf20Sopenharmony_ci rcu_read_unlock(); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci for (i = 0; i < MT76x02_N_WCIDS; i++) { 4078c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 4088c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 4098c2ecf20Sopenharmony_ci struct mt76x02_sta *msta; 4108c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 4118c2ecf20Sopenharmony_ci void *priv; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci wcid = rcu_dereference_protected(dev->mt76.wcid[i], 4148c2ecf20Sopenharmony_ci lockdep_is_held(&dev->mt76.mutex)); 4158c2ecf20Sopenharmony_ci if (!wcid) 4168c2ecf20Sopenharmony_ci continue; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci rcu_assign_pointer(dev->mt76.wcid[i], NULL); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci priv = msta = container_of(wcid, struct mt76x02_sta, wcid); 4218c2ecf20Sopenharmony_ci sta = container_of(priv, struct ieee80211_sta, drv_priv); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci priv = msta->vif; 4248c2ecf20Sopenharmony_ci vif = container_of(priv, struct ieee80211_vif, drv_priv); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci __mt76_sta_remove(&dev->mt76, vif, sta); 4278c2ecf20Sopenharmony_ci memset(msta, 0, sizeof(*msta)); 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci dev->mphy.vif_mask = 0; 4318c2ecf20Sopenharmony_ci dev->mt76.beacon_mask = 0; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void mt76x02_watchdog_reset(struct mt76x02_dev *dev) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci u32 mask = dev->mt76.mmio.irqmask; 4378c2ecf20Sopenharmony_ci bool restart = dev->mt76.mcu_ops->mcu_restart; 4388c2ecf20Sopenharmony_ci int i; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci ieee80211_stop_queues(dev->mt76.hw); 4418c2ecf20Sopenharmony_ci set_bit(MT76_RESET, &dev->mphy.state); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci tasklet_disable(&dev->mt76.pre_tbtt_tasklet); 4448c2ecf20Sopenharmony_ci mt76_worker_disable(&dev->mt76.tx_worker); 4458c2ecf20Sopenharmony_ci napi_disable(&dev->mt76.tx_napi); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) { 4488c2ecf20Sopenharmony_ci napi_disable(&dev->mt76.napi[i]); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci dev->mcu_timeout = 0; 4548c2ecf20Sopenharmony_ci if (restart) 4558c2ecf20Sopenharmony_ci mt76x02_reset_state(dev); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (dev->mt76.beacon_mask) 4588c2ecf20Sopenharmony_ci mt76_clear(dev, MT_BEACON_TIME_CFG, 4598c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_BEACON_TX | 4608c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_TBTT_EN); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci mt76x02_irq_disable(dev, mask); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* perform device reset */ 4658c2ecf20Sopenharmony_ci mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); 4668c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MAC_SYS_CTRL, 0); 4678c2ecf20Sopenharmony_ci mt76_clear(dev, MT_WPDMA_GLO_CFG, 4688c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN); 4698c2ecf20Sopenharmony_ci usleep_range(5000, 10000); 4708c2ecf20Sopenharmony_ci mt76_wr(dev, MT_INT_SOURCE_CSR, 0xffffffff); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* let fw reset DMA */ 4738c2ecf20Sopenharmony_ci mt76_set(dev, 0x734, 0x3); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (restart) 4768c2ecf20Sopenharmony_ci mt76_mcu_restart(dev); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci for (i = 0; i < __MT_TXQ_MAX; i++) 4798c2ecf20Sopenharmony_ci mt76_queue_tx_cleanup(dev, i, true); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) { 4828c2ecf20Sopenharmony_ci mt76_queue_rx_reset(dev, i); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci mt76x02_mac_start(dev); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (dev->ed_monitor) 4888c2ecf20Sopenharmony_ci mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (dev->mt76.beacon_mask && !restart) 4918c2ecf20Sopenharmony_ci mt76_set(dev, MT_BEACON_TIME_CFG, 4928c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_BEACON_TX | 4938c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_TBTT_EN); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci mt76x02_irq_enable(dev, mask); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci clear_bit(MT76_RESET, &dev->mphy.state); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci mt76_worker_enable(&dev->mt76.tx_worker); 5028c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.tx_napi); 5038c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci tasklet_enable(&dev->mt76.pre_tbtt_tasklet); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci mt76_for_each_q_rx(&dev->mt76, i) { 5088c2ecf20Sopenharmony_ci napi_enable(&dev->mt76.napi[i]); 5098c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[i]); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (restart) { 5138c2ecf20Sopenharmony_ci set_bit(MT76_RESTART, &dev->mphy.state); 5148c2ecf20Sopenharmony_ci mt76x02_mcu_function_select(dev, Q_SELECT, 1); 5158c2ecf20Sopenharmony_ci ieee80211_restart_hw(dev->mt76.hw); 5168c2ecf20Sopenharmony_ci } else { 5178c2ecf20Sopenharmony_ci ieee80211_wake_queues(dev->mt76.hw); 5188c2ecf20Sopenharmony_ci mt76_txq_schedule_all(&dev->mphy); 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_civoid mt76x02_reconfig_complete(struct ieee80211_hw *hw, 5238c2ecf20Sopenharmony_ci enum ieee80211_reconfig_type reconfig_type) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = hw->priv; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) 5288c2ecf20Sopenharmony_ci return; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci clear_bit(MT76_RESTART, &dev->mphy.state); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void mt76x02_check_tx_hang(struct mt76x02_dev *dev) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci if (test_bit(MT76_RESTART, &dev->mphy.state)) 5378c2ecf20Sopenharmony_ci return; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (mt76x02_tx_hang(dev)) { 5408c2ecf20Sopenharmony_ci if (++dev->tx_hang_check >= MT_TX_HANG_TH) 5418c2ecf20Sopenharmony_ci goto restart; 5428c2ecf20Sopenharmony_ci } else { 5438c2ecf20Sopenharmony_ci dev->tx_hang_check = 0; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (dev->mcu_timeout) 5478c2ecf20Sopenharmony_ci goto restart; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cirestart: 5528c2ecf20Sopenharmony_ci mt76x02_watchdog_reset(dev); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci dev->tx_hang_reset++; 5558c2ecf20Sopenharmony_ci dev->tx_hang_check = 0; 5568c2ecf20Sopenharmony_ci memset(dev->mt76.tx_dma_idx, 0xff, 5578c2ecf20Sopenharmony_ci sizeof(dev->mt76.tx_dma_idx)); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_civoid mt76x02_wdt_work(struct work_struct *work) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, 5638c2ecf20Sopenharmony_ci wdt_work.work); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci mt76x02_check_tx_hang(dev); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work, 5688c2ecf20Sopenharmony_ci MT_WATCHDOG_TIME); 5698c2ecf20Sopenharmony_ci} 570