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