aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c142
1 files changed, 66 insertions, 76 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
index 2486cda3243b..13d77f8fca86 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
@@ -46,11 +46,9 @@ static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
return 0;
- mutex_lock(&sdio->sched.lock);
sdio->sched.pse_mcu_quota += pse_mcu_quota;
sdio->sched.pse_data_quota += pse_data_quota;
sdio->sched.ple_data_quota += ple_data_quota;
- mutex_unlock(&sdio->sched.lock);
return pse_data_quota + ple_data_quota + pse_mcu_quota;
}
@@ -105,10 +103,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
buf = page_address(page);
- sdio_claim_host(sdio->func);
err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
- sdio_release_host(sdio->func);
-
if (err < 0) {
dev_err(dev->dev, "sdio read data failed:%d\n", err);
__free_pages(page, order);
@@ -138,19 +133,52 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
return i;
}
-static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
- int buf_sz, int *pse_size, int *ple_size)
+static int mt7663s_rx_handler(struct mt76_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+ struct mt76s_intr *intr = sdio->intr_data;
+ int nframes = 0, ret;
+
+ ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
+ if (ret < 0)
+ return ret;
+
+ trace_dev_irq(dev, intr->isr, 0);
+
+ if (intr->isr & WHIER_RX0_DONE_INT_EN) {
+ ret = mt7663s_rx_run_queue(dev, 0, intr);
+ if (ret > 0) {
+ mt76_worker_schedule(&sdio->net_worker);
+ nframes += ret;
+ }
+ }
+
+ if (intr->isr & WHIER_RX1_DONE_INT_EN) {
+ ret = mt7663s_rx_run_queue(dev, 1, intr);
+ if (ret > 0) {
+ mt76_worker_schedule(&sdio->net_worker);
+ nframes += ret;
+ }
+ }
+
+ nframes += !!mt7663s_refill_sched_quota(dev, intr->tx.wtqcr);
+
+ return nframes;
+}
+
+static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
+ int *pse_size, int *ple_size)
{
int pse_sz;
pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
- if (qid == MT_TXQ_MCU) {
+ if (mcu) {
if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
return -EBUSY;
} else {
if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
- sdio->sched.ple_data_quota < *ple_size)
+ sdio->sched.ple_data_quota < *ple_size + 1)
return -EBUSY;
*ple_size = *ple_size + 1;
@@ -160,17 +188,15 @@ static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
return 0;
}
-static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
+static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
int pse_size, int ple_size)
{
- mutex_lock(&sdio->sched.lock);
- if (qid == MT_TXQ_MCU) {
+ if (mcu) {
sdio->sched.pse_mcu_quota -= pse_size;
} else {
sdio->sched.pse_data_quota -= pse_size;
sdio->sched.ple_data_quota -= ple_size;
}
- mutex_unlock(&sdio->sched.lock);
}
static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
@@ -181,22 +207,20 @@ static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
if (len > sdio->func->cur_blksize)
len = roundup(len, sdio->func->cur_blksize);
- sdio_claim_host(sdio->func);
err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
- sdio_release_host(sdio->func);
-
if (err)
dev_err(dev->dev, "sdio write failed: %d\n", err);
return err;
}
-static int mt7663s_tx_run_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
+static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
- int err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
- struct mt76_queue *q = dev->q_tx[qid];
+ int qid, err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
+ bool mcu = q == dev->q_mcu[MT_MCUQ_WM];
struct mt76_sdio *sdio = &dev->sdio;
+ qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid;
while (q->first != q->head) {
struct mt76_queue_entry *e = &q->entry[q->first];
struct sk_buff *iter;
@@ -214,7 +238,7 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
if (len + e->skb->len + 4 > MT76S_XMIT_BUF_SZ)
break;
- if (mt7663s_tx_pick_quota(sdio, qid, e->buf_sz, &pse_sz,
+ if (mt7663s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
&ple_sz))
break;
@@ -240,78 +264,44 @@ next:
if (err)
return err;
}
- mt7663s_tx_update_quota(sdio, qid, pse_sz, ple_sz);
+ mt7663s_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
- return nframes;
-}
-
-void mt7663s_tx_work(struct work_struct *work)
-{
- struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
- tx.xmit_work);
- struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
- int i, nframes = 0;
+ mt76_worker_schedule(&sdio->status_worker);
- for (i = 0; i < MT_TXQ_MCU_WA; i++) {
- int ret;
-
- ret = mt7663s_tx_run_queue(dev, i);
- if (ret < 0)
- break;
-
- nframes += ret;
- }
- if (nframes)
- queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
-
- queue_work(sdio->txrx_wq, &sdio->tx.status_work);
+ return nframes;
}
-void mt7663s_rx_work(struct work_struct *work)
+void mt7663s_txrx_worker(struct mt76_worker *w)
{
- struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
- rx.recv_work);
+ struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
+ txrx_worker);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
- struct mt76s_intr *intr = sdio->intr_data;
- int nframes = 0, ret;
+ int i, nframes, ret;
/* disable interrupt */
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
- ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
- sdio_release_host(sdio->func);
-
- if (ret < 0)
- goto out;
- trace_dev_irq(dev, intr->isr, 0);
+ do {
+ nframes = 0;
- if (intr->isr & WHIER_RX0_DONE_INT_EN) {
- ret = mt7663s_rx_run_queue(dev, 0, intr);
- if (ret > 0) {
- queue_work(sdio->txrx_wq, &sdio->rx.net_work);
- nframes += ret;
+ /* tx */
+ for (i = 0; i <= MT_TXQ_PSD; i++) {
+ ret = mt7663s_tx_run_queue(dev, dev->phy.q_tx[i]);
+ if (ret > 0)
+ nframes += ret;
}
- }
-
- if (intr->isr & WHIER_RX1_DONE_INT_EN) {
- ret = mt7663s_rx_run_queue(dev, 1, intr);
- if (ret > 0) {
- queue_work(sdio->txrx_wq, &sdio->rx.net_work);
+ ret = mt7663s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
+ if (ret > 0)
nframes += ret;
- }
- }
- if (mt7663s_refill_sched_quota(dev, intr->tx.wtqcr))
- queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
+ /* rx */
+ ret = mt7663s_rx_handler(dev);
+ if (ret > 0)
+ nframes += ret;
+ } while (nframes > 0);
- if (nframes) {
- queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
- return;
- }
-out:
/* enable interrupt */
- sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
sdio_release_host(sdio->func);
}
@@ -324,5 +314,5 @@ void mt7663s_sdio_irq(struct sdio_func *func)
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
return;
- queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
+ mt76_worker_schedule(&sdio->txrx_worker);
}