2020-08-25 05:30:02

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/9] mt76: mt7615: fix reading airtime statistics

- change the WTBL LMAC access function to set the mapping window only once
- use ac * 2 as offset, since each AC has separate words for rx and tx

Signed-off-by: Felix Fietkau <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7915/mac.c | 25 +++++++++++--------
1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 9e17be5005e9..ff08a59c747c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -88,13 +88,12 @@ 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 */
@@ -121,6 +120,7 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev)

while (true) {
bool clear = false;
+ u32 addr;
u16 idx;

spin_lock_bh(&dev->sta_poll_lock);
@@ -133,20 +133,23 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev)
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++) {
+ 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 + IEEE80211_NUM_ACS];
+ 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) {
--
2.28.0


2020-08-25 05:30:02

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/9] mt76: mt7915: optimize mt7915_mac_sta_poll

Since DMA completion does not imply tx completion, it makes more sense to
poll for airtime from mt7915_mac_tx_free.
Reduce the runtime of the function by moving all items from dev->sta_poll_list
to a local list once and process any stations that were added afterwards
on the next run

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 1 -
drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 13 ++++++++++---
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 -
3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index 8a1ae08d9572..f6c18a08d414 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -95,7 +95,6 @@ static int mt7915_poll_tx(struct napi_struct *napi, int budget)
dev = container_of(napi, struct mt7915_dev, mt76.tx_napi);

mt7915_tx_cleanup(dev);
- mt7915_mac_sta_poll(dev);

tasklet_schedule(&dev->mt76.tx_tasklet);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index ff08a59c747c..06bb8d0103ba 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -97,7 +97,7 @@ static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid)
}

/* 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,
@@ -114,8 +114,13 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev)
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) {
@@ -124,11 +129,11 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev)
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);
@@ -929,6 +934,8 @@ 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);
}

void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index cbe84c4aac75..63d4802b4df4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -436,7 +436,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);
--
2.28.0

2020-08-25 05:31:02

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 7/9] mt76: mt7915: add support for accessing mapped registers via bus ops

Makes it possible to read/write them via debugfs, similar to mt7615/7603

Signed-off-by: Felix Fietkau <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7915/dma.c | 108 ++++++++++++++++++
.../wireless/mediatek/mt76/mt7915/mt7915.h | 1 +
2 files changed, 109 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index bdc694609c01..477d125ec5df 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -130,12 +130,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 */
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index 63d4802b4df4..83685a974224 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -141,6 +141,7 @@ struct mt7915_dev {
struct mt76_phy mphy;
};

+ const struct mt76_bus_ops *bus_ops;
struct mt7915_phy phy;

u16 chainmask;
--
2.28.0

2020-08-25 05:31:02

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 3/9] mt76: dma: update q->queued immediately on cleanup

Tx cleanup and tx enqueuing can run in parallel. In order to avoid queue
starvation issues under load, update q->queued immediately.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/dma.c | 39 +++++++++---------------
1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index ade2d58b8da9..7545b552db25 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -152,10 +152,8 @@ 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_entry entry;
- unsigned int n_swq_queued[8] = {};
- unsigned int n_queued = 0;
bool wake = false;
- int i, last;
+ int last;

if (!q)
return;
@@ -165,13 +163,14 @@ 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) {
+ int swq_qid = -1;
+
mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);
if (entry.schedule)
- n_swq_queued[entry.qid]++;
+ swq_qid = entry.qid;

q->tail = (q->tail + 1) % q->ndesc;
- n_queued++;

if (entry.skb)
dev->drv->tx_complete_skb(dev, qid, &entry);
@@ -184,29 +183,21 @@ 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];
+ spin_lock_bh(&q->lock);
+ if (swq_qid >= 4)
+ dev->q_tx[__MT_TXQ_MAX + swq_qid - 4].swq_queued--;
+ else if (swq_qid >= 0)
+ dev->q_tx[swq_qid].swq_queued--;
+ q->queued--;
+ spin_unlock_bh(&q->lock);
}

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 &&
@@ -217,8 +208,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);
}
--
2.28.0

2020-08-25 05:31:03

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 9/9] mt76: mt7603: check for single-stream EEPROM configuration

Some devices using MT7628 or MT7603 have only one antenna chain connected.
Detect these using the EEPROM rx/tx path settings

Reported-by: Qin Wei <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h | 3 +++
drivers/net/wireless/mediatek/mt76/mt7603/init.c | 12 ++++++++++--
2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
index b893facfba48..4687d6dc00dc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
@@ -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
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index 94196599797e..43dbabccc083 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -510,11 +510,17 @@ mt7603_init_txpower(struct mt7603_dev *dev,
}
}

+static inline bool is_mt7688(struct mt7603_dev *dev)
+{
+ return mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4);
+}
+
int mt7603_register_device(struct mt7603_dev *dev)
{
struct mt76_bus_ops *bus_ops;
struct ieee80211_hw *hw = mt76_hw(dev);
struct wiphy *wiphy = hw->wiphy;
+ u8 *eeprom = (u8 *)dev->mt76.eeprom.data;
int ret;

dev->bus_ops = dev->mt76.bus;
@@ -536,9 +542,11 @@ 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 */
+ /* Check for 1SS devices */
dev->mphy.antenna_mask = 3;
- if (mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4))
+ 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;

dev->slottime = 9;
--
2.28.0

