mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
mt76 patches for 5.10
* mt7663 runtime power management improvements * performance improvements * sdio support fixes * testmode fixes * mt7622 fixes * 7915 A-MSDU offload * cleanups -----BEGIN PGP SIGNATURE----- Comment: GPGTools - http://gpgtools.org iEYEABECAAYFAl9sxPEACgkQ130UHQKnbvXSXQCfc21mudzbYN4qcdgW8hJG+22L SWEAnAkhE1NSXvFU19WSLMv119s/E5TZ =qKN0 -----END PGP SIGNATURE----- Merge tag 'mt76-for-kvalo-2020-09-23' of https://github.com/nbd168/wireless mt76 patches for 5.10 * mt7663 runtime power management improvements * performance improvements * sdio support fixes * testmode fixes * mt7622 fixes * 7915 A-MSDU offload * cleanups # gpg: Signature made Thu 24 Sep 2020 07:10:25 PM EEST using DSA key ID 02A76EF5 # gpg: Good signature from "Felix Fietkau <nbd@nbd.name>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 75D1 1A7D 91A7 710F 4900 42EF D77D 141D 02A7 6EF5
This commit is contained in:
commit
225060c428
|
|
@ -31,15 +31,14 @@ int mt76_queues_read(struct seq_file *s, void *data)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
|
||||
struct mt76_sw_queue *q = &dev->q_tx[i];
|
||||
struct mt76_queue *q = dev->q_tx[i];
|
||||
|
||||
if (!q->q)
|
||||
if (!q)
|
||||
continue;
|
||||
|
||||
seq_printf(s,
|
||||
"%d: queued=%d head=%d tail=%d swq_queued=%d\n",
|
||||
i, q->q->queued, q->q->head, q->q->tail,
|
||||
q->swq_queued);
|
||||
"%d: queued=%d head=%d tail=%d\n",
|
||||
i, q->queued, q->head, q->tail);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,76 @@
|
|||
#include "mt76.h"
|
||||
#include "dma.h"
|
||||
|
||||
static struct mt76_txwi_cache *
|
||||
mt76_alloc_txwi(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *t;
|
||||
dma_addr_t addr;
|
||||
u8 *txwi;
|
||||
int size;
|
||||
|
||||
size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t));
|
||||
txwi = devm_kzalloc(dev->dev, size, GFP_ATOMIC);
|
||||
if (!txwi)
|
||||
return NULL;
|
||||
|
||||
addr = dma_map_single(dev->dev, txwi, dev->drv->txwi_size,
|
||||
DMA_TO_DEVICE);
|
||||
t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size);
|
||||
t->dma_addr = addr;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static struct mt76_txwi_cache *
|
||||
__mt76_get_txwi(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *t = NULL;
|
||||
|
||||
spin_lock(&dev->lock);
|
||||
if (!list_empty(&dev->txwi_cache)) {
|
||||
t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache,
|
||||
list);
|
||||
list_del(&t->list);
|
||||
}
|
||||
spin_unlock(&dev->lock);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static struct mt76_txwi_cache *
|
||||
mt76_get_txwi(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *t = __mt76_get_txwi(dev);
|
||||
|
||||
if (t)
|
||||
return t;
|
||||
|
||||
return mt76_alloc_txwi(dev);
|
||||
}
|
||||
|
||||
void
|
||||
mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
spin_lock(&dev->lock);
|
||||
list_add(&t->list, &dev->txwi_cache);
|
||||
spin_unlock(&dev->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_put_txwi);
|
||||
|
||||
static void
|
||||
mt76_free_pending_txwi(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *t;
|
||||
|
||||
while ((t = __mt76_get_txwi(dev)) != NULL)
|
||||
dma_unmap_single(dev->dev, t->dma_addr, dev->drv->txwi_size,
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static int
|
||||
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
int idx, int n_desc, int bufsize,
|
||||
|
|
@ -49,6 +119,7 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
|||
struct mt76_queue_buf *buf, int nbufs, u32 info,
|
||||
struct sk_buff *skb, void *txwi)
|
||||
{
|
||||
struct mt76_queue_entry *entry;
|
||||
struct mt76_desc *desc;
|
||||
u32 ctrl;
|
||||
int i, idx = -1;
|
||||
|
|
@ -61,10 +132,27 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
|||
for (i = 0; i < nbufs; i += 2, buf += 2) {
|
||||
u32 buf0 = buf[0].addr, buf1 = 0;
|
||||
|
||||
idx = q->head;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
|
||||
desc = &q->desc[idx];
|
||||
entry = &q->entry[idx];
|
||||
|
||||
if (buf[0].skip_unmap)
|
||||
entry->skip_buf0 = true;
|
||||
entry->skip_buf1 = i == nbufs - 1;
|
||||
|
||||
entry->dma_addr[0] = buf[0].addr;
|
||||
entry->dma_len[0] = buf[0].len;
|
||||
|
||||
ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
|
||||
if (i < nbufs - 1) {
|
||||
entry->dma_addr[1] = buf[1].addr;
|
||||
entry->dma_len[1] = buf[1].len;
|
||||
buf1 = buf[1].addr;
|
||||
ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
|
||||
if (buf[1].skip_unmap)
|
||||
entry->skip_buf1 = true;
|
||||
}
|
||||
|
||||
if (i == nbufs - 1)
|
||||
|
|
@ -72,11 +160,6 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
|||
else if (i == nbufs - 2)
|
||||
ctrl |= MT_DMA_CTL_LAST_SEC1;
|
||||
|
||||
idx = q->head;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
|
||||
desc = &q->desc[idx];
|
||||
|
||||
WRITE_ONCE(desc->buf0, cpu_to_le32(buf0));
|
||||
WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
|
||||
WRITE_ONCE(desc->info, cpu_to_le32(info));
|
||||
|
|
@ -96,24 +179,14 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,
|
|||
struct mt76_queue_entry *prev_e)
|
||||
{
|
||||
struct mt76_queue_entry *e = &q->entry[idx];
|
||||
__le32 __ctrl = READ_ONCE(q->desc[idx].ctrl);
|
||||
u32 ctrl = le32_to_cpu(__ctrl);
|
||||
|
||||
if (!e->skip_buf0) {
|
||||
__le32 addr = READ_ONCE(q->desc[idx].buf0);
|
||||
u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl);
|
||||
|
||||
dma_unmap_single(dev->dev, le32_to_cpu(addr), len,
|
||||
if (!e->skip_buf0)
|
||||
dma_unmap_single(dev->dev, e->dma_addr[0], e->dma_len[0],
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
if (!(ctrl & MT_DMA_CTL_LAST_SEC0)) {
|
||||
__le32 addr = READ_ONCE(q->desc[idx].buf1);
|
||||
u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN1, ctrl);
|
||||
|
||||
dma_unmap_single(dev->dev, le32_to_cpu(addr), len,
|
||||
if (!e->skip_buf1)
|
||||
dma_unmap_single(dev->dev, e->dma_addr[1], e->dma_len[1],
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
if (e->txwi == DMA_DUMMY_DATA)
|
||||
e->txwi = NULL;
|
||||
|
|
@ -137,19 +210,17 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
|
|||
static void
|
||||
mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
|
||||
{
|
||||
wmb();
|
||||
writel(q->head, &q->regs->cpu_idx);
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
|
||||
{
|
||||
struct mt76_sw_queue *sq = &dev->q_tx[qid];
|
||||
struct mt76_queue *q = sq->q;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
struct mt76_queue_entry entry;
|
||||
unsigned int n_swq_queued[8] = {};
|
||||
unsigned int n_queued = 0;
|
||||
bool wake = false;
|
||||
int i, last;
|
||||
int last;
|
||||
|
||||
if (!q)
|
||||
return;
|
||||
|
|
@ -159,16 +230,9 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
|
|||
else
|
||||
last = readl(&q->regs->dma_idx);
|
||||
|
||||
while ((q->queued > n_queued) && q->tail != last) {
|
||||
while (q->queued > 0 && q->tail != last) {
|
||||
mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);
|
||||
if (entry.schedule)
|
||||
n_swq_queued[entry.qid]++;
|
||||
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
n_queued++;
|
||||
|
||||
if (entry.skb)
|
||||
dev->drv->tx_complete_skb(dev, qid, &entry);
|
||||
mt76_queue_tx_complete(dev, q, &entry);
|
||||
|
||||
if (entry.txwi) {
|
||||
if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE))
|
||||
|
|
@ -178,29 +242,14 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
|
|||
|
||||
if (!flush && q->tail == last)
|
||||
last = readl(&q->regs->dma_idx);
|
||||
}
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
|
||||
q->queued -= n_queued;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (!n_swq_queued[i])
|
||||
continue;
|
||||
|
||||
dev->q_tx[i].swq_queued -= n_swq_queued[i];
|
||||
}
|
||||
|
||||
/* ext PHY */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (!n_swq_queued[i])
|
||||
continue;
|
||||
|
||||
dev->q_tx[__MT_TXQ_MAX + i].swq_queued -= n_swq_queued[4 + i];
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
spin_lock_bh(&q->lock);
|
||||
mt76_dma_sync_idx(dev, q);
|
||||
mt76_dma_kick_queue(dev, q);
|
||||
spin_unlock_bh(&q->lock);
|
||||
}
|
||||
|
||||
wake = wake && q->stopped &&
|
||||
|
|
@ -211,8 +260,6 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
|
|||
if (!q->queued)
|
||||
wake_up(&dev->tx_wait);
|
||||
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
if (wake)
|
||||
ieee80211_wake_queue(dev->hw, qid);
|
||||
}
|
||||
|
|
@ -227,7 +274,7 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
|
|||
void *buf = e->buf;
|
||||
int buf_len = SKB_WITH_OVERHEAD(q->buf_size);
|
||||
|
||||
buf_addr = le32_to_cpu(READ_ONCE(desc->buf0));
|
||||
buf_addr = e->dma_addr[0];
|
||||
if (len) {
|
||||
u32 ctl = le32_to_cpu(READ_ONCE(desc->ctrl));
|
||||
*len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctl);
|
||||
|
|
@ -268,7 +315,7 @@ static int
|
|||
mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid,
|
||||
struct sk_buff *skb, u32 tx_info)
|
||||
{
|
||||
struct mt76_queue *q = dev->q_tx[qid].q;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
struct mt76_queue_buf buf;
|
||||
dma_addr_t addr;
|
||||
|
||||
|
|
@ -300,7 +347,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
|
|||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct mt76_queue *q = dev->q_tx[qid].q;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
struct mt76_tx_info tx_info = {
|
||||
.skb = skb,
|
||||
};
|
||||
|
|
@ -378,7 +425,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
|
|||
|
||||
e.skb = tx_info.skb;
|
||||
e.txwi = t;
|
||||
dev->drv->tx_complete_skb(dev, qid, &e);
|
||||
dev->drv->tx_complete_skb(dev, &e);
|
||||
mt76_put_txwi(dev, t);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -612,6 +659,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
|
|||
{
|
||||
int i;
|
||||
|
||||
mt76_worker_disable(&dev->tx_worker);
|
||||
netif_napi_del(&dev->tx_napi);
|
||||
for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++)
|
||||
mt76_dma_tx_cleanup(dev, i, true);
|
||||
|
|
@ -620,5 +668,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
|
|||
netif_napi_del(&dev->napi[i]);
|
||||
mt76_dma_rx_cleanup(dev, &dev->q_rx[i]);
|
||||
}
|
||||
|
||||
mt76_free_pending_txwi(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_dma_cleanup);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
|
||||
*/
|
||||
#include <linux/sched.h>
|
||||
#include <linux/of.h>
|
||||
#include "mt76.h"
|
||||
|
||||
|
|
@ -304,11 +305,11 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
|
|||
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
|
||||
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
|
||||
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
|
||||
ieee80211_hw_set(hw, TX_AMSDU);
|
||||
|
||||
/* TODO: avoid linearization for SDIO */
|
||||
if (!mt76_is_sdio(dev))
|
||||
if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
|
||||
ieee80211_hw_set(hw, TX_AMSDU);
|
||||
ieee80211_hw_set(hw, TX_FRAG_LIST);
|
||||
}
|
||||
|
||||
ieee80211_hw_set(hw, MFP_CAPABLE);
|
||||
ieee80211_hw_set(hw, AP_LINK_PS);
|
||||
|
|
@ -433,14 +434,13 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
|
|||
skb_queue_head_init(&dev->mcu.res_q);
|
||||
init_waitqueue_head(&dev->mcu.wait);
|
||||
mutex_init(&dev->mcu.mutex);
|
||||
dev->tx_worker.fn = mt76_tx_worker;
|
||||
|
||||
INIT_LIST_HEAD(&dev->txwi_cache);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
|
||||
skb_queue_head_init(&dev->rx_skb[i]);
|
||||
|
||||
tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
|
||||
|
||||
dev->wq = alloc_ordered_workqueue("mt76", 0);
|
||||
if (!dev->wq) {
|
||||
ieee80211_free_hw(hw);
|
||||
|
|
@ -483,7 +483,14 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
|
|||
return ret;
|
||||
}
|
||||
|
||||
return ieee80211_register_hw(hw);
|
||||
ret = ieee80211_register_hw(hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
|
||||
sched_set_fifo_low(dev->tx_worker.task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_register_device);
|
||||
|
||||
|
|
@ -500,12 +507,11 @@ EXPORT_SYMBOL_GPL(mt76_unregister_device);
|
|||
|
||||
void mt76_free_device(struct mt76_dev *dev)
|
||||
{
|
||||
mt76_worker_teardown(&dev->tx_worker);
|
||||
if (dev->wq) {
|
||||
destroy_workqueue(dev->wq);
|
||||
dev->wq = NULL;
|
||||
}
|
||||
if (mt76_is_mmio(dev))
|
||||
mt76_tx_free(dev);
|
||||
ieee80211_free_hw(dev->hw);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_free_device);
|
||||
|
|
@ -540,7 +546,7 @@ bool mt76_has_tx_pending(struct mt76_phy *phy)
|
|||
offset = __MT_TXQ_MAX * (phy != &dev->phy);
|
||||
|
||||
for (i = 0; i < __MT_TXQ_MAX; i++) {
|
||||
q = dev->q_tx[offset + i].q;
|
||||
q = dev->q_tx[offset + i];
|
||||
if (q && q->queued)
|
||||
return true;
|
||||
}
|
||||
|
|
@ -870,7 +876,6 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
|
|||
struct ieee80211_hw *hw;
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
bool ps;
|
||||
int i;
|
||||
|
||||
hw = mt76_phy_hw(dev, status->ext_phy);
|
||||
if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
|
||||
|
|
@ -920,20 +925,6 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
|
|||
|
||||
dev->drv->sta_ps(dev, sta, ps);
|
||||
ieee80211_sta_ps_transition(sta, ps);
|
||||
|
||||
if (ps)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
|
||||
struct mt76_txq *mtxq;
|
||||
|
||||
if (!sta->txq[i])
|
||||
continue;
|
||||
|
||||
mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
|
||||
if (!skb_queue_empty(&mtxq->retry_q))
|
||||
ieee80211_schedule_txq(hw, sta->txq[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
|
||||
|
|
@ -995,8 +986,6 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
|
|||
|
||||
mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
|
||||
mtxq->wcid = wcid;
|
||||
|
||||
mt76_txq_init(dev, sta->txq[i]);
|
||||
}
|
||||
|
||||
ewma_signal_init(&wcid->rssi);
|
||||
|
|
@ -1024,8 +1013,6 @@ void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
|
|||
dev->drv->sta_remove(dev, vif, sta);
|
||||
|
||||
mt76_tx_status_check(dev, wcid, true);
|
||||
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
|
||||
mt76_txq_remove(dev, sta->txq[i]);
|
||||
mt76_wcid_mask_clear(dev->wcid_mask, idx);
|
||||
mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,13 @@
|
|||
#include "util.h"
|
||||
#include "testmode.h"
|
||||
|
||||
#define MT_TX_RING_SIZE 256
|
||||
#define MT_MCU_RING_SIZE 32
|
||||
#define MT_RX_BUF_SIZE 2048
|
||||
#define MT_SKB_HEAD_LEN 128
|
||||
|
||||
#define MT_MAX_NON_AQL_PKT 16
|
||||
#define MT_TXQ_FREE_THR 32
|
||||
|
||||
struct mt76_dev;
|
||||
struct mt76_phy;
|
||||
struct mt76_wcid;
|
||||
|
|
@ -79,7 +81,8 @@ enum mt76_rxq_id {
|
|||
|
||||
struct mt76_queue_buf {
|
||||
dma_addr_t addr;
|
||||
int len;
|
||||
u16 len;
|
||||
bool skip_unmap;
|
||||
};
|
||||
|
||||
struct mt76_tx_info {
|
||||
|
|
@ -99,9 +102,11 @@ struct mt76_queue_entry {
|
|||
struct urb *urb;
|
||||
int buf_sz;
|
||||
};
|
||||
enum mt76_txq_id qid;
|
||||
u32 dma_addr[2];
|
||||
u16 dma_len[2];
|
||||
u16 wcid;
|
||||
bool skip_buf0:1;
|
||||
bool schedule:1;
|
||||
bool skip_buf1:1;
|
||||
bool done:1;
|
||||
};
|
||||
|
||||
|
|
@ -135,13 +140,6 @@ struct mt76_queue {
|
|||
struct page_frag_cache rx_page;
|
||||
};
|
||||
|
||||
struct mt76_sw_queue {
|
||||
struct mt76_queue *q;
|
||||
|
||||
struct list_head swq;
|
||||
int swq_queued;
|
||||
};
|
||||
|
||||
struct mt76_mcu_ops {
|
||||
u32 headroom;
|
||||
u32 tailroom;
|
||||
|
|
@ -204,6 +202,7 @@ DECLARE_EWMA(signal, 10, 8);
|
|||
struct mt76_wcid {
|
||||
struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS];
|
||||
|
||||
atomic_t non_aql_packets;
|
||||
unsigned long flags;
|
||||
|
||||
struct ewma_signal rssi;
|
||||
|
|
@ -214,6 +213,7 @@ struct mt76_wcid {
|
|||
|
||||
u8 sta:1;
|
||||
u8 ext_phy:1;
|
||||
u8 amsdu:1;
|
||||
|
||||
u8 rx_check_pn;
|
||||
u8 rx_key_pn[IEEE80211_NUM_TIDS][6];
|
||||
|
|
@ -226,11 +226,8 @@ struct mt76_wcid {
|
|||
};
|
||||
|
||||
struct mt76_txq {
|
||||
struct mt76_sw_queue *swq;
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
struct sk_buff_head retry_q;
|
||||
|
||||
u16 agg_ssn;
|
||||
bool send_bar;
|
||||
bool aggr;
|
||||
|
|
@ -309,6 +306,7 @@ struct mt76_hw_cap {
|
|||
#define MT_DRV_SW_RX_AIRTIME BIT(2)
|
||||
#define MT_DRV_RX_DMA_HDR BIT(3)
|
||||
#define MT_DRV_HW_MGMT_TXQ BIT(4)
|
||||
#define MT_DRV_AMSDU_OFFLOAD BIT(5)
|
||||
|
||||
struct mt76_driver_ops {
|
||||
u32 drv_flags;
|
||||
|
|
@ -322,7 +320,7 @@ struct mt76_driver_ops {
|
|||
struct ieee80211_sta *sta,
|
||||
struct mt76_tx_info *tx_info);
|
||||
|
||||
void (*tx_complete_skb)(struct mt76_dev *dev, enum mt76_txq_id qid,
|
||||
void (*tx_complete_skb)(struct mt76_dev *dev,
|
||||
struct mt76_queue_entry *e);
|
||||
|
||||
bool (*tx_status_data)(struct mt76_dev *dev, u8 *update);
|
||||
|
|
@ -445,14 +443,24 @@ struct mt76_usb {
|
|||
} mcu;
|
||||
};
|
||||
|
||||
#define MT76S_XMIT_BUF_SZ (16 * PAGE_SIZE)
|
||||
struct mt76_sdio {
|
||||
struct task_struct *tx_kthread;
|
||||
struct task_struct *kthread;
|
||||
struct workqueue_struct *txrx_wq;
|
||||
struct {
|
||||
struct work_struct xmit_work;
|
||||
struct work_struct status_work;
|
||||
} tx;
|
||||
struct {
|
||||
struct work_struct recv_work;
|
||||
struct work_struct net_work;
|
||||
} rx;
|
||||
|
||||
struct work_struct stat_work;
|
||||
|
||||
unsigned long state;
|
||||
u8 *xmit_buf[MT_TXQ_MCU_WA];
|
||||
|
||||
struct sdio_func *func;
|
||||
void *intr_data;
|
||||
|
||||
struct {
|
||||
struct mutex lock;
|
||||
|
|
@ -593,12 +601,12 @@ struct mt76_dev {
|
|||
struct sk_buff_head rx_skb[__MT_RXQ_MAX];
|
||||
|
||||
struct list_head txwi_cache;
|
||||
struct mt76_sw_queue q_tx[2 * __MT_TXQ_MAX];
|
||||
struct mt76_queue *q_tx[2 * __MT_TXQ_MAX];
|
||||
struct mt76_queue q_rx[__MT_RXQ_MAX];
|
||||
const struct mt76_queue_ops *queue_ops;
|
||||
int tx_dma_idx[4];
|
||||
|
||||
struct tasklet_struct tx_tasklet;
|
||||
struct mt76_worker tx_worker;
|
||||
struct napi_struct tx_napi;
|
||||
struct delayed_work mac_work;
|
||||
|
||||
|
|
@ -892,14 +900,13 @@ static inline bool mt76_testmode_enabled(struct mt76_dev *dev)
|
|||
void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
|
||||
void mt76_tx(struct mt76_phy *dev, struct ieee80211_sta *sta,
|
||||
struct mt76_wcid *wcid, struct sk_buff *skb);
|
||||
void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq);
|
||||
void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq);
|
||||
void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
|
||||
void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
|
||||
bool send_bar);
|
||||
void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb);
|
||||
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid);
|
||||
void mt76_txq_schedule_all(struct mt76_phy *phy);
|
||||
void mt76_tx_tasklet(unsigned long data);
|
||||
void mt76_tx_worker(struct mt76_worker *w);
|
||||
void mt76_release_buffered_frames(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tids, int nframes,
|
||||
|
|
@ -932,7 +939,7 @@ struct sk_buff *mt76_tx_status_skb_get(struct mt76_dev *dev,
|
|||
struct sk_buff_head *list);
|
||||
void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,
|
||||
struct sk_buff_head *list);
|
||||
void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb);
|
||||
void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb);
|
||||
void mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid,
|
||||
bool flush);
|
||||
int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
|
|
@ -996,8 +1003,6 @@ mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb)
|
|||
return hw;
|
||||
}
|
||||
|
||||
void mt76_tx_free(struct mt76_dev *dev);
|
||||
struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev);
|
||||
void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
|
||||
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
|
||||
struct napi_struct *napi);
|
||||
|
|
@ -1005,6 +1010,8 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
|
|||
struct napi_struct *napi);
|
||||
void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames);
|
||||
void mt76_testmode_tx_pending(struct mt76_dev *dev);
|
||||
void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
struct mt76_queue_entry *e);
|
||||
|
||||
/* usb */
|
||||
static inline bool mt76u_urb_error(struct urb *urb)
|
||||
|
|
@ -1039,7 +1046,7 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
|
|||
return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout);
|
||||
}
|
||||
|
||||
int mt76_skb_adjust_pad(struct sk_buff *skb);
|
||||
int mt76_skb_adjust_pad(struct sk_buff *skb, int pad);
|
||||
int mt76u_vendor_request(struct mt76_dev *dev, u8 req,
|
||||
u8 req_type, u16 val, u16 offset,
|
||||
void *buf, size_t len);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
|||
mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, mvif->sta.wcid.idx) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID,
|
||||
dev->mt76.q_tx[MT_TXQ_CAB].q->hw_idx) |
|
||||
dev->mt76.q_tx[MT_TXQ_CAB]->hw_idx) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8));
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
|
|||
data.dev = dev;
|
||||
__skb_queue_head_init(&data.q);
|
||||
|
||||
q = dev->mt76.q_tx[MT_TXQ_BEACON].q;
|
||||
q = dev->mt76.q_tx[MT_TXQ_BEACON];
|
||||
spin_lock_bh(&q->lock);
|
||||
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
|
|
@ -95,7 +95,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
|
|||
if (dev->mt76.csa_complete)
|
||||
goto out;
|
||||
|
||||
q = dev->mt76.q_tx[MT_TXQ_CAB].q;
|
||||
q = dev->mt76.q_tx[MT_TXQ_CAB];
|
||||
do {
|
||||
nframes = skb_queue_len(&data.q);
|
||||
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
|
||||
|
|
@ -136,7 +136,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
|
|||
|
||||
out:
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_BEACON, false);
|
||||
if (dev->mt76.q_tx[MT_TXQ_BEACON].q->queued >
|
||||
if (dev->mt76.q_tx[MT_TXQ_BEACON]->queued >
|
||||
hweight8(dev->mt76.beacon_mask))
|
||||
dev->beacon_check++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get,
|
|||
mt7603_edcca_set, "%lld\n");
|
||||
|
||||
static int
|
||||
mt7603_ampdu_stat_read(struct seq_file *file, void *data)
|
||||
mt7603_ampdu_stat_show(struct seq_file *file, void *data)
|
||||
{
|
||||
struct mt7603_dev *dev = file->private;
|
||||
int bound[3], i, range;
|
||||
|
|
@ -91,18 +91,7 @@ mt7603_ampdu_stat_read(struct seq_file *file, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_ampdu_stat_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return single_open(f, mt7603_ampdu_stat_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ampdu_stat = {
|
||||
.open = mt7603_ampdu_stat_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(mt7603_ampdu_stat);
|
||||
|
||||
void mt7603_init_debugfs(struct mt7603_dev *dev)
|
||||
{
|
||||
|
|
@ -112,7 +101,8 @@ void mt7603_init_debugfs(struct mt7603_dev *dev)
|
|||
if (!dir)
|
||||
return;
|
||||
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev,
|
||||
&mt7603_ampdu_stat_fops);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir,
|
||||
mt76_queues_read);
|
||||
debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
#include "../dma.h"
|
||||
|
||||
static int
|
||||
mt7603_init_tx_queue(struct mt7603_dev *dev, struct mt76_sw_queue *q,
|
||||
int idx, int n_desc)
|
||||
mt7603_init_tx_queue(struct mt7603_dev *dev, int qid, int idx, int n_desc)
|
||||
{
|
||||
struct mt76_queue *hwq;
|
||||
int err;
|
||||
|
|
@ -19,8 +18,7 @@ mt7603_init_tx_queue(struct mt7603_dev *dev, struct mt76_sw_queue *q,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
INIT_LIST_HEAD(&q->swq);
|
||||
q->q = hwq;
|
||||
dev->mt76.q_tx[qid] = hwq;
|
||||
|
||||
mt7603_irq_enable(dev, MT_INT_TX_DONE(idx));
|
||||
|
||||
|
|
@ -123,7 +121,7 @@ void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
|||
mt76_rx(&dev->mt76, q, skb);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
|
|
@ -165,7 +163,7 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget)
|
|||
|
||||
mt7603_mac_sta_poll(dev);
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_schedule(&dev->mt76.tx_worker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -193,29 +191,28 @@ int mt7603_dma_init(struct mt7603_dev *dev)
|
|||
mt7603_pse_client_reset(dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[i],
|
||||
wmm_queue_map[i],
|
||||
MT_TX_RING_SIZE);
|
||||
ret = mt7603_init_tx_queue(dev, i, wmm_queue_map[i],
|
||||
MT7603_TX_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
|
||||
MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
|
||||
ret = mt7603_init_tx_queue(dev, MT_TXQ_PSD,
|
||||
MT_TX_HW_QUEUE_MGMT, MT7603_PSD_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
|
||||
ret = mt7603_init_tx_queue(dev, MT_TXQ_MCU,
|
||||
MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_BEACON],
|
||||
ret = mt7603_init_tx_queue(dev, MT_TXQ_BEACON,
|
||||
MT_TX_HW_QUEUE_BCN, MT_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_CAB],
|
||||
ret = mt7603_init_tx_queue(dev, MT_TXQ_CAB,
|
||||
MT_TX_HW_QUEUE_BMC, MT_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -249,6 +246,5 @@ void mt7603_dma_cleanup(struct mt7603_dev *dev)
|
|||
MT_WPDMA_GLO_CFG_RX_DMA_EN |
|
||||
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
|
||||
|
||||
tasklet_kill(&dev->mt76.tx_tasklet);
|
||||
mt76_dma_cleanup(&dev->mt76);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,8 +147,14 @@ static int mt7603_check_eeprom(struct mt76_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool is_mt7688(struct mt7603_dev *dev)
|
||||
{
|
||||
return mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4);
|
||||
}
|
||||
|
||||
int mt7603_eeprom_init(struct mt7603_dev *dev)
|
||||
{
|
||||
u8 *eeprom;
|
||||
int ret;
|
||||
|
||||
ret = mt7603_eeprom_load(dev);
|
||||
|
|
@ -163,9 +169,16 @@ int mt7603_eeprom_init(struct mt7603_dev *dev)
|
|||
MT7603_EEPROM_SIZE);
|
||||
}
|
||||
|
||||
eeprom = (u8 *)dev->mt76.eeprom.data;
|
||||
dev->mt76.cap.has_2ghz = true;
|
||||
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
|
||||
ETH_ALEN);
|
||||
memcpy(dev->mt76.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN);
|
||||
|
||||
/* Check for 1SS devices */
|
||||
dev->mphy.antenna_mask = 3;
|
||||
if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 ||
|
||||
FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 ||
|
||||
is_mt7688(dev))
|
||||
dev->mphy.antenna_mask = 1;
|
||||
|
||||
mt76_eeprom_override(&dev->mt76);
|
||||
|
||||
|
|
|
|||
|
|
@ -85,4 +85,7 @@ enum mt7603_eeprom_source {
|
|||
MT_EE_SRC_FLASH,
|
||||
};
|
||||
|
||||
#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0)
|
||||
#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -536,11 +536,6 @@ int mt7603_register_device(struct mt7603_dev *dev)
|
|||
tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet,
|
||||
(unsigned long)dev);
|
||||
|
||||
/* Check for 7688, which only has 1SS */
|
||||
dev->mphy.antenna_mask = 3;
|
||||
if (mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4))
|
||||
dev->mphy.antenna_mask = 1;
|
||||
|
||||
dev->slottime = 9;
|
||||
dev->sensitivity_limit = 28;
|
||||
dev->dynamic_sensitivity = true;
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ void mt7603_mac_sta_poll(struct mt7603_dev *dev)
|
|||
|
||||
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
|
||||
for (i = 0; i < 4; i++) {
|
||||
struct mt76_queue *q = dev->mt76.q_tx[i].q;
|
||||
struct mt76_queue *q = dev->mt76.q_tx[i];
|
||||
u8 qidx = q->hw_idx;
|
||||
u8 tid = ac_to_tid[i];
|
||||
u32 txtime = airtime[qidx];
|
||||
|
|
@ -592,7 +592,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
|
|||
switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
|
||||
case MT_PHY_TYPE_CCK:
|
||||
cck = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_OFDM:
|
||||
i = mt76_get_rate(&dev->mt76, sband, i, cck);
|
||||
break;
|
||||
|
|
@ -896,7 +896,7 @@ mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
|
|||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct mt76_queue *q = dev->mt76.q_tx[qid].q;
|
||||
struct mt76_queue *q = dev->mt76.q_tx[qid];
|
||||
struct mt7603_vif *mvif;
|
||||
int wlan_idx;
|
||||
int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
|
||||
|
|
@ -1036,6 +1036,8 @@ int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
IEEE80211_TX_CTL_CLEAR_PS_FILT)) ||
|
||||
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
|
||||
mt7603_wtbl_set_ps(dev, msta, false);
|
||||
|
||||
mt76_tx_check_agg_ssn(sta, tx_info->skb);
|
||||
}
|
||||
|
||||
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
|
||||
|
|
@ -1161,7 +1163,7 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
|||
switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
|
||||
case MT_PHY_TYPE_CCK:
|
||||
cck = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_OFDM:
|
||||
if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ)
|
||||
sband = &dev->mphy.sband_5g.sband;
|
||||
|
|
@ -1269,8 +1271,7 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void mt7603_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e)
|
||||
void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
|
||||
{
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
struct sk_buff *skb = e->skb;
|
||||
|
|
@ -1280,10 +1281,8 @@ void mt7603_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
|||
return;
|
||||
}
|
||||
|
||||
if (qid < 4)
|
||||
dev->tx_hang_check = 0;
|
||||
|
||||
mt76_tx_complete_skb(mdev, skb);
|
||||
dev->tx_hang_check = 0;
|
||||
mt76_tx_complete_skb(mdev, e->wcid, skb);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -1403,7 +1402,7 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
|
|||
/* lock/unlock all queues to ensure that no tx is pending */
|
||||
mt76_txq_schedule_all(&dev->mphy);
|
||||
|
||||
tasklet_disable(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_disable(&dev->mt76.tx_worker);
|
||||
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
|
||||
napi_disable(&dev->mt76.napi[0]);
|
||||
napi_disable(&dev->mt76.napi[1]);
|
||||
|
|
@ -1452,7 +1451,7 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
|
|||
clear_bit(MT76_RESET, &dev->mphy.state);
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
tasklet_enable(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_enable(&dev->mt76.tx_worker);
|
||||
napi_enable(&dev->mt76.tx_napi);
|
||||
napi_schedule(&dev->mt76.tx_napi);
|
||||
|
||||
|
|
@ -1515,7 +1514,7 @@ static bool mt7603_tx_hang(struct mt7603_dev *dev)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
q = dev->mt76.q_tx[i].q;
|
||||
q = dev->mt76.q_tx[i];
|
||||
|
||||
if (!q->queued)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
|
||||
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
|
||||
mtxq->wcid = &mvif->sta.wcid;
|
||||
mt76_txq_init(&dev->mt76, vif->txq);
|
||||
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
|
||||
|
||||
out:
|
||||
|
|
@ -99,7 +98,6 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
mt7603_beacon_set_timer(dev, mvif->idx, 0);
|
||||
|
||||
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
|
||||
mt76_txq_remove(&dev->mt76, vif->txq);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
|
|
@ -514,7 +512,7 @@ mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
|
|||
u16 cw_max = (1 << 10) - 1;
|
||||
u32 val;
|
||||
|
||||
queue = dev->mt76.q_tx[queue].q->hw_idx;
|
||||
queue = dev->mt76.q_tx[queue]->hw_idx;
|
||||
|
||||
if (params->cw_min)
|
||||
cw_min = params->cw_min;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#define MT7603_MCU_RX_RING_SIZE 64
|
||||
#define MT7603_RX_RING_SIZE 128
|
||||
#define MT7603_TX_RING_SIZE 256
|
||||
#define MT7603_PSD_RING_SIZE 128
|
||||
|
||||
#define MT7603_FIRMWARE_E1 "mt7603_e1.bin"
|
||||
#define MT7603_FIRMWARE_E2 "mt7603_e2.bin"
|
||||
|
|
@ -241,8 +243,7 @@ int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
struct ieee80211_sta *sta,
|
||||
struct mt76_tx_info *tx_info);
|
||||
|
||||
void mt7603_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e);
|
||||
void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
|
||||
|
||||
void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
(mt76_rr(dev, MT_HW_REV) & 0xff);
|
||||
dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
ret = devm_request_irq(mdev->dev, pdev->irq, mt7603_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ mt76_wmac_probe(struct platform_device *pdev)
|
|||
(mt76_rr(dev, MT_HW_REV) & 0xff);
|
||||
dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
ret = devm_request_irq(mdev->dev, irq, mt7603_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -165,15 +165,14 @@ mt7615_reset_test_set(void *data, u64 val)
|
|||
if (!mt7615_wait_for_mcu_init(dev))
|
||||
return 0;
|
||||
|
||||
mt7615_mutex_acquire(dev);
|
||||
|
||||
skb = alloc_skb(1, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, 1);
|
||||
mt76_tx_queue_skb_raw(dev, 0, skb, 0);
|
||||
|
||||
mt7615_mutex_acquire(dev);
|
||||
mt76_tx_queue_skb_raw(dev, 0, skb, 0);
|
||||
mt7615_mutex_release(dev);
|
||||
|
||||
return 0;
|
||||
|
|
@ -221,7 +220,7 @@ mt7615_ampdu_stat_read_phy(struct mt7615_phy *phy,
|
|||
}
|
||||
|
||||
static int
|
||||
mt7615_ampdu_stat_read(struct seq_file *file, void *data)
|
||||
mt7615_ampdu_stat_show(struct seq_file *file, void *data)
|
||||
{
|
||||
struct mt7615_dev *dev = file->private;
|
||||
|
||||
|
|
@ -235,18 +234,7 @@ mt7615_ampdu_stat_read(struct seq_file *file, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7615_ampdu_stat_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return single_open(f, mt7615_ampdu_stat_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ampdu_stat = {
|
||||
.open = mt7615_ampdu_stat_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(mt7615_ampdu_stat);
|
||||
|
||||
static void
|
||||
mt7615_radio_read_phy(struct mt7615_phy *phy, struct seq_file *s)
|
||||
|
|
@ -340,15 +328,15 @@ mt7615_queues_read(struct seq_file *s, void *data)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
|
||||
struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id];
|
||||
struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
|
||||
|
||||
if (!q->q)
|
||||
if (!q)
|
||||
continue;
|
||||
|
||||
seq_printf(s,
|
||||
"%s: queued=%d head=%d tail=%d\n",
|
||||
queue_map[i].queue, q->q->queued, q->q->head,
|
||||
q->q->tail);
|
||||
queue_map[i].queue, q->queued, q->head,
|
||||
q->tail);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -393,7 +381,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
|
|||
mt76_queues_read);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
|
||||
mt7615_queues_acq);
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev, &mt7615_ampdu_stat_fops);
|
||||
debugfs_create_file("scs", 0600, dir, dev, &fops_scs);
|
||||
debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc);
|
||||
debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@
|
|||
#include "mac.h"
|
||||
|
||||
static int
|
||||
mt7615_init_tx_queue(struct mt7615_dev *dev, struct mt76_sw_queue *q,
|
||||
int idx, int n_desc)
|
||||
mt7615_init_tx_queue(struct mt7615_dev *dev, int qid, int idx, int n_desc)
|
||||
{
|
||||
struct mt76_queue *hwq;
|
||||
int err;
|
||||
|
|
@ -26,8 +25,7 @@ mt7615_init_tx_queue(struct mt7615_dev *dev, struct mt76_sw_queue *q,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
INIT_LIST_HEAD(&q->swq);
|
||||
q->q = hwq;
|
||||
dev->mt76.q_tx[qid] = hwq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -45,19 +43,18 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
|
||||
ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[i],
|
||||
wmm_queue_map[i],
|
||||
ret = mt7615_init_tx_queue(dev, i, wmm_queue_map[i],
|
||||
MT7615_TX_RING_SIZE / 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
|
||||
ret = mt7615_init_tx_queue(dev, MT_TXQ_PSD,
|
||||
MT7622_TXQ_MGMT, MT7615_TX_MGMT_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
|
||||
ret = mt7615_init_tx_queue(dev, MT_TXQ_MCU,
|
||||
MT7622_TXQ_MCU, MT7615_TX_MCU_RING_SIZE);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -65,10 +62,9 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
|
|||
static int
|
||||
mt7615_init_tx_queues(struct mt7615_dev *dev)
|
||||
{
|
||||
struct mt76_sw_queue *q;
|
||||
int ret, i;
|
||||
|
||||
ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL],
|
||||
ret = mt7615_init_tx_queue(dev, MT_TXQ_FWDL,
|
||||
MT7615_TXQ_FWDL,
|
||||
MT7615_TX_FWDL_RING_SIZE);
|
||||
if (ret)
|
||||
|
|
@ -77,52 +73,28 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
|
|||
if (!is_mt7615(&dev->mt76))
|
||||
return mt7622_init_tx_queues_multi(dev);
|
||||
|
||||
ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[0], 0,
|
||||
MT7615_TX_RING_SIZE);
|
||||
ret = mt7615_init_tx_queue(dev, 0, 0, MT7615_TX_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 1; i < MT_TXQ_MCU; i++) {
|
||||
q = &dev->mt76.q_tx[i];
|
||||
INIT_LIST_HEAD(&q->swq);
|
||||
q->q = dev->mt76.q_tx[0].q;
|
||||
}
|
||||
for (i = 1; i < MT_TXQ_MCU; i++)
|
||||
dev->mt76.q_tx[i] = dev->mt76.q_tx[0];
|
||||
|
||||
ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
|
||||
MT7615_TXQ_MCU,
|
||||
ret = mt7615_init_tx_queue(dev, MT_TXQ_MCU, MT7615_TXQ_MCU,
|
||||
MT7615_TX_MCU_RING_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7615_tx_cleanup(struct mt7615_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
|
||||
if (is_mt7615(&dev->mt76)) {
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
|
||||
} else {
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++)
|
||||
mt76_queue_tx_cleanup(dev, i, false);
|
||||
}
|
||||
}
|
||||
|
||||
static int mt7615_poll_tx(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct mt7615_dev *dev;
|
||||
|
||||
dev = container_of(napi, struct mt7615_dev, mt76.tx_napi);
|
||||
|
||||
mt7615_tx_cleanup(dev);
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
|
||||
|
||||
if (napi_complete_done(napi, 0))
|
||||
mt7615_irq_enable(dev, MT_INT_TX_DONE_ALL);
|
||||
|
||||
mt7615_tx_cleanup(dev);
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -306,7 +278,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
|
|||
MT_WPDMA_GLO_CFG_RX_DMA_EN);
|
||||
|
||||
/* enable interrupts for TX/RX rings */
|
||||
mt7615_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
|
||||
mt7615_irq_enable(dev, MT_INT_RX_DONE_ALL | mt7615_tx_mcu_int_mask(dev) |
|
||||
MT_INT_MCU_CMD);
|
||||
|
||||
if (is_mt7622(&dev->mt76))
|
||||
|
|
@ -325,6 +297,5 @@ void mt7615_dma_cleanup(struct mt7615_dev *dev)
|
|||
MT_WPDMA_GLO_CFG_RX_DMA_EN);
|
||||
mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET);
|
||||
|
||||
tasklet_kill(&dev->mt76.tx_tasklet);
|
||||
mt76_dma_cleanup(&dev->mt76);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
|
|||
case MT_EE_2GHZ:
|
||||
dev->mt76.cap.has_2ghz = true;
|
||||
break;
|
||||
case MT_EE_DBDC:
|
||||
dev->dbdc_support = true;
|
||||
/* fall through */
|
||||
default:
|
||||
dev->mt76.cap.has_2ghz = true;
|
||||
dev->mt76.cap.has_5ghz = true;
|
||||
|
|
|
|||
|
|
@ -217,6 +217,22 @@ static const struct ieee80211_iface_limit if_limits[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination if_comb_radar[] = {
|
||||
{
|
||||
.limits = if_limits,
|
||||
.n_limits = ARRAY_SIZE(if_limits),
|
||||
.max_interfaces = 4,
|
||||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = true,
|
||||
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
||||
BIT(NL80211_CHAN_WIDTH_20) |
|
||||
BIT(NL80211_CHAN_WIDTH_40) |
|
||||
BIT(NL80211_CHAN_WIDTH_80) |
|
||||
BIT(NL80211_CHAN_WIDTH_160) |
|
||||
BIT(NL80211_CHAN_WIDTH_80P80),
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination if_comb[] = {
|
||||
{
|
||||
.limits = if_limits,
|
||||
|
|
@ -306,8 +322,13 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
|
|||
hw->sta_data_size = sizeof(struct mt7615_sta);
|
||||
hw->vif_data_size = sizeof(struct mt7615_vif);
|
||||
|
||||
wiphy->iface_combinations = if_comb;
|
||||
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
||||
if (is_mt7663(&phy->dev->mt76)) {
|
||||
wiphy->iface_combinations = if_comb;
|
||||
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
||||
} else {
|
||||
wiphy->iface_combinations = if_comb_radar;
|
||||
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_radar);
|
||||
}
|
||||
wiphy->reg_notifier = mt7615_regd_notifier;
|
||||
|
||||
wiphy->max_sched_scan_plan_interval = MT7615_MAX_SCHED_SCAN_INTERVAL;
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
|
|||
switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
|
||||
case MT_PHY_TYPE_CCK:
|
||||
cck = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_OFDM:
|
||||
i = mt76_get_rate(&dev->mt76, sband, i, cck);
|
||||
break;
|
||||
|
|
@ -1271,7 +1271,7 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
|
|||
switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
|
||||
case MT_PHY_TYPE_CCK:
|
||||
cck = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_OFDM:
|
||||
mphy = &dev->mphy;
|
||||
if (sta->wcid.ext_phy && dev->mt76.phy2)
|
||||
|
|
@ -1400,6 +1400,9 @@ mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
|
|||
{
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct mt76_txwi_cache *txwi;
|
||||
__le32 *txwi_data;
|
||||
u32 val;
|
||||
u8 wcid;
|
||||
|
||||
trace_mac_tx_free(dev, token);
|
||||
|
||||
|
|
@ -1410,9 +1413,13 @@ mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
|
|||
if (!txwi)
|
||||
return;
|
||||
|
||||
txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
|
||||
val = le32_to_cpu(txwi_data[1]);
|
||||
wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
|
||||
|
||||
mt7615_txp_skb_unmap(mdev, txwi);
|
||||
if (txwi->skb) {
|
||||
mt76_tx_complete_skb(mdev, txwi->skb);
|
||||
mt76_tx_complete_skb(mdev, wcid, txwi->skb);
|
||||
txwi->skb = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1424,6 +1431,14 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
|
|||
struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data;
|
||||
u8 i, count;
|
||||
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
|
||||
if (is_mt7615(&dev->mt76)) {
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
|
||||
} else {
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++)
|
||||
mt76_queue_tx_cleanup(dev, i, false);
|
||||
}
|
||||
|
||||
count = FIELD_GET(MT_TX_FREE_MSDU_ID_CNT, le16_to_cpu(free->ctrl));
|
||||
if (is_mt7615(&dev->mt76)) {
|
||||
__le16 *token = &free->token[0];
|
||||
|
|
@ -1439,11 +1454,15 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
|
|||
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
mt7615_mac_sta_poll(dev);
|
||||
rcu_read_unlock();
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
mt7615_pm_power_save_sched(dev);
|
||||
mt76_worker_schedule(&dev->mt76.tx_worker);
|
||||
}
|
||||
|
||||
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
|
|
@ -1478,7 +1497,7 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
|||
mt76_rx(&dev->mt76, q, skb);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
|
|
@ -1845,7 +1864,7 @@ void mt7615_pm_wake_work(struct work_struct *work)
|
|||
pm.wake_work);
|
||||
mphy = dev->phy.mt76;
|
||||
|
||||
if (mt7615_driver_own(dev)) {
|
||||
if (mt7615_mcu_set_drv_ctrl(dev)) {
|
||||
dev_err(mphy->dev->dev, "failed to wake device\n");
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1853,12 +1872,13 @@ void mt7615_pm_wake_work(struct work_struct *work)
|
|||
spin_lock_bh(&dev->pm.txq_lock);
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
struct mt7615_sta *msta = dev->pm.tx_q[i].msta;
|
||||
struct mt76_wcid *wcid = msta ? &msta->wcid : NULL;
|
||||
struct ieee80211_sta *sta = NULL;
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
if (!dev->pm.tx_q[i].skb)
|
||||
continue;
|
||||
|
||||
wcid = msta ? &msta->wcid : &dev->mt76.global_wcid;
|
||||
if (msta && wcid->sta)
|
||||
sta = container_of((void *)msta, struct ieee80211_sta,
|
||||
drv_priv);
|
||||
|
|
@ -1868,7 +1888,7 @@ void mt7615_pm_wake_work(struct work_struct *work)
|
|||
}
|
||||
spin_unlock_bh(&dev->pm.txq_lock);
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_schedule(&dev->mt76.tx_worker);
|
||||
|
||||
out:
|
||||
ieee80211_wake_queues(mphy->hw);
|
||||
|
|
@ -1943,7 +1963,7 @@ void mt7615_pm_power_save_work(struct work_struct *work)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!mt7615_firmware_own(dev))
|
||||
if (!mt7615_mcu_set_fw_ctrl(dev))
|
||||
return;
|
||||
out:
|
||||
queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
|
||||
|
|
@ -2110,7 +2130,7 @@ void mt7615_mac_reset_work(struct work_struct *work)
|
|||
if (ext_phy)
|
||||
mt76_txq_schedule_all(ext_phy);
|
||||
|
||||
tasklet_disable(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_disable(&dev->mt76.tx_worker);
|
||||
napi_disable(&dev->mt76.napi[0]);
|
||||
napi_disable(&dev->mt76.napi[1]);
|
||||
napi_disable(&dev->mt76.tx_napi);
|
||||
|
|
@ -2131,7 +2151,7 @@ void mt7615_mac_reset_work(struct work_struct *work)
|
|||
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
|
||||
clear_bit(MT76_RESET, &dev->mphy.state);
|
||||
|
||||
tasklet_enable(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_enable(&dev->mt76.tx_worker);
|
||||
napi_enable(&dev->mt76.tx_napi);
|
||||
napi_schedule(&dev->mt76.tx_napi);
|
||||
|
||||
|
|
|
|||
|
|
@ -205,7 +205,6 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
|
|||
if (vif->txq) {
|
||||
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
|
||||
mtxq->wcid = &mvif->sta.wcid;
|
||||
mt76_txq_init(&dev->mt76, vif->txq);
|
||||
}
|
||||
|
||||
ret = mt7615_mcu_add_dev_info(dev, vif, true);
|
||||
|
|
@ -256,8 +255,6 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
|
|||
mt7615_mcu_add_dev_info(dev, vif, false);
|
||||
|
||||
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
|
||||
if (vif->txq)
|
||||
mt76_txq_remove(&dev->mt76, vif->txq);
|
||||
|
||||
dev->mphy.vif_mask &= ~BIT(mvif->idx);
|
||||
dev->omac_mask &= ~BIT(mvif->omac_idx);
|
||||
|
|
@ -361,7 +358,10 @@ mt7615_queue_key_update(struct mt7615_dev *dev, enum set_key_cmd cmd,
|
|||
wd->key.keylen = key->keylen;
|
||||
wd->key.cmd = cmd;
|
||||
|
||||
spin_lock_bh(&dev->mt76.lock);
|
||||
list_add_tail(&wd->node, &dev->wd_head);
|
||||
spin_unlock_bh(&dev->mt76.lock);
|
||||
|
||||
queue_work(dev->mt76.wq, &dev->wtbl_work);
|
||||
|
||||
return 0;
|
||||
|
|
@ -703,7 +703,8 @@ mt7615_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
|
|||
return;
|
||||
}
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
dev->pm.last_activity = jiffies;
|
||||
mt76_worker_schedule(&dev->mt76.tx_worker);
|
||||
}
|
||||
|
||||
static void mt7615_tx(struct ieee80211_hw *hw,
|
||||
|
|
@ -732,6 +733,7 @@ static void mt7615_tx(struct ieee80211_hw *hw,
|
|||
}
|
||||
|
||||
if (!test_bit(MT76_STATE_PM, &mphy->state)) {
|
||||
dev->pm.last_activity = jiffies;
|
||||
mt76_tx(mphy, control->sta, wcid, skb);
|
||||
return;
|
||||
}
|
||||
|
|
@ -813,7 +815,6 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
case IEEE80211_AMPDU_TX_START:
|
||||
ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid);
|
||||
params->ssn = ssn;
|
||||
mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
|
||||
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_CONT:
|
||||
|
|
|
|||
|
|
@ -324,6 +324,97 @@ int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)
|
|||
sizeof(req), false);
|
||||
}
|
||||
|
||||
static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
|
||||
{
|
||||
if (!is_mt7622(&dev->mt76))
|
||||
return;
|
||||
|
||||
regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC,
|
||||
MT_INFRACFG_MISC_AP2CONN_WAKE,
|
||||
!en * MT_INFRACFG_MISC_AP2CONN_WAKE);
|
||||
}
|
||||
|
||||
static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
|
||||
{
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
u32 addr;
|
||||
int err;
|
||||
|
||||
addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST;
|
||||
mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
|
||||
|
||||
mt7622_trigger_hif_int(dev, true);
|
||||
|
||||
addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
|
||||
err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
|
||||
|
||||
mt7622_trigger_hif_int(dev, false);
|
||||
|
||||
if (err) {
|
||||
dev_err(mdev->dev, "driver own failed\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
clear_bit(MT76_STATE_PM, &mphy->state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
|
||||
{
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
int i;
|
||||
|
||||
if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
|
||||
mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
|
||||
if (mt76_poll_msec(dev, MT_CONN_HIF_ON_LPCTL,
|
||||
MT_CFG_LPCR_HOST_FW_OWN, 0, 50))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == MT7615_DRV_OWN_RETRY_COUNT) {
|
||||
dev_err(dev->mt76.dev, "driver own failed\n");
|
||||
set_bit(MT76_STATE_PM, &mphy->state);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
dev->pm.last_activity = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
|
||||
{
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
int err = 0;
|
||||
u32 addr;
|
||||
|
||||
if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
|
||||
return 0;
|
||||
|
||||
mt7622_trigger_hif_int(dev, true);
|
||||
|
||||
addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
|
||||
mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
|
||||
|
||||
if (is_mt7622(&dev->mt76) &&
|
||||
!mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN,
|
||||
MT_CFG_LPCR_HOST_FW_OWN, 3000)) {
|
||||
dev_err(dev->mt76.dev, "Timeout for firmware own\n");
|
||||
clear_bit(MT76_STATE_PM, &mphy->state);
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
mt7622_trigger_hif_int(dev, false);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
|
|
@ -1106,7 +1197,7 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
|
|||
tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht),
|
||||
wtbl_tlv, sta_wtbl);
|
||||
ht = (struct wtbl_ht *)tlv;
|
||||
ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING;
|
||||
ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING);
|
||||
ht->af = sta->ht_cap.ampdu_factor;
|
||||
ht->mm = sta->ht_cap.ampdu_density;
|
||||
ht->ht = 1;
|
||||
|
|
@ -1124,7 +1215,7 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
|
|||
tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht),
|
||||
wtbl_tlv, sta_wtbl);
|
||||
vht = (struct wtbl_vht *)tlv;
|
||||
vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC,
|
||||
vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
|
||||
vht->vht = 1;
|
||||
|
||||
af = (sta->vht_cap.cap &
|
||||
|
|
@ -1314,6 +1405,8 @@ static const struct mt7615_mcu_ops wtbl_update_ops = {
|
|||
.add_tx_ba = mt7615_mcu_wtbl_tx_ba,
|
||||
.add_rx_ba = mt7615_mcu_wtbl_rx_ba,
|
||||
.sta_add = mt7615_mcu_wtbl_sta_add,
|
||||
.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
|
||||
.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
@ -1410,6 +1503,8 @@ static const struct mt7615_mcu_ops sta_update_ops = {
|
|||
.add_tx_ba = mt7615_mcu_sta_tx_ba,
|
||||
.add_rx_ba = mt7615_mcu_sta_rx_ba,
|
||||
.sta_add = mt7615_mcu_add_sta,
|
||||
.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
|
||||
.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
@ -1823,6 +1918,8 @@ static const struct mt7615_mcu_ops uni_update_ops = {
|
|||
.add_tx_ba = mt7615_mcu_uni_tx_ba,
|
||||
.add_rx_ba = mt7615_mcu_uni_rx_ba,
|
||||
.sta_add = mt7615_mcu_uni_add_sta,
|
||||
.set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl,
|
||||
.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
|
||||
};
|
||||
|
||||
static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data,
|
||||
|
|
@ -1895,81 +1992,6 @@ static int mt7615_mcu_start_patch(struct mt7615_dev *dev)
|
|||
&req, sizeof(req), true);
|
||||
}
|
||||
|
||||
static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
|
||||
{
|
||||
if (!is_mt7622(&dev->mt76))
|
||||
return;
|
||||
|
||||
regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC,
|
||||
MT_INFRACFG_MISC_AP2CONN_WAKE,
|
||||
!en * MT_INFRACFG_MISC_AP2CONN_WAKE);
|
||||
}
|
||||
|
||||
int mt7615_driver_own(struct mt7615_dev *dev)
|
||||
{
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
int i;
|
||||
|
||||
if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state))
|
||||
goto out;
|
||||
|
||||
mt7622_trigger_hif_int(dev, true);
|
||||
|
||||
for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
|
||||
u32 addr;
|
||||
|
||||
addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST;
|
||||
mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
|
||||
|
||||
addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
|
||||
if (mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 50))
|
||||
break;
|
||||
}
|
||||
|
||||
mt7622_trigger_hif_int(dev, false);
|
||||
|
||||
if (i == MT7615_DRV_OWN_RETRY_COUNT) {
|
||||
dev_err(mdev->dev, "driver own failed\n");
|
||||
set_bit(MT76_STATE_PM, &mphy->state);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
dev->pm.last_activity = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_driver_own);
|
||||
|
||||
int mt7615_firmware_own(struct mt7615_dev *dev)
|
||||
{
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
int err = 0;
|
||||
u32 addr;
|
||||
|
||||
if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
|
||||
return 0;
|
||||
|
||||
mt7622_trigger_hif_int(dev, true);
|
||||
|
||||
addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
|
||||
mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
|
||||
|
||||
if (is_mt7622(&dev->mt76) &&
|
||||
!mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN,
|
||||
MT_CFG_LPCR_HOST_FW_OWN, 300)) {
|
||||
dev_err(dev->mt76.dev, "Timeout for firmware own\n");
|
||||
clear_bit(MT76_STATE_PM, &mphy->state);
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
mt7622_trigger_hif_int(dev, false);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_firmware_own);
|
||||
|
||||
static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
|
||||
{
|
||||
const struct mt7615_patch_hdr *hdr;
|
||||
|
|
@ -2451,7 +2473,7 @@ int mt7615_mcu_init(struct mt7615_dev *dev)
|
|||
|
||||
dev->mt76.mcu_ops = &mt7615_mcu_ops,
|
||||
|
||||
ret = mt7615_driver_own(dev);
|
||||
ret = mt7615_mcu_drv_pmctrl(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -2481,7 +2503,7 @@ EXPORT_SYMBOL_GPL(mt7615_mcu_init);
|
|||
void mt7615_mcu_exit(struct mt7615_dev *dev)
|
||||
{
|
||||
__mt76_mcu_restart(&dev->mt76);
|
||||
mt7615_firmware_own(dev);
|
||||
mt7615_mcu_set_fw_ctrl(dev);
|
||||
skb_queue_purge(&dev->mt76.mcu.res_q);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_mcu_exit);
|
||||
|
|
@ -2846,14 +2868,6 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
|
|||
.center_chan2 = ieee80211_frequency_to_channel(freq2),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
if (dev->mt76.test.state == MT76_TM_STATE_TX_FRAMES &&
|
||||
dev->mt76.test.tx_antenna_mask) {
|
||||
req.tx_streams = hweight8(dev->mt76.test.tx_antenna_mask);
|
||||
req.rx_streams_mask = dev->mt76.test.tx_antenna_mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
||||
req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
|
||||
else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
|
||||
|
|
@ -3278,7 +3292,7 @@ static int mt7615_dcoc_freq_idx(u16 freq, u8 bw)
|
|||
freq = freq_bw40[idx];
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
|
||||
freq);
|
||||
|
|
|
|||
|
|
@ -101,30 +101,29 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
|
|||
static void mt7615_irq_tasklet(unsigned long data)
|
||||
{
|
||||
struct mt7615_dev *dev = (struct mt7615_dev *)data;
|
||||
u32 intr, mask = 0;
|
||||
u32 intr, mask = 0, tx_mcu_mask = mt7615_tx_mcu_int_mask(dev);
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
|
||||
intr &= dev->mt76.mmio.irqmask;
|
||||
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
|
||||
|
||||
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
|
||||
intr &= dev->mt76.mmio.irqmask;
|
||||
|
||||
if (intr & MT_INT_TX_DONE_ALL) {
|
||||
mask |= MT_INT_TX_DONE_ALL;
|
||||
mask |= intr & MT_INT_RX_DONE_ALL;
|
||||
if (intr & tx_mcu_mask)
|
||||
mask |= tx_mcu_mask;
|
||||
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
|
||||
|
||||
if (intr & tx_mcu_mask)
|
||||
napi_schedule(&dev->mt76.tx_napi);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE(0)) {
|
||||
mask |= 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)) {
|
||||
mask |= MT_INT_RX_DONE(1);
|
||||
if (intr & MT_INT_RX_DONE(1))
|
||||
napi_schedule(&dev->mt76.napi[1]);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_MCU_CMD) {
|
||||
u32 val = mt76_rr(dev, MT_MCU_CMD);
|
||||
|
|
@ -135,8 +134,6 @@ static void mt7615_irq_tasklet(unsigned long data)
|
|||
wake_up(&dev->reset_wait);
|
||||
}
|
||||
}
|
||||
|
||||
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
|
||||
}
|
||||
|
||||
static u32 __mt7615_reg_addr(struct mt7615_dev *dev, u32 addr)
|
||||
|
|
@ -227,6 +224,8 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
|
|||
bus_ops->rmw = mt7615_rmw;
|
||||
dev->mt76.bus = bus_ops;
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
ret = devm_request_irq(mdev->dev, irq, mt7615_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -220,6 +220,8 @@ struct mt7615_phy {
|
|||
#define mt7615_mcu_add_bss_info(phy, ...) (phy->dev)->mcu_ops->add_bss_info((phy), __VA_ARGS__)
|
||||
#define mt7615_mcu_add_beacon(dev, ...) (dev)->mcu_ops->add_beacon_offload((dev), __VA_ARGS__)
|
||||
#define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__)
|
||||
#define mt7615_mcu_set_drv_ctrl(dev) (dev)->mcu_ops->set_drv_ctrl((dev))
|
||||
#define mt7615_mcu_set_fw_ctrl(dev) (dev)->mcu_ops->set_fw_ctrl((dev))
|
||||
struct mt7615_mcu_ops {
|
||||
int (*add_tx_ba)(struct mt7615_dev *dev,
|
||||
struct ieee80211_ampdu_params *params,
|
||||
|
|
@ -238,6 +240,8 @@ struct mt7615_mcu_ops {
|
|||
struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, bool enable);
|
||||
int (*set_pm_state)(struct mt7615_dev *dev, int band, int state);
|
||||
int (*set_drv_ctrl)(struct mt7615_dev *dev);
|
||||
int (*set_fw_ctrl)(struct mt7615_dev *dev);
|
||||
};
|
||||
|
||||
struct mt7615_dev {
|
||||
|
|
@ -278,6 +282,7 @@ struct mt7615_dev {
|
|||
|
||||
bool fw_debug;
|
||||
bool flash_eeprom;
|
||||
bool dbdc_support;
|
||||
|
||||
spinlock_t token_lock;
|
||||
struct idr token;
|
||||
|
|
@ -535,6 +540,11 @@ static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac)
|
|||
return lmac_queue_map[ac];
|
||||
}
|
||||
|
||||
static inline u32 mt7615_tx_mcu_int_mask(struct mt7615_dev *dev)
|
||||
{
|
||||
return MT_INT_TX_DONE(dev->mt76.q_tx[MT_TXQ_MCU]->hw_idx);
|
||||
}
|
||||
|
||||
void mt7615_dma_reset(struct mt7615_dev *dev);
|
||||
void mt7615_scan_work(struct work_struct *work);
|
||||
void mt7615_roc_work(struct work_struct *work);
|
||||
|
|
@ -608,8 +618,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
struct ieee80211_sta *sta,
|
||||
struct mt76_tx_info *tx_info);
|
||||
|
||||
void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e);
|
||||
void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
|
||||
|
||||
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb);
|
||||
|
|
@ -638,8 +647,6 @@ int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif);
|
||||
int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *chan, int duration);
|
||||
int mt7615_firmware_own(struct mt7615_dev *dev);
|
||||
int mt7615_driver_own(struct mt7615_dev *dev);
|
||||
|
||||
int mt7615_init_debugfs(struct mt7615_dev *dev);
|
||||
int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq);
|
||||
|
|
@ -666,7 +673,6 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
struct mt76_tx_info *tx_info);
|
||||
bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update);
|
||||
void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
|
||||
enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e);
|
||||
void mt7663_usb_sdio_wtbl_work(struct work_struct *work);
|
||||
int mt7663_usb_sdio_register_device(struct mt7615_dev *dev);
|
||||
|
|
@ -675,9 +681,8 @@ int mt7663u_mcu_init(struct mt7615_dev *dev);
|
|||
/* sdio */
|
||||
u32 mt7663s_read_pcr(struct mt7615_dev *dev);
|
||||
int mt7663s_mcu_init(struct mt7615_dev *dev);
|
||||
int mt7663s_driver_own(struct mt7615_dev *dev);
|
||||
int mt7663s_firmware_own(struct mt7615_dev *dev);
|
||||
int mt7663s_kthread_run(void *data);
|
||||
void mt7663s_tx_work(struct work_struct *work);
|
||||
void mt7663s_rx_work(struct work_struct *work);
|
||||
void mt7663s_sdio_irq(struct sdio_func *func);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
}
|
||||
|
||||
napi_disable(&mdev->tx_napi);
|
||||
tasklet_kill(&mdev->tx_tasklet);
|
||||
mt76_worker_disable(&mdev->tx_worker);
|
||||
|
||||
mt76_for_each_q_rx(mdev, i) {
|
||||
napi_disable(&mdev->napi[i]);
|
||||
|
|
@ -118,7 +118,7 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
if (err)
|
||||
goto restore;
|
||||
|
||||
err = mt7615_firmware_own(dev);
|
||||
err = mt7615_mcu_set_fw_ctrl(dev);
|
||||
if (err)
|
||||
goto restore;
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ static int mt7615_pci_resume(struct pci_dev *pdev)
|
|||
bool pdma_reset;
|
||||
int i, err;
|
||||
|
||||
err = mt7615_driver_own(dev);
|
||||
err = mt7615_mcu_set_drv_ctrl(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -162,6 +162,7 @@ static int mt7615_pci_resume(struct pci_dev *pdev)
|
|||
if (pdma_reset)
|
||||
dev_err(mdev->dev, "PDMA engine must be reinitialized\n");
|
||||
|
||||
mt76_worker_enable(&mdev->tx_worker);
|
||||
mt76_for_each_q_rx(mdev, i) {
|
||||
napi_enable(&mdev->napi[i]);
|
||||
napi_schedule(&mdev->napi[i]);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ static void mt7615_init_work(struct work_struct *work)
|
|||
mt7615_phy_init(dev);
|
||||
mt7615_mcu_del_wtbl_all(dev);
|
||||
mt7615_check_offload_capability(dev);
|
||||
|
||||
if (dev->dbdc_support)
|
||||
mt7615_register_ext_phy(dev);
|
||||
}
|
||||
|
||||
static int mt7615_init_hardware(struct mt7615_dev *dev)
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@
|
|||
#include "../dma.h"
|
||||
#include "mac.h"
|
||||
|
||||
void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e)
|
||||
void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
|
||||
{
|
||||
if (!e->txwi) {
|
||||
dev_kfree_skb_any(e->skb);
|
||||
|
|
@ -45,7 +44,7 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
|||
}
|
||||
|
||||
if (e->skb)
|
||||
mt76_tx_complete_skb(mdev, e->skb);
|
||||
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -107,6 +106,7 @@ mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info,
|
|||
/* pass partial skb header to fw */
|
||||
tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp);
|
||||
tx_info->buf[1].len = MT_CT_PARSE_LEN;
|
||||
tx_info->buf[1].skip_unmap = true;
|
||||
tx_info->nbuf = MT_CT_DMA_BUF_NUM;
|
||||
|
||||
txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD);
|
||||
|
|
|
|||
|
|
@ -575,7 +575,7 @@ enum mt7615_reg_base {
|
|||
#define MT_MCU_PTA_BASE 0x81060000
|
||||
#define MT_MCU_PTA(_n) (MT_MCU_PTA_BASE + (_n))
|
||||
|
||||
#define MT_ANT_SWITCH_CON(n) MT_MCU_PTA(0x0c8)
|
||||
#define MT_ANT_SWITCH_CON(_n) MT_MCU_PTA(0x0c8 + ((_n) - 1) * 4)
|
||||
#define MT_ANT_SWITCH_CON_MODE(_n) (GENMASK(4, 0) << (_n * 8))
|
||||
#define MT_ANT_SWITCH_CON_MODE1(_n) (GENMASK(3, 0) << (_n * 8))
|
||||
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ static int mt7663s_probe(struct sdio_func *func,
|
|||
{
|
||||
static const struct mt76_driver_ops drv_ops = {
|
||||
.txwi_size = MT_USB_TXD_SIZE,
|
||||
.drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ,
|
||||
.drv_flags = MT_DRV_RX_DMA_HDR,
|
||||
.tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb,
|
||||
.tx_complete_skb = mt7663_usb_sdio_tx_complete_skb,
|
||||
.tx_status_data = mt7663_usb_sdio_tx_status_data,
|
||||
|
|
@ -346,7 +346,7 @@ static int mt7663s_probe(struct sdio_func *func,
|
|||
struct ieee80211_ops *ops;
|
||||
struct mt7615_dev *dev;
|
||||
struct mt76_dev *mdev;
|
||||
int ret;
|
||||
int i, ret;
|
||||
|
||||
ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops),
|
||||
GFP_KERNEL);
|
||||
|
|
@ -364,23 +364,39 @@ static int mt7663s_probe(struct sdio_func *func,
|
|||
dev->ops = ops;
|
||||
sdio_set_drvdata(func, dev);
|
||||
|
||||
mdev->sdio.tx_kthread = kthread_create(mt7663s_kthread_run, dev,
|
||||
"mt7663s_tx");
|
||||
if (IS_ERR(mdev->sdio.tx_kthread))
|
||||
return PTR_ERR(mdev->sdio.tx_kthread);
|
||||
|
||||
ret = mt76s_init(mdev, func, &mt7663s_ops);
|
||||
if (ret < 0)
|
||||
goto err_free;
|
||||
|
||||
INIT_WORK(&mdev->sdio.tx.xmit_work, mt7663s_tx_work);
|
||||
INIT_WORK(&mdev->sdio.rx.recv_work, mt7663s_rx_work);
|
||||
|
||||
ret = mt7663s_hw_init(dev, func);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
goto err_deinit;
|
||||
|
||||
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
|
||||
(mt76_rr(dev, MT_HW_REV) & 0xff);
|
||||
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
|
||||
|
||||
mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
|
||||
sizeof(struct mt76s_intr),
|
||||
GFP_KERNEL);
|
||||
if (!mdev->sdio.intr_data) {
|
||||
ret = -ENOMEM;
|
||||
goto err_deinit;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mdev->sdio.xmit_buf); i++) {
|
||||
mdev->sdio.xmit_buf[i] = devm_kmalloc(mdev->dev,
|
||||
MT76S_XMIT_BUF_SZ,
|
||||
GFP_KERNEL);
|
||||
if (!mdev->sdio.xmit_buf[i]) {
|
||||
ret = -ENOMEM;
|
||||
goto err_deinit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = mt76s_alloc_queues(&dev->mt76);
|
||||
if (ret)
|
||||
goto err_deinit;
|
||||
|
|
@ -426,9 +442,11 @@ static int mt7663s_suspend(struct device *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
|
||||
|
||||
mt76s_stop_txrx(&mdev->mt76);
|
||||
|
||||
return mt7663s_firmware_own(mdev);
|
||||
return mt7615_mcu_set_fw_ctrl(mdev);
|
||||
}
|
||||
|
||||
static int mt7663s_resume(struct device *dev)
|
||||
|
|
@ -437,7 +455,7 @@ static int mt7663s_resume(struct device *dev)
|
|||
struct mt7615_dev *mdev = sdio_get_drvdata(func);
|
||||
int err;
|
||||
|
||||
err = mt7663s_driver_own(mdev);
|
||||
err = mt7615_mcu_set_drv_ctrl(mdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
mt76_queue_kick(dev, mdev->q_tx[MT_TXQ_MCU].q);
|
||||
mt76_queue_kick(dev, mdev->q_tx[MT_TXQ_MCU]);
|
||||
if (wait_resp)
|
||||
ret = mt7615_mcu_wait_response(dev, cmd, seq);
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int mt7663s_driver_own(struct mt7615_dev *dev)
|
||||
static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev)
|
||||
{
|
||||
struct sdio_func *func = dev->mt76.sdio.func;
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
|
|
@ -75,7 +75,7 @@ int mt7663s_driver_own(struct mt7615_dev *dev)
|
|||
|
||||
sdio_claim_host(func);
|
||||
|
||||
sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, 0);
|
||||
sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL);
|
||||
|
||||
ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
|
||||
status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
|
||||
|
|
@ -95,7 +95,7 @@ int mt7663s_driver_own(struct mt7615_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mt7663s_firmware_own(struct mt7615_dev *dev)
|
||||
static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev)
|
||||
{
|
||||
struct sdio_func *func = dev->mt76.sdio.func;
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
|
|
@ -107,7 +107,7 @@ int mt7663s_firmware_own(struct mt7615_dev *dev)
|
|||
|
||||
sdio_claim_host(func);
|
||||
|
||||
sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, 0);
|
||||
sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL);
|
||||
|
||||
ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
|
||||
!(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000);
|
||||
|
|
@ -132,9 +132,10 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
|
|||
.mcu_rr = mt7615_mcu_reg_rr,
|
||||
.mcu_wr = mt7615_mcu_reg_wr,
|
||||
};
|
||||
struct mt7615_mcu_ops *mcu_ops;
|
||||
int ret;
|
||||
|
||||
ret = mt7663s_driver_own(dev);
|
||||
ret = mt7663s_mcu_drv_pmctrl(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -152,6 +153,15 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
mcu_ops = devm_kmemdup(dev->mt76.dev, dev->mcu_ops, sizeof(*mcu_ops),
|
||||
GFP_KERNEL);
|
||||
if (!mcu_ops)
|
||||
return -ENOMEM;
|
||||
|
||||
mcu_ops->set_drv_ctrl = mt7663s_mcu_drv_pmctrl;
|
||||
mcu_ops->set_fw_ctrl = mt7663s_mcu_fw_pmctrl;
|
||||
dev->mcu_ops = mcu_ops;
|
||||
|
||||
ret = mt7663s_mcu_init_sched(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -19,21 +19,40 @@
|
|||
#include "sdio.h"
|
||||
#include "mac.h"
|
||||
|
||||
static void mt7663s_refill_sched_quota(struct mt7615_dev *dev, u32 *data)
|
||||
static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
|
||||
{
|
||||
struct mt76_sdio *sdio = &dev->mt76.sdio;
|
||||
u32 ple_ac_data_quota[] = {
|
||||
FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
|
||||
FIELD_GET(TXQ_CNT_H, data[3]), /* VI */
|
||||
FIELD_GET(TXQ_CNT_L, data[3]), /* BE */
|
||||
FIELD_GET(TXQ_CNT_H, data[2]), /* BK */
|
||||
};
|
||||
u32 pse_ac_data_quota[] = {
|
||||
FIELD_GET(TXQ_CNT_H, data[1]), /* VO */
|
||||
FIELD_GET(TXQ_CNT_L, data[1]), /* VI */
|
||||
FIELD_GET(TXQ_CNT_H, data[0]), /* BE */
|
||||
FIELD_GET(TXQ_CNT_L, data[0]), /* BK */
|
||||
};
|
||||
u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]);
|
||||
u32 pse_data_quota = 0, ple_data_quota = 0;
|
||||
struct mt76_sdio *sdio = &dev->sdio;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) {
|
||||
pse_data_quota += pse_ac_data_quota[i];
|
||||
ple_data_quota += ple_ac_data_quota[i];
|
||||
}
|
||||
|
||||
if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sdio->sched.lock);
|
||||
sdio->sched.pse_data_quota += FIELD_GET(TXQ_CNT_L, data[0]) + /* BK */
|
||||
FIELD_GET(TXQ_CNT_H, data[0]) + /* BE */
|
||||
FIELD_GET(TXQ_CNT_L, data[1]) + /* VI */
|
||||
FIELD_GET(TXQ_CNT_H, data[1]); /* VO */
|
||||
sdio->sched.ple_data_quota += FIELD_GET(TXQ_CNT_H, data[2]) + /* BK */
|
||||
FIELD_GET(TXQ_CNT_L, data[3]) + /* BE */
|
||||
FIELD_GET(TXQ_CNT_H, data[3]) + /* VI */
|
||||
FIELD_GET(TXQ_CNT_L, data[4]); /* VO */
|
||||
sdio->sched.pse_mcu_quota += FIELD_GET(TXQ_CNT_L, data[2]);
|
||||
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;
|
||||
}
|
||||
|
||||
static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len,
|
||||
|
|
@ -61,11 +80,11 @@ static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len,
|
|||
return skb;
|
||||
}
|
||||
|
||||
static int mt7663s_rx_run_queue(struct mt7615_dev *dev, enum mt76_rxq_id qid,
|
||||
static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
|
||||
struct mt76s_intr *intr)
|
||||
{
|
||||
struct mt76_queue *q = &dev->mt76.q_rx[qid];
|
||||
struct mt76_sdio *sdio = &dev->mt76.sdio;
|
||||
struct mt76_queue *q = &dev->q_rx[qid];
|
||||
struct mt76_sdio *sdio = &dev->sdio;
|
||||
int len = 0, err, i, order;
|
||||
struct page *page;
|
||||
u8 *buf;
|
||||
|
|
@ -86,15 +105,18 @@ static int mt7663s_rx_run_queue(struct mt7615_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->mt76.dev, "sdio read data failed:%d\n", err);
|
||||
dev_err(dev->dev, "sdio read data failed:%d\n", err);
|
||||
__free_pages(page, order);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < intr->rx.num[qid]; i++) {
|
||||
int index = (q->tail + i) % q->ndesc;
|
||||
int index = (q->head + i) % q->ndesc;
|
||||
struct mt76_queue_entry *e = &q->entry[index];
|
||||
|
||||
len = intr->rx.len[qid][i];
|
||||
|
|
@ -109,160 +131,198 @@ static int mt7663s_rx_run_queue(struct mt7615_dev *dev, enum mt76_rxq_id qid,
|
|||
__free_pages(page, order);
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
q->tail = (q->tail + i) % q->ndesc;
|
||||
q->head = (q->head + i) % q->ndesc;
|
||||
q->queued += i;
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
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)
|
||||
{
|
||||
int pse_sz;
|
||||
|
||||
pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
|
||||
|
||||
if (qid == MT_TXQ_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)
|
||||
return -EBUSY;
|
||||
|
||||
*ple_size = *ple_size + 1;
|
||||
}
|
||||
*pse_size = *pse_size + pse_sz;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
|
||||
int pse_size, int ple_size)
|
||||
{
|
||||
mutex_lock(&sdio->sched.lock);
|
||||
if (qid == MT_TXQ_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)
|
||||
{
|
||||
struct mt76_sdio *sdio = &dev->sdio;
|
||||
int err;
|
||||
|
||||
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_update_sched(struct mt7615_dev *dev,
|
||||
struct mt76_queue_entry *e,
|
||||
bool mcu)
|
||||
static int mt7663s_tx_run_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
|
||||
{
|
||||
struct mt76_sdio *sdio = &dev->mt76.sdio;
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int size, ret = -EBUSY;
|
||||
int err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
struct mt76_sdio *sdio = &dev->sdio;
|
||||
|
||||
size = DIV_ROUND_UP(e->buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
|
||||
|
||||
if (mcu) {
|
||||
if (!test_bit(MT76_STATE_MCU_RUNNING, &mphy->state))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sdio->sched.lock);
|
||||
if (sdio->sched.pse_mcu_quota > size) {
|
||||
sdio->sched.pse_mcu_quota -= size;
|
||||
ret = 0;
|
||||
}
|
||||
mutex_unlock(&sdio->sched.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdr = (struct ieee80211_hdr *)(e->skb->data + MT_USB_TXD_SIZE);
|
||||
if (ieee80211_is_ctl(hdr->frame_control))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sdio->sched.lock);
|
||||
if (sdio->sched.pse_data_quota > size &&
|
||||
sdio->sched.ple_data_quota > 0) {
|
||||
sdio->sched.pse_data_quota -= size;
|
||||
sdio->sched.ple_data_quota--;
|
||||
ret = 0;
|
||||
}
|
||||
mutex_unlock(&sdio->sched.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt7663s_tx_run_queue(struct mt7615_dev *dev, struct mt76_queue *q)
|
||||
{
|
||||
bool mcu = q == dev->mt76.q_tx[MT_TXQ_MCU].q;
|
||||
struct mt76_sdio *sdio = &dev->mt76.sdio;
|
||||
int nframes = 0;
|
||||
|
||||
while (q->first != q->tail) {
|
||||
while (q->first != q->head) {
|
||||
struct mt76_queue_entry *e = &q->entry[q->first];
|
||||
int err, len = e->skb->len;
|
||||
struct sk_buff *iter;
|
||||
|
||||
if (mt7663s_tx_update_sched(dev, e, mcu))
|
||||
if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
|
||||
__skb_put_zero(e->skb, 4);
|
||||
err = __mt7663s_xmit_queue(dev, e->skb->data,
|
||||
e->skb->len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (len + e->skb->len + 4 > MT76S_XMIT_BUF_SZ)
|
||||
break;
|
||||
|
||||
if (len > sdio->func->cur_blksize)
|
||||
len = roundup(len, sdio->func->cur_blksize);
|
||||
if (mt7663s_tx_pick_quota(sdio, qid, e->buf_sz, &pse_sz,
|
||||
&ple_sz))
|
||||
break;
|
||||
|
||||
/* TODO: skb_walk_frags and then write to SDIO port */
|
||||
err = sdio_writesb(sdio->func, MCR_WTDR1, e->skb->data, len);
|
||||
if (err) {
|
||||
dev_err(dev->mt76.dev, "sdio write failed: %d\n", err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
e->done = true;
|
||||
q->first = (q->first + 1) % q->ndesc;
|
||||
memcpy(sdio->xmit_buf[qid] + len, e->skb->data,
|
||||
skb_headlen(e->skb));
|
||||
len += skb_headlen(e->skb);
|
||||
nframes++;
|
||||
|
||||
skb_walk_frags(e->skb, iter) {
|
||||
memcpy(sdio->xmit_buf[qid] + len, iter->data,
|
||||
iter->len);
|
||||
len += iter->len;
|
||||
nframes++;
|
||||
}
|
||||
next:
|
||||
q->first = (q->first + 1) % q->ndesc;
|
||||
e->done = true;
|
||||
}
|
||||
|
||||
if (nframes) {
|
||||
memset(sdio->xmit_buf[qid] + len, 0, 4);
|
||||
err = __mt7663s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
mt7663s_tx_update_quota(sdio, qid, pse_sz, ple_sz);
|
||||
|
||||
return nframes;
|
||||
}
|
||||
|
||||
static int mt7663s_tx_run_queues(struct mt7615_dev *dev)
|
||||
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;
|
||||
|
||||
for (i = 0; i < MT_TXQ_MCU_WA; i++) {
|
||||
int ret;
|
||||
|
||||
ret = mt7663s_tx_run_queue(dev, dev->mt76.q_tx[i].q);
|
||||
ret = mt7663s_tx_run_queue(dev, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
nframes += ret;
|
||||
}
|
||||
if (nframes)
|
||||
queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
|
||||
|
||||
return nframes;
|
||||
queue_work(sdio->txrx_wq, &sdio->tx.status_work);
|
||||
}
|
||||
|
||||
int mt7663s_kthread_run(void *data)
|
||||
void mt7663s_rx_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7615_dev *dev = data;
|
||||
struct mt76_phy *mphy = &dev->mt76.phy;
|
||||
struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
|
||||
rx.recv_work);
|
||||
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
|
||||
struct mt76s_intr *intr = sdio->intr_data;
|
||||
int nframes = 0, ret;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
int 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);
|
||||
|
||||
cond_resched();
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
sdio_claim_host(dev->mt76.sdio.func);
|
||||
ret = mt7663s_tx_run_queues(dev);
|
||||
sdio_release_host(dev->mt76.sdio.func);
|
||||
trace_dev_irq(dev, intr->isr, 0);
|
||||
|
||||
if (ret <= 0 || !test_bit(MT76_STATE_RUNNING, &mphy->state)) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
} else {
|
||||
wake_up_process(dev->mt76.sdio.kthread);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
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);
|
||||
nframes += ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (mt7663s_refill_sched_quota(dev, intr->tx.wtqcr))
|
||||
queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void mt7663s_sdio_irq(struct sdio_func *func)
|
||||
{
|
||||
struct mt7615_dev *dev = sdio_get_drvdata(func);
|
||||
struct mt76_sdio *sdio = &dev->mt76.sdio;
|
||||
struct mt76s_intr intr;
|
||||
|
||||
/* disable interrupt */
|
||||
sdio_writel(func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, 0);
|
||||
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
|
||||
return;
|
||||
|
||||
do {
|
||||
sdio_readsb(func, &intr, MCR_WHISR, sizeof(struct mt76s_intr));
|
||||
trace_dev_irq(&dev->mt76, intr.isr, 0);
|
||||
|
||||
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
|
||||
goto out;
|
||||
|
||||
if (intr.isr & WHIER_RX0_DONE_INT_EN) {
|
||||
mt7663s_rx_run_queue(dev, 0, &intr);
|
||||
wake_up_process(sdio->kthread);
|
||||
}
|
||||
|
||||
if (intr.isr & WHIER_RX1_DONE_INT_EN) {
|
||||
mt7663s_rx_run_queue(dev, 1, &intr);
|
||||
wake_up_process(sdio->kthread);
|
||||
}
|
||||
|
||||
if (intr.isr & WHIER_TX_DONE_INT_EN) {
|
||||
mt7663s_refill_sched_quota(dev, intr.tx.wtqcr);
|
||||
mt7663s_tx_run_queues(dev);
|
||||
wake_up_process(sdio->kthread);
|
||||
}
|
||||
} while (intr.isr);
|
||||
out:
|
||||
/* enable interrupt */
|
||||
sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, 0);
|
||||
queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ mt7615_tm_set_tx_power(struct mt7615_phy *phy)
|
|||
if (dev->mt76.test.state != MT76_TM_STATE_OFF)
|
||||
tx_power = dev->mt76.test.tx_power;
|
||||
|
||||
len = sizeof(req_hdr) + MT7615_EE_MAX - MT_EE_NIC_CONF_0;
|
||||
len = MT7615_EE_MAX - MT_EE_NIC_CONF_0;
|
||||
skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
|
@ -80,13 +80,12 @@ mt7615_tm_set_tx_power(struct mt7615_phy *phy)
|
|||
|
||||
target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains;
|
||||
for (i = 0; i < target_chains; i++) {
|
||||
int index;
|
||||
|
||||
ret = mt7615_eeprom_get_target_power_index(dev, chandef->chan, i);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
index = ret - MT_EE_NIC_CONF_0;
|
||||
if (tx_power && tx_power[i])
|
||||
data[ret - MT_EE_NIC_CONF_0] = tx_power[i];
|
||||
}
|
||||
|
|
@ -191,7 +190,7 @@ mt7615_tm_set_tx_antenna(struct mt7615_dev *dev, bool en)
|
|||
for (i = 0; i < 4; i++) {
|
||||
mt76_rmw_field(dev, MT_WF_PHY_RFINTF3_0(i),
|
||||
MT_WF_PHY_RFINTF3_0_ANT,
|
||||
td->tx_antenna_mask & BIT(i) ? 0 : 0xa);
|
||||
(td->tx_antenna_mask & BIT(i)) ? 0 : 0xa);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -180,9 +180,7 @@ static int mt7663u_suspend(struct usb_interface *intf, pm_message_t state)
|
|||
}
|
||||
|
||||
mt76u_stop_rx(&dev->mt76);
|
||||
|
||||
mt76u_stop_tx(&dev->mt76);
|
||||
tasklet_kill(&dev->mt76.tx_tasklet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
|
|||
int cmd, bool wait_resp)
|
||||
{
|
||||
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
|
||||
int ret, seq, ep;
|
||||
int ret, seq, ep, len, pad;
|
||||
|
||||
mutex_lock(&mdev->mcu.mutex);
|
||||
|
||||
|
|
@ -28,8 +28,10 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
|
|||
else
|
||||
ep = MT_EP_OUT_AC_BE;
|
||||
|
||||
put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len)));
|
||||
ret = mt76_skb_adjust_pad(skb);
|
||||
len = skb->len;
|
||||
put_unaligned_le32(len, skb_push(skb, sizeof(len)));
|
||||
pad = round_up(skb->len, 4) + 4 - skb->len;
|
||||
ret = mt76_skb_adjust_pad(skb, pad);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,6 @@ bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)
|
|||
EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_status_data);
|
||||
|
||||
void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
|
||||
enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e)
|
||||
{
|
||||
unsigned int headroom = MT_USB_TXD_SIZE;
|
||||
|
|
@ -235,7 +234,7 @@ void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
|
|||
headroom += MT_USB_HDR_SIZE;
|
||||
skb_pull(e->skb, headroom);
|
||||
|
||||
mt76_tx_complete_skb(mdev, e->skb);
|
||||
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_complete_skb);
|
||||
|
||||
|
|
@ -248,6 +247,7 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
|
||||
struct sk_buff *skb = tx_info->skb;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int pad;
|
||||
|
||||
if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) &&
|
||||
!msta->rate_probe) {
|
||||
|
|
@ -259,10 +259,16 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
}
|
||||
|
||||
mt7663_usb_sdio_write_txwi(dev, wcid, qid, sta, skb);
|
||||
if (mt76_is_usb(mdev))
|
||||
put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len)));
|
||||
if (mt76_is_usb(mdev)) {
|
||||
u32 len = skb->len;
|
||||
|
||||
return mt76_skb_adjust_pad(skb);
|
||||
put_unaligned_le32(len, skb_push(skb, sizeof(len)));
|
||||
pad = round_up(skb->len, 4) + 4 - skb->len;
|
||||
} else {
|
||||
pad = round_up(skb->len, 4) - skb->len;
|
||||
}
|
||||
|
||||
return mt76_skb_adjust_pad(skb, pad);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_prepare_skb);
|
||||
|
||||
|
|
@ -359,14 +365,15 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/* check hw sg support in order to enable AMSDU */
|
||||
if (dev->mt76.usb.sg_en || mt76_is_sdio(&dev->mt76))
|
||||
hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM;
|
||||
else
|
||||
hw->max_tx_fragments = 1;
|
||||
hw->extra_tx_headroom += MT_USB_TXD_SIZE;
|
||||
if (mt76_is_usb(&dev->mt76))
|
||||
if (mt76_is_usb(&dev->mt76)) {
|
||||
hw->extra_tx_headroom += MT_USB_HDR_SIZE;
|
||||
/* check hw sg support in order to enable AMSDU */
|
||||
if (dev->mt76.usb.sg_en)
|
||||
hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM;
|
||||
else
|
||||
hw->max_tx_fragments = 1;
|
||||
}
|
||||
|
||||
err = mt76_register_device(&dev->mt76, true, mt7615_rates,
|
||||
ARRAY_SIZE(mt7615_rates));
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "eeprom.h"
|
||||
#include "mcu.h"
|
||||
#include "initvals.h"
|
||||
#include "initvals_init.h"
|
||||
#include "../mt76x02_phy.h"
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -11,139 +11,6 @@
|
|||
|
||||
#include "phy.h"
|
||||
|
||||
static const struct mt76_reg_pair common_mac_reg_table[] = {
|
||||
{ MT_BCN_OFFSET(0), 0xf8f0e8e0 },
|
||||
{ MT_BCN_OFFSET(1), 0x6f77d0c8 },
|
||||
{ MT_LEGACY_BASIC_RATE, 0x0000013f },
|
||||
{ MT_HT_BASIC_RATE, 0x00008003 },
|
||||
{ MT_MAC_SYS_CTRL, 0x00000000 },
|
||||
{ MT_RX_FILTR_CFG, 0x00017f97 },
|
||||
{ MT_BKOFF_SLOT_CFG, 0x00000209 },
|
||||
{ MT_TX_SW_CFG0, 0x00000000 },
|
||||
{ MT_TX_SW_CFG1, 0x00080606 },
|
||||
{ MT_TX_LINK_CFG, 0x00001020 },
|
||||
{ MT_TX_TIMEOUT_CFG, 0x000a2090 },
|
||||
{ MT_MAX_LEN_CFG, 0xa0fff | 0x00001000 },
|
||||
{ MT_LED_CFG, 0x7f031e46 },
|
||||
{ MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
|
||||
{ MT_PBF_RX_MAX_PCNT, 0x0000fe9f },
|
||||
{ MT_TX_RETRY_CFG, 0x47d01f0f },
|
||||
{ MT_AUTO_RSP_CFG, 0x00000013 },
|
||||
{ MT_CCK_PROT_CFG, 0x07f40003 },
|
||||
{ MT_OFDM_PROT_CFG, 0x07f42004 },
|
||||
{ MT_PBF_CFG, 0x00f40006 },
|
||||
{ MT_WPDMA_GLO_CFG, 0x00000030 },
|
||||
{ MT_GF20_PROT_CFG, 0x01742004 },
|
||||
{ MT_GF40_PROT_CFG, 0x03f42084 },
|
||||
{ MT_MM20_PROT_CFG, 0x01742004 },
|
||||
{ MT_MM40_PROT_CFG, 0x03f42084 },
|
||||
{ MT_TXOP_CTRL_CFG, 0x0000583f },
|
||||
{ MT_TX_RTS_CFG, 0x00ffff20 },
|
||||
{ MT_EXP_ACK_TIME, 0x002400ca },
|
||||
{ MT_TXOP_HLDR_ET, 0x00000002 },
|
||||
{ MT_XIFS_TIME_CFG, 0x33a41010 },
|
||||
{ MT_PWR_PIN_CFG, 0x00000000 },
|
||||
};
|
||||
|
||||
static const struct mt76_reg_pair mt76x0_mac_reg_table[] = {
|
||||
{ MT_IOCFG_6, 0xa0040080 },
|
||||
{ MT_PBF_SYS_CTRL, 0x00080c00 },
|
||||
{ MT_PBF_CFG, 0x77723c1f },
|
||||
{ MT_FCE_PSE_CTRL, 0x00000001 },
|
||||
{ MT_AMPDU_MAX_LEN_20M1S, 0xAAA99887 },
|
||||
{ MT_TX_SW_CFG0, 0x00000601 },
|
||||
{ MT_TX_SW_CFG1, 0x00040000 },
|
||||
{ MT_TX_SW_CFG2, 0x00000000 },
|
||||
{ 0xa44, 0x00000000 },
|
||||
{ MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
|
||||
{ MT_TSO_CTRL, 0x00000000 },
|
||||
{ MT_BB_PA_MODE_CFG1, 0x00500055 },
|
||||
{ MT_RF_PA_MODE_CFG1, 0x00500055 },
|
||||
{ MT_TX_ALC_CFG_0, 0x2F2F000C },
|
||||
{ MT_TX0_BB_GAIN_ATTEN, 0x00000000 },
|
||||
{ MT_TX_PWR_CFG_0, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_1, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_2, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_3, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_4, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_7, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_8, 0x0000003A },
|
||||
{ MT_TX_PWR_CFG_9, 0x0000003A },
|
||||
{ 0x150C, 0x00000002 },
|
||||
{ 0x1238, 0x001700C8 },
|
||||
{ MT_LDO_CTRL_0, 0x00A647B6 },
|
||||
{ MT_LDO_CTRL_1, 0x6B006464 },
|
||||
{ MT_HT_BASIC_RATE, 0x00004003 },
|
||||
{ MT_HT_CTRL_CFG, 0x000001FF },
|
||||
{ MT_TXOP_HLDR_ET, 0x00000000 },
|
||||
{ MT_PN_PAD_MODE, 0x00000003 },
|
||||
{ MT_TX_PROT_CFG6, 0xe3f42004 },
|
||||
{ MT_TX_PROT_CFG7, 0xe3f42084 },
|
||||
{ MT_TX_PROT_CFG8, 0xe3f42104 },
|
||||
{ MT_VHT_HT_FBK_CFG1, 0xedcba980 },
|
||||
};
|
||||
|
||||
static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = {
|
||||
{ MT_BBP(CORE, 1), 0x00000002 },
|
||||
{ MT_BBP(CORE, 4), 0x00000000 },
|
||||
{ MT_BBP(CORE, 24), 0x00000000 },
|
||||
{ MT_BBP(CORE, 32), 0x4003000a },
|
||||
{ MT_BBP(CORE, 42), 0x00000000 },
|
||||
{ MT_BBP(CORE, 44), 0x00000000 },
|
||||
{ MT_BBP(IBI, 11), 0x0FDE8081 },
|
||||
{ MT_BBP(AGC, 0), 0x00021400 },
|
||||
{ MT_BBP(AGC, 1), 0x00000003 },
|
||||
{ MT_BBP(AGC, 2), 0x003A6464 },
|
||||
{ MT_BBP(AGC, 15), 0x88A28CB8 },
|
||||
{ MT_BBP(AGC, 22), 0x00001E21 },
|
||||
{ MT_BBP(AGC, 23), 0x0000272C },
|
||||
{ MT_BBP(AGC, 24), 0x00002F3A },
|
||||
{ MT_BBP(AGC, 25), 0x8000005A },
|
||||
{ MT_BBP(AGC, 26), 0x007C2005 },
|
||||
{ MT_BBP(AGC, 33), 0x00003238 },
|
||||
{ MT_BBP(AGC, 34), 0x000A0C0C },
|
||||
{ MT_BBP(AGC, 37), 0x2121262C },
|
||||
{ MT_BBP(AGC, 41), 0x38383E45 },
|
||||
{ MT_BBP(AGC, 57), 0x00001010 },
|
||||
{ MT_BBP(AGC, 59), 0xBAA20E96 },
|
||||
{ MT_BBP(AGC, 63), 0x00000001 },
|
||||
{ MT_BBP(TXC, 0), 0x00280403 },
|
||||
{ MT_BBP(TXC, 1), 0x00000000 },
|
||||
{ MT_BBP(RXC, 1), 0x00000012 },
|
||||
{ MT_BBP(RXC, 2), 0x00000011 },
|
||||
{ MT_BBP(RXC, 3), 0x00000005 },
|
||||
{ MT_BBP(RXC, 4), 0x00000000 },
|
||||
{ MT_BBP(RXC, 5), 0xF977C4EC },
|
||||
{ MT_BBP(RXC, 7), 0x00000090 },
|
||||
{ MT_BBP(TXO, 8), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 0), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 4), 0x00000004 },
|
||||
{ MT_BBP(TXBE, 6), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 8), 0x00000014 },
|
||||
{ MT_BBP(TXBE, 9), 0x20000000 },
|
||||
{ MT_BBP(TXBE, 10), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 12), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 13), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 14), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 15), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 16), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 17), 0x00000000 },
|
||||
{ MT_BBP(RXFE, 1), 0x00008800 },
|
||||
{ MT_BBP(RXFE, 3), 0x00000000 },
|
||||
{ MT_BBP(RXFE, 4), 0x00000000 },
|
||||
{ MT_BBP(RXO, 13), 0x00000192 },
|
||||
{ MT_BBP(RXO, 14), 0x00060612 },
|
||||
{ MT_BBP(RXO, 15), 0xC8321B18 },
|
||||
{ MT_BBP(RXO, 16), 0x0000001E },
|
||||
{ MT_BBP(RXO, 17), 0x00000000 },
|
||||
{ MT_BBP(RXO, 18), 0xCC00A993 },
|
||||
{ MT_BBP(RXO, 19), 0xB9CB9CB9 },
|
||||
{ MT_BBP(RXO, 20), 0x26c00057 },
|
||||
{ MT_BBP(RXO, 21), 0x00000001 },
|
||||
{ MT_BBP(RXO, 24), 0x00000006 },
|
||||
{ MT_BBP(RXO, 28), 0x0000003F },
|
||||
};
|
||||
|
||||
static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = {
|
||||
{ RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 4), 0x1FEDA049 } },
|
||||
{ RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 4), 0x1FECA054 } },
|
||||
|
|
@ -215,16 +82,4 @@ static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = {
|
|||
{ RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXFE, 0), 0x895000E0 } },
|
||||
};
|
||||
|
||||
static const struct mt76_reg_pair mt76x0_dcoc_tab[] = {
|
||||
{ MT_BBP(CAL, 47), 0x000010F0 },
|
||||
{ MT_BBP(CAL, 48), 0x00008080 },
|
||||
{ MT_BBP(CAL, 49), 0x00000F07 },
|
||||
{ MT_BBP(CAL, 50), 0x00000040 },
|
||||
{ MT_BBP(CAL, 51), 0x00000404 },
|
||||
{ MT_BBP(CAL, 52), 0x00080803 },
|
||||
{ MT_BBP(CAL, 53), 0x00000704 },
|
||||
{ MT_BBP(CAL, 54), 0x00002828 },
|
||||
{ MT_BBP(CAL, 55), 0x00005050 },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
159
drivers/net/wireless/mediatek/mt76/mt76x0/initvals_init.h
Normal file
159
drivers/net/wireless/mediatek/mt76/mt76x0/initvals_init.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* (c) Copyright 2002-2010, Ralink Technology, Inc.
|
||||
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
|
||||
* Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
|
||||
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __MT76X0U_INITVALS_INIT_H
|
||||
#define __MT76X0U_INITVALS_INIT_H
|
||||
|
||||
#include "phy.h"
|
||||
|
||||
static const struct mt76_reg_pair common_mac_reg_table[] = {
|
||||
{ MT_BCN_OFFSET(0), 0xf8f0e8e0 },
|
||||
{ MT_BCN_OFFSET(1), 0x6f77d0c8 },
|
||||
{ MT_LEGACY_BASIC_RATE, 0x0000013f },
|
||||
{ MT_HT_BASIC_RATE, 0x00008003 },
|
||||
{ MT_MAC_SYS_CTRL, 0x00000000 },
|
||||
{ MT_RX_FILTR_CFG, 0x00017f97 },
|
||||
{ MT_BKOFF_SLOT_CFG, 0x00000209 },
|
||||
{ MT_TX_SW_CFG0, 0x00000000 },
|
||||
{ MT_TX_SW_CFG1, 0x00080606 },
|
||||
{ MT_TX_LINK_CFG, 0x00001020 },
|
||||
{ MT_TX_TIMEOUT_CFG, 0x000a2090 },
|
||||
{ MT_MAX_LEN_CFG, 0xa0fff | 0x00001000 },
|
||||
{ MT_LED_CFG, 0x7f031e46 },
|
||||
{ MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
|
||||
{ MT_PBF_RX_MAX_PCNT, 0x0000fe9f },
|
||||
{ MT_TX_RETRY_CFG, 0x47d01f0f },
|
||||
{ MT_AUTO_RSP_CFG, 0x00000013 },
|
||||
{ MT_CCK_PROT_CFG, 0x07f40003 },
|
||||
{ MT_OFDM_PROT_CFG, 0x07f42004 },
|
||||
{ MT_PBF_CFG, 0x00f40006 },
|
||||
{ MT_WPDMA_GLO_CFG, 0x00000030 },
|
||||
{ MT_GF20_PROT_CFG, 0x01742004 },
|
||||
{ MT_GF40_PROT_CFG, 0x03f42084 },
|
||||
{ MT_MM20_PROT_CFG, 0x01742004 },
|
||||
{ MT_MM40_PROT_CFG, 0x03f42084 },
|
||||
{ MT_TXOP_CTRL_CFG, 0x0000583f },
|
||||
{ MT_TX_RTS_CFG, 0x00ffff20 },
|
||||
{ MT_EXP_ACK_TIME, 0x002400ca },
|
||||
{ MT_TXOP_HLDR_ET, 0x00000002 },
|
||||
{ MT_XIFS_TIME_CFG, 0x33a41010 },
|
||||
{ MT_PWR_PIN_CFG, 0x00000000 },
|
||||
};
|
||||
|
||||
static const struct mt76_reg_pair mt76x0_mac_reg_table[] = {
|
||||
{ MT_IOCFG_6, 0xa0040080 },
|
||||
{ MT_PBF_SYS_CTRL, 0x00080c00 },
|
||||
{ MT_PBF_CFG, 0x77723c1f },
|
||||
{ MT_FCE_PSE_CTRL, 0x00000001 },
|
||||
{ MT_AMPDU_MAX_LEN_20M1S, 0xAAA99887 },
|
||||
{ MT_TX_SW_CFG0, 0x00000601 },
|
||||
{ MT_TX_SW_CFG1, 0x00040000 },
|
||||
{ MT_TX_SW_CFG2, 0x00000000 },
|
||||
{ 0xa44, 0x00000000 },
|
||||
{ MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
|
||||
{ MT_TSO_CTRL, 0x00000000 },
|
||||
{ MT_BB_PA_MODE_CFG1, 0x00500055 },
|
||||
{ MT_RF_PA_MODE_CFG1, 0x00500055 },
|
||||
{ MT_TX_ALC_CFG_0, 0x2F2F000C },
|
||||
{ MT_TX0_BB_GAIN_ATTEN, 0x00000000 },
|
||||
{ MT_TX_PWR_CFG_0, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_1, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_2, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_3, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_4, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_7, 0x3A3A3A3A },
|
||||
{ MT_TX_PWR_CFG_8, 0x0000003A },
|
||||
{ MT_TX_PWR_CFG_9, 0x0000003A },
|
||||
{ 0x150C, 0x00000002 },
|
||||
{ 0x1238, 0x001700C8 },
|
||||
{ MT_LDO_CTRL_0, 0x00A647B6 },
|
||||
{ MT_LDO_CTRL_1, 0x6B006464 },
|
||||
{ MT_HT_BASIC_RATE, 0x00004003 },
|
||||
{ MT_HT_CTRL_CFG, 0x000001FF },
|
||||
{ MT_TXOP_HLDR_ET, 0x00000000 },
|
||||
{ MT_PN_PAD_MODE, 0x00000003 },
|
||||
{ MT_TX_PROT_CFG6, 0xe3f42004 },
|
||||
{ MT_TX_PROT_CFG7, 0xe3f42084 },
|
||||
{ MT_TX_PROT_CFG8, 0xe3f42104 },
|
||||
{ MT_VHT_HT_FBK_CFG1, 0xedcba980 },
|
||||
};
|
||||
|
||||
static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = {
|
||||
{ MT_BBP(CORE, 1), 0x00000002 },
|
||||
{ MT_BBP(CORE, 4), 0x00000000 },
|
||||
{ MT_BBP(CORE, 24), 0x00000000 },
|
||||
{ MT_BBP(CORE, 32), 0x4003000a },
|
||||
{ MT_BBP(CORE, 42), 0x00000000 },
|
||||
{ MT_BBP(CORE, 44), 0x00000000 },
|
||||
{ MT_BBP(IBI, 11), 0x0FDE8081 },
|
||||
{ MT_BBP(AGC, 0), 0x00021400 },
|
||||
{ MT_BBP(AGC, 1), 0x00000003 },
|
||||
{ MT_BBP(AGC, 2), 0x003A6464 },
|
||||
{ MT_BBP(AGC, 15), 0x88A28CB8 },
|
||||
{ MT_BBP(AGC, 22), 0x00001E21 },
|
||||
{ MT_BBP(AGC, 23), 0x0000272C },
|
||||
{ MT_BBP(AGC, 24), 0x00002F3A },
|
||||
{ MT_BBP(AGC, 25), 0x8000005A },
|
||||
{ MT_BBP(AGC, 26), 0x007C2005 },
|
||||
{ MT_BBP(AGC, 33), 0x00003238 },
|
||||
{ MT_BBP(AGC, 34), 0x000A0C0C },
|
||||
{ MT_BBP(AGC, 37), 0x2121262C },
|
||||
{ MT_BBP(AGC, 41), 0x38383E45 },
|
||||
{ MT_BBP(AGC, 57), 0x00001010 },
|
||||
{ MT_BBP(AGC, 59), 0xBAA20E96 },
|
||||
{ MT_BBP(AGC, 63), 0x00000001 },
|
||||
{ MT_BBP(TXC, 0), 0x00280403 },
|
||||
{ MT_BBP(TXC, 1), 0x00000000 },
|
||||
{ MT_BBP(RXC, 1), 0x00000012 },
|
||||
{ MT_BBP(RXC, 2), 0x00000011 },
|
||||
{ MT_BBP(RXC, 3), 0x00000005 },
|
||||
{ MT_BBP(RXC, 4), 0x00000000 },
|
||||
{ MT_BBP(RXC, 5), 0xF977C4EC },
|
||||
{ MT_BBP(RXC, 7), 0x00000090 },
|
||||
{ MT_BBP(TXO, 8), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 0), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 4), 0x00000004 },
|
||||
{ MT_BBP(TXBE, 6), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 8), 0x00000014 },
|
||||
{ MT_BBP(TXBE, 9), 0x20000000 },
|
||||
{ MT_BBP(TXBE, 10), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 12), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 13), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 14), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 15), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 16), 0x00000000 },
|
||||
{ MT_BBP(TXBE, 17), 0x00000000 },
|
||||
{ MT_BBP(RXFE, 1), 0x00008800 },
|
||||
{ MT_BBP(RXFE, 3), 0x00000000 },
|
||||
{ MT_BBP(RXFE, 4), 0x00000000 },
|
||||
{ MT_BBP(RXO, 13), 0x00000192 },
|
||||
{ MT_BBP(RXO, 14), 0x00060612 },
|
||||
{ MT_BBP(RXO, 15), 0xC8321B18 },
|
||||
{ MT_BBP(RXO, 16), 0x0000001E },
|
||||
{ MT_BBP(RXO, 17), 0x00000000 },
|
||||
{ MT_BBP(RXO, 18), 0xCC00A993 },
|
||||
{ MT_BBP(RXO, 19), 0xB9CB9CB9 },
|
||||
{ MT_BBP(RXO, 20), 0x26c00057 },
|
||||
{ MT_BBP(RXO, 21), 0x00000001 },
|
||||
{ MT_BBP(RXO, 24), 0x00000006 },
|
||||
{ MT_BBP(RXO, 28), 0x0000003F },
|
||||
};
|
||||
|
||||
static const struct mt76_reg_pair mt76x0_dcoc_tab[] = {
|
||||
{ MT_BBP(CAL, 47), 0x000010F0 },
|
||||
{ MT_BBP(CAL, 48), 0x00008080 },
|
||||
{ MT_BBP(CAL, 49), 0x00000F07 },
|
||||
{ MT_BBP(CAL, 50), 0x00000040 },
|
||||
{ MT_BBP(CAL, 51), 0x00000404 },
|
||||
{ MT_BBP(CAL, 52), 0x00080803 },
|
||||
{ MT_BBP(CAL, 53), 0x00000704 },
|
||||
{ MT_BBP(CAL, 54), 0x00002828 },
|
||||
{ MT_BBP(CAL, 55), 0x00005050 },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -180,6 +180,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
mdev->rev = mt76_rr(dev, MT_ASIC_VERSION);
|
||||
dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev);
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (ret)
|
||||
|
|
@ -202,7 +204,7 @@ static void mt76x0e_cleanup(struct mt76x02_dev *dev)
|
|||
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
|
||||
mt76x0_chip_onoff(dev, false, false);
|
||||
mt76x0e_stop_hw(dev);
|
||||
mt76x02_dma_cleanup(dev);
|
||||
mt76_dma_cleanup(&dev->mt76);
|
||||
mt76x02_mcu_cleanup(dev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -734,7 +734,7 @@ mt76x0_phy_get_delta_power(struct mt76x02_dev *dev, u8 tx_mode,
|
|||
case 1:
|
||||
if (chan->band == NL80211_BAND_2GHZ)
|
||||
tssi_target += 29491; /* 3.6 * 8192 */
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#include "mt76x02_dfs.h"
|
||||
#include "mt76x02_dma.h"
|
||||
|
||||
#define MT76x02_TX_RING_SIZE 512
|
||||
#define MT76x02_PSD_RING_SIZE 128
|
||||
#define MT76x02_N_WCIDS 128
|
||||
#define MT_CALIBRATE_INTERVAL HZ
|
||||
#define MT_MAC_WORK_INTERVAL (HZ / 10)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include "mt76x02.h"
|
||||
|
||||
static int
|
||||
mt76x02_ampdu_stat_read(struct seq_file *file, void *data)
|
||||
mt76x02_ampdu_stat_show(struct seq_file *file, void *data)
|
||||
{
|
||||
struct mt76x02_dev *dev = file->private;
|
||||
int i, j;
|
||||
|
|
@ -31,11 +31,7 @@ mt76x02_ampdu_stat_read(struct seq_file *file, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt76x02_ampdu_stat_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return single_open(f, mt76x02_ampdu_stat_read, inode->i_private);
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(mt76x02_ampdu_stat);
|
||||
|
||||
static int read_txpower(struct seq_file *file, void *data)
|
||||
{
|
||||
|
|
@ -48,15 +44,8 @@ static int read_txpower(struct seq_file *file, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ampdu_stat = {
|
||||
.open = mt76x02_ampdu_stat_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int
|
||||
mt76x02_dfs_stat_read(struct seq_file *file, void *data)
|
||||
mt76x02_dfs_stat_show(struct seq_file *file, void *data)
|
||||
{
|
||||
struct mt76x02_dev *dev = file->private;
|
||||
struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
|
||||
|
|
@ -81,18 +70,7 @@ mt76x02_dfs_stat_read(struct seq_file *file, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt76x02_dfs_stat_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return single_open(f, mt76x02_dfs_stat_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_dfs_stat = {
|
||||
.open = mt76x02_dfs_stat_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(mt76x02_dfs_stat);
|
||||
|
||||
static int read_agc(struct seq_file *file, void *data)
|
||||
{
|
||||
|
|
@ -150,8 +128,8 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev)
|
|||
debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc);
|
||||
|
||||
debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
|
||||
debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat);
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev, &mt76x02_ampdu_stat_fops);
|
||||
debugfs_create_file("dfs_stats", 0400, dir, dev, &mt76x02_dfs_stat_fops);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir,
|
||||
read_txpower);
|
||||
|
||||
|
|
|
|||
|
|
@ -429,11 +429,11 @@ static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev,
|
|||
{
|
||||
struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
|
||||
struct mt76x02_dfs_sw_detector_params *sw_params;
|
||||
u32 width_delta, with_sum, factor, cur_pri;
|
||||
u32 width_delta, with_sum;
|
||||
struct mt76x02_dfs_sequence seq, *seq_p;
|
||||
struct mt76x02_dfs_event_rb *event_rb;
|
||||
struct mt76x02_dfs_event *cur_event;
|
||||
int i, j, end, pri;
|
||||
int i, j, end, pri, factor, cur_pri;
|
||||
|
||||
event_rb = event->engine == 2 ? &dfs_pd->event_rb[1]
|
||||
: &dfs_pd->event_rb[0];
|
||||
|
|
@ -517,7 +517,7 @@ static u16 mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev *dev,
|
|||
struct mt76x02_dfs_sw_detector_params *sw_params;
|
||||
struct mt76x02_dfs_sequence *seq, *tmp_seq;
|
||||
u16 max_seq_len = 0;
|
||||
u32 factor, pri;
|
||||
int factor, pri;
|
||||
|
||||
sw_params = &dfs_pd->sw_dpd_params;
|
||||
list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,5 @@ mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout)
|
|||
|
||||
int mt76x02_dma_init(struct mt76x02_dev *dev);
|
||||
void mt76x02_dma_disable(struct mt76x02_dev *dev);
|
||||
void mt76x02_dma_cleanup(struct mt76x02_dev *dev);
|
||||
|
||||
#endif /* __MT76x02_DMA_H */
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
|
|||
return 0;
|
||||
case MT_PHY_TYPE_HT_GF:
|
||||
txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_HT:
|
||||
txrate->flags |= IEEE80211_TX_RC_MCS;
|
||||
txrate->idx = idx;
|
||||
|
|
@ -349,6 +349,8 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
|
|||
|
||||
memset(txwi, 0, sizeof(*txwi));
|
||||
|
||||
mt76_tx_check_agg_ssn(sta, skb);
|
||||
|
||||
if (!info->control.hw_key && wcid && wcid->hw_key_idx != 0xff &&
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
wcid = NULL;
|
||||
|
|
@ -462,7 +464,7 @@ mt76x02_tx_rate_fallback(struct ieee80211_tx_rate *rates, int idx, int phy)
|
|||
rates[1].idx = 0;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
rates[1].idx = max_t(int, rates[0].idx - 1, 0);
|
||||
break;
|
||||
|
|
@ -677,7 +679,7 @@ mt76x02_mac_process_rate(struct mt76x02_dev *dev,
|
|||
return 0;
|
||||
case MT_PHY_TYPE_HT_GF:
|
||||
status->enc_flags |= RX_ENC_FLAG_HT_GF;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_HT:
|
||||
status->encoding = RX_ENC_HT;
|
||||
status->rate_idx = idx;
|
||||
|
|
@ -898,8 +900,7 @@ void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq)
|
|||
}
|
||||
}
|
||||
|
||||
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e)
|
||||
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
|
||||
{
|
||||
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
|
||||
struct mt76x02_txwi *txwi;
|
||||
|
|
@ -916,7 +917,7 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
|||
txwi = (struct mt76x02_txwi *)txwi_ptr;
|
||||
trace_mac_txdone(mdev, txwi->wcid, txwi->pktid);
|
||||
|
||||
mt76_tx_complete_skb(mdev, e->skb);
|
||||
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb);
|
||||
|
||||
|
|
|
|||
|
|
@ -194,8 +194,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
|
|||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta, int len);
|
||||
void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq);
|
||||
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e);
|
||||
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
|
||||
void mt76x02_update_channel(struct mt76_dev *mdev);
|
||||
void mt76x02_mac_work(struct work_struct *work);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
|
||||
{
|
||||
struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
|
||||
struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD].q;
|
||||
struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD];
|
||||
struct beacon_bc_data data = {};
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
|
@ -104,8 +104,7 @@ 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)
|
||||
mt76x02_init_tx_queue(struct mt76x02_dev *dev, int qid, int idx, int n_desc)
|
||||
{
|
||||
struct mt76_queue *hwq;
|
||||
int err;
|
||||
|
|
@ -118,8 +117,7 @@ mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_sw_queue *q,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
INIT_LIST_HEAD(&q->swq);
|
||||
q->q = hwq;
|
||||
dev->mt76.q_tx[qid] = hwq;
|
||||
|
||||
mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx));
|
||||
|
||||
|
|
@ -151,9 +149,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);
|
||||
|
|
@ -178,7 +178,7 @@ static int mt76x02_poll_tx(struct napi_struct *napi, int budget)
|
|||
for (i = MT_TXQ_MCU; i >= 0; i--)
|
||||
mt76_queue_tx_cleanup(dev, i, false);
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_schedule(&dev->mt76.tx_worker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -197,8 +197,7 @@ 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);
|
||||
dev->mt76.tx_worker.fn = mt76x02_tx_worker;
|
||||
tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
|
||||
(unsigned long)dev);
|
||||
|
||||
|
|
@ -210,19 +209,18 @@ 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 = mt76x02_init_tx_queue(dev, i, mt76_ac_to_hwq(i),
|
||||
MT76x02_TX_RING_SIZE);
|
||||
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 = mt76x02_init_tx_queue(dev, MT_TXQ_PSD,
|
||||
MT_TX_HW_QUEUE_MGMT, MT76x02_PSD_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
|
||||
ret = mt76x02_init_tx_queue(dev, MT_TXQ_MCU,
|
||||
MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -263,9 +261,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 +272,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;
|
||||
|
||||
if (intr & MT_INT_RX_DONE(0)) {
|
||||
mt76x02_irq_disable(dev, MT_INT_RX_DONE(0));
|
||||
mt76x02_irq_disable(dev, mask);
|
||||
|
||||
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 +292,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->mt76.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 +324,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,7 +357,7 @@ static bool mt76x02_tx_hang(struct mt76x02_dev *dev)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
q = dev->mt76.q_tx[i].q;
|
||||
q = dev->mt76.q_tx[i];
|
||||
|
||||
if (!q->queued)
|
||||
continue;
|
||||
|
|
@ -453,7 +441,7 @@ 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);
|
||||
|
||||
mt76_for_each_q_rx(&dev->mt76, i) {
|
||||
|
|
@ -510,7 +498,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
|
|||
|
||||
clear_bit(MT76_RESET, &dev->mphy.state);
|
||||
|
||||
tasklet_enable(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_enable(&dev->mt76.tx_worker);
|
||||
napi_enable(&dev->mt76.tx_napi);
|
||||
napi_schedule(&dev->mt76.tx_napi);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
|
|||
enum mt76_txq_id qid, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta,
|
||||
struct mt76_tx_info *tx_info);
|
||||
void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e);
|
||||
void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
|
||||
void mt76x02u_init_beacon_config(struct mt76x02_dev *dev);
|
||||
void mt76x02u_exit_beacon_config(struct mt76x02_dev *dev);
|
||||
#endif /* __MT76x02_USB_H */
|
||||
|
|
|
|||
|
|
@ -15,11 +15,10 @@ static void mt76x02u_remove_dma_hdr(struct sk_buff *skb)
|
|||
mt76x02_remove_hdr_pad(skb, 2);
|
||||
}
|
||||
|
||||
void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e)
|
||||
void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
|
||||
{
|
||||
mt76x02u_remove_dma_hdr(e->skb);
|
||||
mt76_tx_complete_skb(mdev, e->skb);
|
||||
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb);
|
||||
|
||||
|
|
@ -46,7 +45,7 @@ EXPORT_SYMBOL_GPL(mt76x02u_mac_start);
|
|||
|
||||
int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
|
||||
{
|
||||
u32 info;
|
||||
u32 info, pad;
|
||||
|
||||
/* Buffer layout:
|
||||
* | 4B | xfer len | pad | 4B |
|
||||
|
|
@ -58,7 +57,8 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
|
|||
FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags;
|
||||
put_unaligned_le32(info, skb_push(skb, sizeof(info)));
|
||||
|
||||
return mt76_skb_adjust_pad(skb);
|
||||
pad = round_up(skb->len, 4) + 4 - skb->len;
|
||||
return mt76_skb_adjust_pad(skb, pad);
|
||||
}
|
||||
|
||||
int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
|
||||
|
|
@ -67,7 +67,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
|
|||
struct mt76_tx_info *tx_info)
|
||||
{
|
||||
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
|
||||
int pid, len = tx_info->skb->len, ep = q2ep(mdev->q_tx[qid].q->hw_idx);
|
||||
int pid, len = tx_info->skb->len, ep = q2ep(mdev->q_tx[qid]->hw_idx);
|
||||
struct mt76x02_txwi *txwi;
|
||||
bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU;
|
||||
enum mt76_qsel qsel;
|
||||
|
|
|
|||
|
|
@ -294,8 +294,6 @@ mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
|
|||
mvif->group_wcid.hw_key_idx = -1;
|
||||
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
|
||||
mtxq->wcid = &mvif->group_wcid;
|
||||
|
||||
mt76_txq_init(&dev->mt76, vif->txq);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -347,7 +345,6 @@ void mt76x02_remove_interface(struct ieee80211_hw *hw,
|
|||
struct mt76x02_dev *dev = hw->priv;
|
||||
struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
|
||||
|
||||
mt76_txq_remove(&dev->mt76, vif->txq);
|
||||
dev->mphy.vif_mask &= ~BIT(mvif->idx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_remove_interface);
|
||||
|
|
@ -490,7 +487,7 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
u8 cw_min = 5, cw_max = 10, qid;
|
||||
u32 val;
|
||||
|
||||
qid = dev->mt76.q_tx[queue].q->hw_idx;
|
||||
qid = dev->mt76.q_tx[queue]->hw_idx;
|
||||
|
||||
if (params->cw_min)
|
||||
cw_min = fls(params->cw_min);
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
mdev->rev = mt76_rr(dev, MT_ASIC_VERSION);
|
||||
dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev);
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (ret)
|
||||
|
|
@ -111,7 +113,7 @@ mt76x2e_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
|
||||
napi_disable(&mdev->tx_napi);
|
||||
tasklet_kill(&mdev->pre_tbtt_tasklet);
|
||||
tasklet_kill(&mdev->tx_tasklet);
|
||||
mt76_worker_disable(&mdev->tx_worker);
|
||||
|
||||
mt76_for_each_q_rx(mdev, i)
|
||||
napi_disable(&mdev->napi[i]);
|
||||
|
|
@ -145,6 +147,7 @@ mt76x2e_resume(struct pci_dev *pdev)
|
|||
|
||||
pci_restore_state(pdev);
|
||||
|
||||
mt76_worker_enable(&mdev->tx_worker);
|
||||
mt76_for_each_q_rx(mdev, i) {
|
||||
napi_enable(&mdev->napi[i]);
|
||||
napi_schedule(&mdev->napi[i]);
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ void mt76x2_cleanup(struct mt76x02_dev *dev)
|
|||
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
|
||||
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
|
||||
mt76x2_stop_hardware(dev);
|
||||
mt76x02_dma_cleanup(dev);
|
||||
mt76_dma_cleanup(&dev->mt76);
|
||||
mt76x02_mcu_cleanup(dev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ static int mt7915_ser_trigger_set(void *data, u64 val)
|
|||
switch (val) {
|
||||
case SER_SET_RECOVER_L1:
|
||||
case SER_SET_RECOVER_L2:
|
||||
/* fall through */
|
||||
ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -292,15 +291,15 @@ mt7915_queues_read(struct seq_file *s, void *data)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
|
||||
struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id];
|
||||
struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
|
||||
|
||||
if (!q->q)
|
||||
if (!q)
|
||||
continue;
|
||||
|
||||
seq_printf(s,
|
||||
"%s: queued=%d head=%d tail=%d\n",
|
||||
queue_map[i].queue, q->q->queued, q->q->head,
|
||||
q->q->tail);
|
||||
queue_map[i].queue, q->queued, q->head,
|
||||
q->tail);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -400,7 +399,7 @@ static int mt7915_sta_fixed_rate_set(void *data, u64 rate)
|
|||
struct ieee80211_sta *sta = data;
|
||||
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
|
||||
return mt7915_mcu_set_fixed_rate(msta->vif->dev, sta, rate);
|
||||
return mt7915_mcu_set_fixed_rate(msta->vif->phy->dev, sta, rate);
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
static int
|
||||
mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc)
|
||||
{
|
||||
struct mt76_sw_queue *q;
|
||||
struct mt76_queue *hwq;
|
||||
int err, i;
|
||||
|
||||
|
|
@ -21,18 +20,14 @@ mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < MT_TXQ_MCU; i++) {
|
||||
q = &dev->mt76.q_tx[i];
|
||||
INIT_LIST_HEAD(&q->swq);
|
||||
q->q = hwq;
|
||||
}
|
||||
for (i = 0; i < MT_TXQ_MCU; i++)
|
||||
dev->mt76.q_tx[i] = hwq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_init_mcu_queue(struct mt7915_dev *dev, struct mt76_sw_queue *q,
|
||||
int idx, int n_desc)
|
||||
mt7915_init_mcu_queue(struct mt7915_dev *dev, int qid, int idx, int n_desc)
|
||||
{
|
||||
struct mt76_queue *hwq;
|
||||
int err;
|
||||
|
|
@ -45,8 +40,7 @@ mt7915_init_mcu_queue(struct mt7915_dev *dev, struct mt76_sw_queue *q,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
INIT_LIST_HEAD(&q->swq);
|
||||
q->q = hwq;
|
||||
dev->mt76.q_tx[qid] = hwq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -72,7 +66,7 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
|||
mt76_rx(&dev->mt76, q, skb);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
|
|
@ -84,8 +78,6 @@ mt7915_tx_cleanup(struct mt7915_dev *dev)
|
|||
{
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU_WA, false);
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
|
||||
}
|
||||
|
||||
static int mt7915_poll_tx(struct napi_struct *napi, int budget)
|
||||
|
|
@ -97,13 +89,7 @@ static int mt7915_poll_tx(struct napi_struct *napi, int budget)
|
|||
mt7915_tx_cleanup(dev);
|
||||
|
||||
if (napi_complete_done(napi, 0))
|
||||
mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL);
|
||||
|
||||
mt7915_tx_cleanup(dev);
|
||||
|
||||
mt7915_mac_sta_poll(dev);
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
mt7915_irq_enable(dev, MT_INT_TX_DONE_MCU);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -138,12 +124,120 @@ void mt7915_dma_prefetch(struct mt7915_dev *dev)
|
|||
mt76_wr(dev, MT_WFDMA1_RX_RING3_EXT_CTRL, PREFETCH(0x480, 0x0));
|
||||
}
|
||||
|
||||
static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr)
|
||||
{
|
||||
static const struct {
|
||||
u32 phys;
|
||||
u32 mapped;
|
||||
u32 size;
|
||||
} fixed_map[] = {
|
||||
{ 0x54000000, 0x02000, 0x1000 }, /* WFDMA PCIE0 MCU DMA0 */
|
||||
{ 0x55000000, 0x03000, 0x1000 }, /* WFDMA PCIE0 MCU DMA1 */
|
||||
{ 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */
|
||||
{ 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */
|
||||
{ 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */
|
||||
{ 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */
|
||||
{ 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */
|
||||
{ 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */
|
||||
{ 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */
|
||||
{ 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */
|
||||
{ 0x820cc000, 0x0e000, 0x2000 }, /* WF_UMAC_TOP (PP) */
|
||||
{ 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */
|
||||
{ 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */
|
||||
{ 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
|
||||
{ 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */
|
||||
{ 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */
|
||||
{ 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
|
||||
{ 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
|
||||
{ 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
|
||||
{ 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
|
||||
{ 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
|
||||
{ 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */
|
||||
{ 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */
|
||||
{ 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
|
||||
{ 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */
|
||||
{ 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
|
||||
{ 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */
|
||||
{ 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */
|
||||
{ 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */
|
||||
{ 0x820f3000, 0xa0c00, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */
|
||||
{ 0x820f4000, 0xa1000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */
|
||||
{ 0x820f5000, 0xa1400, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */
|
||||
{ 0x820f7000, 0xa1e00, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */
|
||||
{ 0x820f9000, 0xa3400, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */
|
||||
{ 0x820fa000, 0xa4000, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */
|
||||
{ 0x820fb000, 0xa4200, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */
|
||||
{ 0x820fc000, 0xa4600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_INT) */
|
||||
{ 0x820fd000, 0xa4800, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */
|
||||
};
|
||||
int i;
|
||||
|
||||
if (addr < 0x100000)
|
||||
return addr;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fixed_map); i++) {
|
||||
u32 ofs;
|
||||
|
||||
if (addr < fixed_map[i].phys)
|
||||
continue;
|
||||
|
||||
ofs = addr - fixed_map[i].phys;
|
||||
if (ofs > fixed_map[i].size)
|
||||
continue;
|
||||
|
||||
return fixed_map[i].mapped + ofs;
|
||||
}
|
||||
|
||||
if ((addr >= 0x18000000 && addr < 0x18c00000) ||
|
||||
(addr >= 0x70000000 && addr < 0x78000000) ||
|
||||
(addr >= 0x7c000000 && addr < 0x7c400000))
|
||||
return mt7915_reg_map_l1(dev, addr);
|
||||
|
||||
return mt7915_reg_map_l2(dev, addr);
|
||||
}
|
||||
|
||||
static u32 mt7915_rr(struct mt76_dev *mdev, u32 offset)
|
||||
{
|
||||
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
|
||||
u32 addr = __mt7915_reg_addr(dev, offset);
|
||||
|
||||
return dev->bus_ops->rr(mdev, addr);
|
||||
}
|
||||
|
||||
static void mt7915_wr(struct mt76_dev *mdev, u32 offset, u32 val)
|
||||
{
|
||||
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
|
||||
u32 addr = __mt7915_reg_addr(dev, offset);
|
||||
|
||||
dev->bus_ops->wr(mdev, addr, val);
|
||||
}
|
||||
|
||||
static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
|
||||
{
|
||||
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
|
||||
u32 addr = __mt7915_reg_addr(dev, offset);
|
||||
|
||||
return dev->bus_ops->rmw(mdev, addr, mask, val);
|
||||
}
|
||||
|
||||
int mt7915_dma_init(struct mt7915_dev *dev)
|
||||
{
|
||||
/* Increase buffer size to receive large VHT/HE MPDUs */
|
||||
struct mt76_bus_ops *bus_ops;
|
||||
int rx_buf_size = MT_RX_BUF_SIZE * 2;
|
||||
int ret;
|
||||
|
||||
dev->bus_ops = dev->mt76.bus;
|
||||
bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops),
|
||||
GFP_KERNEL);
|
||||
if (!bus_ops)
|
||||
return -ENOMEM;
|
||||
|
||||
bus_ops->rr = mt7915_rr;
|
||||
bus_ops->wr = mt7915_wr;
|
||||
bus_ops->rmw = mt7915_rmw;
|
||||
dev->mt76.bus = bus_ops;
|
||||
|
||||
mt76_dma_attach(&dev->mt76);
|
||||
|
||||
/* configure global setting */
|
||||
|
|
@ -168,22 +262,19 @@ int mt7915_dma_init(struct mt7915_dev *dev)
|
|||
return ret;
|
||||
|
||||
/* command to WM */
|
||||
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
|
||||
MT7915_TXQ_MCU_WM,
|
||||
ret = mt7915_init_mcu_queue(dev, MT_TXQ_MCU, MT7915_TXQ_MCU_WM,
|
||||
MT7915_TX_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* command to WA */
|
||||
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU_WA],
|
||||
MT7915_TXQ_MCU_WA,
|
||||
ret = mt7915_init_mcu_queue(dev, MT_TXQ_MCU_WA, MT7915_TXQ_MCU_WA,
|
||||
MT7915_TX_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* firmware download */
|
||||
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL],
|
||||
MT7915_TXQ_FWDL,
|
||||
ret = mt7915_init_mcu_queue(dev, MT_TXQ_FWDL, MT7915_TXQ_FWDL,
|
||||
MT7915_TX_FWDL_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -248,7 +339,7 @@ int mt7915_dma_init(struct mt7915_dev *dev)
|
|||
MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN);
|
||||
|
||||
/* enable interrupts for TX/RX rings */
|
||||
mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
|
||||
mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_MCU |
|
||||
MT_INT_MCU_CMD);
|
||||
|
||||
return 0;
|
||||
|
|
@ -281,6 +372,5 @@ void mt7915_dma_cleanup(struct mt7915_dev *dev)
|
|||
MT_WFDMA0_RST_DMASHDL_ALL_RST |
|
||||
MT_WFDMA0_RST_LOGIC_RST);
|
||||
|
||||
tasklet_kill(&dev->mt76.tx_tasklet);
|
||||
mt76_dma_cleanup(&dev->mt76);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,6 +135,12 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
|
|||
|
||||
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
|
||||
|
||||
/*
|
||||
* force firmware operation mode into normal state,
|
||||
* which should be set before firmware download stage.
|
||||
*/
|
||||
mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
|
||||
|
||||
ret = mt7915_mcu_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -612,6 +618,7 @@ int mt7915_register_ext_phy(struct mt7915_dev *dev)
|
|||
mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1;
|
||||
mt7915_init_wiphy(mphy->hw);
|
||||
|
||||
INIT_LIST_HEAD(&phy->stats_list);
|
||||
INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work);
|
||||
|
||||
/*
|
||||
|
|
@ -652,7 +659,10 @@ int mt7915_register_device(struct mt7915_dev *dev)
|
|||
dev->phy.dev = dev;
|
||||
dev->phy.mt76 = &dev->mt76.phy;
|
||||
dev->mt76.phy.priv = &dev->phy;
|
||||
INIT_LIST_HEAD(&dev->phy.stats_list);
|
||||
INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
|
||||
INIT_DELAYED_WORK(&dev->phy.mac_work, mt7915_mac_work);
|
||||
INIT_LIST_HEAD(&dev->sta_rc_list);
|
||||
INIT_LIST_HEAD(&dev->sta_poll_list);
|
||||
spin_lock_init(&dev->sta_poll_lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -88,17 +88,16 @@ bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask)
|
|||
0, 5000);
|
||||
}
|
||||
|
||||
static u32 mt7915_mac_wtbl_lmac_read(struct mt7915_dev *dev, u16 wcid,
|
||||
u16 addr)
|
||||
static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid)
|
||||
{
|
||||
mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
|
||||
FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
|
||||
|
||||
return mt76_rr(dev, MT_WTBL_LMAC_OFFS(wcid, addr));
|
||||
return MT_WTBL_LMAC_OFFS(wcid, 0);
|
||||
}
|
||||
|
||||
/* TODO: use txfree airtime info to avoid runtime accessing in the long run */
|
||||
void mt7915_mac_sta_poll(struct mt7915_dev *dev)
|
||||
static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
|
||||
{
|
||||
static const u8 ac_to_tid[] = {
|
||||
[IEEE80211_AC_BE] = 0,
|
||||
|
|
@ -106,47 +105,50 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev)
|
|||
[IEEE80211_AC_VI] = 4,
|
||||
[IEEE80211_AC_VO] = 6
|
||||
};
|
||||
static const u8 hw_queue_map[] = {
|
||||
[IEEE80211_AC_BK] = 0,
|
||||
[IEEE80211_AC_BE] = 1,
|
||||
[IEEE80211_AC_VI] = 2,
|
||||
[IEEE80211_AC_VO] = 3,
|
||||
};
|
||||
struct ieee80211_sta *sta;
|
||||
struct mt7915_sta *msta;
|
||||
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
|
||||
LIST_HEAD(sta_poll_list);
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
list_splice_init(&dev->sta_poll_list, &sta_poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
while (true) {
|
||||
bool clear = false;
|
||||
u32 addr;
|
||||
u16 idx;
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (list_empty(&dev->sta_poll_list)) {
|
||||
if (list_empty(&sta_poll_list)) {
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
break;
|
||||
}
|
||||
msta = list_first_entry(&dev->sta_poll_list,
|
||||
msta = list_first_entry(&sta_poll_list,
|
||||
struct mt7915_sta, poll_list);
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
for (i = 0, idx = msta->wcid.idx; i < IEEE80211_NUM_ACS; i++) {
|
||||
u32 tx_last = msta->airtime_ac[i];
|
||||
u32 rx_last = msta->airtime_ac[i + IEEE80211_NUM_ACS];
|
||||
idx = msta->wcid.idx;
|
||||
addr = mt7915_mac_wtbl_lmac_addr(dev, idx) + 20 * 4;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
u32 tx_last = msta->airtime_ac[i];
|
||||
u32 rx_last = msta->airtime_ac[i + 4];
|
||||
|
||||
msta->airtime_ac[i] = mt76_rr(dev, addr);
|
||||
msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
|
||||
|
||||
msta->airtime_ac[i] =
|
||||
mt7915_mac_wtbl_lmac_read(dev, idx, 20 + i);
|
||||
msta->airtime_ac[i + IEEE80211_NUM_ACS] =
|
||||
mt7915_mac_wtbl_lmac_read(dev, idx, 21 + i);
|
||||
tx_time[i] = msta->airtime_ac[i] - tx_last;
|
||||
rx_time[i] = msta->airtime_ac[i + IEEE80211_NUM_ACS] -
|
||||
rx_last;
|
||||
rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
|
||||
|
||||
if ((tx_last | rx_last) & BIT(30))
|
||||
clear = true;
|
||||
|
||||
addr += 8;
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
|
|
@ -161,8 +163,9 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev)
|
|||
sta = container_of((void *)msta, struct ieee80211_sta,
|
||||
drv_priv);
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
u32 tx_cur = tx_time[i];
|
||||
u32 rx_cur = rx_time[hw_queue_map[i]];
|
||||
u8 q = mt7915_lmac_mapping(dev, i);
|
||||
u32 tx_cur = tx_time[q];
|
||||
u32 rx_cur = rx_time[q];
|
||||
u8 tid = ac_to_tid[i];
|
||||
|
||||
if (!tx_cur && !rx_cur)
|
||||
|
|
@ -468,7 +471,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||
switch (mode) {
|
||||
case MT_PHY_TYPE_CCK:
|
||||
cck = true;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_OFDM:
|
||||
i = mt76_get_rate(&dev->mt76, sband, i, cck);
|
||||
break;
|
||||
|
|
@ -487,7 +490,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||
break;
|
||||
case MT_PHY_TYPE_HE_MU:
|
||||
status->flag |= RX_FLAG_RADIOTAP_HE_MU;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_HE_SU:
|
||||
case MT_PHY_TYPE_HE_EXT_SU:
|
||||
case MT_PHY_TYPE_HE_TB:
|
||||
|
|
@ -565,13 +568,15 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
|||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
bool multicast = is_multicast_ether_addr(hdr->addr1);
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct mt76_phy *mphy = &dev->mphy;
|
||||
bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY;
|
||||
u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
|
||||
__le16 fc = hdr->frame_control;
|
||||
u16 tx_count = 4, seqno = 0;
|
||||
u16 tx_count = 15, seqno = 0;
|
||||
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
u32 val;
|
||||
|
||||
if (vif) {
|
||||
|
|
@ -587,6 +592,10 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
|||
fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
|
||||
fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
|
||||
|
||||
txwi[4] = 0;
|
||||
txwi[5] = 0;
|
||||
txwi[6] = 0;
|
||||
|
||||
if (beacon) {
|
||||
p_fmt = MT_TX_TYPE_FW;
|
||||
q_idx = MT_LMAC_BCN0;
|
||||
|
|
@ -599,6 +608,20 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
|||
mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb));
|
||||
}
|
||||
|
||||
if (ieee80211_is_action(fc) &&
|
||||
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
|
||||
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
|
||||
u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
|
||||
|
||||
txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA);
|
||||
tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
} else if (ieee80211_is_back_req(hdr->frame_control)) {
|
||||
struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr;
|
||||
u16 control = le16_to_cpu(bar->control);
|
||||
|
||||
tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control);
|
||||
}
|
||||
|
||||
val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
|
||||
FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
|
||||
FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
|
||||
|
|
@ -609,8 +632,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
|||
FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
|
||||
FIELD_PREP(MT_TXD1_HDR_INFO,
|
||||
ieee80211_get_hdrlen_from_skb(skb) / 2) |
|
||||
FIELD_PREP(MT_TXD1_TID,
|
||||
skb->priority & IEEE80211_QOS_CTL_TID_MASK) |
|
||||
FIELD_PREP(MT_TXD1_TID, tid) |
|
||||
FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
|
||||
|
||||
if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)
|
||||
|
|
@ -634,10 +656,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
|||
}
|
||||
txwi[2] = cpu_to_le32(val);
|
||||
|
||||
txwi[4] = 0;
|
||||
txwi[5] = 0;
|
||||
txwi[6] = 0;
|
||||
|
||||
if (!ieee80211_is_data(fc) || multicast) {
|
||||
u16 rate;
|
||||
|
||||
|
|
@ -665,20 +683,24 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
|||
|
||||
val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
|
||||
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
|
||||
if (wcid->amsdu)
|
||||
val |= MT_TXD7_HW_AMSDU;
|
||||
txwi[7] = cpu_to_le32(val);
|
||||
|
||||
val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
|
||||
if (ieee80211_is_data_qos(fc)) {
|
||||
seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
|
||||
val |= MT_TXD3_SN_VALID;
|
||||
} else if (ieee80211_is_back_req(fc)) {
|
||||
struct ieee80211_bar *bar;
|
||||
if (info->flags & IEEE80211_TX_CTL_INJECTED) {
|
||||
seqno = le16_to_cpu(hdr->seq_ctrl);
|
||||
|
||||
bar = (struct ieee80211_bar *)skb->data;
|
||||
seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num));
|
||||
val |= MT_TXD3_SN_VALID;
|
||||
if (ieee80211_is_back_req(hdr->frame_control)) {
|
||||
struct ieee80211_bar *bar;
|
||||
|
||||
bar = (struct ieee80211_bar *)skb->data;
|
||||
seqno = le16_to_cpu(bar->start_seq_num);
|
||||
}
|
||||
|
||||
val |= MT_TXD3_SN_VALID |
|
||||
FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
|
||||
}
|
||||
val |= FIELD_PREP(MT_TXD3_SEQ, seqno);
|
||||
txwi[3] |= cpu_to_le32(val);
|
||||
}
|
||||
|
||||
|
|
@ -715,6 +737,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
|
||||
/* pass partial skb header to fw */
|
||||
tx_info->buf[1].len = MT_CT_PARSE_LEN;
|
||||
tx_info->buf[1].skip_unmap = true;
|
||||
tx_info->nbuf = MT_CT_DMA_BUF_NUM;
|
||||
|
||||
txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD);
|
||||
|
|
@ -747,45 +770,29 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
mt7915_tx_check_aggr_tid(struct mt7915_sta *msta, u8 tid)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
spin_lock_bh(&msta->ampdu_lock);
|
||||
if (msta->ampdu_state[tid] == MT7915_AGGR_STOP)
|
||||
ret = true;
|
||||
spin_unlock_bh(&msta->ampdu_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
|
||||
mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct mt7915_sta *msta;
|
||||
u16 tid;
|
||||
u16 fc, tid;
|
||||
u32 val;
|
||||
|
||||
if (!sta->ht_cap.ht_supported)
|
||||
if (!sta || !sta->ht_cap.ht_supported)
|
||||
return;
|
||||
|
||||
if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
|
||||
tid = FIELD_GET(MT_TXD1_TID, le32_to_cpu(txwi[1]));
|
||||
if (tid >= 6) /* skip VO queue */
|
||||
return;
|
||||
|
||||
if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
|
||||
return;
|
||||
|
||||
if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
|
||||
val = le32_to_cpu(txwi[2]);
|
||||
fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
|
||||
FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
|
||||
if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
|
||||
return;
|
||||
|
||||
msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
tid = ieee80211_get_tid(hdr);
|
||||
|
||||
if (mt7915_tx_check_aggr_tid(msta, tid)) {
|
||||
if (!test_and_set_bit(tid, &msta->ampdu_state))
|
||||
ieee80211_start_tx_ba_session(sta, tid, 0);
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_PROGRESS);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -822,8 +829,6 @@ mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
|
|||
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
info->flags |= IEEE80211_TX_STAT_AMPDU;
|
||||
else if (sta)
|
||||
mt7915_tx_check_aggr(sta, skb);
|
||||
|
||||
if (stat)
|
||||
ieee80211_tx_info_clear_status(info);
|
||||
|
|
@ -864,6 +869,10 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||
struct ieee80211_sta *sta = NULL;
|
||||
u8 i, count;
|
||||
|
||||
/* clean DMA queues and unmap buffers first */
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
|
||||
|
||||
/*
|
||||
* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE,
|
||||
* to the time ack is received or dropped by hw (air + hw queue time).
|
||||
|
|
@ -880,6 +889,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||
*/
|
||||
if (info & MT_TX_FREE_PAIR) {
|
||||
struct mt7915_sta *msta;
|
||||
struct mt7915_phy *phy;
|
||||
struct mt76_wcid *wcid;
|
||||
u16 idx;
|
||||
|
||||
|
|
@ -891,8 +901,13 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||
continue;
|
||||
|
||||
msta = container_of(wcid, struct mt7915_sta, wcid);
|
||||
ieee80211_queue_work(mt76_hw(dev), &msta->stats_work);
|
||||
continue;
|
||||
phy = msta->vif->phy;
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (list_empty(&msta->stats_list))
|
||||
list_add_tail(&msta->stats_list, &phy->stats_list);
|
||||
if (list_empty(&msta->poll_list))
|
||||
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
|
||||
|
|
@ -907,6 +922,21 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||
|
||||
mt7915_txp_skb_unmap(mdev, txwi);
|
||||
if (txwi->skb) {
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txwi->skb);
|
||||
void *txwi_ptr = mt76_get_txwi_ptr(mdev, txwi);
|
||||
|
||||
if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
mt7915_tx_check_aggr(sta, txwi_ptr);
|
||||
|
||||
if (sta && !info->tx_time_est) {
|
||||
struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
|
||||
int pending;
|
||||
|
||||
pending = atomic_dec_return(&wcid->non_aql_packets);
|
||||
if (pending < 0)
|
||||
atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
|
||||
}
|
||||
|
||||
mt7915_tx_complete_status(mdev, txwi->skb, sta, stat);
|
||||
txwi->skb = NULL;
|
||||
}
|
||||
|
|
@ -914,10 +944,12 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||
mt76_put_txwi(mdev, txwi);
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
mt7915_mac_sta_poll(dev);
|
||||
mt76_worker_schedule(&dev->mt76.tx_worker);
|
||||
}
|
||||
|
||||
void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e)
|
||||
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
|
||||
{
|
||||
struct mt7915_dev *dev;
|
||||
|
||||
|
|
@ -1186,7 +1218,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
|
|||
if (ext_phy)
|
||||
mt76_txq_schedule_all(ext_phy);
|
||||
|
||||
tasklet_disable(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_disable(&dev->mt76.tx_worker);
|
||||
napi_disable(&dev->mt76.napi[0]);
|
||||
napi_disable(&dev->mt76.napi[1]);
|
||||
napi_disable(&dev->mt76.napi[2]);
|
||||
|
|
@ -1206,7 +1238,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
|
|||
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
|
||||
clear_bit(MT76_RESET, &dev->mphy.state);
|
||||
|
||||
tasklet_enable(&dev->mt76.tx_tasklet);
|
||||
mt76_worker_enable(&dev->mt76.tx_worker);
|
||||
napi_enable(&dev->mt76.tx_napi);
|
||||
napi_schedule(&dev->mt76.tx_napi);
|
||||
|
||||
|
|
@ -1281,39 +1313,63 @@ mt7915_mac_update_mib_stats(struct mt7915_phy *phy)
|
|||
}
|
||||
}
|
||||
|
||||
void mt7915_mac_sta_stats_work(struct work_struct *work)
|
||||
static void
|
||||
mt7915_mac_sta_stats_work(struct mt7915_phy *phy)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_vif *vif;
|
||||
struct mt7915_sta_stats *stats;
|
||||
struct mt7915_dev *dev = phy->dev;
|
||||
struct mt7915_sta *msta;
|
||||
struct mt7915_dev *dev;
|
||||
|
||||
msta = container_of(work, struct mt7915_sta, stats_work);
|
||||
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
|
||||
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
|
||||
dev = msta->vif->dev;
|
||||
stats = &msta->stats;
|
||||
|
||||
/* use MT_TX_FREE_RATE to report Tx rate for further devices */
|
||||
if (time_after(jiffies, stats->jiffies + HZ)) {
|
||||
mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO,
|
||||
msta->wcid.idx);
|
||||
|
||||
stats->jiffies = jiffies;
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(IEEE80211_RC_SUPP_RATES_CHANGED |
|
||||
IEEE80211_RC_NSS_CHANGED |
|
||||
IEEE80211_RC_BW_CHANGED, &stats->changed))
|
||||
mt7915_mcu_add_rate_ctrl(dev, vif, sta);
|
||||
|
||||
if (test_and_clear_bit(IEEE80211_RC_SMPS_CHANGED, &stats->changed))
|
||||
mt7915_mcu_add_smps(dev, vif, sta);
|
||||
LIST_HEAD(list);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (list_empty(&msta->poll_list))
|
||||
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
|
||||
list_splice_init(&phy->stats_list, &list);
|
||||
|
||||
while (!list_empty(&list)) {
|
||||
msta = list_first_entry(&list, struct mt7915_sta, stats_list);
|
||||
list_del_init(&msta->stats_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
/* use MT_TX_FREE_RATE to report Tx rate for further devices */
|
||||
mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
void mt7915_mac_sta_rc_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_vif *vif;
|
||||
struct mt7915_sta *msta;
|
||||
u32 changed;
|
||||
LIST_HEAD(list);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
list_splice_init(&dev->sta_rc_list, &list);
|
||||
|
||||
while (!list_empty(&list)) {
|
||||
msta = list_first_entry(&list, struct mt7915_sta, rc_list);
|
||||
list_del_init(&msta->rc_list);
|
||||
changed = msta->stats.changed;
|
||||
msta->stats.changed = 0;
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
|
||||
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
|
||||
|
||||
if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
|
||||
IEEE80211_RC_NSS_CHANGED |
|
||||
IEEE80211_RC_BW_CHANGED))
|
||||
mt7915_mcu_add_rate_ctrl(dev, vif, sta);
|
||||
|
||||
if (changed & IEEE80211_RC_SMPS_CHANGED)
|
||||
mt7915_mcu_add_smps(dev, vif, sta);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
|
|
@ -1335,6 +1391,11 @@ void mt7915_mac_work(struct work_struct *work)
|
|||
mt7915_mac_update_mib_stats(phy);
|
||||
}
|
||||
|
||||
if (++phy->sta_work_count == 10) {
|
||||
phy->sta_work_count = 0;
|
||||
mt7915_mac_sta_stats_work(phy);
|
||||
};
|
||||
|
||||
mutex_unlock(&mdev->mutex);
|
||||
|
||||
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
|
|||
goto out;
|
||||
}
|
||||
mvif->omac_idx = idx;
|
||||
mvif->dev = dev;
|
||||
mvif->phy = phy;
|
||||
mvif->band_idx = ext_phy;
|
||||
|
||||
if (ext_phy)
|
||||
|
|
@ -155,6 +155,8 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
|
|||
|
||||
idx = MT7915_WTBL_RESERVED - mvif->idx;
|
||||
|
||||
INIT_LIST_HEAD(&mvif->sta.rc_list);
|
||||
INIT_LIST_HEAD(&mvif->sta.stats_list);
|
||||
INIT_LIST_HEAD(&mvif->sta.poll_list);
|
||||
mvif->sta.wcid.idx = idx;
|
||||
mvif->sta.wcid.ext_phy = mvif->band_idx;
|
||||
|
|
@ -167,7 +169,6 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
|
|||
if (vif->txq) {
|
||||
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
|
||||
mtxq->wcid = &mvif->sta.wcid;
|
||||
mt76_txq_init(&dev->mt76, vif->txq);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -190,8 +191,6 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
|
|||
mt7915_mcu_add_dev_info(dev, vif, false);
|
||||
|
||||
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
|
||||
if (vif->txq)
|
||||
mt76_txq_remove(&dev->mt76, vif->txq);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
phy->mt76->vif_mask &= ~BIT(mvif->idx);
|
||||
|
|
@ -493,9 +492,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
|||
if (idx < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
INIT_LIST_HEAD(&msta->rc_list);
|
||||
INIT_LIST_HEAD(&msta->stats_list);
|
||||
INIT_LIST_HEAD(&msta->poll_list);
|
||||
INIT_WORK(&msta->stats_work, mt7915_mac_sta_stats_work);
|
||||
spin_lock_init(&msta->ampdu_lock);
|
||||
msta->vif = mvif;
|
||||
msta->wcid.sta = 1;
|
||||
msta->wcid.idx = idx;
|
||||
|
|
@ -528,6 +527,10 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
|||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
list_del_init(&msta->poll_list);
|
||||
if (!list_empty(&msta->stats_list))
|
||||
list_del_init(&msta->stats_list);
|
||||
if (!list_empty(&msta->rc_list))
|
||||
list_del_init(&msta->rc_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
|
|
@ -603,23 +606,21 @@ mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
mtxq->aggr = true;
|
||||
mtxq->send_bar = false;
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_OPERATIONAL);
|
||||
mt7915_mcu_add_tx_ba(dev, params, true);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_FLUSH:
|
||||
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
|
||||
mtxq->aggr = false;
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP);
|
||||
clear_bit(tid, &msta->ampdu_state);
|
||||
mt7915_mcu_add_tx_ba(dev, params, false);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_START);
|
||||
set_bit(tid, &msta->ampdu_state);
|
||||
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_CONT:
|
||||
mtxq->aggr = false;
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP);
|
||||
clear_bit(tid, &msta->ampdu_state);
|
||||
mt7915_mcu_add_tx_ba(dev, params, false);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
|
|
@ -789,18 +790,16 @@ mt7915_sta_rc_update(struct ieee80211_hw *hw,
|
|||
struct ieee80211_sta *sta,
|
||||
u32 changed)
|
||||
{
|
||||
struct mt7915_dev *dev = mt7915_hw_dev(hw);
|
||||
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(vif, sta->addr);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
msta->stats.changed |= changed;
|
||||
if (list_empty(&msta->rc_list))
|
||||
list_add_tail(&msta->rc_list, &dev->sta_rc_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
set_bit(changed, &msta->stats.changed);
|
||||
ieee80211_queue_work(hw, &msta->stats_work);
|
||||
ieee80211_queue_work(hw, &dev->rc_work);
|
||||
}
|
||||
|
||||
const struct ieee80211_ops mt7915_ops = {
|
||||
|
|
|
|||
|
|
@ -522,6 +522,9 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||
return;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
||||
if (!wcid)
|
||||
return;
|
||||
|
||||
msta = container_of(wcid, struct mt7915_sta, wcid);
|
||||
stats = &msta->stats;
|
||||
|
||||
|
|
@ -714,8 +717,8 @@ mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len,
|
|||
ptlv = skb_put(skb, sub_len);
|
||||
memcpy(ptlv, &tlv, sizeof(tlv));
|
||||
|
||||
*sub_ntlv = cpu_to_le16(le16_to_cpu(*sub_ntlv) + 1);
|
||||
*len = cpu_to_le16(le16_to_cpu(*len) + sub_len);
|
||||
le16_add_cpu(sub_ntlv, 1);
|
||||
le16_add_cpu(len, sub_len);
|
||||
|
||||
return ptlv;
|
||||
}
|
||||
|
|
@ -933,11 +936,11 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
|
|||
tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
|
||||
|
||||
he = (struct bss_info_he *)tlv;
|
||||
he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext * 4;
|
||||
he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
|
||||
if (!he->he_pe_duration)
|
||||
he->he_pe_duration = DEFAULT_HE_PE_DURATION;
|
||||
|
||||
he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th * 32);
|
||||
he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
|
||||
if (!he->he_rts_thres)
|
||||
he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
|
||||
|
||||
|
|
@ -946,6 +949,23 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
|
|||
he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb)
|
||||
{
|
||||
#define TXD_CMP_MAP1 GENMASK(15, 0)
|
||||
#define TXD_CMP_MAP2 (GENMASK(31, 0) & ~BIT(23))
|
||||
struct bss_info_hw_amsdu *amsdu;
|
||||
struct tlv *tlv;
|
||||
|
||||
tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu));
|
||||
|
||||
amsdu = (struct bss_info_hw_amsdu *)tlv;
|
||||
amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1);
|
||||
amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2);
|
||||
amsdu->trig_thres = cpu_to_le16(2);
|
||||
amsdu->enable = true;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7915_vif *mvif)
|
||||
{
|
||||
|
|
@ -1020,6 +1040,7 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
|
|||
mt7915_mcu_bss_rfch_tlv(skb, vif, phy);
|
||||
mt7915_mcu_bss_bmc_tlv(skb, phy);
|
||||
mt7915_mcu_bss_ra_tlv(skb, vif, phy);
|
||||
mt7915_mcu_bss_hw_amsdu_tlv(skb);
|
||||
|
||||
if (vif->bss_conf.he_support)
|
||||
mt7915_mcu_bss_he_tlv(skb, vif, phy);
|
||||
|
|
@ -1178,6 +1199,9 @@ mt7915_mcu_sta_ba(struct mt7915_dev *dev,
|
|||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
if (enable && tx && !params->amsdu)
|
||||
msta->wcid.amsdu = false;
|
||||
|
||||
skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta,
|
||||
MT7915_STA_UPDATE_MAX_SIZE);
|
||||
if (IS_ERR(skb))
|
||||
|
|
@ -1407,7 +1431,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
|
|||
|
||||
he->max_nss_mcs[CMD_HE_MCS_BW160] =
|
||||
he_cap->he_mcs_nss_supp.rx_mcs_160;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
he->max_nss_mcs[CMD_HE_MCS_BW80] =
|
||||
he_cap->he_mcs_nss_supp.rx_mcs_80;
|
||||
|
|
@ -1440,6 +1464,38 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
|
|||
he->pkt_ext = 2;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_mcu_sta_uapsd_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct sta_rec_uapsd *uapsd;
|
||||
struct tlv *tlv;
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_AP || !sta->wme)
|
||||
return;
|
||||
|
||||
tlv = mt7915_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd));
|
||||
uapsd = (struct sta_rec_uapsd *)tlv;
|
||||
|
||||
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) {
|
||||
uapsd->dac_map |= BIT(3);
|
||||
uapsd->tac_map |= BIT(3);
|
||||
}
|
||||
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) {
|
||||
uapsd->dac_map |= BIT(2);
|
||||
uapsd->tac_map |= BIT(2);
|
||||
}
|
||||
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) {
|
||||
uapsd->dac_map |= BIT(1);
|
||||
uapsd->tac_map |= BIT(1);
|
||||
}
|
||||
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) {
|
||||
uapsd->dac_map |= BIT(0);
|
||||
uapsd->tac_map |= BIT(0);
|
||||
}
|
||||
uapsd->max_sp = sta->max_sp;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
|
||||
{
|
||||
|
|
@ -1511,9 +1567,40 @@ mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif,
|
|||
MCU_EXT_CMD_STA_REC_UPDATE, true);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
|
||||
{
|
||||
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
struct sta_rec_amsdu *amsdu;
|
||||
struct tlv *tlv;
|
||||
|
||||
if (!sta->max_amsdu_len)
|
||||
return;
|
||||
|
||||
tlv = mt7915_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
|
||||
amsdu = (struct sta_rec_amsdu *)tlv;
|
||||
amsdu->max_amsdu_num = 8;
|
||||
amsdu->amsdu_en = true;
|
||||
amsdu->max_mpdu_size = sta->max_amsdu_len >=
|
||||
IEEE80211_MAX_MPDU_LEN_VHT_7991;
|
||||
msta->wcid.amsdu = true;
|
||||
}
|
||||
|
||||
static bool
|
||||
mt7915_hw_amsdu_supported(struct ieee80211_vif *vif)
|
||||
{
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
|
||||
struct ieee80211_sta *sta)
|
||||
struct ieee80211_sta *sta, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct tlv *tlv;
|
||||
|
||||
|
|
@ -1524,6 +1611,9 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
|
|||
tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
|
||||
ht = (struct sta_rec_ht *)tlv;
|
||||
ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
|
||||
|
||||
if (mt7915_hw_amsdu_supported(vif))
|
||||
mt7915_mcu_sta_amsdu_tlv(skb, sta);
|
||||
}
|
||||
|
||||
/* starec vht */
|
||||
|
|
@ -1540,6 +1630,9 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
|
|||
/* starec he */
|
||||
if (sta->he_cap.has_he)
|
||||
mt7915_mcu_sta_he_tlv(skb, sta);
|
||||
|
||||
/* starec uapsd */
|
||||
mt7915_mcu_sta_uapsd_tlv(skb, sta, vif);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2176,7 +2269,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
|
|||
|
||||
mt7915_mcu_sta_basic_tlv(skb, vif, sta, enable);
|
||||
if (enable && sta)
|
||||
mt7915_mcu_sta_tlv(dev, skb, sta);
|
||||
mt7915_mcu_sta_tlv(dev, skb, sta, vif);
|
||||
|
||||
sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
|
||||
|
||||
|
|
@ -2335,14 +2428,6 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
|
|||
struct bss_info_bcn *bcn;
|
||||
int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE;
|
||||
|
||||
rskb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len);
|
||||
if (IS_ERR(rskb))
|
||||
return PTR_ERR(rskb);
|
||||
|
||||
tlv = mt7915_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
|
||||
bcn = (struct bss_info_bcn *)tlv;
|
||||
bcn->enable = en;
|
||||
|
||||
skb = ieee80211_beacon_get_template(hw, vif, &offs);
|
||||
if (!skb)
|
||||
return -EINVAL;
|
||||
|
|
@ -2353,6 +2438,16 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
rskb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len);
|
||||
if (IS_ERR(rskb)) {
|
||||
dev_kfree_skb(skb);
|
||||
return PTR_ERR(rskb);
|
||||
}
|
||||
|
||||
tlv = mt7915_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
|
||||
bcn = (struct bss_info_bcn *)tlv;
|
||||
bcn->enable = en;
|
||||
|
||||
if (mvif->band_idx) {
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
|
||||
|
|
@ -2901,6 +2996,7 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
|
|||
struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
|
||||
struct edca *e = &req.edca[ac];
|
||||
|
||||
e->set = WMM_PARAM_SET;
|
||||
e->queue = ac + mvif->wmm_idx * MT7915_MAX_WMM_SETS;
|
||||
e->aifs = q->aifs;
|
||||
e->txop = cpu_to_le16(q->txop);
|
||||
|
|
@ -3052,8 +3148,10 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
|
|||
.channel_band = chandef->chan->band,
|
||||
};
|
||||
|
||||
if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
|
||||
chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
|
||||
if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
||||
req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
|
||||
else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
|
||||
chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
|
||||
req.switch_reason = CH_SWITCH_DFS;
|
||||
else
|
||||
req.switch_reason = CH_SWITCH_NORMAL;
|
||||
|
|
|
|||
|
|
@ -402,6 +402,16 @@ struct bss_info_ra {
|
|||
__le32 fast_interval;
|
||||
} __packed;
|
||||
|
||||
struct bss_info_hw_amsdu {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
__le32 cmp_bitmap_0;
|
||||
__le32 cmp_bitmap_1;
|
||||
__le16 trig_thres;
|
||||
u8 enable;
|
||||
u8 rsv;
|
||||
} __packed;
|
||||
|
||||
struct bss_info_he {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
|
|
@ -645,6 +655,17 @@ struct sta_rec_vht {
|
|||
u8 rsv[3];
|
||||
} __packed;
|
||||
|
||||
struct sta_rec_uapsd {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
u8 dac_map;
|
||||
u8 tac_map;
|
||||
u8 max_sp;
|
||||
u8 rsv0;
|
||||
__le16 listen_interval;
|
||||
u8 rsv1[2];
|
||||
} __packed;
|
||||
|
||||
struct sta_rec_muru {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
|
|
@ -725,6 +746,15 @@ struct sta_rec_ba {
|
|||
__le16 winsize;
|
||||
} __packed;
|
||||
|
||||
struct sta_rec_amsdu {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
u8 max_amsdu_num;
|
||||
u8 max_mpdu_size;
|
||||
u8 amsdu_en;
|
||||
u8 rsv;
|
||||
} __packed;
|
||||
|
||||
struct sec_key {
|
||||
u8 cipher_id;
|
||||
u8 cipher_len;
|
||||
|
|
@ -951,6 +981,8 @@ enum {
|
|||
sizeof(struct sta_rec_he) + \
|
||||
sizeof(struct sta_rec_ba) + \
|
||||
sizeof(struct sta_rec_vht) + \
|
||||
sizeof(struct sta_rec_uapsd) + \
|
||||
sizeof(struct sta_rec_amsdu) + \
|
||||
sizeof(struct tlv) + \
|
||||
MT7915_WTBL_UPDATE_MAX_SIZE)
|
||||
|
||||
|
|
@ -962,6 +994,7 @@ enum {
|
|||
sizeof(struct bss_info_basic) +\
|
||||
sizeof(struct bss_info_rf_ch) +\
|
||||
sizeof(struct bss_info_ra) + \
|
||||
sizeof(struct bss_info_hw_amsdu) +\
|
||||
sizeof(struct bss_info_he) + \
|
||||
sizeof(struct bss_info_bmc_rate) +\
|
||||
sizeof(struct bss_info_ext_bss) +\
|
||||
|
|
|
|||
|
|
@ -62,13 +62,6 @@ enum mt7915_rxq_id {
|
|||
MT7915_RXQ_MCU_WA,
|
||||
};
|
||||
|
||||
enum mt7915_ampdu_state {
|
||||
MT7915_AGGR_STOP,
|
||||
MT7915_AGGR_PROGRESS,
|
||||
MT7915_AGGR_START,
|
||||
MT7915_AGGR_OPERATIONAL
|
||||
};
|
||||
|
||||
struct mt7915_sta_stats {
|
||||
struct rate_info prob_rate;
|
||||
struct rate_info tx_rate;
|
||||
|
|
@ -83,14 +76,14 @@ struct mt7915_sta {
|
|||
|
||||
struct mt7915_vif *vif;
|
||||
|
||||
struct list_head stats_list;
|
||||
struct list_head poll_list;
|
||||
struct list_head rc_list;
|
||||
u32 airtime_ac[8];
|
||||
|
||||
struct mt7915_sta_stats stats;
|
||||
struct work_struct stats_work;
|
||||
|
||||
spinlock_t ampdu_lock;
|
||||
enum mt7915_ampdu_state ampdu_state[IEEE80211_NUM_TIDS];
|
||||
unsigned long ampdu_state;
|
||||
};
|
||||
|
||||
struct mt7915_vif {
|
||||
|
|
@ -100,7 +93,7 @@ struct mt7915_vif {
|
|||
u8 wmm_idx;
|
||||
|
||||
struct mt7915_sta sta;
|
||||
struct mt7915_dev *dev;
|
||||
struct mt7915_phy *phy;
|
||||
|
||||
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
|
||||
};
|
||||
|
|
@ -135,9 +128,11 @@ struct mt7915_phy {
|
|||
u32 ampdu_ref;
|
||||
|
||||
struct mib_stats mib;
|
||||
struct list_head stats_list;
|
||||
|
||||
struct delayed_work mac_work;
|
||||
u8 mac_work_count;
|
||||
u8 sta_work_count;
|
||||
};
|
||||
|
||||
struct mt7915_dev {
|
||||
|
|
@ -146,15 +141,18 @@ struct mt7915_dev {
|
|||
struct mt76_phy mphy;
|
||||
};
|
||||
|
||||
const struct mt76_bus_ops *bus_ops;
|
||||
struct mt7915_phy phy;
|
||||
|
||||
u16 chainmask;
|
||||
|
||||
struct work_struct init_work;
|
||||
struct work_struct rc_work;
|
||||
struct work_struct reset_work;
|
||||
wait_queue_head_t reset_wait;
|
||||
u32 reset_state;
|
||||
|
||||
struct list_head sta_rc_list;
|
||||
struct list_head sta_poll_list;
|
||||
spinlock_t sta_poll_lock;
|
||||
|
||||
|
|
@ -260,26 +258,8 @@ mt7915_ext_phy(struct mt7915_dev *dev)
|
|||
|
||||
static inline u8 mt7915_lmac_mapping(struct mt7915_dev *dev, u8 ac)
|
||||
{
|
||||
static const u8 lmac_queue_map[] = {
|
||||
[IEEE80211_AC_BK] = MT_LMAC_AC00,
|
||||
[IEEE80211_AC_BE] = MT_LMAC_AC01,
|
||||
[IEEE80211_AC_VI] = MT_LMAC_AC02,
|
||||
[IEEE80211_AC_VO] = MT_LMAC_AC03,
|
||||
};
|
||||
|
||||
if (WARN_ON_ONCE(ac >= ARRAY_SIZE(lmac_queue_map)))
|
||||
return MT_LMAC_AC01; /* BE */
|
||||
|
||||
return lmac_queue_map[ac];
|
||||
}
|
||||
|
||||
static inline void
|
||||
mt7915_set_aggr_state(struct mt7915_sta *msta, u8 tid,
|
||||
enum mt7915_ampdu_state state)
|
||||
{
|
||||
spin_lock_bh(&msta->ampdu_lock);
|
||||
msta->ampdu_state[tid] = state;
|
||||
spin_unlock_bh(&msta->ampdu_lock);
|
||||
/* LMAC uses the reverse order of mac80211 AC indexes */
|
||||
return 3 - ac;
|
||||
}
|
||||
|
||||
extern const struct ieee80211_ops mt7915_ops;
|
||||
|
|
@ -448,7 +428,6 @@ mt7915_l2_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val)
|
|||
bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask);
|
||||
void mt7915_mac_reset_counters(struct mt7915_phy *phy);
|
||||
void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);
|
||||
void mt7915_mac_sta_poll(struct mt7915_dev *dev);
|
||||
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
||||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_key_conf *key, bool beacon);
|
||||
|
|
@ -461,13 +440,12 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
|||
struct ieee80211_sta *sta);
|
||||
void mt7915_mac_work(struct work_struct *work);
|
||||
void mt7915_mac_reset_work(struct work_struct *work);
|
||||
void mt7915_mac_sta_stats_work(struct work_struct *work);
|
||||
void mt7915_mac_sta_rc_work(struct work_struct *work);
|
||||
int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
||||
enum mt76_txq_id qid, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta,
|
||||
struct mt76_tx_info *tx_info);
|
||||
void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e);
|
||||
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
|
||||
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb);
|
||||
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
|
||||
|
|
|
|||
|
|
@ -29,9 +29,10 @@ mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
|
|||
static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
|
||||
{
|
||||
struct mt7915_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))
|
||||
|
|
@ -39,27 +40,23 @@ static irqreturn_t mt7915_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;
|
||||
if (intr & MT_INT_TX_DONE_MCU)
|
||||
mask |= MT_INT_TX_DONE_MCU;
|
||||
|
||||
if (intr & MT_INT_TX_DONE_ALL) {
|
||||
mt7915_irq_disable(dev, MT_INT_TX_DONE_ALL);
|
||||
mt7915_irq_disable(dev, mask);
|
||||
|
||||
if (intr & MT_INT_TX_DONE_MCU)
|
||||
napi_schedule(&dev->mt76.tx_napi);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE_DATA) {
|
||||
mt7915_irq_disable(dev, MT_INT_RX_DONE_DATA);
|
||||
if (intr & MT_INT_RX_DONE_DATA)
|
||||
napi_schedule(&dev->mt76.napi[0]);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE_WM) {
|
||||
mt7915_irq_disable(dev, MT_INT_RX_DONE_WM);
|
||||
if (intr & MT_INT_RX_DONE_WM)
|
||||
napi_schedule(&dev->mt76.napi[1]);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE_WA) {
|
||||
mt7915_irq_disable(dev, MT_INT_RX_DONE_WA);
|
||||
if (intr & MT_INT_RX_DONE_WA)
|
||||
napi_schedule(&dev->mt76.napi[2]);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_MCU_CMD) {
|
||||
u32 val = mt76_rr(dev, MT_MCU_CMD);
|
||||
|
|
@ -103,7 +100,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
|
|||
static const struct mt76_driver_ops drv_ops = {
|
||||
/* txwi_size = txd size + txp size */
|
||||
.txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp),
|
||||
.drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ,
|
||||
.drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ |
|
||||
MT_DRV_AMSDU_OFFLOAD,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX |
|
||||
SURVEY_INFO_TIME_RX |
|
||||
SURVEY_INFO_TIME_BSS_RX,
|
||||
|
|
@ -149,6 +147,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
|
|||
(mt7915_l1_rr(dev, MT_HW_REV) & 0xff);
|
||||
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
/* master switch of PCIe tnterrupt enable */
|
||||
mt7915_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
|
||||
|
||||
|
|
|
|||
|
|
@ -313,9 +313,17 @@
|
|||
#define MT_INT_RX_DONE_WA BIT(1)
|
||||
#define MT_INT_RX_DONE(_n) ((_n) ? BIT((_n) - 1) : BIT(16))
|
||||
#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | BIT(16))
|
||||
#define MT_INT_TX_DONE_ALL (BIT(15) | GENMASK(27, 26) | BIT(30))
|
||||
#define MT_INT_TX_DONE_MCU_WA BIT(15)
|
||||
#define MT_INT_TX_DONE_FWDL BIT(26)
|
||||
#define MT_INT_TX_DONE_MCU_WM BIT(27)
|
||||
#define MT_INT_TX_DONE_BAND0 BIT(30)
|
||||
#define MT_INT_TX_DONE_BAND1 BIT(31)
|
||||
#define MT_INT_MCU_CMD BIT(29)
|
||||
|
||||
#define MT_INT_TX_DONE_MCU (MT_INT_TX_DONE_MCU_WA | \
|
||||
MT_INT_TX_DONE_MCU_WM | \
|
||||
MT_INT_TX_DONE_FWDL)
|
||||
|
||||
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
|
||||
#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
|
||||
|
||||
|
|
@ -352,6 +360,13 @@
|
|||
#define MT_HIF_REMAP_L2_BASE GENMASK(31, 12)
|
||||
#define MT_HIF_REMAP_BASE_L2 0x00000
|
||||
|
||||
#define MT_SWDEF_BASE 0x41f200
|
||||
#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs))
|
||||
#define MT_SWDEF_MODE MT_SWDEF(0x3c)
|
||||
#define MT_SWDEF_NORMAL_MODE 0
|
||||
#define MT_SWDEF_ICAP_MODE 1
|
||||
#define MT_SWDEF_SPECTRUM_MODE 2
|
||||
|
||||
#define MT_TOP_BASE 0x18060000
|
||||
#define MT_TOP(ofs) (MT_TOP_BASE + (ofs))
|
||||
|
||||
|
|
|
|||
|
|
@ -42,15 +42,13 @@ static int mt76s_alloc_tx(struct mt76_dev *dev)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < MT_TXQ_MCU_WA; i++) {
|
||||
INIT_LIST_HEAD(&dev->q_tx[i].swq);
|
||||
|
||||
q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&q->lock);
|
||||
q->hw_idx = i;
|
||||
dev->q_tx[i].q = q;
|
||||
dev->q_tx[i] = q;
|
||||
|
||||
q->entry = devm_kcalloc(dev->dev,
|
||||
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
|
||||
|
|
@ -68,6 +66,10 @@ void mt76s_stop_txrx(struct mt76_dev *dev)
|
|||
{
|
||||
struct mt76_sdio *sdio = &dev->sdio;
|
||||
|
||||
cancel_work_sync(&sdio->tx.xmit_work);
|
||||
cancel_work_sync(&sdio->tx.status_work);
|
||||
cancel_work_sync(&sdio->rx.recv_work);
|
||||
cancel_work_sync(&sdio->rx.net_work);
|
||||
cancel_work_sync(&sdio->stat_work);
|
||||
clear_bit(MT76_READING_STATS, &dev->phy.state);
|
||||
|
||||
|
|
@ -94,8 +96,8 @@ mt76s_get_next_rx_entry(struct mt76_queue *q)
|
|||
|
||||
spin_lock_bh(&q->lock);
|
||||
if (q->queued > 0) {
|
||||
e = &q->entry[q->head];
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
e = &q->entry[q->tail];
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
q->queued--;
|
||||
}
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
|
@ -129,39 +131,27 @@ mt76s_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
|
|||
return nframes;
|
||||
}
|
||||
|
||||
static int mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
|
||||
static void mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
|
||||
{
|
||||
struct mt76_sw_queue *sq = &dev->q_tx[qid];
|
||||
u32 n_dequeued = 0, n_sw_dequeued = 0;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
struct mt76_queue_entry entry;
|
||||
struct mt76_queue *q = sq->q;
|
||||
bool wake;
|
||||
|
||||
while (q->queued > n_dequeued) {
|
||||
if (!q->entry[q->head].done)
|
||||
while (q->queued > 0) {
|
||||
if (!q->entry[q->tail].done)
|
||||
break;
|
||||
|
||||
if (q->entry[q->head].schedule) {
|
||||
q->entry[q->head].schedule = false;
|
||||
n_sw_dequeued++;
|
||||
entry = q->entry[q->tail];
|
||||
q->entry[q->tail].done = false;
|
||||
|
||||
if (qid == MT_TXQ_MCU) {
|
||||
dev_kfree_skb(entry.skb);
|
||||
entry.skb = NULL;
|
||||
}
|
||||
|
||||
entry = q->entry[q->head];
|
||||
q->entry[q->head].done = false;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
n_dequeued++;
|
||||
|
||||
if (qid == MT_TXQ_MCU)
|
||||
dev_kfree_skb(entry.skb);
|
||||
else
|
||||
dev->drv->tx_complete_skb(dev, qid, &entry);
|
||||
mt76_queue_tx_complete(dev, q, &entry);
|
||||
}
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
|
||||
sq->swq_queued -= n_sw_dequeued;
|
||||
q->queued -= n_dequeued;
|
||||
|
||||
wake = q->stopped && q->queued < q->ndesc - 8;
|
||||
if (wake)
|
||||
q->stopped = false;
|
||||
|
|
@ -169,19 +159,13 @@ static int mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
|
|||
if (!q->queued)
|
||||
wake_up(&dev->tx_wait);
|
||||
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
if (qid == MT_TXQ_MCU)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
mt76_txq_schedule(&dev->phy, qid);
|
||||
|
||||
if (wake)
|
||||
ieee80211_wake_queue(dev->hw, qid);
|
||||
|
||||
wake_up_process(dev->sdio.tx_kthread);
|
||||
out:
|
||||
return n_dequeued;
|
||||
}
|
||||
|
||||
static void mt76s_tx_status_data(struct work_struct *work)
|
||||
|
|
@ -214,12 +198,12 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
|
|||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct mt76_queue *q = dev->q_tx[qid].q;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
struct mt76_tx_info tx_info = {
|
||||
.skb = skb,
|
||||
};
|
||||
int err, len = skb->len;
|
||||
u16 idx = q->tail;
|
||||
u16 idx = q->head;
|
||||
|
||||
if (q->queued == q->ndesc)
|
||||
return -ENOSPC;
|
||||
|
|
@ -229,9 +213,9 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
q->entry[q->tail].skb = tx_info.skb;
|
||||
q->entry[q->tail].buf_sz = len;
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
q->entry[q->head].skb = tx_info.skb;
|
||||
q->entry[q->head].buf_sz = len;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
q->queued++;
|
||||
|
||||
return idx;
|
||||
|
|
@ -241,25 +225,31 @@ static int
|
|||
mt76s_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid,
|
||||
struct sk_buff *skb, u32 tx_info)
|
||||
{
|
||||
struct mt76_queue *q = dev->q_tx[qid].q;
|
||||
int ret = -ENOSPC, len = skb->len;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
int ret = -ENOSPC, len = skb->len, pad;
|
||||
|
||||
if (q->queued == q->ndesc)
|
||||
goto error;
|
||||
|
||||
pad = round_up(skb->len, 4) - skb->len;
|
||||
ret = mt76_skb_adjust_pad(skb, pad);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
if (q->queued == q->ndesc)
|
||||
goto out;
|
||||
|
||||
ret = mt76_skb_adjust_pad(skb);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
q->entry[q->tail].buf_sz = len;
|
||||
q->entry[q->tail].skb = skb;
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
q->entry[q->head].buf_sz = len;
|
||||
q->entry[q->head].skb = skb;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
q->queued++;
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +257,7 @@ static void mt76s_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
|
|||
{
|
||||
struct mt76_sdio *sdio = &dev->sdio;
|
||||
|
||||
wake_up_process(sdio->tx_kthread);
|
||||
queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
|
||||
}
|
||||
|
||||
static const struct mt76_queue_ops sdio_queue_ops = {
|
||||
|
|
@ -276,41 +266,37 @@ static const struct mt76_queue_ops sdio_queue_ops = {
|
|||
.tx_queue_skb_raw = mt76s_tx_queue_skb_raw,
|
||||
};
|
||||
|
||||
static int mt76s_kthread_run(void *data)
|
||||
static void mt76s_tx_work(struct work_struct *work)
|
||||
{
|
||||
struct mt76_dev *dev = data;
|
||||
struct mt76_phy *mphy = &dev->phy;
|
||||
struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
|
||||
tx.status_work);
|
||||
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
|
||||
int i;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
int i, nframes = 0;
|
||||
for (i = 0; i < MT_TXQ_MCU_WA; i++)
|
||||
mt76s_process_tx_queue(dev, i);
|
||||
|
||||
cond_resched();
|
||||
if (dev->drv->tx_status_data &&
|
||||
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
|
||||
queue_work(dev->wq, &dev->sdio.stat_work);
|
||||
}
|
||||
|
||||
/* rx processing */
|
||||
local_bh_disable();
|
||||
rcu_read_lock();
|
||||
static void mt76s_rx_work(struct work_struct *work)
|
||||
{
|
||||
struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
|
||||
rx.net_work);
|
||||
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
|
||||
int i;
|
||||
|
||||
mt76_for_each_q_rx(dev, i)
|
||||
nframes += mt76s_process_rx_queue(dev, &dev->q_rx[i]);
|
||||
/* rx processing */
|
||||
local_bh_disable();
|
||||
rcu_read_lock();
|
||||
|
||||
rcu_read_unlock();
|
||||
local_bh_enable();
|
||||
mt76_for_each_q_rx(dev, i)
|
||||
mt76s_process_rx_queue(dev, &dev->q_rx[i]);
|
||||
|
||||
/* tx processing */
|
||||
for (i = 0; i < MT_TXQ_MCU_WA; i++)
|
||||
nframes += mt76s_process_tx_queue(dev, i);
|
||||
|
||||
if (dev->drv->tx_status_data &&
|
||||
!test_and_set_bit(MT76_READING_STATS, &mphy->state))
|
||||
queue_work(dev->wq, &dev->sdio.stat_work);
|
||||
|
||||
if (!nframes || !test_bit(MT76_STATE_RUNNING, &mphy->state)) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
rcu_read_unlock();
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
void mt76s_deinit(struct mt76_dev *dev)
|
||||
|
|
@ -318,9 +304,11 @@ void mt76s_deinit(struct mt76_dev *dev)
|
|||
struct mt76_sdio *sdio = &dev->sdio;
|
||||
int i;
|
||||
|
||||
kthread_stop(sdio->kthread);
|
||||
kthread_stop(sdio->tx_kthread);
|
||||
mt76s_stop_txrx(dev);
|
||||
if (sdio->txrx_wq) {
|
||||
destroy_workqueue(sdio->txrx_wq);
|
||||
sdio->txrx_wq = NULL;
|
||||
}
|
||||
|
||||
sdio_claim_host(sdio->func);
|
||||
sdio_release_irq(sdio->func);
|
||||
|
|
@ -348,11 +336,15 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
|
|||
{
|
||||
struct mt76_sdio *sdio = &dev->sdio;
|
||||
|
||||
sdio->kthread = kthread_create(mt76s_kthread_run, dev, "mt76s");
|
||||
if (IS_ERR(sdio->kthread))
|
||||
return PTR_ERR(sdio->kthread);
|
||||
sdio->txrx_wq = alloc_workqueue("mt76s_txrx_wq",
|
||||
WQ_UNBOUND | WQ_HIGHPRI,
|
||||
WQ_UNBOUND_MAX_ACTIVE);
|
||||
if (!sdio->txrx_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&sdio->stat_work, mt76s_tx_status_data);
|
||||
INIT_WORK(&sdio->tx.status_work, mt76s_tx_work);
|
||||
INIT_WORK(&sdio->rx.net_work, mt76s_rx_work);
|
||||
|
||||
mutex_init(&sdio->sched.lock);
|
||||
dev->queue_ops = &sdio_queue_ops;
|
||||
|
|
|
|||
|
|
@ -29,11 +29,12 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev)
|
|||
return;
|
||||
|
||||
qid = skb_get_queue_mapping(skb);
|
||||
q = dev->q_tx[qid].q;
|
||||
q = dev->q_tx[qid];
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
|
||||
while (td->tx_pending > 0 && q->queued < q->ndesc / 2) {
|
||||
while (td->tx_pending > 0 && td->tx_queued - td->tx_done < 1000 &&
|
||||
q->queued < q->ndesc / 2) {
|
||||
int ret;
|
||||
|
||||
ret = dev->queue_ops->tx_queue_skb(dev, qid, skb_get(skb), wcid, NULL);
|
||||
|
|
@ -160,7 +161,7 @@ mt76_testmode_tx_start(struct mt76_dev *dev)
|
|||
td->tx_queued = 0;
|
||||
td->tx_done = 0;
|
||||
td->tx_pending = td->tx_count;
|
||||
tasklet_schedule(&dev->tx_tasklet);
|
||||
mt76_worker_schedule(&dev->tx_worker);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -168,11 +169,11 @@ mt76_testmode_tx_stop(struct mt76_dev *dev)
|
|||
{
|
||||
struct mt76_testmode_data *td = &dev->test;
|
||||
|
||||
tasklet_disable(&dev->tx_tasklet);
|
||||
mt76_worker_disable(&dev->tx_worker);
|
||||
|
||||
td->tx_pending = 0;
|
||||
|
||||
tasklet_enable(&dev->tx_tasklet);
|
||||
mt76_worker_enable(&dev->tx_worker);
|
||||
|
||||
wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, 10 * HZ);
|
||||
|
||||
|
|
@ -442,9 +443,13 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
|
|||
mutex_lock(&dev->mutex);
|
||||
|
||||
if (tb[MT76_TM_ATTR_STATS]) {
|
||||
err = -EINVAL;
|
||||
|
||||
a = nla_nest_start(msg, MT76_TM_ATTR_STATS);
|
||||
err = mt76_testmode_dump_stats(dev, msg);
|
||||
nla_nest_end(msg, a);
|
||||
if (a) {
|
||||
err = mt76_testmode_dump_stats(dev, msg);
|
||||
nla_nest_end(msg, a);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,75 +5,6 @@
|
|||
|
||||
#include "mt76.h"
|
||||
|
||||
static struct mt76_txwi_cache *
|
||||
mt76_alloc_txwi(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *t;
|
||||
dma_addr_t addr;
|
||||
u8 *txwi;
|
||||
int size;
|
||||
|
||||
size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t));
|
||||
txwi = devm_kzalloc(dev->dev, size, GFP_ATOMIC);
|
||||
if (!txwi)
|
||||
return NULL;
|
||||
|
||||
addr = dma_map_single(dev->dev, txwi, dev->drv->txwi_size,
|
||||
DMA_TO_DEVICE);
|
||||
t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size);
|
||||
t->dma_addr = addr;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static struct mt76_txwi_cache *
|
||||
__mt76_get_txwi(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *t = NULL;
|
||||
|
||||
spin_lock_bh(&dev->lock);
|
||||
if (!list_empty(&dev->txwi_cache)) {
|
||||
t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache,
|
||||
list);
|
||||
list_del(&t->list);
|
||||
}
|
||||
spin_unlock_bh(&dev->lock);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
struct mt76_txwi_cache *
|
||||
mt76_get_txwi(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *t = __mt76_get_txwi(dev);
|
||||
|
||||
if (t)
|
||||
return t;
|
||||
|
||||
return mt76_alloc_txwi(dev);
|
||||
}
|
||||
|
||||
void
|
||||
mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&dev->lock);
|
||||
list_add(&t->list, &dev->txwi_cache);
|
||||
spin_unlock_bh(&dev->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_put_txwi);
|
||||
|
||||
void mt76_tx_free(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *t;
|
||||
|
||||
while ((t = __mt76_get_txwi(dev)) != NULL)
|
||||
dma_unmap_single(dev->dev, t->dma_addr, dev->drv->txwi_size,
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static int
|
||||
mt76_txq_get_qid(struct ieee80211_txq *txq)
|
||||
{
|
||||
|
|
@ -83,17 +14,27 @@ mt76_txq_get_qid(struct ieee80211_txq *txq)
|
|||
return txq->ac;
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb)
|
||||
void
|
||||
mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_txq *txq;
|
||||
struct mt76_txq *mtxq;
|
||||
u8 tid;
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
if (!sta || !ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
!ieee80211_is_data_present(hdr->frame_control))
|
||||
return;
|
||||
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
txq = sta->txq[tid];
|
||||
mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
if (!mtxq->aggr)
|
||||
return;
|
||||
|
||||
mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_tx_check_agg_ssn);
|
||||
|
||||
void
|
||||
mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list)
|
||||
|
|
@ -231,7 +172,32 @@ mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_tx_status_check);
|
||||
|
||||
void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb)
|
||||
static void
|
||||
mt76_tx_check_non_aql(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct mt76_wcid *wcid;
|
||||
int pending;
|
||||
|
||||
if (info->tx_time_est)
|
||||
return;
|
||||
|
||||
if (wcid_idx >= ARRAY_SIZE(dev->wcid))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->wcid[wcid_idx]);
|
||||
if (wcid) {
|
||||
pending = atomic_dec_return(&wcid->non_aql_packets);
|
||||
if (pending < 0)
|
||||
atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hw *hw;
|
||||
struct sk_buff_head list;
|
||||
|
|
@ -244,6 +210,8 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb)
|
|||
}
|
||||
#endif
|
||||
|
||||
mt76_tx_check_non_aql(dev, wcid_idx, skb);
|
||||
|
||||
if (!skb->prev) {
|
||||
hw = mt76_tx_status_get_hw(dev, skb);
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
|
|
@ -256,6 +224,32 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_tx_complete_skb);
|
||||
|
||||
static int
|
||||
__mt76_tx_queue_skb(struct mt76_dev *dev, int qid, struct sk_buff *skb,
|
||||
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
|
||||
bool *stop)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct mt76_queue *q;
|
||||
bool non_aql;
|
||||
int pending;
|
||||
int idx;
|
||||
|
||||
non_aql = !info->tx_time_est;
|
||||
idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, sta);
|
||||
if (idx < 0 || !sta || !non_aql)
|
||||
return idx;
|
||||
|
||||
wcid = (struct mt76_wcid *)sta->drv_priv;
|
||||
q = dev->q_tx[qid];
|
||||
q->entry[idx].wcid = wcid->idx;
|
||||
pending = atomic_inc_return(&wcid->non_aql_packets);
|
||||
if (stop && pending >= MT_MAX_NON_AQL_PKT)
|
||||
*stop = true;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
void
|
||||
mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
|
||||
struct mt76_wcid *wcid, struct sk_buff *skb)
|
||||
|
|
@ -288,26 +282,13 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
|
|||
ieee80211_get_tx_rates(info->control.vif, sta, skb,
|
||||
info->control.rates, 1);
|
||||
|
||||
if (sta && ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
struct ieee80211_txq *txq;
|
||||
struct mt76_txq *mtxq;
|
||||
u8 tid;
|
||||
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
txq = sta->txq[tid];
|
||||
mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
|
||||
if (mtxq->aggr)
|
||||
mt76_check_agg_ssn(mtxq, skb);
|
||||
}
|
||||
|
||||
if (ext_phy)
|
||||
info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
|
||||
|
||||
q = dev->q_tx[qid].q;
|
||||
q = dev->q_tx[qid];
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, sta);
|
||||
__mt76_tx_queue_skb(dev, qid, skb, wcid, sta, NULL);
|
||||
dev->queue_ops->kick(dev, q);
|
||||
|
||||
if (q->queued > q->ndesc - 8 && !q->stopped) {
|
||||
|
|
@ -320,23 +301,13 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
|
|||
EXPORT_SYMBOL_GPL(mt76_tx);
|
||||
|
||||
static struct sk_buff *
|
||||
mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq, bool ps)
|
||||
mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq)
|
||||
{
|
||||
struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
|
||||
struct ieee80211_tx_info *info;
|
||||
bool ext_phy = phy != &phy->dev->phy;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = skb_dequeue(&mtxq->retry_q);
|
||||
if (skb) {
|
||||
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
if (ps && skb_queue_empty(&mtxq->retry_q))
|
||||
ieee80211_sta_set_buffered(txq->sta, tid, false);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
skb = ieee80211_tx_dequeue(phy->hw, txq);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
|
@ -361,7 +332,7 @@ mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
|
|||
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
|
||||
mt76_skb_set_moredata(skb, !last);
|
||||
dev->queue_ops->tx_queue_skb(dev, MT_TXQ_PSD, skb, wcid, sta);
|
||||
__mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, wcid, sta, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -373,7 +344,7 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
|||
struct mt76_phy *phy = hw->priv;
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct sk_buff *last_skb = NULL;
|
||||
struct mt76_queue *hwq = dev->q_tx[MT_TXQ_PSD].q;
|
||||
struct mt76_queue *hwq = dev->q_tx[MT_TXQ_PSD];
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&hwq->lock);
|
||||
|
|
@ -386,13 +357,10 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
|||
continue;
|
||||
|
||||
do {
|
||||
skb = mt76_txq_dequeue(phy, mtxq, true);
|
||||
skb = mt76_txq_dequeue(phy, mtxq);
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
if (mtxq->aggr)
|
||||
mt76_check_agg_ssn(mtxq, skb);
|
||||
|
||||
nframes--;
|
||||
if (last_skb)
|
||||
mt76_queue_ps_skb(dev, sta, last_skb, false);
|
||||
|
|
@ -413,26 +381,26 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
|||
EXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
|
||||
|
||||
static int
|
||||
mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_sw_queue *sq,
|
||||
mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
|
||||
struct mt76_txq *mtxq)
|
||||
{
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
|
||||
enum mt76_txq_id qid = mt76_txq_get_qid(txq);
|
||||
struct mt76_wcid *wcid = mtxq->wcid;
|
||||
struct mt76_queue *hwq = sq->q;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sk_buff *skb;
|
||||
int n_frames = 1, limit;
|
||||
struct ieee80211_tx_rate tx_rate;
|
||||
bool ampdu;
|
||||
bool probe;
|
||||
int n_frames = 1;
|
||||
bool stop = false;
|
||||
int idx;
|
||||
|
||||
if (test_bit(MT_WCID_FLAG_PS, &wcid->flags))
|
||||
return 0;
|
||||
|
||||
skb = mt76_txq_dequeue(phy, mtxq, false);
|
||||
if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT)
|
||||
return 0;
|
||||
|
||||
skb = mt76_txq_dequeue(phy, mtxq);
|
||||
if (!skb)
|
||||
return 0;
|
||||
|
||||
|
|
@ -440,62 +408,39 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_sw_queue *sq,
|
|||
if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
|
||||
ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
|
||||
info->control.rates, 1);
|
||||
tx_rate = info->control.rates[0];
|
||||
|
||||
probe = (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
|
||||
ampdu = IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU;
|
||||
limit = ampdu ? 16 : 3;
|
||||
|
||||
if (ampdu)
|
||||
mt76_check_agg_ssn(mtxq, skb);
|
||||
|
||||
idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, txq->sta);
|
||||
|
||||
idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
|
||||
if (idx < 0)
|
||||
return idx;
|
||||
|
||||
do {
|
||||
bool cur_ampdu;
|
||||
|
||||
if (probe)
|
||||
break;
|
||||
|
||||
if (test_bit(MT76_RESET, &phy->state))
|
||||
if (test_bit(MT76_STATE_PM, &phy->state) ||
|
||||
test_bit(MT76_RESET, &phy->state))
|
||||
return -EBUSY;
|
||||
|
||||
skb = mt76_txq_dequeue(phy, mtxq, false);
|
||||
if (stop)
|
||||
break;
|
||||
|
||||
if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
|
||||
break;
|
||||
|
||||
skb = mt76_txq_dequeue(phy, mtxq);
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
cur_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
|
||||
if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
|
||||
ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
|
||||
info->control.rates, 1);
|
||||
|
||||
if (ampdu != cur_ampdu ||
|
||||
(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) {
|
||||
skb_queue_tail(&mtxq->retry_q, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
info->control.rates[0] = tx_rate;
|
||||
|
||||
if (cur_ampdu)
|
||||
mt76_check_agg_ssn(mtxq, skb);
|
||||
|
||||
idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid,
|
||||
txq->sta);
|
||||
idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
|
||||
if (idx < 0)
|
||||
return idx;
|
||||
break;
|
||||
|
||||
n_frames++;
|
||||
} while (n_frames < limit);
|
||||
} while (1);
|
||||
|
||||
if (!probe) {
|
||||
hwq->entry[idx].qid = sq - dev->q_tx;
|
||||
hwq->entry[idx].schedule = true;
|
||||
sq->swq_queued++;
|
||||
}
|
||||
|
||||
dev->queue_ops->kick(dev, hwq);
|
||||
dev->queue_ops->kick(dev, q);
|
||||
|
||||
return n_frames;
|
||||
}
|
||||
|
|
@ -504,23 +449,23 @@ static int
|
|||
mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
|
||||
{
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct mt76_sw_queue *sq = &dev->q_tx[qid];
|
||||
struct mt76_queue *hwq = sq->q;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
struct ieee80211_txq *txq;
|
||||
struct mt76_txq *mtxq;
|
||||
struct mt76_wcid *wcid;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_bh(&hwq->lock);
|
||||
spin_lock_bh(&q->lock);
|
||||
while (1) {
|
||||
if (sq->swq_queued >= 4)
|
||||
break;
|
||||
|
||||
if (test_bit(MT76_RESET, &phy->state)) {
|
||||
if (test_bit(MT76_STATE_PM, &phy->state) ||
|
||||
test_bit(MT76_RESET, &phy->state)) {
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
|
||||
break;
|
||||
|
||||
txq = ieee80211_next_txq(phy->hw, qid);
|
||||
if (!txq)
|
||||
break;
|
||||
|
|
@ -538,32 +483,26 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
|
|||
u8 tid = txq->tid;
|
||||
|
||||
mtxq->send_bar = false;
|
||||
spin_unlock_bh(&hwq->lock);
|
||||
spin_unlock_bh(&q->lock);
|
||||
ieee80211_send_bar(vif, sta->addr, tid, agg_ssn);
|
||||
spin_lock_bh(&hwq->lock);
|
||||
spin_lock_bh(&q->lock);
|
||||
}
|
||||
|
||||
ret += mt76_txq_send_burst(phy, sq, mtxq);
|
||||
ieee80211_return_txq(phy->hw, txq,
|
||||
!skb_queue_empty(&mtxq->retry_q));
|
||||
ret += mt76_txq_send_burst(phy, q, mtxq);
|
||||
ieee80211_return_txq(phy->hw, txq, false);
|
||||
}
|
||||
spin_unlock_bh(&hwq->lock);
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid)
|
||||
{
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct mt76_sw_queue *sq = &dev->q_tx[qid];
|
||||
int len;
|
||||
|
||||
if (qid >= 4)
|
||||
return;
|
||||
|
||||
if (sq->swq_queued >= 4)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
do {
|
||||
|
|
@ -585,9 +524,9 @@ void mt76_txq_schedule_all(struct mt76_phy *phy)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_txq_schedule_all);
|
||||
|
||||
void mt76_tx_tasklet(unsigned long data)
|
||||
void mt76_tx_worker(struct mt76_worker *w)
|
||||
{
|
||||
struct mt76_dev *dev = (struct mt76_dev *)data;
|
||||
struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
|
||||
|
||||
mt76_txq_schedule_all(&dev->phy);
|
||||
if (dev->phy2)
|
||||
|
|
@ -612,8 +551,8 @@ void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
|
|||
if (!txq)
|
||||
continue;
|
||||
|
||||
hwq = dev->q_tx[mt76_txq_get_qid(txq)];
|
||||
mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
hwq = mtxq->swq->q;
|
||||
|
||||
spin_lock_bh(&hwq->lock);
|
||||
mtxq->send_bar = mtxq->aggr && send_bar;
|
||||
|
|
@ -630,38 +569,10 @@ void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
|
|||
if (!test_bit(MT76_STATE_RUNNING, &phy->state))
|
||||
return;
|
||||
|
||||
tasklet_schedule(&dev->tx_tasklet);
|
||||
mt76_worker_schedule(&dev->tx_worker);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_wake_tx_queue);
|
||||
|
||||
void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ieee80211_hw *hw;
|
||||
struct mt76_txq *mtxq;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!txq)
|
||||
return;
|
||||
|
||||
mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
|
||||
while ((skb = skb_dequeue(&mtxq->retry_q)) != NULL) {
|
||||
hw = mt76_tx_status_get_hw(dev, skb);
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_txq_remove);
|
||||
|
||||
void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq)
|
||||
{
|
||||
struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
|
||||
skb_queue_head_init(&mtxq->retry_q);
|
||||
|
||||
mtxq->swq = &dev->q_tx[mt76_txq_get_qid(txq)];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_txq_init);
|
||||
|
||||
u8 mt76_ac_to_hwq(u8 ac)
|
||||
{
|
||||
static const u8 wmm_queue_map[] = {
|
||||
|
|
@ -678,13 +589,9 @@ u8 mt76_ac_to_hwq(u8 ac)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_ac_to_hwq);
|
||||
|
||||
int mt76_skb_adjust_pad(struct sk_buff *skb)
|
||||
int mt76_skb_adjust_pad(struct sk_buff *skb, int pad)
|
||||
{
|
||||
struct sk_buff *iter, *last = skb;
|
||||
u32 pad;
|
||||
|
||||
/* Add zero pad of 4 - 7 bytes */
|
||||
pad = round_up(skb->len, 4) + 4 - skb->len;
|
||||
|
||||
/* First packet of a A-MSDU burst keeps track of the whole burst
|
||||
* length, need to update length of it and the last packet.
|
||||
|
|
@ -706,3 +613,16 @@ int mt76_skb_adjust_pad(struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_skb_adjust_pad);
|
||||
|
||||
void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
struct mt76_queue_entry *e)
|
||||
{
|
||||
if (e->skb)
|
||||
dev->drv->tx_complete_skb(dev, e);
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
q->queued--;
|
||||
spin_unlock_bh(&q->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_queue_tx_complete);
|
||||
|
|
|
|||
|
|
@ -497,8 +497,8 @@ mt76u_get_next_rx_entry(struct mt76_queue *q)
|
|||
|
||||
spin_lock_irqsave(&q->lock, flags);
|
||||
if (q->queued > 0) {
|
||||
urb = q->entry[q->head].urb;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
urb = q->entry[q->tail].urb;
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
q->queued--;
|
||||
}
|
||||
spin_unlock_irqrestore(&q->lock, flags);
|
||||
|
|
@ -616,16 +616,16 @@ static void mt76u_complete_rx(struct urb *urb)
|
|||
default:
|
||||
dev_err_ratelimited(dev->dev, "rx urb failed: %d\n",
|
||||
urb->status);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&q->lock, flags);
|
||||
if (WARN_ONCE(q->entry[q->tail].urb != urb, "rx urb mismatch"))
|
||||
if (WARN_ONCE(q->entry[q->head].urb != urb, "rx urb mismatch"))
|
||||
goto out;
|
||||
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
q->queued++;
|
||||
tasklet_schedule(&dev->usb.rx_tasklet);
|
||||
out:
|
||||
|
|
@ -792,43 +792,27 @@ int mt76u_resume_rx(struct mt76_dev *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mt76u_resume_rx);
|
||||
|
||||
static void mt76u_tx_tasklet(unsigned long data)
|
||||
static void mt76u_tx_worker(struct mt76_worker *w)
|
||||
{
|
||||
struct mt76_dev *dev = (struct mt76_dev *)data;
|
||||
struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
|
||||
struct mt76_queue_entry entry;
|
||||
struct mt76_sw_queue *sq;
|
||||
struct mt76_queue *q;
|
||||
bool wake;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
u32 n_dequeued = 0, n_sw_dequeued = 0;
|
||||
q = dev->q_tx[i];
|
||||
|
||||
sq = &dev->q_tx[i];
|
||||
q = sq->q;
|
||||
|
||||
while (q->queued > n_dequeued) {
|
||||
if (!q->entry[q->head].done)
|
||||
while (q->queued > 0) {
|
||||
if (!q->entry[q->tail].done)
|
||||
break;
|
||||
|
||||
if (q->entry[q->head].schedule) {
|
||||
q->entry[q->head].schedule = false;
|
||||
n_sw_dequeued++;
|
||||
}
|
||||
entry = q->entry[q->tail];
|
||||
q->entry[q->tail].done = false;
|
||||
|
||||
entry = q->entry[q->head];
|
||||
q->entry[q->head].done = false;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
n_dequeued++;
|
||||
|
||||
dev->drv->tx_complete_skb(dev, i, &entry);
|
||||
mt76_queue_tx_complete(dev, q, &entry);
|
||||
}
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
|
||||
sq->swq_queued -= n_sw_dequeued;
|
||||
q->queued -= n_dequeued;
|
||||
|
||||
wake = q->stopped && q->queued < q->ndesc - 8;
|
||||
if (wake)
|
||||
q->stopped = false;
|
||||
|
|
@ -836,8 +820,6 @@ static void mt76u_tx_tasklet(unsigned long data)
|
|||
if (!q->queued)
|
||||
wake_up(&dev->tx_wait);
|
||||
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
mt76_txq_schedule(&dev->phy, i);
|
||||
|
||||
if (dev->drv->tx_status_data &&
|
||||
|
|
@ -882,7 +864,7 @@ static void mt76u_complete_tx(struct urb *urb)
|
|||
dev_err(dev->dev, "tx urb failed: %d\n", urb->status);
|
||||
e->done = true;
|
||||
|
||||
tasklet_schedule(&dev->tx_tasklet);
|
||||
mt76_worker_schedule(&dev->tx_worker);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -909,11 +891,11 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
|
|||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct mt76_queue *q = dev->q_tx[qid].q;
|
||||
struct mt76_queue *q = dev->q_tx[qid];
|
||||
struct mt76_tx_info tx_info = {
|
||||
.skb = skb,
|
||||
};
|
||||
u16 idx = q->tail;
|
||||
u16 idx = q->head;
|
||||
int err;
|
||||
|
||||
if (q->queued == q->ndesc)
|
||||
|
|
@ -932,7 +914,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
|
|||
q->entry[idx].urb, mt76u_complete_tx,
|
||||
&q->entry[idx]);
|
||||
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
q->entry[idx].skb = tx_info.skb;
|
||||
q->queued++;
|
||||
|
||||
|
|
@ -944,7 +926,7 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
|
|||
struct urb *urb;
|
||||
int err;
|
||||
|
||||
while (q->first != q->tail) {
|
||||
while (q->first != q->head) {
|
||||
urb = q->entry[q->first].urb;
|
||||
|
||||
trace_submit_urb(dev, urb);
|
||||
|
|
@ -987,10 +969,8 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
|
|||
int i, j, err;
|
||||
|
||||
for (i = 0; i <= MT_TXQ_PSD; i++) {
|
||||
INIT_LIST_HEAD(&dev->q_tx[i].swq);
|
||||
|
||||
if (i >= IEEE80211_NUM_ACS) {
|
||||
dev->q_tx[i].q = dev->q_tx[0].q;
|
||||
dev->q_tx[i] = dev->q_tx[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1000,7 +980,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
|
|||
|
||||
spin_lock_init(&q->lock);
|
||||
q->hw_idx = mt76u_ac_to_hwq(dev, i);
|
||||
dev->q_tx[i].q = q;
|
||||
dev->q_tx[i] = q;
|
||||
|
||||
q->entry = devm_kcalloc(dev->dev,
|
||||
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
|
||||
|
|
@ -1027,7 +1007,7 @@ static void mt76u_free_tx(struct mt76_dev *dev)
|
|||
struct mt76_queue *q;
|
||||
int j;
|
||||
|
||||
q = dev->q_tx[i].q;
|
||||
q = dev->q_tx[i];
|
||||
if (!q)
|
||||
continue;
|
||||
|
||||
|
|
@ -1040,6 +1020,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
|
|||
{
|
||||
int ret;
|
||||
|
||||
mt76_worker_disable(&dev->tx_worker);
|
||||
|
||||
ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(&dev->phy),
|
||||
HZ / 5);
|
||||
if (!ret) {
|
||||
|
|
@ -1050,7 +1032,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
|
|||
dev_err(dev->dev, "timed out waiting for pending tx\n");
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
q = dev->q_tx[i].q;
|
||||
q = dev->q_tx[i];
|
||||
if (!q)
|
||||
continue;
|
||||
|
||||
|
|
@ -1058,32 +1040,26 @@ void mt76u_stop_tx(struct mt76_dev *dev)
|
|||
usb_kill_urb(q->entry[j].urb);
|
||||
}
|
||||
|
||||
tasklet_kill(&dev->tx_tasklet);
|
||||
|
||||
/* On device removal we maight queue skb's, but mt76u_tx_kick()
|
||||
* will fail to submit urb, cleanup those skb's manually.
|
||||
*/
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
q = dev->q_tx[i].q;
|
||||
q = dev->q_tx[i];
|
||||
if (!q)
|
||||
continue;
|
||||
|
||||
/* Assure we are in sync with killed tasklet. */
|
||||
spin_lock_bh(&q->lock);
|
||||
while (q->queued) {
|
||||
entry = q->entry[q->head];
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
q->queued--;
|
||||
entry = q->entry[q->tail];
|
||||
q->entry[q->tail].done = false;
|
||||
|
||||
dev->drv->tx_complete_skb(dev, i, &entry);
|
||||
}
|
||||
spin_unlock_bh(&q->lock);
|
||||
mt76_queue_tx_complete(dev, q, &entry);
|
||||
}
|
||||
}
|
||||
|
||||
cancel_work_sync(&dev->usb.stat_work);
|
||||
clear_bit(MT76_READING_STATS, &dev->phy.state);
|
||||
|
||||
mt76_worker_enable(&dev->tx_worker);
|
||||
|
||||
mt76_tx_status_check(dev, NULL, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76u_stop_tx);
|
||||
|
|
@ -1133,8 +1109,8 @@ int mt76u_init(struct mt76_dev *dev,
|
|||
mt76u_ops.rmw = ext ? mt76u_rmw_ext : mt76u_rmw;
|
||||
mt76u_ops.write_copy = ext ? mt76u_copy_ext : mt76u_copy;
|
||||
|
||||
dev->tx_worker.fn = mt76u_tx_worker;
|
||||
tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev);
|
||||
tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev);
|
||||
INIT_WORK(&usb->stat_work, mt76u_tx_status_data);
|
||||
|
||||
usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1);
|
||||
|
|
|
|||
|
|
@ -110,4 +110,32 @@ int mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi);
|
||||
|
||||
int __mt76_worker_fn(void *ptr)
|
||||
{
|
||||
struct mt76_worker *w = ptr;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
if (kthread_should_park()) {
|
||||
kthread_parkme();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) {
|
||||
schedule();
|
||||
continue;
|
||||
}
|
||||
|
||||
set_bit(MT76_WORKER_RUNNING, &w->state);
|
||||
set_current_state(TASK_RUNNING);
|
||||
w->fn(w);
|
||||
cond_resched();
|
||||
clear_bit(MT76_WORKER_RUNNING, &w->state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__mt76_worker_fn);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
|
|
|||
|
|
@ -10,6 +10,19 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
struct mt76_worker
|
||||
{
|
||||
struct task_struct *task;
|
||||
void (*fn)(struct mt76_worker *);
|
||||
unsigned long state;
|
||||
};
|
||||
|
||||
enum {
|
||||
MT76_WORKER_SCHEDULED,
|
||||
MT76_WORKER_RUNNING,
|
||||
};
|
||||
|
||||
#define MT76_INCR(_var, _size) \
|
||||
(_var = (((_var) + 1) % (_size)))
|
||||
|
|
@ -45,4 +58,67 @@ mt76_skb_set_moredata(struct sk_buff *skb, bool enable)
|
|||
hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
}
|
||||
|
||||
int __mt76_worker_fn(void *ptr);
|
||||
|
||||
static inline int
|
||||
mt76_worker_setup(struct ieee80211_hw *hw, struct mt76_worker *w,
|
||||
void (*fn)(struct mt76_worker *),
|
||||
const char *name)
|
||||
{
|
||||
const char *dev_name = wiphy_name(hw->wiphy);
|
||||
int ret;
|
||||
|
||||
if (fn)
|
||||
w->fn = fn;
|
||||
w->task = kthread_create(__mt76_worker_fn, w, "mt76-%s %s",
|
||||
name, dev_name);
|
||||
|
||||
ret = PTR_ERR_OR_ZERO(w->task);
|
||||
if (ret) {
|
||||
w->task = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
wake_up_process(w->task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mt76_worker_schedule(struct mt76_worker *w)
|
||||
{
|
||||
if (!w->task)
|
||||
return;
|
||||
|
||||
if (!test_and_set_bit(MT76_WORKER_SCHEDULED, &w->state) &&
|
||||
!test_bit(MT76_WORKER_RUNNING, &w->state))
|
||||
wake_up_process(w->task);
|
||||
}
|
||||
|
||||
static inline void mt76_worker_disable(struct mt76_worker *w)
|
||||
{
|
||||
if (!w->task)
|
||||
return;
|
||||
|
||||
kthread_park(w->task);
|
||||
WRITE_ONCE(w->state, 0);
|
||||
}
|
||||
|
||||
static inline void mt76_worker_enable(struct mt76_worker *w)
|
||||
{
|
||||
if (!w->task)
|
||||
return;
|
||||
|
||||
kthread_unpark(w->task);
|
||||
mt76_worker_schedule(w);
|
||||
}
|
||||
|
||||
static inline void mt76_worker_teardown(struct mt76_worker *w)
|
||||
{
|
||||
if (!w->task)
|
||||
return;
|
||||
|
||||
kthread_stop(w->task);
|
||||
w->task = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user