Path: blob/main/sys/contrib/dev/mediatek/mt76/dma.c
108058 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (C) 2016 Felix Fietkau <[email protected]>3*/45#include <linux/dma-mapping.h>6#if defined(__FreeBSD__)7#include <linux/cache.h>8#include <net/page_pool/helpers.h>9#endif10#include "mt76.h"11#include "dma.h"1213static struct mt76_txwi_cache *14mt76_alloc_txwi(struct mt76_dev *dev)15{16struct mt76_txwi_cache *t;17dma_addr_t addr;18u8 *txwi;19int size;2021size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t));22txwi = kzalloc(size, GFP_ATOMIC);23if (!txwi)24return NULL;2526addr = dma_map_single(dev->dma_dev, txwi, dev->drv->txwi_size,27DMA_TO_DEVICE);28if (unlikely(dma_mapping_error(dev->dma_dev, addr))) {29kfree(txwi);30return NULL;31}3233t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size);34t->dma_addr = addr;3536return t;37}3839static struct mt76_txwi_cache *40mt76_alloc_rxwi(struct mt76_dev *dev)41{42struct mt76_txwi_cache *t;4344t = kzalloc(L1_CACHE_ALIGN(sizeof(*t)), GFP_ATOMIC);45if (!t)46return NULL;4748t->ptr = NULL;49return t;50}5152static struct mt76_txwi_cache *53__mt76_get_txwi(struct mt76_dev *dev)54{55struct mt76_txwi_cache *t = NULL;5657spin_lock(&dev->lock);58if (!list_empty(&dev->txwi_cache)) {59t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache,60list);61list_del(&t->list);62}63spin_unlock(&dev->lock);6465return t;66}6768static struct mt76_txwi_cache *69__mt76_get_rxwi(struct mt76_dev *dev)70{71struct mt76_txwi_cache *t = NULL;7273spin_lock_bh(&dev->wed_lock);74if (!list_empty(&dev->rxwi_cache)) {75t = list_first_entry(&dev->rxwi_cache, struct mt76_txwi_cache,76list);77list_del(&t->list);78}79spin_unlock_bh(&dev->wed_lock);8081return t;82}8384static struct mt76_txwi_cache *85mt76_get_txwi(struct mt76_dev *dev)86{87struct mt76_txwi_cache *t = __mt76_get_txwi(dev);8889if (t)90return t;9192return mt76_alloc_txwi(dev);93}9495struct mt76_txwi_cache *96mt76_get_rxwi(struct mt76_dev *dev)97{98struct mt76_txwi_cache *t = __mt76_get_rxwi(dev);99100if (t)101return t;102103return mt76_alloc_rxwi(dev);104}105EXPORT_SYMBOL_GPL(mt76_get_rxwi);106107void108mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)109{110if (!t)111return;112113spin_lock(&dev->lock);114list_add(&t->list, &dev->txwi_cache);115spin_unlock(&dev->lock);116}117EXPORT_SYMBOL_GPL(mt76_put_txwi);118119void120mt76_put_rxwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)121{122if (!t)123return;124125spin_lock_bh(&dev->wed_lock);126list_add(&t->list, &dev->rxwi_cache);127spin_unlock_bh(&dev->wed_lock);128}129EXPORT_SYMBOL_GPL(mt76_put_rxwi);130131static void132mt76_free_pending_txwi(struct mt76_dev *dev)133{134struct mt76_txwi_cache *t;135136local_bh_disable();137while ((t = __mt76_get_txwi(dev)) != NULL) {138dma_unmap_single(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,139DMA_TO_DEVICE);140kfree(mt76_get_txwi_ptr(dev, t));141}142local_bh_enable();143}144145void146mt76_free_pending_rxwi(struct mt76_dev *dev)147{148struct mt76_txwi_cache *t;149150local_bh_disable();151while ((t = __mt76_get_rxwi(dev)) != NULL) {152if (t->ptr)153mt76_put_page_pool_buf(t->ptr, false);154kfree(t);155}156local_bh_enable();157}158EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi);159160static void161mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q)162{163if (!mt76_queue_is_wed_rro(q))164return;165166q->magic_cnt = 0;167if (mt76_queue_is_wed_rro_ind(q)) {168struct mt76_wed_rro_desc *rro_desc;169u32 data1 = FIELD_PREP(RRO_IND_DATA1_MAGIC_CNT_MASK,170MT_DMA_WED_IND_CMD_CNT - 1);171int i;172173rro_desc = (struct mt76_wed_rro_desc *)q->desc;174for (i = 0; i < q->ndesc; i++) {175struct mt76_wed_rro_ind *cmd;176177cmd = (struct mt76_wed_rro_ind *)&rro_desc[i];178cmd->data1 = cpu_to_le32(data1);179}180} else if (mt76_queue_is_wed_rro_rxdmad_c(q)) {181struct mt76_rro_rxdmad_c *dmad = (void *)q->desc;182u32 data3 = FIELD_PREP(RRO_RXDMAD_DATA3_MAGIC_CNT_MASK,183MT_DMA_MAGIC_CNT - 1);184int i;185186for (i = 0; i < q->ndesc; i++)187dmad[i].data3 = cpu_to_le32(data3);188}189}190191static void192mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)193{194Q_WRITE(q, desc_base, q->desc_dma);195if ((q->flags & MT_QFLAG_WED_RRO_EN) && !mt76_npu_device_active(dev))196Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc);197else198Q_WRITE(q, ring_size, q->ndesc);199200if (mt76_queue_is_npu_tx(q)) {201writel(q->desc_dma, &q->regs->desc_base);202writel(q->ndesc, &q->regs->ring_size);203}204q->head = Q_READ(q, dma_idx);205q->tail = q->head;206}207208void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,209bool reset_idx)210{211if (!q || !q->ndesc)212return;213214if (!mt76_queue_is_wed_rro_ind(q) &&215!mt76_queue_is_wed_rro_rxdmad_c(q) && !mt76_queue_is_npu(q)) {216int i;217218/* clear descriptors */219for (i = 0; i < q->ndesc; i++)220q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);221}222223mt76_dma_queue_magic_cnt_init(dev, q);224if (reset_idx) {225if (mt76_queue_is_emi(q))226*q->emi_cpu_idx = 0;227else228Q_WRITE(q, cpu_idx, 0);229Q_WRITE(q, dma_idx, 0);230}231mt76_dma_sync_idx(dev, q);232}233234static int235mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,236struct mt76_queue_buf *buf, void *data)237{238struct mt76_queue_entry *entry = &q->entry[q->head];239struct mt76_txwi_cache *txwi = NULL;240u32 buf1 = 0, ctrl, info = 0;241struct mt76_desc *desc;242int idx = q->head;243int rx_token;244245if (mt76_queue_is_wed_rro_ind(q)) {246struct mt76_wed_rro_desc *rro_desc;247248rro_desc = (struct mt76_wed_rro_desc *)q->desc;249data = &rro_desc[q->head];250goto done;251} else if (mt76_queue_is_wed_rro_rxdmad_c(q)) {252data = &q->desc[q->head];253goto done;254}255256desc = &q->desc[q->head];257ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);258#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT259buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32);260#endif261262if (mt76_queue_is_wed_rx(q) || mt76_queue_is_wed_rro_data(q)) {263txwi = mt76_get_rxwi(dev);264if (!txwi)265return -ENOMEM;266267rx_token = mt76_rx_token_consume(dev, data, txwi, buf->addr);268if (rx_token < 0) {269mt76_put_rxwi(dev, txwi);270return -ENOMEM;271}272273buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token);274ctrl |= MT_DMA_CTL_TO_HOST;275276txwi->qid = q - dev->q_rx;277}278279if (mt76_queue_is_wed_rro_msdu_pg(q) &&280dev->drv->rx_rro_add_msdu_page) {281if (dev->drv->rx_rro_add_msdu_page(dev, q, buf->addr, data))282return -ENOMEM;283}284285if (q->flags & MT_QFLAG_WED_RRO_EN) {286info |= FIELD_PREP(MT_DMA_MAGIC_MASK, q->magic_cnt);287if ((q->head + 1) == q->ndesc)288q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_MAGIC_CNT;289}290291WRITE_ONCE(desc->buf0, cpu_to_le32(buf->addr));292WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));293WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));294WRITE_ONCE(desc->info, cpu_to_le32(info));295296done:297entry->dma_addr[0] = buf->addr;298entry->dma_len[0] = buf->len;299entry->txwi = txwi;300entry->buf = data;301entry->wcid = 0xffff;302entry->skip_buf1 = true;303q->head = (q->head + 1) % q->ndesc;304q->queued++;305306return idx;307}308309static int310mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,311struct mt76_queue_buf *buf, int nbufs, u32 info,312struct sk_buff *skb, void *txwi)313{314struct mt76_queue_entry *entry;315struct mt76_desc *desc;316int i, idx = -1;317u32 ctrl, next;318319if (txwi) {320q->entry[q->head].txwi = DMA_DUMMY_DATA;321q->entry[q->head].skip_buf0 = true;322}323324for (i = 0; i < nbufs; i += 2, buf += 2) {325u32 buf0 = buf[0].addr, buf1 = 0;326327idx = q->head;328next = (q->head + 1) % q->ndesc;329330desc = &q->desc[idx];331entry = &q->entry[idx];332333if (buf[0].skip_unmap)334entry->skip_buf0 = true;335entry->skip_buf1 = i == nbufs - 1;336337entry->dma_addr[0] = buf[0].addr;338entry->dma_len[0] = buf[0].len;339340ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);341#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT342info |= FIELD_PREP(MT_DMA_CTL_SDP0_H, buf[0].addr >> 32);343#endif344if (i < nbufs - 1) {345entry->dma_addr[1] = buf[1].addr;346entry->dma_len[1] = buf[1].len;347buf1 = buf[1].addr;348ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);349#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT350info |= FIELD_PREP(MT_DMA_CTL_SDP1_H,351buf[1].addr >> 32);352#endif353if (buf[1].skip_unmap)354entry->skip_buf1 = true;355}356357if (i == nbufs - 1)358ctrl |= MT_DMA_CTL_LAST_SEC0;359else if (i == nbufs - 2)360ctrl |= MT_DMA_CTL_LAST_SEC1;361362WRITE_ONCE(desc->buf0, cpu_to_le32(buf0));363WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));364WRITE_ONCE(desc->info, cpu_to_le32(info));365WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));366367q->head = next;368q->queued++;369}370371q->entry[idx].txwi = txwi;372q->entry[idx].skb = skb;373q->entry[idx].wcid = 0xffff;374375return idx;376}377378static void379mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,380struct mt76_queue_entry *prev_e)381{382struct mt76_queue_entry *e = &q->entry[idx];383384if (!e->skip_buf0)385dma_unmap_single(dev->dma_dev, e->dma_addr[0], e->dma_len[0],386DMA_TO_DEVICE);387388if (!e->skip_buf1)389dma_unmap_single(dev->dma_dev, e->dma_addr[1], e->dma_len[1],390DMA_TO_DEVICE);391392if (e->txwi == DMA_DUMMY_DATA)393e->txwi = NULL;394395*prev_e = *e;396memset(e, 0, sizeof(*e));397}398399static void400mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)401{402wmb();403if (mt76_queue_is_emi(q))404*q->emi_cpu_idx = cpu_to_le16(q->head);405else406Q_WRITE(q, cpu_idx, q->head);407}408409static void410mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)411{412struct mt76_queue_entry entry;413int last;414415if (!q || !q->ndesc)416return;417418spin_lock_bh(&q->cleanup_lock);419if (flush)420last = -1;421else422last = Q_READ(q, dma_idx);423424while (q->queued > 0 && q->tail != last) {425mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);426mt76_npu_txdesc_cleanup(q, q->tail);427mt76_queue_tx_complete(dev, q, &entry);428429if (entry.txwi) {430if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE))431mt76_put_txwi(dev, entry.txwi);432}433434if (!flush && q->tail == last)435last = Q_READ(q, dma_idx);436}437spin_unlock_bh(&q->cleanup_lock);438439if (flush) {440spin_lock_bh(&q->lock);441mt76_dma_sync_idx(dev, q);442mt76_dma_kick_queue(dev, q);443spin_unlock_bh(&q->lock);444}445446if (!q->queued)447wake_up(&dev->tx_wait);448}449450static void *451mt76_dma_get_rxdmad_c_buf(struct mt76_dev *dev, struct mt76_queue *q,452int idx, int *len, bool *more)453{454struct mt76_queue_entry *e = &q->entry[idx];455struct mt76_rro_rxdmad_c *dmad = e->buf;456u32 data1 = le32_to_cpu(dmad->data1);457u32 data2 = le32_to_cpu(dmad->data2);458struct mt76_txwi_cache *t;459u16 rx_token_id;460u8 ind_reason;461void *buf;462463rx_token_id = FIELD_GET(RRO_RXDMAD_DATA2_RX_TOKEN_ID_MASK, data2);464t = mt76_rx_token_release(dev, rx_token_id);465if (!t)466return ERR_PTR(-EAGAIN);467468q = &dev->q_rx[t->qid];469dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr,470SKB_WITH_OVERHEAD(q->buf_size),471page_pool_get_dma_dir(q->page_pool));472473if (len)474*len = FIELD_GET(RRO_RXDMAD_DATA1_SDL0_MASK, data1);475if (more)476*more = !FIELD_GET(RRO_RXDMAD_DATA1_LS_MASK, data1);477478buf = t->ptr;479ind_reason = FIELD_GET(RRO_RXDMAD_DATA2_IND_REASON_MASK, data2);480if (ind_reason == MT_DMA_WED_IND_REASON_REPEAT ||481ind_reason == MT_DMA_WED_IND_REASON_OLDPKT) {482mt76_put_page_pool_buf(buf, false);483buf = ERR_PTR(-EAGAIN);484}485t->ptr = NULL;486t->dma_addr = 0;487488mt76_put_rxwi(dev, t);489490return buf;491}492493static void *494mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,495int *len, u32 *info, bool *more, bool *drop, bool flush)496{497struct mt76_queue_entry *e = &q->entry[idx];498struct mt76_desc *desc = &q->desc[idx];499u32 ctrl, desc_info, buf1;500void *buf = e->buf;501502if (mt76_queue_is_wed_rro_rxdmad_c(q) && !flush)503buf = mt76_dma_get_rxdmad_c_buf(dev, q, idx, len, more);504505if (mt76_queue_is_wed_rro(q))506goto done;507508ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));509if (len) {510*len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl);511*more = !(ctrl & MT_DMA_CTL_LAST_SEC0);512}513514desc_info = le32_to_cpu(desc->info);515if (info)516*info = desc_info;517518buf1 = le32_to_cpu(desc->buf1);519mt76_dma_should_drop_buf(drop, ctrl, buf1, desc_info);520521if (mt76_queue_is_wed_rx(q)) {522u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1);523struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token);524525if (!t)526return NULL;527528dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr,529SKB_WITH_OVERHEAD(q->buf_size),530page_pool_get_dma_dir(q->page_pool));531532buf = t->ptr;533t->dma_addr = 0;534t->ptr = NULL;535536mt76_put_rxwi(dev, t);537if (drop)538*drop |= !!(buf1 & MT_DMA_CTL_WO_DROP);539} else {540dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0],541SKB_WITH_OVERHEAD(q->buf_size),542page_pool_get_dma_dir(q->page_pool));543}544545done:546e->buf = NULL;547return buf;548}549550static void *551mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,552int *len, u32 *info, bool *more, bool *drop)553{554int idx = q->tail;555556*more = false;557if (!q->queued)558return NULL;559560if (mt76_queue_is_wed_rro_data(q) || mt76_queue_is_wed_rro_msdu_pg(q))561goto done;562563if (mt76_queue_is_wed_rro_ind(q)) {564struct mt76_wed_rro_ind *cmd;565u8 magic_cnt;566567if (flush)568goto done;569570cmd = q->entry[idx].buf;571magic_cnt = FIELD_GET(RRO_IND_DATA1_MAGIC_CNT_MASK,572le32_to_cpu(cmd->data1));573if (magic_cnt != q->magic_cnt)574return NULL;575576if (q->tail == q->ndesc - 1)577q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_WED_IND_CMD_CNT;578} else if (mt76_queue_is_wed_rro_rxdmad_c(q)) {579struct mt76_rro_rxdmad_c *dmad;580u16 magic_cnt;581582if (flush)583goto done;584585dmad = q->entry[idx].buf;586magic_cnt = FIELD_GET(RRO_RXDMAD_DATA3_MAGIC_CNT_MASK,587le32_to_cpu(dmad->data3));588if (magic_cnt != q->magic_cnt)589return NULL;590591if (q->tail == q->ndesc - 1)592q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_MAGIC_CNT;593} else {594if (flush)595q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE);596else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE)))597return NULL;598}599done:600q->tail = (q->tail + 1) % q->ndesc;601q->queued--;602603return mt76_dma_get_buf(dev, q, idx, len, info, more, drop, flush);604}605606static int607mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,608struct sk_buff *skb, u32 tx_info)609{610struct mt76_queue_buf buf = {};611dma_addr_t addr;612613if (test_bit(MT76_MCU_RESET, &dev->phy.state))614goto error;615616if (q->queued + 1 >= q->ndesc - 1)617goto error;618619addr = dma_map_single(dev->dma_dev, skb->data, skb->len,620DMA_TO_DEVICE);621if (unlikely(dma_mapping_error(dev->dma_dev, addr)))622goto error;623624buf.addr = addr;625buf.len = skb->len;626627spin_lock_bh(&q->lock);628mt76_dma_add_buf(dev, q, &buf, 1, tx_info, skb, NULL);629mt76_dma_kick_queue(dev, q);630spin_unlock_bh(&q->lock);631632return 0;633634error:635dev_kfree_skb(skb);636return -ENOMEM;637}638639static int640mt76_dma_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,641enum mt76_txq_id qid, struct sk_buff *skb,642struct mt76_wcid *wcid, struct ieee80211_sta *sta)643{644struct ieee80211_tx_status status = {645.sta = sta,646};647struct mt76_tx_info tx_info = {648.skb = skb,649};650struct mt76_dev *dev = phy->dev;651struct ieee80211_hw *hw;652int len, n = 0, ret = -ENOMEM;653struct mt76_txwi_cache *t;654struct sk_buff *iter;655dma_addr_t addr;656u8 *txwi;657658if (test_bit(MT76_RESET, &phy->state))659goto free_skb;660661/* TODO: Take into account unlinear skbs */662if (mt76_npu_device_active(dev) && skb_linearize(skb))663goto free_skb;664665t = mt76_get_txwi(dev);666if (!t)667goto free_skb;668669txwi = mt76_get_txwi_ptr(dev, t);670671skb->prev = skb->next = NULL;672if (dev->drv->drv_flags & MT_DRV_TX_ALIGNED4_SKBS)673mt76_insert_hdr_pad(skb);674675len = skb_headlen(skb);676addr = dma_map_single(dev->dma_dev, skb->data, len, DMA_TO_DEVICE);677if (unlikely(dma_mapping_error(dev->dma_dev, addr)))678goto free;679680tx_info.buf[n].addr = t->dma_addr;681tx_info.buf[n++].len = dev->drv->txwi_size;682tx_info.buf[n].addr = addr;683tx_info.buf[n++].len = len;684685skb_walk_frags(skb, iter) {686if (n == ARRAY_SIZE(tx_info.buf))687goto unmap;688689addr = dma_map_single(dev->dma_dev, iter->data, iter->len,690DMA_TO_DEVICE);691if (unlikely(dma_mapping_error(dev->dma_dev, addr)))692goto unmap;693694tx_info.buf[n].addr = addr;695tx_info.buf[n++].len = iter->len;696}697tx_info.nbuf = n;698699if (q->queued + (tx_info.nbuf + 1) / 2 >= q->ndesc - 1) {700ret = -ENOMEM;701goto unmap;702}703704dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,705DMA_TO_DEVICE);706ret = dev->drv->tx_prepare_skb(dev, txwi, qid, wcid, sta, &tx_info);707dma_sync_single_for_device(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,708DMA_TO_DEVICE);709if (ret < 0)710goto unmap;711712if (mt76_npu_device_active(dev))713return mt76_npu_dma_add_buf(phy, q, skb, &tx_info.buf[1], txwi);714715return mt76_dma_add_buf(dev, q, tx_info.buf, tx_info.nbuf,716tx_info.info, tx_info.skb, t);717718unmap:719for (n--; n > 0; n--)720dma_unmap_single(dev->dma_dev, tx_info.buf[n].addr,721tx_info.buf[n].len, DMA_TO_DEVICE);722723free:724#ifdef CONFIG_NL80211_TESTMODE725/* fix tx_done accounting on queue overflow */726if (mt76_is_testmode_skb(dev, skb, &hw)) {727struct mt76_phy *phy = hw->priv;728729if (tx_info.skb == phy->test.tx_skb)730phy->test.tx_done--;731}732#endif733734mt76_put_txwi(dev, t);735736free_skb:737status.skb = tx_info.skb;738hw = mt76_tx_status_get_hw(dev, tx_info.skb);739spin_lock_bh(&dev->rx_lock);740ieee80211_tx_status_ext(hw, &status);741spin_unlock_bh(&dev->rx_lock);742743return ret;744}745746static int747mt76_dma_rx_fill_buf(struct mt76_dev *dev, struct mt76_queue *q,748bool allow_direct)749{750int len = SKB_WITH_OVERHEAD(q->buf_size);751int frames = 0;752753if (!q->ndesc)754return 0;755756while (q->queued < q->ndesc - 1) {757struct mt76_queue_buf qbuf = {};758void *buf = NULL;759int offset;760761if (mt76_queue_is_wed_rro_ind(q) ||762mt76_queue_is_wed_rro_rxdmad_c(q))763goto done;764765buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);766if (!buf)767break;768769qbuf.addr = page_pool_get_dma_addr(virt_to_head_page(buf)) +770offset + q->buf_offset;771done:772qbuf.len = len - q->buf_offset;773qbuf.skip_unmap = false;774if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) {775mt76_put_page_pool_buf(buf, allow_direct);776break;777}778frames++;779}780781if (frames || mt76_queue_is_wed_rx(q))782mt76_dma_kick_queue(dev, q);783784return frames;785}786787int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,788bool allow_direct)789{790int frames;791792spin_lock_bh(&q->lock);793frames = mt76_dma_rx_fill_buf(dev, q, allow_direct);794spin_unlock_bh(&q->lock);795796return frames;797}798799static int800mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,801int idx, int n_desc, int bufsize,802u32 ring_base)803{804int ret, size;805806spin_lock_init(&q->lock);807spin_lock_init(&q->cleanup_lock);808809#if defined(__linux__)810q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;811#elif defined(__FreeBSD__)812q->regs = (void *)((u8 *)dev->mmio.regs + ring_base + idx * MT_RING_SIZE);813#endif814q->ndesc = n_desc;815q->buf_size = bufsize;816q->hw_idx = idx;817q->dev = dev;818819if (mt76_queue_is_wed_rro_ind(q))820size = sizeof(struct mt76_wed_rro_desc);821else if (mt76_queue_is_npu_tx(q))822size = sizeof(struct airoha_npu_tx_dma_desc);823else if (mt76_queue_is_npu_rx(q))824size = sizeof(struct airoha_npu_rx_dma_desc);825else826size = sizeof(struct mt76_desc);827828q->desc = dmam_alloc_coherent(dev->dma_dev, q->ndesc * size,829&q->desc_dma, GFP_KERNEL);830if (!q->desc)831return -ENOMEM;832833mt76_dma_queue_magic_cnt_init(dev, q);834size = q->ndesc * sizeof(*q->entry);835q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);836if (!q->entry)837return -ENOMEM;838839ret = mt76_create_page_pool(dev, q);840if (ret)841return ret;842843mt76_npu_queue_setup(dev, q);844ret = mt76_wed_dma_setup(dev, q, false);845if (ret)846return ret;847848if (mtk_wed_device_active(&dev->mmio.wed)) {849if ((mtk_wed_get_rx_capa(&dev->mmio.wed) && mt76_queue_is_wed_rro(q)) ||850mt76_queue_is_wed_tx_free(q))851return 0;852}853854/* HW specific driver is supposed to reset brand-new EMI queues since855* it needs to set cpu index pointer.856*/857mt76_dma_queue_reset(dev, q, !mt76_queue_is_emi(q));858859return 0;860}861862static void863mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)864{865void *buf;866bool more;867868if (!q->ndesc)869return;870871if (mt76_queue_is_npu(q)) {872mt76_npu_queue_cleanup(dev, q);873return;874}875876do {877spin_lock_bh(&q->lock);878buf = mt76_dma_dequeue(dev, q, true, NULL, NULL, &more, NULL);879spin_unlock_bh(&q->lock);880881if (!buf)882break;883884if (!mt76_queue_is_wed_rro(q))885mt76_put_page_pool_buf(buf, false);886} while (1);887888spin_lock_bh(&q->lock);889if (q->rx_head) {890dev_kfree_skb(q->rx_head);891q->rx_head = NULL;892}893894spin_unlock_bh(&q->lock);895}896897static void898mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)899{900struct mt76_queue *q = &dev->q_rx[qid];901902if (!q->ndesc)903return;904905if (!mt76_queue_is_wed_rro_ind(q) &&906!mt76_queue_is_wed_rro_rxdmad_c(q) && !mt76_queue_is_npu(q)) {907int i;908909for (i = 0; i < q->ndesc; i++)910q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);911}912913mt76_dma_rx_cleanup(dev, q);914915/* reset WED rx queues */916mt76_wed_dma_setup(dev, q, true);917918if (mt76_queue_is_wed_tx_free(q))919return;920921if (mtk_wed_device_active(&dev->mmio.wed) &&922mt76_queue_is_wed_rro(q))923return;924925mt76_dma_sync_idx(dev, q);926if (mt76_queue_is_npu(q))927mt76_npu_fill_rx_queue(dev, q);928else929mt76_dma_rx_fill(dev, q, false);930}931932static void933mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,934int len, bool more, u32 info, bool allow_direct)935{936struct sk_buff *skb = q->rx_head;937struct skb_shared_info *shinfo = skb_shinfo(skb);938int nr_frags = shinfo->nr_frags;939940if (nr_frags < ARRAY_SIZE(shinfo->frags)) {941struct page *page = virt_to_head_page(data);942#if defined(__linux__)943int offset = data - page_address(page) + q->buf_offset;944#elif defined(__FreeBSD__)945int offset = (u8 *)data - (u8 *)page_address(page) + q->buf_offset;946#endif947948skb_add_rx_frag(skb, nr_frags, page, offset, len, q->buf_size);949} else {950mt76_put_page_pool_buf(data, allow_direct);951}952953if (more)954return;955956q->rx_head = NULL;957if (nr_frags < ARRAY_SIZE(shinfo->frags))958dev->drv->rx_skb(dev, q - dev->q_rx, skb, &info);959else960dev_kfree_skb(skb);961}962963static int964mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)965{966int len, data_len, done = 0, dma_idx;967struct sk_buff *skb;968unsigned char *data;969bool check_ddone = false;970bool allow_direct = !mt76_queue_is_wed_rx(q);971bool more;972973if ((q->flags & MT_QFLAG_WED_RRO_EN) ||974(IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&975mt76_queue_is_wed_tx_free(q))) {976dma_idx = Q_READ(q, dma_idx);977check_ddone = true;978}979980while (done < budget) {981bool drop = false;982u32 info;983984if (check_ddone) {985if (q->tail == dma_idx)986dma_idx = Q_READ(q, dma_idx);987988if (q->tail == dma_idx)989break;990}991992data = mt76_dma_dequeue(dev, q, false, &len, &info, &more,993&drop);994if (!data)995break;996997if (PTR_ERR(data) == -EAGAIN) {998done++;999continue;1000}10011002if (mt76_queue_is_wed_rro_ind(q) && dev->drv->rx_rro_ind_process)1003dev->drv->rx_rro_ind_process(dev, data);10041005if (mt76_queue_is_wed_rro(q) &&1006!mt76_queue_is_wed_rro_rxdmad_c(q)) {1007done++;1008continue;1009}10101011if (drop)1012goto free_frag;10131014if (q->rx_head)1015data_len = q->buf_size;1016else1017data_len = SKB_WITH_OVERHEAD(q->buf_size);10181019if (data_len < len + q->buf_offset) {1020dev_kfree_skb(q->rx_head);1021q->rx_head = NULL;1022goto free_frag;1023}10241025if (q->rx_head) {1026mt76_add_fragment(dev, q, data, len, more, info,1027allow_direct);1028continue;1029}10301031if (!more && dev->drv->rx_check &&1032!(dev->drv->rx_check(dev, data, len)))1033goto free_frag;10341035skb = napi_build_skb(data, q->buf_size);1036if (!skb)1037goto free_frag;10381039skb_reserve(skb, q->buf_offset);1040skb_mark_for_recycle(skb);10411042*(u32 *)skb->cb = info;10431044__skb_put(skb, len);1045done++;10461047if (more) {1048q->rx_head = skb;1049continue;1050}10511052dev->drv->rx_skb(dev, q - dev->q_rx, skb, &info);1053continue;10541055free_frag:1056mt76_put_page_pool_buf(data, allow_direct);1057}10581059mt76_dma_rx_fill(dev, q, true);1060return done;1061}10621063int mt76_dma_rx_poll(struct napi_struct *napi, int budget)1064{1065struct mt76_dev *dev;1066int qid, done = 0, cur;10671068dev = mt76_priv(napi->dev);1069qid = napi - dev->napi;10701071rcu_read_lock();10721073do {1074cur = mt76_dma_rx_process(dev, &dev->q_rx[qid], budget - done);1075mt76_rx_poll_complete(dev, qid, napi);1076done += cur;1077} while (cur && done < budget);10781079rcu_read_unlock();10801081if (done < budget && napi_complete(napi))1082dev->drv->rx_poll_complete(dev, qid);10831084return done;1085}1086EXPORT_SYMBOL_GPL(mt76_dma_rx_poll);10871088static void1089mt76_dma_rx_queue_init(struct mt76_dev *dev, enum mt76_rxq_id qid,1090int (*poll)(struct napi_struct *napi, int budget))1091{1092netif_napi_add(dev->napi_dev, &dev->napi[qid], poll);1093mt76_dma_rx_fill_buf(dev, &dev->q_rx[qid], false);1094napi_enable(&dev->napi[qid]);1095}10961097static int1098mt76_dma_init(struct mt76_dev *dev,1099int (*poll)(struct napi_struct *napi, int budget))1100{1101struct mt76_dev **priv;1102int i;11031104dev->napi_dev = alloc_netdev_dummy(sizeof(struct mt76_dev *));1105if (!dev->napi_dev)1106return -ENOMEM;11071108/* napi_dev private data points to mt76_dev parent, so, mt76_dev1109* can be retrieved given napi_dev1110*/1111priv = netdev_priv(dev->napi_dev);1112*priv = dev;11131114dev->tx_napi_dev = alloc_netdev_dummy(sizeof(struct mt76_dev *));1115if (!dev->tx_napi_dev) {1116free_netdev(dev->napi_dev);1117return -ENOMEM;1118}1119priv = netdev_priv(dev->tx_napi_dev);1120*priv = dev;11211122snprintf(dev->napi_dev->name, sizeof(dev->napi_dev->name), "%s",1123wiphy_name(dev->hw->wiphy));1124dev->napi_dev->threaded = 1;1125init_completion(&dev->mmio.wed_reset);1126init_completion(&dev->mmio.wed_reset_complete);11271128mt76_for_each_q_rx(dev, i) {1129if (mt76_queue_is_wed_rro(&dev->q_rx[i]))1130continue;11311132mt76_dma_rx_queue_init(dev, i, poll);1133}11341135return 0;1136}11371138static const struct mt76_queue_ops mt76_dma_ops = {1139.init = mt76_dma_init,1140.alloc = mt76_dma_alloc_queue,1141.reset_q = mt76_dma_queue_reset,1142.tx_queue_skb_raw = mt76_dma_tx_queue_skb_raw,1143.tx_queue_skb = mt76_dma_tx_queue_skb,1144.tx_cleanup = mt76_dma_tx_cleanup,1145.rx_queue_init = mt76_dma_rx_queue_init,1146.rx_cleanup = mt76_dma_rx_cleanup,1147.rx_reset = mt76_dma_rx_reset,1148.kick = mt76_dma_kick_queue,1149};11501151void mt76_dma_attach(struct mt76_dev *dev)1152{1153dev->queue_ops = &mt76_dma_ops;1154}1155EXPORT_SYMBOL_GPL(mt76_dma_attach);11561157void mt76_dma_cleanup(struct mt76_dev *dev)1158{1159int i;11601161mt76_worker_disable(&dev->tx_worker);1162napi_disable(&dev->tx_napi);1163netif_napi_del(&dev->tx_napi);11641165for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {1166struct mt76_phy *phy = dev->phys[i];1167int j;11681169if (!phy)1170continue;11711172for (j = 0; j < ARRAY_SIZE(phy->q_tx); j++)1173mt76_dma_tx_cleanup(dev, phy->q_tx[j], true);1174}11751176for (i = 0; i < ARRAY_SIZE(dev->q_mcu); i++)1177mt76_dma_tx_cleanup(dev, dev->q_mcu[i], true);11781179mt76_for_each_q_rx(dev, i) {1180struct mt76_queue *q = &dev->q_rx[i];11811182if (mtk_wed_device_active(&dev->mmio.wed) &&1183mt76_queue_is_wed_rro(q))1184continue;11851186netif_napi_del(&dev->napi[i]);1187mt76_dma_rx_cleanup(dev, q);11881189page_pool_destroy(q->page_pool);1190}11911192if (mtk_wed_device_active(&dev->mmio.wed))1193mtk_wed_device_detach(&dev->mmio.wed);11941195if (mtk_wed_device_active(&dev->mmio.wed_hif2))1196mtk_wed_device_detach(&dev->mmio.wed_hif2);11971198mt76_free_pending_txwi(dev);1199mt76_free_pending_rxwi(dev);1200free_netdev(dev->napi_dev);1201free_netdev(dev->tx_napi_dev);1202}1203EXPORT_SYMBOL_GPL(mt76_dma_cleanup);120412051206