2020-08-25 05:31:11

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 8/9] mt76: add memory barrier to DMA queue kick

Ensure that descriptor memory has been fully written before letting the
hardware read it

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/dma.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 7545b552db25..24ff21eedbd0 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -143,6 +143,7 @@ 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);
}

--
2.28.0

2020-08-25 05:31:49

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 4/9] mt76: mt7915: schedule tx tasklet in mt7915_mac_tx_free

The previous scheduling round may have been limited by AQL.
More frames might be available after the tx free run.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 2 --
drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 1 +
2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index f6c18a08d414..34e90bb08f0a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -96,8 +96,6 @@ static int mt7915_poll_tx(struct napi_struct *napi, int budget)

mt7915_tx_cleanup(dev);

- tasklet_schedule(&dev->mt76.tx_tasklet);
-
if (napi_complete_done(napi, 0))
mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 06bb8d0103ba..9c920c9f4d2b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -936,6 +936,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
dev_kfree_skb(skb);

mt7915_mac_sta_poll(dev);
+ tasklet_schedule(&dev->mt76.tx_tasklet);
}

void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
--
2.28.0

2020-08-25 05:33:03

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 5/9] mt76: mt7915: significantly reduce interrupt load

On 7615 and newer, DMA completion only triggers unmap, but not free of queued
skbs, since pointers to packets are queued internally.
Because of that, there is no need to process the main data queue immediately
on DMA completion.
To improve performance, mask out the DMA data queue completion interrupt and
process the queue only when we receive a txfree event.
This brings the number of interrupts under load down to a small fraction.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 6 ++----
drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 4 ++++
drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 6 +++---
drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 10 +++++++++-
4 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index 34e90bb08f0a..bdc694609c01 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -84,8 +84,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,7 +95,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_irq_enable(dev, MT_INT_TX_DONE_MCU);

return 0;
}
@@ -242,7 +240,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;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 9c920c9f4d2b..22d12dd3a608 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -874,6 +874,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).
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
index 91bff101664b..fe62b4d853e4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
@@ -41,12 +41,12 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);

mask = intr & MT_INT_RX_DONE_ALL;
- if (intr & MT_INT_TX_DONE_ALL)
- mask |= MT_INT_TX_DONE_ALL;
+ if (intr & MT_INT_TX_DONE_MCU)
+ mask |= MT_INT_TX_DONE_MCU;

mt7915_irq_disable(dev, mask);

- if (intr & MT_INT_TX_DONE_ALL)
+ if (intr & MT_INT_TX_DONE_MCU)
napi_schedule(&dev->mt76.tx_napi);

if (intr & MT_INT_RX_DONE_DATA)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
index e0989141d9da..4b97b47c6b31 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
@@ -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)

--
2.28.0

2020-08-25 05:33:54

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 6/9] mt76: mt7615: significantly reduce interrupt load

On 7615 and newer, DMA completion only triggers unmap, but not free of queued
skbs, since pointers to packets are queued internally.
Because of that, there is no need to process the main data queue immediately
on DMA completion.
To improve performance, mask out the DMA data queue completion interrupt and
process the queue only when we receive a txfree event.
This brings the number of interrupts under load down to a small fraction.

Signed-off-by: Felix Fietkau <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7615/dma.c | 24 +++----------------
.../net/wireless/mediatek/mt76/mt7615/mac.c | 8 +++++++
.../net/wireless/mediatek/mt76/mt7615/mmio.c | 8 +++----
.../wireless/mediatek/mt76/mt7615/mt7615.h | 5 ++++
4 files changed, 20 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 3b375fdf31b8..abb83d4e7712 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -94,34 +94,16 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
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);
-
- mt7615_pm_power_save_sched(dev);
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ 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_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));

return 0;
}
@@ -305,7 +287,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))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index e4aeba17da67..9b8fbf26cd1e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -1424,6 +1424,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];
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
index 99ece641bdef..6de492a4cf02 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
@@ -101,7 +101,7 @@ 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);

@@ -112,11 +112,11 @@ static void mt7615_irq_tasklet(unsigned long data)
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);

mask |= intr & MT_INT_RX_DONE_ALL;
- if (intr & MT_INT_TX_DONE_ALL)
- mask |= MT_INT_TX_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 & MT_INT_TX_DONE_ALL)
+ if (intr & tx_mcu_mask)
napi_schedule(&dev->mt76.tx_napi);

if (intr & MT_INT_RX_DONE(0))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 7567485256f8..bcd09cc52ce8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -540,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].q->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);
--
2.28.0

2020-08-25 11:44:13

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 9/9] mt76: mt7603: check for single-stream EEPROM configuration

Some devices using MT7628 or MT7603 have only one antenna chain connected.
Detect these using the EEPROM rx/tx path settings

Reported-by: Qin Wei <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
---
v2: move to eeprom.c to fix initialization order
.../net/wireless/mediatek/mt76/mt7603/eeprom.c | 17 +++++++++++++++--
.../net/wireless/mediatek/mt76/mt7603/eeprom.h | 3 +++
.../net/wireless/mediatek/mt76/mt7603/init.c | 5 -----
3 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
index 3ee06e2577b8..01f1e0da5ee1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
@@ -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);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
index b893facfba48..4687d6dc00dc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
@@ -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
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index 94196599797e..c4848fafd270 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -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;
--
2.28.0