xref: /linux/drivers/net/wireless/mediatek/mt76/npu.c (revision 84318277d6334c6981ab326d4acc87c6a6ddc9b8)
1*7fb554b1SLorenzo Bianconi // SPDX-License-Identifier: GPL-2.0-only
2*7fb554b1SLorenzo Bianconi /*
3*7fb554b1SLorenzo Bianconi  * Copyright (c) 2025 AIROHA Inc
4*7fb554b1SLorenzo Bianconi  * Author: Lorenzo Bianconi <lorenzo@kernel.org>
5*7fb554b1SLorenzo Bianconi  */
6*7fb554b1SLorenzo Bianconi #include <linux/kernel.h>
7*7fb554b1SLorenzo Bianconi #include <net/flow_offload.h>
8*7fb554b1SLorenzo Bianconi #include <net/pkt_cls.h>
9*7fb554b1SLorenzo Bianconi 
10*7fb554b1SLorenzo Bianconi #include "mt76.h"
11*7fb554b1SLorenzo Bianconi #include "dma.h"
12*7fb554b1SLorenzo Bianconi #include "mt76_connac.h"
13*7fb554b1SLorenzo Bianconi 
14*7fb554b1SLorenzo Bianconi #define MT76_NPU_RX_BUF_SIZE	(1800 + \
15*7fb554b1SLorenzo Bianconi 				 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
16*7fb554b1SLorenzo Bianconi 
17*7fb554b1SLorenzo Bianconi int mt76_npu_fill_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
18*7fb554b1SLorenzo Bianconi {
19*7fb554b1SLorenzo Bianconi 	int nframes = 0;
20*7fb554b1SLorenzo Bianconi 
21*7fb554b1SLorenzo Bianconi 	while (q->queued < q->ndesc - 1) {
22*7fb554b1SLorenzo Bianconi 		struct airoha_npu_rx_dma_desc *desc = (void *)q->desc;
23*7fb554b1SLorenzo Bianconi 		struct mt76_queue_entry *e = &q->entry[q->head];
24*7fb554b1SLorenzo Bianconi 		struct page *page;
25*7fb554b1SLorenzo Bianconi 		int offset;
26*7fb554b1SLorenzo Bianconi 
27*7fb554b1SLorenzo Bianconi 		e->buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
28*7fb554b1SLorenzo Bianconi 		if (!e->buf)
29*7fb554b1SLorenzo Bianconi 			break;
30*7fb554b1SLorenzo Bianconi 
31*7fb554b1SLorenzo Bianconi 		e->dma_len[0] = SKB_WITH_OVERHEAD(q->buf_size);
32*7fb554b1SLorenzo Bianconi 		page = virt_to_head_page(e->buf);
33*7fb554b1SLorenzo Bianconi 		e->dma_addr[0] = page_pool_get_dma_addr(page) + offset;
34*7fb554b1SLorenzo Bianconi 
35*7fb554b1SLorenzo Bianconi 		memset(&desc[q->head], 0, sizeof(*desc));
36*7fb554b1SLorenzo Bianconi 		desc[q->head].addr = e->dma_addr[0];
37*7fb554b1SLorenzo Bianconi 
38*7fb554b1SLorenzo Bianconi 		q->head = (q->head + 1) % q->ndesc;
39*7fb554b1SLorenzo Bianconi 		q->queued++;
40*7fb554b1SLorenzo Bianconi 		nframes++;
41*7fb554b1SLorenzo Bianconi 	}
42*7fb554b1SLorenzo Bianconi 
43*7fb554b1SLorenzo Bianconi 	return nframes;
44*7fb554b1SLorenzo Bianconi }
45*7fb554b1SLorenzo Bianconi 
46*7fb554b1SLorenzo Bianconi void mt76_npu_queue_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
47*7fb554b1SLorenzo Bianconi {
48*7fb554b1SLorenzo Bianconi 	spin_lock_bh(&q->lock);
49*7fb554b1SLorenzo Bianconi 	while (q->queued > 0) {
50*7fb554b1SLorenzo Bianconi 		struct mt76_queue_entry *e = &q->entry[q->tail];
51*7fb554b1SLorenzo Bianconi 
52*7fb554b1SLorenzo Bianconi 		dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0],
53*7fb554b1SLorenzo Bianconi 					e->dma_len[0],
54*7fb554b1SLorenzo Bianconi 					page_pool_get_dma_dir(q->page_pool));
55*7fb554b1SLorenzo Bianconi 		mt76_put_page_pool_buf(e->buf, false);
56*7fb554b1SLorenzo Bianconi 		q->tail = (q->tail + 1) % q->ndesc;
57*7fb554b1SLorenzo Bianconi 		q->queued--;
58*7fb554b1SLorenzo Bianconi 	}
59*7fb554b1SLorenzo Bianconi 	spin_unlock_bh(&q->lock);
60*7fb554b1SLorenzo Bianconi }
61*7fb554b1SLorenzo Bianconi 
62*7fb554b1SLorenzo Bianconi static struct sk_buff *mt76_npu_dequeue(struct mt76_dev *dev,
63*7fb554b1SLorenzo Bianconi 					struct mt76_queue *q,
64*7fb554b1SLorenzo Bianconi 					u32 *info)
65*7fb554b1SLorenzo Bianconi {
66*7fb554b1SLorenzo Bianconi 	struct airoha_npu_rx_dma_desc *desc = (void *)q->desc;
67*7fb554b1SLorenzo Bianconi 	int i, nframes, index = q->tail;
68*7fb554b1SLorenzo Bianconi 	struct sk_buff *skb = NULL;
69*7fb554b1SLorenzo Bianconi 
70*7fb554b1SLorenzo Bianconi 	nframes = FIELD_GET(NPU_RX_DMA_PKT_COUNT_MASK, desc[index].info);
71*7fb554b1SLorenzo Bianconi 	nframes = max_t(int, nframes, 1);
72*7fb554b1SLorenzo Bianconi 
73*7fb554b1SLorenzo Bianconi 	for (i = 0; i < nframes; i++) {
74*7fb554b1SLorenzo Bianconi 		struct mt76_queue_entry *e = &q->entry[index];
75*7fb554b1SLorenzo Bianconi 		int len = FIELD_GET(NPU_RX_DMA_DESC_CUR_LEN_MASK,
76*7fb554b1SLorenzo Bianconi 				    desc[index].ctrl);
77*7fb554b1SLorenzo Bianconi 
78*7fb554b1SLorenzo Bianconi 		if (!FIELD_GET(NPU_RX_DMA_DESC_DONE_MASK, desc[index].ctrl)) {
79*7fb554b1SLorenzo Bianconi 			dev_kfree_skb(skb);
80*7fb554b1SLorenzo Bianconi 			return NULL;
81*7fb554b1SLorenzo Bianconi 		}
82*7fb554b1SLorenzo Bianconi 
83*7fb554b1SLorenzo Bianconi 		dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0],
84*7fb554b1SLorenzo Bianconi 					e->dma_len[0],
85*7fb554b1SLorenzo Bianconi 					page_pool_get_dma_dir(q->page_pool));
86*7fb554b1SLorenzo Bianconi 
87*7fb554b1SLorenzo Bianconi 		if (!skb) {
88*7fb554b1SLorenzo Bianconi 			skb = napi_build_skb(e->buf, q->buf_size);
89*7fb554b1SLorenzo Bianconi 			if (!skb)
90*7fb554b1SLorenzo Bianconi 				return NULL;
91*7fb554b1SLorenzo Bianconi 
92*7fb554b1SLorenzo Bianconi 			__skb_put(skb, len);
93*7fb554b1SLorenzo Bianconi 			skb_reset_mac_header(skb);
94*7fb554b1SLorenzo Bianconi 			skb_mark_for_recycle(skb);
95*7fb554b1SLorenzo Bianconi 		} else {
96*7fb554b1SLorenzo Bianconi 			struct skb_shared_info *shinfo = skb_shinfo(skb);
97*7fb554b1SLorenzo Bianconi 			struct page *page = virt_to_head_page(e->buf);
98*7fb554b1SLorenzo Bianconi 			int nr_frags = shinfo->nr_frags;
99*7fb554b1SLorenzo Bianconi 
100*7fb554b1SLorenzo Bianconi 			if (nr_frags < ARRAY_SIZE(shinfo->frags))
101*7fb554b1SLorenzo Bianconi 				skb_add_rx_frag(skb, nr_frags, page,
102*7fb554b1SLorenzo Bianconi 						e->buf - page_address(page),
103*7fb554b1SLorenzo Bianconi 						len, q->buf_size);
104*7fb554b1SLorenzo Bianconi 		}
105*7fb554b1SLorenzo Bianconi 
106*7fb554b1SLorenzo Bianconi 		*info = desc[index].info;
107*7fb554b1SLorenzo Bianconi 		index = (index + 1) % q->ndesc;
108*7fb554b1SLorenzo Bianconi 	}
109*7fb554b1SLorenzo Bianconi 	q->tail = index;
110*7fb554b1SLorenzo Bianconi 	q->queued -= i;
111*7fb554b1SLorenzo Bianconi 	Q_WRITE(q, dma_idx, q->tail);
112*7fb554b1SLorenzo Bianconi 
113*7fb554b1SLorenzo Bianconi 	return skb;
114*7fb554b1SLorenzo Bianconi }
115*7fb554b1SLorenzo Bianconi 
116*7fb554b1SLorenzo Bianconi void mt76_npu_check_ppe(struct mt76_dev *dev, struct sk_buff *skb,
117*7fb554b1SLorenzo Bianconi 			u32 info)
118*7fb554b1SLorenzo Bianconi {
119*7fb554b1SLorenzo Bianconi 	struct airoha_ppe_dev *ppe_dev;
120*7fb554b1SLorenzo Bianconi 	u16 reason, hash;
121*7fb554b1SLorenzo Bianconi 
122*7fb554b1SLorenzo Bianconi 	if (!mt76_npu_device_active(dev))
123*7fb554b1SLorenzo Bianconi 		return;
124*7fb554b1SLorenzo Bianconi 
125*7fb554b1SLorenzo Bianconi 	rcu_read_lock();
126*7fb554b1SLorenzo Bianconi 
127*7fb554b1SLorenzo Bianconi 	ppe_dev = rcu_dereference(dev->mmio.ppe_dev);
128*7fb554b1SLorenzo Bianconi 	if (!ppe_dev)
129*7fb554b1SLorenzo Bianconi 		goto out;
130*7fb554b1SLorenzo Bianconi 
131*7fb554b1SLorenzo Bianconi 	hash = FIELD_GET(NPU_RX_DMA_FOE_ID_MASK, info);
132*7fb554b1SLorenzo Bianconi 	skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
133*7fb554b1SLorenzo Bianconi 
134*7fb554b1SLorenzo Bianconi 	reason = FIELD_GET(NPU_RX_DMA_CRSN_MASK, info);
135*7fb554b1SLorenzo Bianconi 	if (reason == PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
136*7fb554b1SLorenzo Bianconi 		skb_set_mac_header(skb, 0);
137*7fb554b1SLorenzo Bianconi 		airoha_ppe_dev_check_skb(ppe_dev, skb, hash, true);
138*7fb554b1SLorenzo Bianconi 	}
139*7fb554b1SLorenzo Bianconi out:
140*7fb554b1SLorenzo Bianconi 	rcu_read_unlock();
141*7fb554b1SLorenzo Bianconi }
142*7fb554b1SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_npu_check_ppe);
143*7fb554b1SLorenzo Bianconi 
144*7fb554b1SLorenzo Bianconi static int mt76_npu_rx_poll(struct napi_struct *napi, int budget)
145*7fb554b1SLorenzo Bianconi {
146*7fb554b1SLorenzo Bianconi 	struct mt76_dev *dev = mt76_priv(napi->dev);
147*7fb554b1SLorenzo Bianconi 	enum mt76_rxq_id qid = napi - dev->napi;
148*7fb554b1SLorenzo Bianconi 	struct airoha_npu *npu;
149*7fb554b1SLorenzo Bianconi 	int done = 0;
150*7fb554b1SLorenzo Bianconi 
151*7fb554b1SLorenzo Bianconi 	rcu_read_lock();
152*7fb554b1SLorenzo Bianconi 
153*7fb554b1SLorenzo Bianconi 	npu = rcu_dereference(dev->mmio.npu);
154*7fb554b1SLorenzo Bianconi 	if (!npu)
155*7fb554b1SLorenzo Bianconi 		goto out;
156*7fb554b1SLorenzo Bianconi 
157*7fb554b1SLorenzo Bianconi 	while (done < budget) {
158*7fb554b1SLorenzo Bianconi 		struct sk_buff *skb;
159*7fb554b1SLorenzo Bianconi 		u32 info = 0;
160*7fb554b1SLorenzo Bianconi 
161*7fb554b1SLorenzo Bianconi 		skb = mt76_npu_dequeue(dev, &dev->q_rx[qid], &info);
162*7fb554b1SLorenzo Bianconi 		if (!skb)
163*7fb554b1SLorenzo Bianconi 			break;
164*7fb554b1SLorenzo Bianconi 
165*7fb554b1SLorenzo Bianconi 		dev->drv->rx_skb(dev, qid, skb, &info);
166*7fb554b1SLorenzo Bianconi 		mt76_rx_poll_complete(dev, qid, napi);
167*7fb554b1SLorenzo Bianconi 		done++;
168*7fb554b1SLorenzo Bianconi 	}
169*7fb554b1SLorenzo Bianconi 
170*7fb554b1SLorenzo Bianconi 	mt76_npu_fill_rx_queue(dev, &dev->q_rx[qid]);
171*7fb554b1SLorenzo Bianconi out:
172*7fb554b1SLorenzo Bianconi 	if (done < budget && napi_complete(napi))
173*7fb554b1SLorenzo Bianconi 		dev->drv->rx_poll_complete(dev, qid);
174*7fb554b1SLorenzo Bianconi 
175*7fb554b1SLorenzo Bianconi 	rcu_read_unlock();
176*7fb554b1SLorenzo Bianconi 
177*7fb554b1SLorenzo Bianconi 	return done;
178*7fb554b1SLorenzo Bianconi }
179*7fb554b1SLorenzo Bianconi 
180*7fb554b1SLorenzo Bianconi static irqreturn_t mt76_npu_irq_handler(int irq, void *q_instance)
181*7fb554b1SLorenzo Bianconi {
182*7fb554b1SLorenzo Bianconi 	struct mt76_queue *q = q_instance;
183*7fb554b1SLorenzo Bianconi 	struct mt76_dev *dev = q->dev;
184*7fb554b1SLorenzo Bianconi 	int qid = q - &dev->q_rx[0];
185*7fb554b1SLorenzo Bianconi 	int index = qid - MT_RXQ_NPU0;
186*7fb554b1SLorenzo Bianconi 	struct airoha_npu *npu;
187*7fb554b1SLorenzo Bianconi 	u32 status;
188*7fb554b1SLorenzo Bianconi 
189*7fb554b1SLorenzo Bianconi 	rcu_read_lock();
190*7fb554b1SLorenzo Bianconi 
191*7fb554b1SLorenzo Bianconi 	npu = rcu_dereference(dev->mmio.npu);
192*7fb554b1SLorenzo Bianconi 	if (!npu)
193*7fb554b1SLorenzo Bianconi 		goto out;
194*7fb554b1SLorenzo Bianconi 
195*7fb554b1SLorenzo Bianconi 	status = airoha_npu_wlan_get_irq_status(npu, index);
196*7fb554b1SLorenzo Bianconi 	airoha_npu_wlan_set_irq_status(npu, status);
197*7fb554b1SLorenzo Bianconi 
198*7fb554b1SLorenzo Bianconi 	airoha_npu_wlan_disable_irq(npu, index);
199*7fb554b1SLorenzo Bianconi 	napi_schedule(&dev->napi[qid]);
200*7fb554b1SLorenzo Bianconi out:
201*7fb554b1SLorenzo Bianconi 	rcu_read_unlock();
202*7fb554b1SLorenzo Bianconi 
203*7fb554b1SLorenzo Bianconi 	return IRQ_HANDLED;
204*7fb554b1SLorenzo Bianconi }
205*7fb554b1SLorenzo Bianconi 
206*7fb554b1SLorenzo Bianconi int mt76_npu_dma_add_buf(struct mt76_phy *phy, struct mt76_queue *q,
207*7fb554b1SLorenzo Bianconi 			 struct sk_buff *skb, struct mt76_queue_buf *buf,
208*7fb554b1SLorenzo Bianconi 			 void *txwi_ptr)
209*7fb554b1SLorenzo Bianconi {
210*7fb554b1SLorenzo Bianconi 	u16 txwi_len = min_t(u16, phy->dev->drv->txwi_size, NPU_TXWI_LEN);
211*7fb554b1SLorenzo Bianconi 	struct airoha_npu_tx_dma_desc *desc = (void *)q->desc;
212*7fb554b1SLorenzo Bianconi 	int ret;
213*7fb554b1SLorenzo Bianconi 
214*7fb554b1SLorenzo Bianconi 	/* TODO: Take into account unlinear skbs */
215*7fb554b1SLorenzo Bianconi 	memcpy(desc[q->head].txwi, txwi_ptr, txwi_len);
216*7fb554b1SLorenzo Bianconi 	desc[q->head].addr = buf->addr;
217*7fb554b1SLorenzo Bianconi 	desc[q->head].ctrl = FIELD_PREP(NPU_TX_DMA_DESC_VEND_LEN_MASK, txwi_len) |
218*7fb554b1SLorenzo Bianconi 			     FIELD_PREP(NPU_TX_DMA_DESC_LEN_MASK, skb->len) |
219*7fb554b1SLorenzo Bianconi 			     NPU_TX_DMA_DESC_DONE_MASK;
220*7fb554b1SLorenzo Bianconi 
221*7fb554b1SLorenzo Bianconi 	ret = q->head;
222*7fb554b1SLorenzo Bianconi 	q->entry[q->head].skip_buf0 = true;
223*7fb554b1SLorenzo Bianconi 	q->entry[q->head].skip_buf1 = true;
224*7fb554b1SLorenzo Bianconi 	q->entry[q->head].txwi = NULL;
225*7fb554b1SLorenzo Bianconi 	q->entry[q->head].skb = NULL;
226*7fb554b1SLorenzo Bianconi 	q->entry[q->head].wcid = 0xffff;
227*7fb554b1SLorenzo Bianconi 
228*7fb554b1SLorenzo Bianconi 	q->head = (q->head + 1) % q->ndesc;
229*7fb554b1SLorenzo Bianconi 	q->queued++;
230*7fb554b1SLorenzo Bianconi 
231*7fb554b1SLorenzo Bianconi 	return ret;
232*7fb554b1SLorenzo Bianconi }
233*7fb554b1SLorenzo Bianconi 
234*7fb554b1SLorenzo Bianconi void mt76_npu_txdesc_cleanup(struct mt76_queue *q, int index)
235*7fb554b1SLorenzo Bianconi {
236*7fb554b1SLorenzo Bianconi 	struct airoha_npu_tx_dma_desc *desc = (void *)q->desc;
237*7fb554b1SLorenzo Bianconi 
238*7fb554b1SLorenzo Bianconi 	if (!mt76_queue_is_npu_tx(q))
239*7fb554b1SLorenzo Bianconi 		return;
240*7fb554b1SLorenzo Bianconi 
241*7fb554b1SLorenzo Bianconi 	desc[index].ctrl &= ~NPU_TX_DMA_DESC_DONE_MASK;
242*7fb554b1SLorenzo Bianconi }
243*7fb554b1SLorenzo Bianconi 
244*7fb554b1SLorenzo Bianconi void mt76_npu_queue_setup(struct mt76_dev *dev, struct mt76_queue *q)
245*7fb554b1SLorenzo Bianconi {
246*7fb554b1SLorenzo Bianconi 	int qid = FIELD_GET(MT_QFLAG_WED_RING, q->flags);
247*7fb554b1SLorenzo Bianconi 	bool xmit = mt76_queue_is_npu_tx(q);
248*7fb554b1SLorenzo Bianconi 	struct airoha_npu *npu;
249*7fb554b1SLorenzo Bianconi 
250*7fb554b1SLorenzo Bianconi 	if (!mt76_queue_is_npu(q))
251*7fb554b1SLorenzo Bianconi 		return;
252*7fb554b1SLorenzo Bianconi 
253*7fb554b1SLorenzo Bianconi 	npu = rcu_dereference_protected(dev->mmio.npu, &dev->mutex);
254*7fb554b1SLorenzo Bianconi 	if (npu)
255*7fb554b1SLorenzo Bianconi 		q->wed_regs = airoha_npu_wlan_get_queue_addr(npu, qid, xmit);
256*7fb554b1SLorenzo Bianconi }
257*7fb554b1SLorenzo Bianconi 
258*7fb554b1SLorenzo Bianconi int mt76_npu_rx_queue_init(struct mt76_dev *dev, struct mt76_queue *q)
259*7fb554b1SLorenzo Bianconi {
260*7fb554b1SLorenzo Bianconi 	int err, irq, qid = q - &dev->q_rx[0];
261*7fb554b1SLorenzo Bianconi 	int size, index = qid - MT_RXQ_NPU0;
262*7fb554b1SLorenzo Bianconi 	struct airoha_npu *npu;
263*7fb554b1SLorenzo Bianconi 	const char *name;
264*7fb554b1SLorenzo Bianconi 
265*7fb554b1SLorenzo Bianconi 	mutex_lock(&dev->mutex);
266*7fb554b1SLorenzo Bianconi 
267*7fb554b1SLorenzo Bianconi 	npu = rcu_dereference_protected(dev->mmio.npu, &dev->mutex);
268*7fb554b1SLorenzo Bianconi 	irq = npu && index < ARRAY_SIZE(npu->irqs) ? npu->irqs[index]
269*7fb554b1SLorenzo Bianconi 						   : -EINVAL;
270*7fb554b1SLorenzo Bianconi 	if (irq < 0) {
271*7fb554b1SLorenzo Bianconi 		err = irq;
272*7fb554b1SLorenzo Bianconi 		goto out;
273*7fb554b1SLorenzo Bianconi 	}
274*7fb554b1SLorenzo Bianconi 
275*7fb554b1SLorenzo Bianconi 	q->flags = MT_NPU_Q_RX(index);
276*7fb554b1SLorenzo Bianconi 	size = qid == MT_RXQ_NPU1 ? NPU_RX1_DESC_NUM : NPU_RX0_DESC_NUM;
277*7fb554b1SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, q, 0, size,
278*7fb554b1SLorenzo Bianconi 				    MT76_NPU_RX_BUF_SIZE, 0);
279*7fb554b1SLorenzo Bianconi 	if (err)
280*7fb554b1SLorenzo Bianconi 		goto out;
281*7fb554b1SLorenzo Bianconi 
282*7fb554b1SLorenzo Bianconi 	name = devm_kasprintf(dev->dev, GFP_KERNEL, "mt76-npu.%d", index);
283*7fb554b1SLorenzo Bianconi 	if (!name) {
284*7fb554b1SLorenzo Bianconi 		err = -ENOMEM;
285*7fb554b1SLorenzo Bianconi 		goto out;
286*7fb554b1SLorenzo Bianconi 	}
287*7fb554b1SLorenzo Bianconi 
288*7fb554b1SLorenzo Bianconi 	err = devm_request_irq(dev->dev, irq, mt76_npu_irq_handler,
289*7fb554b1SLorenzo Bianconi 			       IRQF_SHARED, name, q);
290*7fb554b1SLorenzo Bianconi 	if (err)
291*7fb554b1SLorenzo Bianconi 		goto out;
292*7fb554b1SLorenzo Bianconi 
293*7fb554b1SLorenzo Bianconi 	netif_napi_add(dev->napi_dev, &dev->napi[qid], mt76_npu_rx_poll);
294*7fb554b1SLorenzo Bianconi 	mt76_npu_fill_rx_queue(dev, q);
295*7fb554b1SLorenzo Bianconi 	napi_enable(&dev->napi[qid]);
296*7fb554b1SLorenzo Bianconi out:
297*7fb554b1SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
298*7fb554b1SLorenzo Bianconi 
299*7fb554b1SLorenzo Bianconi 	return err;
300*7fb554b1SLorenzo Bianconi }
301*7fb554b1SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_npu_rx_queue_init);
302*7fb554b1SLorenzo Bianconi 
303*7fb554b1SLorenzo Bianconi static int mt76_npu_setup_tc_block_cb(enum tc_setup_type type,
304*7fb554b1SLorenzo Bianconi 				      void *type_data, void *cb_priv)
305*7fb554b1SLorenzo Bianconi {
306*7fb554b1SLorenzo Bianconi 	struct mt76_phy *phy = cb_priv;
307*7fb554b1SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
308*7fb554b1SLorenzo Bianconi 	struct airoha_ppe_dev *ppe_dev;
309*7fb554b1SLorenzo Bianconi 	int err = -EOPNOTSUPP;
310*7fb554b1SLorenzo Bianconi 
311*7fb554b1SLorenzo Bianconi 	if (type != TC_SETUP_CLSFLOWER)
312*7fb554b1SLorenzo Bianconi 		return -EOPNOTSUPP;
313*7fb554b1SLorenzo Bianconi 
314*7fb554b1SLorenzo Bianconi 	mutex_lock(&dev->mutex);
315*7fb554b1SLorenzo Bianconi 
316*7fb554b1SLorenzo Bianconi 	ppe_dev = rcu_dereference_protected(dev->mmio.ppe_dev, &dev->mutex);
317*7fb554b1SLorenzo Bianconi 	if (ppe_dev)
318*7fb554b1SLorenzo Bianconi 		err = airoha_ppe_dev_setup_tc_block_cb(ppe_dev, type_data);
319*7fb554b1SLorenzo Bianconi 
320*7fb554b1SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
321*7fb554b1SLorenzo Bianconi 
322*7fb554b1SLorenzo Bianconi 	return err;
323*7fb554b1SLorenzo Bianconi }
324*7fb554b1SLorenzo Bianconi 
325*7fb554b1SLorenzo Bianconi static int mt76_npu_setup_tc_block(struct mt76_phy *phy,
326*7fb554b1SLorenzo Bianconi 				   struct net_device *dev,
327*7fb554b1SLorenzo Bianconi 				   struct flow_block_offload *f)
328*7fb554b1SLorenzo Bianconi {
329*7fb554b1SLorenzo Bianconi 	flow_setup_cb_t *cb = mt76_npu_setup_tc_block_cb;
330*7fb554b1SLorenzo Bianconi 	static LIST_HEAD(block_cb_list);
331*7fb554b1SLorenzo Bianconi 	struct flow_block_cb *block_cb;
332*7fb554b1SLorenzo Bianconi 
333*7fb554b1SLorenzo Bianconi 	if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
334*7fb554b1SLorenzo Bianconi 		return -EOPNOTSUPP;
335*7fb554b1SLorenzo Bianconi 
336*7fb554b1SLorenzo Bianconi 	if (!tc_can_offload(dev))
337*7fb554b1SLorenzo Bianconi 		return -EOPNOTSUPP;
338*7fb554b1SLorenzo Bianconi 
339*7fb554b1SLorenzo Bianconi 	f->driver_block_list = &block_cb_list;
340*7fb554b1SLorenzo Bianconi 	switch (f->command) {
341*7fb554b1SLorenzo Bianconi 	case FLOW_BLOCK_BIND:
342*7fb554b1SLorenzo Bianconi 		block_cb = flow_block_cb_lookup(f->block, cb, dev);
343*7fb554b1SLorenzo Bianconi 		if (block_cb) {
344*7fb554b1SLorenzo Bianconi 			flow_block_cb_incref(block_cb);
345*7fb554b1SLorenzo Bianconi 			return 0;
346*7fb554b1SLorenzo Bianconi 		}
347*7fb554b1SLorenzo Bianconi 
348*7fb554b1SLorenzo Bianconi 		block_cb = flow_block_cb_alloc(cb, dev, phy, NULL);
349*7fb554b1SLorenzo Bianconi 		if (IS_ERR(block_cb))
350*7fb554b1SLorenzo Bianconi 			return PTR_ERR(block_cb);
351*7fb554b1SLorenzo Bianconi 
352*7fb554b1SLorenzo Bianconi 		flow_block_cb_incref(block_cb);
353*7fb554b1SLorenzo Bianconi 		flow_block_cb_add(block_cb, f);
354*7fb554b1SLorenzo Bianconi 		list_add_tail(&block_cb->driver_list, &block_cb_list);
355*7fb554b1SLorenzo Bianconi 		return 0;
356*7fb554b1SLorenzo Bianconi 	case FLOW_BLOCK_UNBIND:
357*7fb554b1SLorenzo Bianconi 		block_cb = flow_block_cb_lookup(f->block, cb, dev);
358*7fb554b1SLorenzo Bianconi 		if (!block_cb)
359*7fb554b1SLorenzo Bianconi 			return -ENOENT;
360*7fb554b1SLorenzo Bianconi 
361*7fb554b1SLorenzo Bianconi 		if (!flow_block_cb_decref(block_cb)) {
362*7fb554b1SLorenzo Bianconi 			flow_block_cb_remove(block_cb, f);
363*7fb554b1SLorenzo Bianconi 			list_del(&block_cb->driver_list);
364*7fb554b1SLorenzo Bianconi 		}
365*7fb554b1SLorenzo Bianconi 		return 0;
366*7fb554b1SLorenzo Bianconi 	default:
367*7fb554b1SLorenzo Bianconi 		return -EOPNOTSUPP;
368*7fb554b1SLorenzo Bianconi 	}
369*7fb554b1SLorenzo Bianconi }
370*7fb554b1SLorenzo Bianconi 
371*7fb554b1SLorenzo Bianconi int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
372*7fb554b1SLorenzo Bianconi 			  struct net_device *dev, enum tc_setup_type type,
373*7fb554b1SLorenzo Bianconi 			  void *type_data)
374*7fb554b1SLorenzo Bianconi {
375*7fb554b1SLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
376*7fb554b1SLorenzo Bianconi 
377*7fb554b1SLorenzo Bianconi 	if (!tc_can_offload(dev))
378*7fb554b1SLorenzo Bianconi 		return -EOPNOTSUPP;
379*7fb554b1SLorenzo Bianconi 
380*7fb554b1SLorenzo Bianconi 	if (!mt76_npu_device_active(phy->dev))
381*7fb554b1SLorenzo Bianconi 		return -EOPNOTSUPP;
382*7fb554b1SLorenzo Bianconi 
383*7fb554b1SLorenzo Bianconi 	switch (type) {
384*7fb554b1SLorenzo Bianconi 	case TC_SETUP_BLOCK:
385*7fb554b1SLorenzo Bianconi 	case TC_SETUP_FT:
386*7fb554b1SLorenzo Bianconi 		return mt76_npu_setup_tc_block(phy, dev, type_data);
387*7fb554b1SLorenzo Bianconi 	default:
388*7fb554b1SLorenzo Bianconi 		return -EOPNOTSUPP;
389*7fb554b1SLorenzo Bianconi 	}
390*7fb554b1SLorenzo Bianconi }
391*7fb554b1SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_npu_net_setup_tc);
392*7fb554b1SLorenzo Bianconi 
393*7fb554b1SLorenzo Bianconi void mt76_npu_disable_irqs(struct mt76_dev *dev)
394*7fb554b1SLorenzo Bianconi {
395*7fb554b1SLorenzo Bianconi 	struct airoha_npu *npu;
396*7fb554b1SLorenzo Bianconi 	int i;
397*7fb554b1SLorenzo Bianconi 
398*7fb554b1SLorenzo Bianconi 	rcu_read_lock();
399*7fb554b1SLorenzo Bianconi 
400*7fb554b1SLorenzo Bianconi 	npu = rcu_dereference(dev->mmio.npu);
401*7fb554b1SLorenzo Bianconi 	if (!npu)
402*7fb554b1SLorenzo Bianconi 		goto unlock;
403*7fb554b1SLorenzo Bianconi 
404*7fb554b1SLorenzo Bianconi 	for (i = MT_RXQ_NPU0; i <= MT_RXQ_NPU1; i++) {
405*7fb554b1SLorenzo Bianconi 		int qid = i - MT_RXQ_NPU0;
406*7fb554b1SLorenzo Bianconi 		u32 status;
407*7fb554b1SLorenzo Bianconi 
408*7fb554b1SLorenzo Bianconi 		status = airoha_npu_wlan_get_irq_status(npu, qid);
409*7fb554b1SLorenzo Bianconi 		airoha_npu_wlan_set_irq_status(npu, status);
410*7fb554b1SLorenzo Bianconi 		airoha_npu_wlan_disable_irq(npu, qid);
411*7fb554b1SLorenzo Bianconi 	}
412*7fb554b1SLorenzo Bianconi unlock:
413*7fb554b1SLorenzo Bianconi 	rcu_read_unlock();
414*7fb554b1SLorenzo Bianconi }
415*7fb554b1SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_npu_disable_irqs);
416*7fb554b1SLorenzo Bianconi 
417*7fb554b1SLorenzo Bianconi int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type)
418*7fb554b1SLorenzo Bianconi {
419*7fb554b1SLorenzo Bianconi 	struct airoha_ppe_dev *ppe_dev;
420*7fb554b1SLorenzo Bianconi 	struct airoha_npu *npu;
421*7fb554b1SLorenzo Bianconi 	int err = 0;
422*7fb554b1SLorenzo Bianconi 
423*7fb554b1SLorenzo Bianconi 	/* NPU offloading is only supported by MT7992 */
424*7fb554b1SLorenzo Bianconi 	if (!is_mt7992(dev))
425*7fb554b1SLorenzo Bianconi 		return 0;
426*7fb554b1SLorenzo Bianconi 
427*7fb554b1SLorenzo Bianconi 	mutex_lock(&dev->mutex);
428*7fb554b1SLorenzo Bianconi 
429*7fb554b1SLorenzo Bianconi 	npu = airoha_npu_get(dev->dev);
430*7fb554b1SLorenzo Bianconi 	if (IS_ERR(npu)) {
431*7fb554b1SLorenzo Bianconi 		request_module("airoha-npu");
432*7fb554b1SLorenzo Bianconi 		npu = airoha_npu_get(dev->dev);
433*7fb554b1SLorenzo Bianconi 	}
434*7fb554b1SLorenzo Bianconi 
435*7fb554b1SLorenzo Bianconi 	if (IS_ERR(npu)) {
436*7fb554b1SLorenzo Bianconi 		err = PTR_ERR(npu);
437*7fb554b1SLorenzo Bianconi 		goto error_unlock;
438*7fb554b1SLorenzo Bianconi 	}
439*7fb554b1SLorenzo Bianconi 
440*7fb554b1SLorenzo Bianconi 	ppe_dev = airoha_ppe_get_dev(dev->dev);
441*7fb554b1SLorenzo Bianconi 	if (IS_ERR(ppe_dev)) {
442*7fb554b1SLorenzo Bianconi 		request_module("airoha-eth");
443*7fb554b1SLorenzo Bianconi 		ppe_dev = airoha_ppe_get_dev(dev->dev);
444*7fb554b1SLorenzo Bianconi 	}
445*7fb554b1SLorenzo Bianconi 
446*7fb554b1SLorenzo Bianconi 	if (IS_ERR(ppe_dev)) {
447*7fb554b1SLorenzo Bianconi 		err = PTR_ERR(ppe_dev);
448*7fb554b1SLorenzo Bianconi 		goto error_npu_put;
449*7fb554b1SLorenzo Bianconi 	}
450*7fb554b1SLorenzo Bianconi 
451*7fb554b1SLorenzo Bianconi 	err = airoha_npu_wlan_init_reserved_memory(npu);
452*7fb554b1SLorenzo Bianconi 	if (err)
453*7fb554b1SLorenzo Bianconi 		goto error_ppe_put;
454*7fb554b1SLorenzo Bianconi 
455*7fb554b1SLorenzo Bianconi 	dev->dma_dev = npu->dev;
456*7fb554b1SLorenzo Bianconi 	dev->mmio.phy_addr = phy_addr;
457*7fb554b1SLorenzo Bianconi 	dev->mmio.npu_type = type;
458*7fb554b1SLorenzo Bianconi 	/* NPU offloading requires HW-RRO for RX packet reordering. */
459*7fb554b1SLorenzo Bianconi 	dev->hwrro_mode = MT76_HWRRO_V3_1;
460*7fb554b1SLorenzo Bianconi 
461*7fb554b1SLorenzo Bianconi 	rcu_assign_pointer(dev->mmio.npu, npu);
462*7fb554b1SLorenzo Bianconi 	rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev);
463*7fb554b1SLorenzo Bianconi 	synchronize_rcu();
464*7fb554b1SLorenzo Bianconi 
465*7fb554b1SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
466*7fb554b1SLorenzo Bianconi 
467*7fb554b1SLorenzo Bianconi 	return 0;
468*7fb554b1SLorenzo Bianconi 
469*7fb554b1SLorenzo Bianconi error_ppe_put:
470*7fb554b1SLorenzo Bianconi 	airoha_ppe_put_dev(ppe_dev);
471*7fb554b1SLorenzo Bianconi error_npu_put:
472*7fb554b1SLorenzo Bianconi 	airoha_npu_put(npu);
473*7fb554b1SLorenzo Bianconi error_unlock:
474*7fb554b1SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
475*7fb554b1SLorenzo Bianconi 
476*7fb554b1SLorenzo Bianconi 	return err;
477*7fb554b1SLorenzo Bianconi }
478*7fb554b1SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_npu_init);
479*7fb554b1SLorenzo Bianconi 
480*7fb554b1SLorenzo Bianconi void mt76_npu_deinit(struct mt76_dev *dev)
481*7fb554b1SLorenzo Bianconi {
482*7fb554b1SLorenzo Bianconi 	struct airoha_ppe_dev *ppe_dev;
483*7fb554b1SLorenzo Bianconi 	struct airoha_npu *npu;
484*7fb554b1SLorenzo Bianconi 
485*7fb554b1SLorenzo Bianconi 	mutex_lock(&dev->mutex);
486*7fb554b1SLorenzo Bianconi 
487*7fb554b1SLorenzo Bianconi 	npu = rcu_replace_pointer(dev->mmio.npu, NULL,
488*7fb554b1SLorenzo Bianconi 				  lockdep_is_held(&dev->mutex));
489*7fb554b1SLorenzo Bianconi 	if (npu)
490*7fb554b1SLorenzo Bianconi 		airoha_npu_put(npu);
491*7fb554b1SLorenzo Bianconi 
492*7fb554b1SLorenzo Bianconi 	ppe_dev = rcu_replace_pointer(dev->mmio.ppe_dev, NULL,
493*7fb554b1SLorenzo Bianconi 				      lockdep_is_held(&dev->mutex));
494*7fb554b1SLorenzo Bianconi 	if (ppe_dev)
495*7fb554b1SLorenzo Bianconi 		airoha_ppe_put_dev(ppe_dev);
496*7fb554b1SLorenzo Bianconi 
497*7fb554b1SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
498*7fb554b1SLorenzo Bianconi 
499*7fb554b1SLorenzo Bianconi 	mt76_npu_queue_cleanup(dev, &dev->q_rx[MT_RXQ_NPU0]);
500*7fb554b1SLorenzo Bianconi 	mt76_npu_queue_cleanup(dev, &dev->q_rx[MT_RXQ_NPU1]);
501*7fb554b1SLorenzo Bianconi }
502