diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c')
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 203 |
1 files changed, 94 insertions, 109 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index cbbe986655fe..dd71c1c95cc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> @@ -11,17 +11,22 @@ #include "mt76x02_mcu.h" #include "trace.h" -static void mt76x02_pre_tbtt_tasklet(unsigned long arg) +static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t) { - struct mt76x02_dev *dev = (struct mt76x02_dev *)arg; - struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD].q; - struct beacon_bc_data data = {}; + struct mt76x02_dev *dev = from_tasklet(dev, t, mt76.pre_tbtt_tasklet); + struct mt76_dev *mdev = &dev->mt76; + struct mt76_queue *q = dev->mphy.q_tx[MT_TXQ_PSD]; + struct beacon_bc_data data = { + .dev = dev, + }; struct sk_buff *skb; int i; - if (mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL) + if (dev->mphy.offchannel) return; + __skb_queue_head_init(&data.q); + mt76x02_resync_beacon_timer(dev); /* Prevent corrupt transmissions during update */ @@ -30,14 +35,17 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg) ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, - mt76x02_update_beacon_iter, dev); + mt76x02_update_beacon_iter, &data); + + while ((skb = __skb_dequeue(&data.q)) != NULL) + mt76x02_mac_set_beacon(dev, skb); mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~(0xff00 >> dev->beacon_data_count)); - mt76_csa_check(&dev->mt76); + mt76_csa_check(mdev); - if (dev->mt76.csa_complete) + if (mdev->csa_complete) return; mt76x02_enqueue_buffered_bc(dev, &data, 8); @@ -52,16 +60,16 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg) mt76_skb_set_moredata(data.tail[i], false); } - spin_lock_bh(&q->lock); + spin_lock(&q->lock); while ((skb = __skb_dequeue(&data.q)) != NULL) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; - mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, &mvif->group_wcid, + mt76_tx_queue_skb(dev, q, MT_TXQ_PSD, skb, &mvif->group_wcid, NULL); } - spin_unlock_bh(&q->lock); + spin_unlock(&q->lock); } static void mt76x02e_pre_tbtt_enable(struct mt76x02_dev *dev, bool en) @@ -104,29 +112,6 @@ void mt76x02e_init_beacon_config(struct mt76x02_dev *dev) EXPORT_SYMBOL_GPL(mt76x02e_init_beacon_config); static int -mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_sw_queue *q, - int idx, int n_desc) -{ - struct mt76_queue *hwq; - int err; - - hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL); - if (!hwq) - return -ENOMEM; - - err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE); - if (err < 0) - return err; - - INIT_LIST_HEAD(&q->swq); - q->q = hwq; - - mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx)); - - return 0; -} - -static int mt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q, int idx, int n_desc, int bufsize) { @@ -151,9 +136,11 @@ static void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev) mt76x02_send_tx_status(dev, &stat, &update); } -static void mt76x02_tx_tasklet(unsigned long data) +static void mt76x02_tx_worker(struct mt76_worker *w) { - struct mt76x02_dev *dev = (struct mt76x02_dev *)data; + struct mt76x02_dev *dev; + + dev = container_of(w, struct mt76x02_dev, mt76.tx_worker); mt76x02_mac_poll_tx_status(dev, false); mt76x02_process_tx_status_fifo(dev); @@ -169,23 +156,24 @@ static int mt76x02_poll_tx(struct napi_struct *napi, int budget) mt76x02_mac_poll_tx_status(dev, false); - for (i = MT_TXQ_MCU; i >= 0; i--) - mt76_queue_tx_cleanup(dev, i, false); + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); + for (i = MT_TXQ_PSD; i >= 0; i--) + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false); if (napi_complete_done(napi, 0)) mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL); - for (i = MT_TXQ_MCU; i >= 0; i--) - mt76_queue_tx_cleanup(dev, i, false); + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); + for (i = MT_TXQ_PSD; i >= 0; i--) + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false); - tasklet_schedule(&dev->mt76.tx_tasklet); + mt76_worker_schedule(&dev->mt76.tx_worker); return 0; } int mt76x02_dma_init(struct mt76x02_dev *dev) { - struct mt76_txwi_cache __maybe_unused *t; int i, ret, fifo_size; struct mt76_queue *q; void *status_fifo; @@ -197,10 +185,8 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) if (!status_fifo) return -ENOMEM; - tasklet_init(&dev->mt76.tx_tasklet, mt76x02_tx_tasklet, - (unsigned long)dev); - tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet, - (unsigned long)dev); + dev->mt76.tx_worker.fn = mt76x02_tx_worker; + tasklet_setup(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet); spin_lock_init(&dev->txstatus_fifo_lock); kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); @@ -210,23 +196,32 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[i], - mt76_ac_to_hwq(i), - MT_TX_RING_SIZE); + ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i), + MT76x02_TX_RING_SIZE, + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } - ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD], - MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE); + ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, + MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; - ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU], - MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE); + ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_TX_HW_QUEUE_MCU, + MT_MCU_RING_SIZE, MT_TX_RING_BASE); if (ret) return ret; + mt76x02_irq_enable(dev, + MT_INT_TX_DONE(IEEE80211_AC_VO) | + MT_INT_TX_DONE(IEEE80211_AC_VI) | + MT_INT_TX_DONE(IEEE80211_AC_BE) | + MT_INT_TX_DONE(IEEE80211_AC_BK) | + MT_INT_TX_DONE(MT_TX_HW_QUEUE_MGMT) | + MT_INT_TX_DONE(MT_TX_HW_QUEUE_MCU)); + ret = mt76x02_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, MT_MCU_RING_SIZE, MT_RX_BUF_SIZE); if (ret) @@ -239,12 +234,12 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) if (ret) return ret; - ret = mt76_init_queues(dev); + ret = mt76_init_queues(dev, mt76_dma_rx_poll); if (ret) return ret; - netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi, - mt76x02_poll_tx, NAPI_POLL_WEIGHT); + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + mt76x02_poll_tx); napi_enable(&dev->mt76.tx_napi); return 0; @@ -263,9 +258,10 @@ EXPORT_SYMBOL_GPL(mt76x02_rx_poll_complete); irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance) { struct mt76x02_dev *dev = dev_instance; - u32 intr; + u32 intr, mask; intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + intr &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_INT_SOURCE_CSR, intr); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) @@ -273,17 +269,17 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance) trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); - intr &= dev->mt76.mmio.irqmask; + mask = intr & (MT_INT_RX_DONE_ALL | MT_INT_GPTIMER); + if (intr & (MT_INT_TX_DONE_ALL | MT_INT_TX_STAT)) + mask |= MT_INT_TX_DONE_ALL; + + mt76x02_irq_disable(dev, mask); - if (intr & MT_INT_RX_DONE(0)) { - mt76x02_irq_disable(dev, MT_INT_RX_DONE(0)); + if (intr & MT_INT_RX_DONE(0)) napi_schedule(&dev->mt76.napi[0]); - } - if (intr & MT_INT_RX_DONE(1)) { - mt76x02_irq_disable(dev, MT_INT_RX_DONE(1)); + if (intr & MT_INT_RX_DONE(1)) napi_schedule(&dev->mt76.napi[1]); - } if (intr & MT_INT_PRE_TBTT) tasklet_schedule(&dev->mt76.pre_tbtt_tasklet); @@ -293,21 +289,17 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance) if (dev->mt76.csa_complete) mt76_csa_finish(&dev->mt76); else - mt76_queue_kick(dev, dev->mt76.q_tx[MT_TXQ_PSD].q); + mt76_queue_kick(dev, dev->mphy.q_tx[MT_TXQ_PSD]); } if (intr & MT_INT_TX_STAT) mt76x02_mac_poll_tx_status(dev, true); - if (intr & (MT_INT_TX_STAT | MT_INT_TX_DONE_ALL)) { - mt76x02_irq_disable(dev, MT_INT_TX_DONE_ALL); + if (intr & (MT_INT_TX_STAT | MT_INT_TX_DONE_ALL)) napi_schedule(&dev->mt76.tx_napi); - } - if (intr & MT_INT_GPTIMER) { - mt76x02_irq_disable(dev, MT_INT_GPTIMER); + if (intr & MT_INT_GPTIMER) tasklet_schedule(&dev->dfs_pd.dfs_tasklet); - } return IRQ_HANDLED; } @@ -329,13 +321,6 @@ static void mt76x02_dma_enable(struct mt76x02_dev *dev) MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); } -void mt76x02_dma_cleanup(struct mt76x02_dev *dev) -{ - tasklet_kill(&dev->mt76.tx_tasklet); - mt76_dma_cleanup(&dev->mt76); -} -EXPORT_SYMBOL_GPL(mt76x02_dma_cleanup); - void mt76x02_dma_disable(struct mt76x02_dev *dev) { u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG); @@ -369,20 +354,22 @@ static bool mt76x02_tx_hang(struct mt76x02_dev *dev) int i; for (i = 0; i < 4; i++) { - q = dev->mt76.q_tx[i].q; - - if (!q->queued) - continue; + q = dev->mphy.q_tx[i]; prev_dma_idx = dev->mt76.tx_dma_idx[i]; dma_idx = readl(&q->regs->dma_idx); dev->mt76.tx_dma_idx[i] = dma_idx; - if (prev_dma_idx == dma_idx) - break; + if (!q->queued || prev_dma_idx != dma_idx) { + dev->tx_hang_check[i] = 0; + continue; + } + + if (++dev->tx_hang_check[i] >= MT_TX_HANG_TH) + return true; } - return i < 4; + return false; } static void mt76x02_key_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -435,11 +422,11 @@ static void mt76x02_reset_state(struct mt76x02_dev *dev) priv = msta->vif; vif = container_of(priv, struct ieee80211_vif, drv_priv); - __mt76_sta_remove(&dev->mt76, vif, sta); + __mt76_sta_remove(&dev->mphy, vif, sta); memset(msta, 0, sizeof(*msta)); } - dev->vif_mask = 0; + dev->mt76.vif_mask = 0; dev->mt76.beacon_mask = 0; } @@ -453,11 +440,12 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) set_bit(MT76_RESET, &dev->mphy.state); tasklet_disable(&dev->mt76.pre_tbtt_tasklet); - tasklet_disable(&dev->mt76.tx_tasklet); + mt76_worker_disable(&dev->mt76.tx_worker); napi_disable(&dev->mt76.tx_napi); - for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++) + mt76_for_each_q_rx(&dev->mt76, i) { napi_disable(&dev->mt76.napi[i]); + } mutex_lock(&dev->mt76.mutex); @@ -486,13 +474,16 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) if (restart) mt76_mcu_restart(dev); + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true); for (i = 0; i < __MT_TXQ_MAX; i++) - mt76_queue_tx_cleanup(dev, i, true); + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); mt76_for_each_q_rx(&dev->mt76, i) { mt76_queue_rx_reset(dev, i); } + mt76_tx_status_check(&dev->mt76, true); + mt76x02_mac_start(dev); if (dev->ed_monitor) @@ -509,16 +500,20 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) clear_bit(MT76_RESET, &dev->mphy.state); - tasklet_enable(&dev->mt76.tx_tasklet); - napi_enable(&dev->mt76.tx_napi); - napi_schedule(&dev->mt76.tx_napi); - + mt76_worker_enable(&dev->mt76.tx_worker); tasklet_enable(&dev->mt76.pre_tbtt_tasklet); - for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++) { + napi_enable(&dev->mt76.tx_napi); + mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); + } + + local_bh_disable(); + napi_schedule(&dev->mt76.tx_napi); + mt76_for_each_q_rx(&dev->mt76, i) { napi_schedule(&dev->mt76.napi[i]); } + local_bh_enable(); if (restart) { set_bit(MT76_RESTART, &dev->mphy.state); @@ -547,23 +542,13 @@ static void mt76x02_check_tx_hang(struct mt76x02_dev *dev) if (test_bit(MT76_RESTART, &dev->mphy.state)) return; - if (mt76x02_tx_hang(dev)) { - if (++dev->tx_hang_check >= MT_TX_HANG_TH) - goto restart; - } else { - dev->tx_hang_check = 0; - } - - if (dev->mcu_timeout) - goto restart; - - return; + if (!mt76x02_tx_hang(dev) && !dev->mcu_timeout) + return; -restart: mt76x02_watchdog_reset(dev); dev->tx_hang_reset++; - dev->tx_hang_check = 0; + memset(dev->tx_hang_check, 0, sizeof(dev->tx_hang_check)); memset(dev->mt76.tx_dma_idx, 0xff, sizeof(dev->mt76.tx_dma_idx)); } |
