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