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 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; 496c92544dSBjoern A. Zeeb sdio->sched.pse_data_quota += pse_data_quota; 506c92544dSBjoern A. Zeeb sdio->sched.ple_data_quota += ple_data_quota; 516c92544dSBjoern A. Zeeb 526c92544dSBjoern A. Zeeb return pse_data_quota + ple_data_quota + pse_mcu_quota; 536c92544dSBjoern A. Zeeb } 546c92544dSBjoern A. Zeeb 556c92544dSBjoern A. Zeeb static struct sk_buff * 566c92544dSBjoern A. Zeeb mt76s_build_rx_skb(void *data, int data_len, int buf_len) 576c92544dSBjoern A. Zeeb { 586c92544dSBjoern A. Zeeb int len = min_t(int, data_len, MT_SKB_HEAD_LEN); 596c92544dSBjoern A. Zeeb struct sk_buff *skb; 606c92544dSBjoern A. Zeeb 616c92544dSBjoern A. Zeeb skb = alloc_skb(len, GFP_KERNEL); 626c92544dSBjoern A. Zeeb if (!skb) 636c92544dSBjoern A. Zeeb return NULL; 646c92544dSBjoern A. Zeeb 656c92544dSBjoern A. Zeeb skb_put_data(skb, data, len); 666c92544dSBjoern A. Zeeb if (data_len > len) { 676c92544dSBjoern A. Zeeb struct page *page; 686c92544dSBjoern A. Zeeb 696c92544dSBjoern A. Zeeb data += len; 706c92544dSBjoern A. Zeeb page = virt_to_head_page(data); 716c92544dSBjoern A. Zeeb skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, 726c92544dSBjoern A. Zeeb page, data - page_address(page), 736c92544dSBjoern A. Zeeb data_len - len, buf_len); 746c92544dSBjoern A. Zeeb get_page(page); 756c92544dSBjoern A. Zeeb } 766c92544dSBjoern A. Zeeb 776c92544dSBjoern A. Zeeb return skb; 786c92544dSBjoern A. Zeeb } 796c92544dSBjoern A. Zeeb 806c92544dSBjoern A. Zeeb static int 816c92544dSBjoern A. Zeeb mt76s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid, 826c92544dSBjoern A. Zeeb struct mt76s_intr *intr) 836c92544dSBjoern A. Zeeb { 846c92544dSBjoern A. Zeeb struct mt76_queue *q = &dev->q_rx[qid]; 856c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio; 866c92544dSBjoern A. Zeeb int len = 0, err, i; 876c92544dSBjoern A. Zeeb struct page *page; 886c92544dSBjoern A. Zeeb u8 *buf, *end; 896c92544dSBjoern A. Zeeb 906c92544dSBjoern A. Zeeb for (i = 0; i < intr->rx.num[qid]; i++) 916c92544dSBjoern A. Zeeb len += round_up(intr->rx.len[qid][i] + 4, 4); 926c92544dSBjoern A. Zeeb 936c92544dSBjoern A. Zeeb if (!len) 946c92544dSBjoern A. Zeeb return 0; 956c92544dSBjoern A. Zeeb 966c92544dSBjoern A. Zeeb if (len > sdio->func->cur_blksize) 976c92544dSBjoern A. Zeeb len = roundup(len, sdio->func->cur_blksize); 986c92544dSBjoern A. Zeeb 996c92544dSBjoern A. Zeeb page = __dev_alloc_pages(GFP_KERNEL, get_order(len)); 1006c92544dSBjoern A. Zeeb if (!page) 1016c92544dSBjoern A. Zeeb return -ENOMEM; 1026c92544dSBjoern A. Zeeb 1036c92544dSBjoern A. Zeeb buf = page_address(page); 1046c92544dSBjoern A. Zeeb 1056c92544dSBjoern A. Zeeb sdio_claim_host(sdio->func); 1066c92544dSBjoern A. Zeeb err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len); 1076c92544dSBjoern A. Zeeb sdio_release_host(sdio->func); 1086c92544dSBjoern A. Zeeb 1096c92544dSBjoern A. Zeeb if (err < 0) { 1106c92544dSBjoern A. Zeeb dev_err(dev->dev, "sdio read data failed:%d\n", err); 1116c92544dSBjoern A. Zeeb put_page(page); 1126c92544dSBjoern A. Zeeb return err; 1136c92544dSBjoern A. Zeeb } 1146c92544dSBjoern A. Zeeb 1156c92544dSBjoern A. Zeeb end = buf + len; 1166c92544dSBjoern A. Zeeb i = 0; 1176c92544dSBjoern A. Zeeb 1186c92544dSBjoern A. Zeeb while (i < intr->rx.num[qid] && buf < end) { 1196c92544dSBjoern A. Zeeb int index = (q->head + i) % q->ndesc; 1206c92544dSBjoern A. Zeeb struct mt76_queue_entry *e = &q->entry[index]; 1216c92544dSBjoern A. Zeeb __le32 *rxd = (__le32 *)buf; 1226c92544dSBjoern A. Zeeb 1236c92544dSBjoern A. Zeeb /* parse rxd to get the actual packet length */ 1246c92544dSBjoern A. Zeeb len = le32_get_bits(rxd[0], GENMASK(15, 0)); 1256c92544dSBjoern A. Zeeb 1266c92544dSBjoern A. Zeeb /* Optimized path for TXS */ 1276c92544dSBjoern A. Zeeb if (!dev->drv->rx_check || dev->drv->rx_check(dev, buf, len)) { 1286c92544dSBjoern A. Zeeb e->skb = mt76s_build_rx_skb(buf, len, 1296c92544dSBjoern A. Zeeb round_up(len + 4, 4)); 1306c92544dSBjoern A. Zeeb if (!e->skb) 1316c92544dSBjoern A. Zeeb break; 1326c92544dSBjoern A. Zeeb 1336c92544dSBjoern A. Zeeb if (q->queued + i + 1 == q->ndesc) 1346c92544dSBjoern A. Zeeb break; 1356c92544dSBjoern A. Zeeb i++; 1366c92544dSBjoern A. Zeeb } 1376c92544dSBjoern A. Zeeb buf += round_up(len + 4, 4); 1386c92544dSBjoern A. Zeeb } 1396c92544dSBjoern A. Zeeb put_page(page); 1406c92544dSBjoern A. Zeeb 1416c92544dSBjoern A. Zeeb spin_lock_bh(&q->lock); 1426c92544dSBjoern A. Zeeb q->head = (q->head + i) % q->ndesc; 1436c92544dSBjoern A. Zeeb q->queued += i; 1446c92544dSBjoern A. Zeeb spin_unlock_bh(&q->lock); 1456c92544dSBjoern A. Zeeb 1466c92544dSBjoern A. Zeeb return i; 1476c92544dSBjoern A. Zeeb } 1486c92544dSBjoern A. Zeeb 1496c92544dSBjoern A. Zeeb static int mt76s_rx_handler(struct mt76_dev *dev) 1506c92544dSBjoern A. Zeeb { 1516c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio; 1526c92544dSBjoern A. Zeeb struct mt76s_intr intr; 1536c92544dSBjoern A. Zeeb int nframes = 0, ret; 1546c92544dSBjoern A. Zeeb 1556c92544dSBjoern A. Zeeb ret = sdio->parse_irq(dev, &intr); 1566c92544dSBjoern A. Zeeb if (ret) 1576c92544dSBjoern A. Zeeb return ret; 1586c92544dSBjoern A. Zeeb 1596c92544dSBjoern A. Zeeb trace_dev_irq(dev, intr.isr, 0); 1606c92544dSBjoern A. Zeeb 1616c92544dSBjoern A. Zeeb if (intr.isr & WHIER_RX0_DONE_INT_EN) { 1626c92544dSBjoern A. Zeeb ret = mt76s_rx_run_queue(dev, 0, &intr); 1636c92544dSBjoern A. Zeeb if (ret > 0) { 1646c92544dSBjoern A. Zeeb mt76_worker_schedule(&sdio->net_worker); 1656c92544dSBjoern A. Zeeb nframes += ret; 1666c92544dSBjoern A. Zeeb } 1676c92544dSBjoern A. Zeeb } 1686c92544dSBjoern A. Zeeb 1696c92544dSBjoern A. Zeeb if (intr.isr & WHIER_RX1_DONE_INT_EN) { 1706c92544dSBjoern A. Zeeb ret = mt76s_rx_run_queue(dev, 1, &intr); 1716c92544dSBjoern A. Zeeb if (ret > 0) { 1726c92544dSBjoern A. Zeeb mt76_worker_schedule(&sdio->net_worker); 1736c92544dSBjoern A. Zeeb nframes += ret; 1746c92544dSBjoern A. Zeeb } 1756c92544dSBjoern A. Zeeb } 1766c92544dSBjoern A. Zeeb 1776c92544dSBjoern A. Zeeb nframes += !!mt76s_refill_sched_quota(dev, intr.tx.wtqcr); 1786c92544dSBjoern A. Zeeb 1796c92544dSBjoern A. Zeeb return nframes; 1806c92544dSBjoern A. Zeeb } 1816c92544dSBjoern A. Zeeb 1826c92544dSBjoern A. Zeeb static int 1836c92544dSBjoern A. Zeeb mt76s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz, 1846c92544dSBjoern A. Zeeb int *pse_size, int *ple_size) 1856c92544dSBjoern A. Zeeb { 1866c92544dSBjoern A. Zeeb int pse_sz; 1876c92544dSBjoern A. Zeeb 1886c92544dSBjoern A. Zeeb pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, 1896c92544dSBjoern A. Zeeb sdio->sched.pse_page_size); 1906c92544dSBjoern A. Zeeb 1916c92544dSBjoern A. Zeeb if (mcu && sdio->hw_ver == MT76_CONNAC2_SDIO) 1926c92544dSBjoern A. Zeeb pse_sz = 1; 1936c92544dSBjoern A. Zeeb 1946c92544dSBjoern A. Zeeb if (mcu) { 1956c92544dSBjoern A. Zeeb if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz) 1966c92544dSBjoern A. Zeeb return -EBUSY; 1976c92544dSBjoern A. Zeeb } else { 1986c92544dSBjoern A. Zeeb if (sdio->sched.pse_data_quota < *pse_size + pse_sz || 1996c92544dSBjoern A. Zeeb sdio->sched.ple_data_quota < *ple_size + 1) 2006c92544dSBjoern A. Zeeb return -EBUSY; 2016c92544dSBjoern A. Zeeb 2026c92544dSBjoern A. Zeeb *ple_size = *ple_size + 1; 2036c92544dSBjoern A. Zeeb } 2046c92544dSBjoern A. Zeeb *pse_size = *pse_size + pse_sz; 2056c92544dSBjoern A. Zeeb 2066c92544dSBjoern A. Zeeb return 0; 2076c92544dSBjoern A. Zeeb } 2086c92544dSBjoern A. Zeeb 2096c92544dSBjoern A. Zeeb static void 2106c92544dSBjoern A. Zeeb mt76s_tx_update_quota(struct mt76_sdio *sdio, bool mcu, int pse_size, 2116c92544dSBjoern A. Zeeb int ple_size) 2126c92544dSBjoern A. Zeeb { 2136c92544dSBjoern A. Zeeb if (mcu) { 2146c92544dSBjoern A. Zeeb sdio->sched.pse_mcu_quota -= pse_size; 2156c92544dSBjoern A. Zeeb } else { 2166c92544dSBjoern A. Zeeb sdio->sched.pse_data_quota -= pse_size; 2176c92544dSBjoern A. Zeeb sdio->sched.ple_data_quota -= ple_size; 2186c92544dSBjoern A. Zeeb } 2196c92544dSBjoern A. Zeeb } 2206c92544dSBjoern A. Zeeb 2216c92544dSBjoern A. Zeeb static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len) 2226c92544dSBjoern A. Zeeb { 2236c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio; 2246c92544dSBjoern A. Zeeb int err; 2256c92544dSBjoern A. Zeeb 2266c92544dSBjoern A. Zeeb if (len > sdio->func->cur_blksize) 2276c92544dSBjoern A. Zeeb len = roundup(len, sdio->func->cur_blksize); 2286c92544dSBjoern A. Zeeb 2296c92544dSBjoern A. Zeeb sdio_claim_host(sdio->func); 2306c92544dSBjoern A. Zeeb err = sdio_writesb(sdio->func, MCR_WTDR1, data, len); 2316c92544dSBjoern A. Zeeb sdio_release_host(sdio->func); 2326c92544dSBjoern A. Zeeb 2336c92544dSBjoern A. Zeeb if (err) 2346c92544dSBjoern A. Zeeb dev_err(dev->dev, "sdio write failed: %d\n", err); 2356c92544dSBjoern A. Zeeb 2366c92544dSBjoern A. Zeeb return err; 2376c92544dSBjoern A. Zeeb } 2386c92544dSBjoern A. Zeeb 2396c92544dSBjoern A. Zeeb static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q) 2406c92544dSBjoern A. Zeeb { 2416c92544dSBjoern A. Zeeb int err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0; 2426c92544dSBjoern A. Zeeb bool mcu = q == dev->q_mcu[MT_MCUQ_WM]; 2436c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio; 2446c92544dSBjoern A. Zeeb u8 pad; 2456c92544dSBjoern A. Zeeb 2466c92544dSBjoern A. Zeeb while (q->first != q->head) { 2476c92544dSBjoern A. Zeeb struct mt76_queue_entry *e = &q->entry[q->first]; 2486c92544dSBjoern A. Zeeb struct sk_buff *iter; 2496c92544dSBjoern A. Zeeb 2506c92544dSBjoern A. Zeeb smp_rmb(); 2516c92544dSBjoern A. Zeeb 2526c92544dSBjoern A. Zeeb if (test_bit(MT76_MCU_RESET, &dev->phy.state)) 2536c92544dSBjoern A. Zeeb goto next; 2546c92544dSBjoern A. Zeeb 2556c92544dSBjoern A. Zeeb if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) { 2566c92544dSBjoern A. Zeeb __skb_put_zero(e->skb, 4); 257*cbb3ec25SBjoern A. Zeeb err = __skb_grow(e->skb, roundup(e->skb->len, 258*cbb3ec25SBjoern A. Zeeb sdio->func->cur_blksize)); 259*cbb3ec25SBjoern A. Zeeb if (err) 260*cbb3ec25SBjoern A. Zeeb return err; 2616c92544dSBjoern A. Zeeb err = __mt76s_xmit_queue(dev, e->skb->data, 2626c92544dSBjoern A. Zeeb e->skb->len); 2636c92544dSBjoern A. Zeeb if (err) 2646c92544dSBjoern A. Zeeb return err; 2656c92544dSBjoern A. Zeeb 2666c92544dSBjoern A. Zeeb goto next; 2676c92544dSBjoern A. Zeeb } 2686c92544dSBjoern A. Zeeb 2696c92544dSBjoern A. Zeeb pad = roundup(e->skb->len, 4) - e->skb->len; 2706c92544dSBjoern A. Zeeb if (len + e->skb->len + pad + 4 > dev->sdio.xmit_buf_sz) 2716c92544dSBjoern A. Zeeb break; 2726c92544dSBjoern A. Zeeb 2736c92544dSBjoern A. Zeeb if (mt76s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz, 2746c92544dSBjoern A. Zeeb &ple_sz)) 2756c92544dSBjoern A. Zeeb break; 2766c92544dSBjoern A. Zeeb 2776c92544dSBjoern A. Zeeb memcpy(sdio->xmit_buf + len, e->skb->data, skb_headlen(e->skb)); 2786c92544dSBjoern A. Zeeb len += skb_headlen(e->skb); 2796c92544dSBjoern A. Zeeb nframes++; 2806c92544dSBjoern A. Zeeb 2816c92544dSBjoern A. Zeeb skb_walk_frags(e->skb, iter) { 2826c92544dSBjoern A. Zeeb memcpy(sdio->xmit_buf + len, iter->data, iter->len); 2836c92544dSBjoern A. Zeeb len += iter->len; 2846c92544dSBjoern A. Zeeb nframes++; 2856c92544dSBjoern A. Zeeb } 2866c92544dSBjoern A. Zeeb 2876c92544dSBjoern A. Zeeb if (unlikely(pad)) { 2886c92544dSBjoern A. Zeeb memset(sdio->xmit_buf + len, 0, pad); 2896c92544dSBjoern A. Zeeb len += pad; 2906c92544dSBjoern A. Zeeb } 2916c92544dSBjoern A. Zeeb next: 2926c92544dSBjoern A. Zeeb q->first = (q->first + 1) % q->ndesc; 2936c92544dSBjoern A. Zeeb e->done = true; 2946c92544dSBjoern A. Zeeb } 2956c92544dSBjoern A. Zeeb 2966c92544dSBjoern A. Zeeb if (nframes) { 2976c92544dSBjoern A. Zeeb memset(sdio->xmit_buf + len, 0, 4); 2986c92544dSBjoern A. Zeeb err = __mt76s_xmit_queue(dev, sdio->xmit_buf, len + 4); 2996c92544dSBjoern A. Zeeb if (err) 3006c92544dSBjoern A. Zeeb return err; 3016c92544dSBjoern A. Zeeb } 3026c92544dSBjoern A. Zeeb mt76s_tx_update_quota(sdio, mcu, pse_sz, ple_sz); 3036c92544dSBjoern A. Zeeb 3046c92544dSBjoern A. Zeeb mt76_worker_schedule(&sdio->status_worker); 3056c92544dSBjoern A. Zeeb 3066c92544dSBjoern A. Zeeb return nframes; 3076c92544dSBjoern A. Zeeb } 3086c92544dSBjoern A. Zeeb 3096c92544dSBjoern A. Zeeb void mt76s_txrx_worker(struct mt76_sdio *sdio) 3106c92544dSBjoern A. Zeeb { 3116c92544dSBjoern A. Zeeb struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); 3126c92544dSBjoern A. Zeeb int i, nframes, ret; 3136c92544dSBjoern A. Zeeb 3146c92544dSBjoern A. Zeeb /* disable interrupt */ 3156c92544dSBjoern A. Zeeb sdio_claim_host(sdio->func); 3166c92544dSBjoern A. Zeeb sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); 3176c92544dSBjoern A. Zeeb sdio_release_host(sdio->func); 3186c92544dSBjoern A. Zeeb 3196c92544dSBjoern A. Zeeb do { 3206c92544dSBjoern A. Zeeb nframes = 0; 3216c92544dSBjoern A. Zeeb 3226c92544dSBjoern A. Zeeb /* tx */ 3236c92544dSBjoern A. Zeeb for (i = 0; i <= MT_TXQ_PSD; i++) { 3246c92544dSBjoern A. Zeeb ret = mt76s_tx_run_queue(dev, dev->phy.q_tx[i]); 3256c92544dSBjoern A. Zeeb if (ret > 0) 3266c92544dSBjoern A. Zeeb nframes += ret; 3276c92544dSBjoern A. Zeeb } 3286c92544dSBjoern A. Zeeb ret = mt76s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]); 3296c92544dSBjoern A. Zeeb if (ret > 0) 3306c92544dSBjoern A. Zeeb nframes += ret; 3316c92544dSBjoern A. Zeeb 3326c92544dSBjoern A. Zeeb /* rx */ 3336c92544dSBjoern A. Zeeb ret = mt76s_rx_handler(dev); 3346c92544dSBjoern A. Zeeb if (ret > 0) 3356c92544dSBjoern A. Zeeb nframes += ret; 3366c92544dSBjoern A. Zeeb 3376c92544dSBjoern A. Zeeb if (test_bit(MT76_MCU_RESET, &dev->phy.state) || 3386c92544dSBjoern A. Zeeb test_bit(MT76_STATE_SUSPEND, &dev->phy.state)) { 3396c92544dSBjoern A. Zeeb if (!mt76s_txqs_empty(dev)) 3406c92544dSBjoern A. Zeeb continue; 3416c92544dSBjoern A. Zeeb else 3426c92544dSBjoern A. Zeeb wake_up(&sdio->wait); 3436c92544dSBjoern A. Zeeb } 3446c92544dSBjoern A. Zeeb } while (nframes > 0); 3456c92544dSBjoern A. Zeeb 3466c92544dSBjoern A. Zeeb /* enable interrupt */ 3476c92544dSBjoern A. Zeeb sdio_claim_host(sdio->func); 3486c92544dSBjoern A. Zeeb sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL); 3496c92544dSBjoern A. Zeeb sdio_release_host(sdio->func); 3506c92544dSBjoern A. Zeeb } 3516c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76s_txrx_worker); 3526c92544dSBjoern A. Zeeb 3536c92544dSBjoern A. Zeeb void mt76s_sdio_irq(struct sdio_func *func) 3546c92544dSBjoern A. Zeeb { 3556c92544dSBjoern A. Zeeb struct mt76_dev *dev = sdio_get_drvdata(func); 3566c92544dSBjoern A. Zeeb struct mt76_sdio *sdio = &dev->sdio; 3576c92544dSBjoern A. Zeeb 3586c92544dSBjoern A. Zeeb if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state) || 3596c92544dSBjoern A. Zeeb test_bit(MT76_MCU_RESET, &dev->phy.state)) 3606c92544dSBjoern A. Zeeb return; 3616c92544dSBjoern A. Zeeb 3626c92544dSBjoern A. Zeeb sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); 3636c92544dSBjoern A. Zeeb mt76_worker_schedule(&sdio->txrx_worker); 3646c92544dSBjoern A. Zeeb } 3656c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76s_sdio_irq); 3666c92544dSBjoern A. Zeeb 3676c92544dSBjoern A. Zeeb bool mt76s_txqs_empty(struct mt76_dev *dev) 3686c92544dSBjoern A. Zeeb { 3696c92544dSBjoern A. Zeeb struct mt76_queue *q; 3706c92544dSBjoern A. Zeeb int i; 3716c92544dSBjoern A. Zeeb 3726c92544dSBjoern A. Zeeb for (i = 0; i <= MT_TXQ_PSD + 1; i++) { 3736c92544dSBjoern A. Zeeb if (i <= MT_TXQ_PSD) 3746c92544dSBjoern A. Zeeb q = dev->phy.q_tx[i]; 3756c92544dSBjoern A. Zeeb else 3766c92544dSBjoern A. Zeeb q = dev->q_mcu[MT_MCUQ_WM]; 3776c92544dSBjoern A. Zeeb 3786c92544dSBjoern A. Zeeb if (q->first != q->head) 3796c92544dSBjoern A. Zeeb return false; 3806c92544dSBjoern A. Zeeb } 3816c92544dSBjoern A. Zeeb 3826c92544dSBjoern A. Zeeb return true; 3836c92544dSBjoern A. Zeeb } 3846c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76s_txqs_empty); 385