16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /* Copyright (C) 2020 MediaTek Inc.
36c92544dSBjoern A. Zeeb *
46c92544dSBjoern A. Zeeb * Author: Felix Fietkau <nbd@nbd.name>
56c92544dSBjoern A. Zeeb * Lorenzo Bianconi <lorenzo@kernel.org>
66c92544dSBjoern A. Zeeb * Sean Wang <sean.wang@mediatek.com>
76c92544dSBjoern A. Zeeb */
86c92544dSBjoern A. Zeeb
96c92544dSBjoern A. Zeeb #include <linux/kernel.h>
106c92544dSBjoern A. Zeeb #include <linux/iopoll.h>
116c92544dSBjoern A. Zeeb #include <linux/module.h>
126c92544dSBjoern A. Zeeb
136c92544dSBjoern A. Zeeb #include <linux/mmc/host.h>
146c92544dSBjoern A. Zeeb #include <linux/mmc/sdio_ids.h>
156c92544dSBjoern A. Zeeb #include <linux/mmc/sdio_func.h>
166c92544dSBjoern A. Zeeb
176c92544dSBjoern A. Zeeb #include "trace.h"
186c92544dSBjoern A. Zeeb #include "sdio.h"
196c92544dSBjoern A. Zeeb #include "mt76.h"
206c92544dSBjoern A. Zeeb
mt76s_refill_sched_quota(struct mt76_dev * dev,u32 * data)216c92544dSBjoern A. Zeeb static int mt76s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
226c92544dSBjoern A. Zeeb {
236c92544dSBjoern A. Zeeb u32 ple_ac_data_quota[] = {
246c92544dSBjoern A. Zeeb FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
256c92544dSBjoern A. Zeeb FIELD_GET(TXQ_CNT_H, data[3]), /* VI */
266c92544dSBjoern A. Zeeb FIELD_GET(TXQ_CNT_L, data[3]), /* BE */
276c92544dSBjoern A. Zeeb FIELD_GET(TXQ_CNT_H, data[2]), /* BK */
286c92544dSBjoern A. Zeeb };
296c92544dSBjoern A. Zeeb u32 pse_ac_data_quota[] = {
306c92544dSBjoern A. Zeeb FIELD_GET(TXQ_CNT_H, data[1]), /* VO */
316c92544dSBjoern A. Zeeb FIELD_GET(TXQ_CNT_L, data[1]), /* VI */
326c92544dSBjoern A. Zeeb FIELD_GET(TXQ_CNT_H, data[0]), /* BE */
336c92544dSBjoern A. Zeeb FIELD_GET(TXQ_CNT_L, data[0]), /* BK */
346c92544dSBjoern A. Zeeb };
356c92544dSBjoern A. Zeeb u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]);
366c92544dSBjoern A. Zeeb u32 pse_data_quota = 0, ple_data_quota = 0;
376c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio;
386c92544dSBjoern A. Zeeb int i;
396c92544dSBjoern A. Zeeb
406c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) {
416c92544dSBjoern A. Zeeb pse_data_quota += pse_ac_data_quota[i];
426c92544dSBjoern A. Zeeb ple_data_quota += ple_ac_data_quota[i];
436c92544dSBjoern A. Zeeb }
446c92544dSBjoern A. Zeeb
456c92544dSBjoern A. Zeeb if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
466c92544dSBjoern A. Zeeb return 0;
476c92544dSBjoern A. Zeeb
486c92544dSBjoern A. Zeeb sdio->sched.pse_mcu_quota += pse_mcu_quota;
49*8ba4d145SBjoern A. Zeeb if (sdio->pse_mcu_quota_max &&
50*8ba4d145SBjoern A. Zeeb sdio->sched.pse_mcu_quota > sdio->pse_mcu_quota_max) {
51*8ba4d145SBjoern A. Zeeb sdio->sched.pse_mcu_quota = sdio->pse_mcu_quota_max;
52*8ba4d145SBjoern A. Zeeb }
536c92544dSBjoern A. Zeeb sdio->sched.pse_data_quota += pse_data_quota;
546c92544dSBjoern A. Zeeb sdio->sched.ple_data_quota += ple_data_quota;
556c92544dSBjoern A. Zeeb
566c92544dSBjoern A. Zeeb return pse_data_quota + ple_data_quota + pse_mcu_quota;
576c92544dSBjoern A. Zeeb }
586c92544dSBjoern A. Zeeb
596c92544dSBjoern A. Zeeb static struct sk_buff *
mt76s_build_rx_skb(void * data,int data_len,int buf_len)606c92544dSBjoern A. Zeeb mt76s_build_rx_skb(void *data, int data_len, int buf_len)
616c92544dSBjoern A. Zeeb {
626c92544dSBjoern A. Zeeb int len = min_t(int, data_len, MT_SKB_HEAD_LEN);
636c92544dSBjoern A. Zeeb struct sk_buff *skb;
646c92544dSBjoern A. Zeeb
656c92544dSBjoern A. Zeeb skb = alloc_skb(len, GFP_KERNEL);
666c92544dSBjoern A. Zeeb if (!skb)
676c92544dSBjoern A. Zeeb return NULL;
686c92544dSBjoern A. Zeeb
696c92544dSBjoern A. Zeeb skb_put_data(skb, data, len);
706c92544dSBjoern A. Zeeb if (data_len > len) {
716c92544dSBjoern A. Zeeb struct page *page;
726c92544dSBjoern A. Zeeb
736c92544dSBjoern A. Zeeb data += len;
746c92544dSBjoern A. Zeeb page = virt_to_head_page(data);
756c92544dSBjoern A. Zeeb skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
766c92544dSBjoern A. Zeeb page, data - page_address(page),
776c92544dSBjoern A. Zeeb data_len - len, buf_len);
786c92544dSBjoern A. Zeeb get_page(page);
796c92544dSBjoern A. Zeeb }
806c92544dSBjoern A. Zeeb
816c92544dSBjoern A. Zeeb return skb;
826c92544dSBjoern A. Zeeb }
836c92544dSBjoern A. Zeeb
846c92544dSBjoern A. Zeeb static int
mt76s_rx_run_queue(struct mt76_dev * dev,enum mt76_rxq_id qid,struct mt76s_intr * intr)856c92544dSBjoern A. Zeeb mt76s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
866c92544dSBjoern A. Zeeb struct mt76s_intr *intr)
876c92544dSBjoern A. Zeeb {
886c92544dSBjoern A. Zeeb struct mt76_queue *q = &dev->q_rx[qid];
896c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio;
906c92544dSBjoern A. Zeeb int len = 0, err, i;
916c92544dSBjoern A. Zeeb struct page *page;
926c92544dSBjoern A. Zeeb u8 *buf, *end;
936c92544dSBjoern A. Zeeb
946c92544dSBjoern A. Zeeb for (i = 0; i < intr->rx.num[qid]; i++)
956c92544dSBjoern A. Zeeb len += round_up(intr->rx.len[qid][i] + 4, 4);
966c92544dSBjoern A. Zeeb
976c92544dSBjoern A. Zeeb if (!len)
986c92544dSBjoern A. Zeeb return 0;
996c92544dSBjoern A. Zeeb
1006c92544dSBjoern A. Zeeb if (len > sdio->func->cur_blksize)
1016c92544dSBjoern A. Zeeb len = roundup(len, sdio->func->cur_blksize);
1026c92544dSBjoern A. Zeeb
1036c92544dSBjoern A. Zeeb page = __dev_alloc_pages(GFP_KERNEL, get_order(len));
1046c92544dSBjoern A. Zeeb if (!page)
1056c92544dSBjoern A. Zeeb return -ENOMEM;
1066c92544dSBjoern A. Zeeb
1076c92544dSBjoern A. Zeeb buf = page_address(page);
1086c92544dSBjoern A. Zeeb
1096c92544dSBjoern A. Zeeb sdio_claim_host(sdio->func);
1106c92544dSBjoern A. Zeeb err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
1116c92544dSBjoern A. Zeeb sdio_release_host(sdio->func);
1126c92544dSBjoern A. Zeeb
1136c92544dSBjoern A. Zeeb if (err < 0) {
1146c92544dSBjoern A. Zeeb dev_err(dev->dev, "sdio read data failed:%d\n", err);
1156c92544dSBjoern A. Zeeb put_page(page);
1166c92544dSBjoern A. Zeeb return err;
1176c92544dSBjoern A. Zeeb }
1186c92544dSBjoern A. Zeeb
1196c92544dSBjoern A. Zeeb end = buf + len;
1206c92544dSBjoern A. Zeeb i = 0;
1216c92544dSBjoern A. Zeeb
1226c92544dSBjoern A. Zeeb while (i < intr->rx.num[qid] && buf < end) {
1236c92544dSBjoern A. Zeeb int index = (q->head + i) % q->ndesc;
1246c92544dSBjoern A. Zeeb struct mt76_queue_entry *e = &q->entry[index];
1256c92544dSBjoern A. Zeeb __le32 *rxd = (__le32 *)buf;
1266c92544dSBjoern A. Zeeb
1276c92544dSBjoern A. Zeeb /* parse rxd to get the actual packet length */
1286c92544dSBjoern A. Zeeb len = le32_get_bits(rxd[0], GENMASK(15, 0));
1296c92544dSBjoern A. Zeeb
1306c92544dSBjoern A. Zeeb /* Optimized path for TXS */
1316c92544dSBjoern A. Zeeb if (!dev->drv->rx_check || dev->drv->rx_check(dev, buf, len)) {
1326c92544dSBjoern A. Zeeb e->skb = mt76s_build_rx_skb(buf, len,
1336c92544dSBjoern A. Zeeb round_up(len + 4, 4));
1346c92544dSBjoern A. Zeeb if (!e->skb)
1356c92544dSBjoern A. Zeeb break;
1366c92544dSBjoern A. Zeeb
1376c92544dSBjoern A. Zeeb if (q->queued + i + 1 == q->ndesc)
1386c92544dSBjoern A. Zeeb break;
1396c92544dSBjoern A. Zeeb i++;
1406c92544dSBjoern A. Zeeb }
1416c92544dSBjoern A. Zeeb buf += round_up(len + 4, 4);
1426c92544dSBjoern A. Zeeb }
1436c92544dSBjoern A. Zeeb put_page(page);
1446c92544dSBjoern A. Zeeb
1456c92544dSBjoern A. Zeeb spin_lock_bh(&q->lock);
1466c92544dSBjoern A. Zeeb q->head = (q->head + i) % q->ndesc;
1476c92544dSBjoern A. Zeeb q->queued += i;
1486c92544dSBjoern A. Zeeb spin_unlock_bh(&q->lock);
1496c92544dSBjoern A. Zeeb
1506c92544dSBjoern A. Zeeb return i;
1516c92544dSBjoern A. Zeeb }
1526c92544dSBjoern A. Zeeb
mt76s_rx_handler(struct mt76_dev * dev)1536c92544dSBjoern A. Zeeb static int mt76s_rx_handler(struct mt76_dev *dev)
1546c92544dSBjoern A. Zeeb {
1556c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio;
1566c92544dSBjoern A. Zeeb struct mt76s_intr intr;
1576c92544dSBjoern A. Zeeb int nframes = 0, ret;
1586c92544dSBjoern A. Zeeb
1596c92544dSBjoern A. Zeeb ret = sdio->parse_irq(dev, &intr);
1606c92544dSBjoern A. Zeeb if (ret)
1616c92544dSBjoern A. Zeeb return ret;
1626c92544dSBjoern A. Zeeb
1636c92544dSBjoern A. Zeeb trace_dev_irq(dev, intr.isr, 0);
1646c92544dSBjoern A. Zeeb
1656c92544dSBjoern A. Zeeb if (intr.isr & WHIER_RX0_DONE_INT_EN) {
1666c92544dSBjoern A. Zeeb ret = mt76s_rx_run_queue(dev, 0, &intr);
1676c92544dSBjoern A. Zeeb if (ret > 0) {
1686c92544dSBjoern A. Zeeb mt76_worker_schedule(&sdio->net_worker);
1696c92544dSBjoern A. Zeeb nframes += ret;
1706c92544dSBjoern A. Zeeb }
1716c92544dSBjoern A. Zeeb }
1726c92544dSBjoern A. Zeeb
1736c92544dSBjoern A. Zeeb if (intr.isr & WHIER_RX1_DONE_INT_EN) {
1746c92544dSBjoern A. Zeeb ret = mt76s_rx_run_queue(dev, 1, &intr);
1756c92544dSBjoern A. Zeeb if (ret > 0) {
1766c92544dSBjoern A. Zeeb mt76_worker_schedule(&sdio->net_worker);
1776c92544dSBjoern A. Zeeb nframes += ret;
1786c92544dSBjoern A. Zeeb }
1796c92544dSBjoern A. Zeeb }
1806c92544dSBjoern A. Zeeb
1816c92544dSBjoern A. Zeeb nframes += !!mt76s_refill_sched_quota(dev, intr.tx.wtqcr);
1826c92544dSBjoern A. Zeeb
1836c92544dSBjoern A. Zeeb return nframes;
1846c92544dSBjoern A. Zeeb }
1856c92544dSBjoern A. Zeeb
1866c92544dSBjoern A. Zeeb static int
mt76s_tx_pick_quota(struct mt76_sdio * sdio,bool mcu,int buf_sz,int * pse_size,int * ple_size)1876c92544dSBjoern A. Zeeb mt76s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
1886c92544dSBjoern A. Zeeb int *pse_size, int *ple_size)
1896c92544dSBjoern A. Zeeb {
1906c92544dSBjoern A. Zeeb int pse_sz;
1916c92544dSBjoern A. Zeeb
1926c92544dSBjoern A. Zeeb pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit,
1936c92544dSBjoern A. Zeeb sdio->sched.pse_page_size);
1946c92544dSBjoern A. Zeeb
1956c92544dSBjoern A. Zeeb if (mcu && sdio->hw_ver == MT76_CONNAC2_SDIO)
1966c92544dSBjoern A. Zeeb pse_sz = 1;
1976c92544dSBjoern A. Zeeb
1986c92544dSBjoern A. Zeeb if (mcu) {
1996c92544dSBjoern A. Zeeb if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
2006c92544dSBjoern A. Zeeb return -EBUSY;
2016c92544dSBjoern A. Zeeb } else {
2026c92544dSBjoern A. Zeeb if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
2036c92544dSBjoern A. Zeeb sdio->sched.ple_data_quota < *ple_size + 1)
2046c92544dSBjoern A. Zeeb return -EBUSY;
2056c92544dSBjoern A. Zeeb
2066c92544dSBjoern A. Zeeb *ple_size = *ple_size + 1;
2076c92544dSBjoern A. Zeeb }
2086c92544dSBjoern A. Zeeb *pse_size = *pse_size + pse_sz;
2096c92544dSBjoern A. Zeeb
2106c92544dSBjoern A. Zeeb return 0;
2116c92544dSBjoern A. Zeeb }
2126c92544dSBjoern A. Zeeb
2136c92544dSBjoern A. Zeeb static void
mt76s_tx_update_quota(struct mt76_sdio * sdio,bool mcu,int pse_size,int ple_size)2146c92544dSBjoern A. Zeeb mt76s_tx_update_quota(struct mt76_sdio *sdio, bool mcu, int pse_size,
2156c92544dSBjoern A. Zeeb int ple_size)
2166c92544dSBjoern A. Zeeb {
2176c92544dSBjoern A. Zeeb if (mcu) {
2186c92544dSBjoern A. Zeeb sdio->sched.pse_mcu_quota -= pse_size;
2196c92544dSBjoern A. Zeeb } else {
2206c92544dSBjoern A. Zeeb sdio->sched.pse_data_quota -= pse_size;
2216c92544dSBjoern A. Zeeb sdio->sched.ple_data_quota -= ple_size;
2226c92544dSBjoern A. Zeeb }
2236c92544dSBjoern A. Zeeb }
2246c92544dSBjoern A. Zeeb
__mt76s_xmit_queue(struct mt76_dev * dev,u8 * data,int len)2256c92544dSBjoern A. Zeeb static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
2266c92544dSBjoern A. Zeeb {
2276c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio;
2286c92544dSBjoern A. Zeeb int err;
2296c92544dSBjoern A. Zeeb
2306c92544dSBjoern A. Zeeb if (len > sdio->func->cur_blksize)
2316c92544dSBjoern A. Zeeb len = roundup(len, sdio->func->cur_blksize);
2326c92544dSBjoern A. Zeeb
2336c92544dSBjoern A. Zeeb sdio_claim_host(sdio->func);
2346c92544dSBjoern A. Zeeb err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
2356c92544dSBjoern A. Zeeb sdio_release_host(sdio->func);
2366c92544dSBjoern A. Zeeb
2376c92544dSBjoern A. Zeeb if (err)
2386c92544dSBjoern A. Zeeb dev_err(dev->dev, "sdio write failed: %d\n", err);
2396c92544dSBjoern A. Zeeb
2406c92544dSBjoern A. Zeeb return err;
2416c92544dSBjoern A. Zeeb }
2426c92544dSBjoern A. Zeeb
mt76s_tx_run_queue(struct mt76_dev * dev,struct mt76_queue * q)2436c92544dSBjoern A. Zeeb static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
2446c92544dSBjoern A. Zeeb {
2456c92544dSBjoern A. Zeeb int err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
2466c92544dSBjoern A. Zeeb bool mcu = q == dev->q_mcu[MT_MCUQ_WM];
2476c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio;
2486c92544dSBjoern A. Zeeb u8 pad;
2496c92544dSBjoern A. Zeeb
2506c92544dSBjoern A. Zeeb while (q->first != q->head) {
2516c92544dSBjoern A. Zeeb struct mt76_queue_entry *e = &q->entry[q->first];
2526c92544dSBjoern A. Zeeb struct sk_buff *iter;
2536c92544dSBjoern A. Zeeb
2546c92544dSBjoern A. Zeeb smp_rmb();
2556c92544dSBjoern A. Zeeb
2566c92544dSBjoern A. Zeeb if (test_bit(MT76_MCU_RESET, &dev->phy.state))
2576c92544dSBjoern A. Zeeb goto next;
2586c92544dSBjoern A. Zeeb
2596c92544dSBjoern A. Zeeb if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
2606c92544dSBjoern A. Zeeb __skb_put_zero(e->skb, 4);
261cbb3ec25SBjoern A. Zeeb err = __skb_grow(e->skb, roundup(e->skb->len,
262cbb3ec25SBjoern A. Zeeb sdio->func->cur_blksize));
263cbb3ec25SBjoern A. Zeeb if (err)
264cbb3ec25SBjoern A. Zeeb return err;
2656c92544dSBjoern A. Zeeb err = __mt76s_xmit_queue(dev, e->skb->data,
2666c92544dSBjoern A. Zeeb e->skb->len);
2676c92544dSBjoern A. Zeeb if (err)
2686c92544dSBjoern A. Zeeb return err;
2696c92544dSBjoern A. Zeeb
2706c92544dSBjoern A. Zeeb goto next;
2716c92544dSBjoern A. Zeeb }
2726c92544dSBjoern A. Zeeb
2736c92544dSBjoern A. Zeeb pad = roundup(e->skb->len, 4) - e->skb->len;
2746c92544dSBjoern A. Zeeb if (len + e->skb->len + pad + 4 > dev->sdio.xmit_buf_sz)
2756c92544dSBjoern A. Zeeb break;
2766c92544dSBjoern A. Zeeb
2776c92544dSBjoern A. Zeeb if (mt76s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
2786c92544dSBjoern A. Zeeb &ple_sz))
2796c92544dSBjoern A. Zeeb break;
2806c92544dSBjoern A. Zeeb
2816c92544dSBjoern A. Zeeb memcpy(sdio->xmit_buf + len, e->skb->data, skb_headlen(e->skb));
2826c92544dSBjoern A. Zeeb len += skb_headlen(e->skb);
2836c92544dSBjoern A. Zeeb nframes++;
2846c92544dSBjoern A. Zeeb
2856c92544dSBjoern A. Zeeb skb_walk_frags(e->skb, iter) {
2866c92544dSBjoern A. Zeeb memcpy(sdio->xmit_buf + len, iter->data, iter->len);
2876c92544dSBjoern A. Zeeb len += iter->len;
2886c92544dSBjoern A. Zeeb nframes++;
2896c92544dSBjoern A. Zeeb }
2906c92544dSBjoern A. Zeeb
2916c92544dSBjoern A. Zeeb if (unlikely(pad)) {
2926c92544dSBjoern A. Zeeb memset(sdio->xmit_buf + len, 0, pad);
2936c92544dSBjoern A. Zeeb len += pad;
2946c92544dSBjoern A. Zeeb }
2956c92544dSBjoern A. Zeeb next:
2966c92544dSBjoern A. Zeeb q->first = (q->first + 1) % q->ndesc;
2976c92544dSBjoern A. Zeeb e->done = true;
2986c92544dSBjoern A. Zeeb }
2996c92544dSBjoern A. Zeeb
3006c92544dSBjoern A. Zeeb if (nframes) {
3016c92544dSBjoern A. Zeeb memset(sdio->xmit_buf + len, 0, 4);
3026c92544dSBjoern A. Zeeb err = __mt76s_xmit_queue(dev, sdio->xmit_buf, len + 4);
3036c92544dSBjoern A. Zeeb if (err)
3046c92544dSBjoern A. Zeeb return err;
3056c92544dSBjoern A. Zeeb }
3066c92544dSBjoern A. Zeeb mt76s_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
3076c92544dSBjoern A. Zeeb
3086c92544dSBjoern A. Zeeb mt76_worker_schedule(&sdio->status_worker);
3096c92544dSBjoern A. Zeeb
3106c92544dSBjoern A. Zeeb return nframes;
3116c92544dSBjoern A. Zeeb }
3126c92544dSBjoern A. Zeeb
mt76s_txrx_worker(struct mt76_sdio * sdio)3136c92544dSBjoern A. Zeeb void mt76s_txrx_worker(struct mt76_sdio *sdio)
3146c92544dSBjoern A. Zeeb {
3156c92544dSBjoern A. Zeeb struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
3166c92544dSBjoern A. Zeeb int i, nframes, ret;
3176c92544dSBjoern A. Zeeb
3186c92544dSBjoern A. Zeeb /* disable interrupt */
3196c92544dSBjoern A. Zeeb sdio_claim_host(sdio->func);
3206c92544dSBjoern A. Zeeb sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
3216c92544dSBjoern A. Zeeb sdio_release_host(sdio->func);
3226c92544dSBjoern A. Zeeb
3236c92544dSBjoern A. Zeeb do {
3246c92544dSBjoern A. Zeeb nframes = 0;
3256c92544dSBjoern A. Zeeb
3266c92544dSBjoern A. Zeeb /* tx */
3276c92544dSBjoern A. Zeeb for (i = 0; i <= MT_TXQ_PSD; i++) {
3286c92544dSBjoern A. Zeeb ret = mt76s_tx_run_queue(dev, dev->phy.q_tx[i]);
3296c92544dSBjoern A. Zeeb if (ret > 0)
3306c92544dSBjoern A. Zeeb nframes += ret;
3316c92544dSBjoern A. Zeeb }
3326c92544dSBjoern A. Zeeb ret = mt76s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
3336c92544dSBjoern A. Zeeb if (ret > 0)
3346c92544dSBjoern A. Zeeb nframes += ret;
3356c92544dSBjoern A. Zeeb
3366c92544dSBjoern A. Zeeb /* rx */
3376c92544dSBjoern A. Zeeb ret = mt76s_rx_handler(dev);
3386c92544dSBjoern A. Zeeb if (ret > 0)
3396c92544dSBjoern A. Zeeb nframes += ret;
3406c92544dSBjoern A. Zeeb
3416c92544dSBjoern A. Zeeb if (test_bit(MT76_MCU_RESET, &dev->phy.state) ||
3426c92544dSBjoern A. Zeeb test_bit(MT76_STATE_SUSPEND, &dev->phy.state)) {
3436c92544dSBjoern A. Zeeb if (!mt76s_txqs_empty(dev))
3446c92544dSBjoern A. Zeeb continue;
3456c92544dSBjoern A. Zeeb else
3466c92544dSBjoern A. Zeeb wake_up(&sdio->wait);
3476c92544dSBjoern A. Zeeb }
3486c92544dSBjoern A. Zeeb } while (nframes > 0);
3496c92544dSBjoern A. Zeeb
3506c92544dSBjoern A. Zeeb /* enable interrupt */
3516c92544dSBjoern A. Zeeb sdio_claim_host(sdio->func);
3526c92544dSBjoern A. Zeeb sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
3536c92544dSBjoern A. Zeeb sdio_release_host(sdio->func);
3546c92544dSBjoern A. Zeeb }
3556c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76s_txrx_worker);
3566c92544dSBjoern A. Zeeb
mt76s_sdio_irq(struct sdio_func * func)3576c92544dSBjoern A. Zeeb void mt76s_sdio_irq(struct sdio_func *func)
3586c92544dSBjoern A. Zeeb {
3596c92544dSBjoern A. Zeeb struct mt76_dev *dev = sdio_get_drvdata(func);
3606c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio;
3616c92544dSBjoern A. Zeeb
3626c92544dSBjoern A. Zeeb if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state) ||
3636c92544dSBjoern A. Zeeb test_bit(MT76_MCU_RESET, &dev->phy.state))
3646c92544dSBjoern A. Zeeb return;
3656c92544dSBjoern A. Zeeb
3666c92544dSBjoern A. Zeeb sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
3676c92544dSBjoern A. Zeeb mt76_worker_schedule(&sdio->txrx_worker);
3686c92544dSBjoern A. Zeeb }
3696c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76s_sdio_irq);
3706c92544dSBjoern A. Zeeb
mt76s_txqs_empty(struct mt76_dev * dev)3716c92544dSBjoern A. Zeeb bool mt76s_txqs_empty(struct mt76_dev *dev)
3726c92544dSBjoern A. Zeeb {
3736c92544dSBjoern A. Zeeb struct mt76_queue *q;
3746c92544dSBjoern A. Zeeb int i;
3756c92544dSBjoern A. Zeeb
3766c92544dSBjoern A. Zeeb for (i = 0; i <= MT_TXQ_PSD + 1; i++) {
3776c92544dSBjoern A. Zeeb if (i <= MT_TXQ_PSD)
3786c92544dSBjoern A. Zeeb q = dev->phy.q_tx[i];
3796c92544dSBjoern A. Zeeb else
3806c92544dSBjoern A. Zeeb q = dev->q_mcu[MT_MCUQ_WM];
3816c92544dSBjoern A. Zeeb
3826c92544dSBjoern A. Zeeb if (q->first != q->head)
3836c92544dSBjoern A. Zeeb return false;
3846c92544dSBjoern A. Zeeb }
3856c92544dSBjoern A. Zeeb
3866c92544dSBjoern A. Zeeb return true;
3876c92544dSBjoern A. Zeeb }
3886c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76s_txqs_empty);
389