From b4124a5b1a00d461e40c00755adda8ae05810648 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 12 Sep 2019 16:42:53 +0200 Subject: [PATCH 01/56] mt76: mt7615: fix control frame rx in monitor mode Adjust filters and ensure frames don't get sent to MCU instead of host Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 13 ++++++++++++- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 10 ++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 16 ++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 1104e4c8aaa6..5de04f6e6046 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -20,7 +20,7 @@ static void mt7615_phy_init(struct mt7615_dev *dev) static void mt7615_mac_init(struct mt7615_dev *dev) { - u32 val; + u32 val, mask, set; /* enable band 0/1 clk */ mt76_set(dev, MT_CFG_CCR, @@ -85,6 +85,17 @@ static void mt7615_mac_init(struct mt7615_dev *dev) MT_AGG_ARCR_RATE_DOWN_RATIO_EN | FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) | FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4))); + + mask = MT_DMA_RCFR0_MCU_RX_MGMT | + MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR | + MT_DMA_RCFR0_MCU_RX_CTL_BAR | + MT_DMA_RCFR0_MCU_RX_BYPASS | + MT_DMA_RCFR0_RX_DROPPED_UCAST | + MT_DMA_RCFR0_RX_DROPPED_MCAST; + set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) | + FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2); + mt76_rmw(dev, MT_DMA_BN0RCFR0, mask, set); + mt76_rmw(dev, MT_DMA_BN1RCFR0, mask, set); } static int mt7615_init_hardware(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index b6d78212306a..7252423a89fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -263,6 +263,11 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct mt7615_dev *dev = hw->priv; + u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | + MT_WF_RFCR1_DROP_BF_POLL | + MT_WF_RFCR1_DROP_BA | + MT_WF_RFCR1_DROP_CFEND | + MT_WF_RFCR1_DROP_CFACK; u32 flags = 0; #define MT76_FILTER(_flag, _hw) do { \ @@ -296,6 +301,11 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, *total_flags = flags; mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter); + + if (*total_flags & FIF_CONTROL) + mt76_clear(dev, MT_WF_RFCR1, ctl_flags); + else + mt76_set(dev, MT_WF_RFCR1, ctl_flags); } static void mt7615_bss_info_changed(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index b193814d5cf8..8ecefcb19354 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -176,6 +176,13 @@ #define MT_WF_RFCR_DROP_NDPA BIT(20) #define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) +#define MT_WF_RFCR1 MT_WF_RMAC(0x004) +#define MT_WF_RFCR1_DROP_ACK BIT(4) +#define MT_WF_RFCR1_DROP_BF_POLL BIT(5) +#define MT_WF_RFCR1_DROP_BA BIT(6) +#define MT_WF_RFCR1_DROP_CFEND BIT(7) +#define MT_WF_RFCR1_DROP_CFACK BIT(8) + #define MT_WF_DMA_BASE 0x21800 #define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs)) @@ -183,6 +190,15 @@ #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 2) #define MT_DMA_DCR0_RX_VEC_DROP BIT(17) +#define MT_DMA_BN0RCFR0 MT_WF_DMA(0x070) +#define MT_DMA_BN1RCFR0 MT_WF_DMA(0x0b0) +#define MT_DMA_RCFR0_MCU_RX_MGMT BIT(2) +#define MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR BIT(3) +#define MT_DMA_RCFR0_MCU_RX_CTL_BAR BIT(4) +#define MT_DMA_RCFR0_MCU_RX_BYPASS BIT(21) +#define MT_DMA_RCFR0_RX_DROPPED_UCAST GENMASK(25, 24) +#define MT_DMA_RCFR0_RX_DROPPED_MCAST GENMASK(27, 26) + #define MT_WTBL_BASE 0x30000 #define MT_WTBL_ENTRY_SIZE 256 From c7f647d9bdb062845592bd5fd56d726b554bb48b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 15 Sep 2019 18:43:14 +0200 Subject: [PATCH 02/56] mt76: remove aggr_work field from struct mt76_wcid It is unused Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8aec7ccf2d79..09544a4efd12 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -191,8 +191,6 @@ DECLARE_EWMA(signal, 10, 8); struct mt76_wcid { struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS]; - struct work_struct aggr_work; - unsigned long flags; struct ewma_signal rssi; From b0b2373db7fe3624f2c378795e21d23d9e23b06f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 15 Sep 2019 18:43:59 +0200 Subject: [PATCH 03/56] mt76: use cancel_delayed_work_sync in mt76_rx_aggr_shutdown The workqueue item needs to be fully shut down before the struct can be freed. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 8f3d36a15e17..2276fd4e9ec3 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -257,7 +257,7 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) u8 size = tid->size; int i; - cancel_delayed_work(&tid->reorder_work); + cancel_delayed_work_sync(&tid->reorder_work); spin_lock_bh(&tid->lock); From a670111131db75b53c6377f26b4ccf12fe3912c8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 22 Aug 2019 11:49:10 +0200 Subject: [PATCH 04/56] mt76: remove empty flag in mt76_txq_schedule_list Remove empty flag in mt76_txq_schedule_list and mt76_txq_send_burst since we just need retry_q length to notify mac80211 to reschedule the current tx queue Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index c22a05f06fd0..7ee91d946882 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -378,7 +378,7 @@ EXPORT_SYMBOL_GPL(mt76_release_buffered_frames); static int mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq, - struct mt76_txq *mtxq, bool *empty) + struct mt76_txq *mtxq) { struct ieee80211_txq *txq = mtxq_to_txq(mtxq); enum mt76_txq_id qid = mt76_txq_get_qid(txq); @@ -392,16 +392,12 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq, bool probe; int idx; - if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) { - *empty = true; + if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) return 0; - } skb = mt76_txq_dequeue(dev, mtxq, false); - if (!skb) { - *empty = true; + if (!skb) return 0; - } info = IEEE80211_SKB_CB(skb); if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) @@ -431,10 +427,8 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq, return -EBUSY; skb = mt76_txq_dequeue(dev, mtxq, false); - if (!skb) { - *empty = true; + if (!skb) break; - } info = IEEE80211_SKB_CB(skb); cur_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; @@ -481,8 +475,6 @@ mt76_txq_schedule_list(struct mt76_dev *dev, enum mt76_txq_id qid) spin_lock_bh(&hwq->lock); while (1) { - bool empty = false; - if (sq->swq_queued >= 4) break; @@ -513,10 +505,9 @@ mt76_txq_schedule_list(struct mt76_dev *dev, enum mt76_txq_id qid) spin_lock_bh(&hwq->lock); } - ret += mt76_txq_send_burst(dev, sq, mtxq, &empty); - if (skb_queue_empty(&mtxq->retry_q)) - empty = true; - ieee80211_return_txq(dev->hw, txq, !empty); + ret += mt76_txq_send_burst(dev, sq, mtxq); + ieee80211_return_txq(dev->hw, txq, + !skb_queue_empty(&mtxq->retry_q)); } spin_unlock_bh(&hwq->lock); From af3076db14b1d143d53815bd37033a1b684ed6bc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 5 Sep 2019 18:32:58 +0200 Subject: [PATCH 05/56] mt76: usb: add lockdep_assert_held in __mt76u_vendor_request Introduce lockdep_assert_held macro in __mt76u_vendor_request routine and remove comments regarding usb_ctrl_mtx lock Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 20c6fe510e9d..cac058fc41ef 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -15,7 +15,6 @@ static bool disable_usb_sg; module_param_named(disable_usb_sg, disable_usb_sg, bool, 0644); MODULE_PARM_DESC(disable_usb_sg, "Disable usb scatter-gather support"); -/* should be called with usb_ctrl_mtx locked */ static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len) @@ -24,6 +23,8 @@ static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, unsigned int pipe; int i, ret; + lockdep_assert_held(&dev->usb.usb_ctrl_mtx); + pipe = (req_type & USB_DIR_IN) ? usb_rcvctrlpipe(udev, 0) : usb_sndctrlpipe(udev, 0); for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) { @@ -60,7 +61,6 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req, } EXPORT_SYMBOL_GPL(mt76u_vendor_request); -/* should be called with usb_ctrl_mtx locked */ static u32 __mt76u_rr(struct mt76_dev *dev, u32 addr) { struct mt76_usb *usb = &dev->usb; @@ -103,7 +103,6 @@ static u32 mt76u_rr(struct mt76_dev *dev, u32 addr) return ret; } -/* should be called with usb_ctrl_mtx locked */ static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) { struct mt76_usb *usb = &dev->usb; From 4482455409b044ed64b48e5e9c153469e2df7f86 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 6 Sep 2019 13:19:26 +0100 Subject: [PATCH 06/56] mt76: mt76x0e: make array mt76x0_chan_map static const, makes object smaller Don't populate the array mt76x0_chan_map on the stack but instead make it static const. Makes the object code smaller by 80 bytes. Before: text data bss dec hex filename 7685 1192 0 8877 22ad mediatek/mt76/mt76x0/eeprom.o After: text data bss dec hex filename 7541 1256 0 8797 225d mediatek/mt76/mt76x0/eeprom.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 9d4426f6905f..96368fac4228 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -212,7 +212,7 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev, void mt76x0_get_power_info(struct mt76x02_dev *dev, struct ieee80211_channel *chan, s8 *tp) { - struct mt76x0_chan_map { + static const struct mt76x0_chan_map { u8 chan; u8 offset; } chan_map[] = { From 45971b2385d6a30b7d377c2e24728d680eae7553 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 6 Sep 2019 17:29:04 +0200 Subject: [PATCH 07/56] mt76: mt7615: enable SCS by default Enable Smart Carrier Sense algorithm by default in order to improve performances in a noisy environment Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 5de04f6e6046..ad94a7ce2e10 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -50,7 +50,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev) MT_TMAC_CTCR0_INS_DDLMT_EN); mt7615_mcu_set_rts_thresh(dev, 0x92b); - mt7615_mac_set_scs(dev, false); + mt7615_mac_set_scs(dev, true); mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS, MT_AGG_SCR_NLNAV_MID_PTEC_DIS); From 7b37cce09d187fdc4a2e2a57adb1b2e170d1dfe6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 12 Sep 2019 11:06:35 +0200 Subject: [PATCH 08/56] mt76: mt76x02: move mac_reset_counter in mt76x02_lib module Unify mac_reset_counter routine and move it in mt76x02_lib module since it is shared by all mt76x02 drivers (pci/usb) Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 12 +---------- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 21 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + .../wireless/mediatek/mt76/mt76x2/pci_init.c | 10 +-------- .../wireless/mediatek/mt76/mt76x2/usb_mac.c | 12 +---------- 5 files changed, 25 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index cf7fc307322b..541e81deba83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -150,16 +150,6 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201); } -static void mt76x0_reset_counters(struct mt76x02_dev *dev) -{ - mt76_rr(dev, MT_RX_STAT_0); - mt76_rr(dev, MT_RX_STAT_1); - mt76_rr(dev, MT_RX_STAT_2); - mt76_rr(dev, MT_TX_STA_0); - mt76_rr(dev, MT_TX_STA_1); - mt76_rr(dev, MT_TX_STA_2); -} - int mt76x0_mac_start(struct mt76x02_dev *dev) { mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); @@ -244,7 +234,7 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev) for (i = 0; i < 256; i++) mt76x02_mac_wcid_setup(dev, i, 0, NULL); - mt76x0_reset_counters(dev); + mt76x02_mac_reset_counters(dev); ret = mt76x0_eeprom_init(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index abacb4ea7179..c681601f9114 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -7,6 +7,27 @@ #include "mt76x02.h" #include "mt76x02_trace.h" +void mt76x02_mac_reset_counters(struct mt76x02_dev *dev) +{ + int i; + + mt76_rr(dev, MT_RX_STAT_0); + mt76_rr(dev, MT_RX_STAT_1); + mt76_rr(dev, MT_RX_STAT_2); + mt76_rr(dev, MT_TX_STA_0); + mt76_rr(dev, MT_TX_STA_1); + mt76_rr(dev, MT_TX_STA_2); + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_STAT_FIFO); + + memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters); + static enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index efa4ef945e35..b687341236c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -161,6 +161,7 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) return false; } +void mt76x02_mac_reset_counters(struct mt76x02_dev *dev); void mt76x02_mac_set_short_preamble(struct mt76x02_dev *dev, bool enable); int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx, u8 key_idx, struct ieee80211_key_conf *key); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 343127f2d621..114e4fa4f4f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -148,15 +148,7 @@ int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) int mt76x2_mac_start(struct mt76x02_dev *dev) { - int i; - - for (i = 0; i < 16; i++) - mt76_rr(dev, MT_TX_AGG_CNT(i)); - - for (i = 0; i < 16; i++) - mt76_rr(dev, MT_TX_STAT_FIFO); - - memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); + mt76x02_mac_reset_counters(dev); mt76x02_mac_start(dev); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c index e7fea3a6f1fd..95eb85653bbd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -6,16 +6,6 @@ #include "mt76x2u.h" #include "eeprom.h" -static void mt76x2u_mac_reset_counters(struct mt76x02_dev *dev) -{ - mt76_rr(dev, MT_RX_STAT_0); - mt76_rr(dev, MT_RX_STAT_1); - mt76_rr(dev, MT_RX_STAT_2); - mt76_rr(dev, MT_TX_STA_0); - mt76_rr(dev, MT_TX_STA_1); - mt76_rr(dev, MT_TX_STA_2); -} - static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev) { s8 offset = 0; @@ -104,7 +94,7 @@ int mt76x2u_mac_reset(struct mt76x02_dev *dev) int mt76x2u_mac_start(struct mt76x02_dev *dev) { - mt76x2u_mac_reset_counters(dev); + mt76x02_mac_reset_counters(dev); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); mt76x02_wait_for_wpdma(&dev->mt76, 1000); From ad571c93169bbefd834b2359b782c5a94174c321 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 12 Sep 2019 11:06:36 +0200 Subject: [PATCH 09/56] mt76: mt76x2: move mt76x02_mac_reset_counters in mt76x02_mac_start Move mt76x02_mac_reset_counters in mt76x02_mac_start and get rid of mt76x2_mac_start since it is just a wrapper for mt76x02_mac_start Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/mac.h | 1 - .../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 13 ++----------- .../net/wireless/mediatek/mt76/mt76x2/pci_main.c | 6 ++---- 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index dc773070481d..4e2371c926d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -343,6 +343,7 @@ EXPORT_SYMBOL_GPL(mt76x02_dma_disable); void mt76x02_mac_start(struct mt76x02_dev *dev) { + mt76x02_mac_reset_counters(dev); mt76x02_dma_enable(dev); mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index a1583021e1e9..d5c3d26b94c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -12,7 +12,6 @@ struct mt76x02_dev; struct mt76x2_sta; struct mt76x02_vif; -int mt76x2_mac_start(struct mt76x02_dev *dev); void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force); static inline void mt76x2_mac_resume(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 114e4fa4f4f6..3cf54963854a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -7,6 +7,7 @@ #include "mt76x2.h" #include "eeprom.h" #include "mcu.h" +#include "../mt76x02_mac.h" static void mt76x2_mac_pbf_init(struct mt76x02_dev *dev) @@ -146,14 +147,6 @@ int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) return 0; } -int mt76x2_mac_start(struct mt76x02_dev *dev) -{ - mt76x02_mac_reset_counters(dev); - mt76x02_mac_start(dev); - - return 0; -} - static void mt76x2_power_on_rf_patch(struct mt76x02_dev *dev) { @@ -256,9 +249,7 @@ static int mt76x2_init_hardware(struct mt76x02_dev *dev) return ret; set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); - ret = mt76x2_mac_start(dev); - if (ret) - return ret; + mt76x02_mac_start(dev); ret = mt76x2_mcu_init(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 4971685aafe8..385960dca906 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -4,6 +4,7 @@ */ #include "mt76x2.h" +#include "../mt76x02_mac.h" static int mt76x2_start(struct ieee80211_hw *hw) @@ -11,10 +12,7 @@ mt76x2_start(struct ieee80211_hw *hw) struct mt76x02_dev *dev = hw->priv; int ret; - ret = mt76x2_mac_start(dev); - if (ret) - return ret; - + mt76x02_mac_start(dev); ret = mt76x2_phy_start(dev); if (ret) return ret; From d5b3be417b015d4f401eba05943b5ca33137aecd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 12 Sep 2019 11:06:37 +0200 Subject: [PATCH 10/56] mt76: mt76x0u: reset counter starting the device Remove mt76x02_mac_reset_counters from mt76x0_init_hardware since it will be run starting the device Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 541e81deba83..d7bac4961c7b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -152,6 +152,7 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) int mt76x0_mac_start(struct mt76x02_dev *dev) { + mt76x02_mac_reset_counters(dev); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) @@ -234,8 +235,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev) for (i = 0; i < 256; i++) mt76x02_mac_wcid_setup(dev, i, 0, NULL); - mt76x02_mac_reset_counters(dev); - ret = mt76x0_eeprom_init(dev); if (ret) return ret; From fdb96b06040d0d410705f9b42851a75ec4106ae4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 12 Sep 2019 11:06:38 +0200 Subject: [PATCH 11/56] mt76: mt76x02u: move mt76x02u_mac_start in mt76x02-usb module Unify mt76x02u_mac_start between mt76x2u and mt76x0u since the code is shared between both drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 16 -------------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - .../net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_usb.h | 1 + .../wireless/mediatek/mt76/mt76x02_usb_core.c | 21 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x2/mt76x2u.h | 1 - .../wireless/mediatek/mt76/mt76x2/usb_mac.c | 17 --------------- .../wireless/mediatek/mt76/mt76x2/usb_main.c | 3 ++- 8 files changed, 25 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index d7bac4961c7b..388b54cded1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -150,22 +150,6 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201); } -int mt76x0_mac_start(struct mt76x02_dev *dev) -{ - mt76x02_mac_reset_counters(dev); - mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - - if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) - return -ETIMEDOUT; - - mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); - mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); - - return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0; -} -EXPORT_SYMBOL_GPL(mt76x0_mac_start); - void mt76x0_mac_stop(struct mt76x02_dev *dev) { int i = 200, ok = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 26517e062bdb..82f5b481b723 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -46,7 +46,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev); int mt76x0_register_device(struct mt76x02_dev *dev); void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset); -int mt76x0_mac_start(struct mt76x02_dev *dev); void mt76x0_mac_stop(struct mt76x02_dev *dev); int mt76x0_config(struct ieee80211_hw *hw, u32 changed); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 00a445d27599..4c2b66b53533 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -103,7 +103,7 @@ static int mt76x0u_start(struct ieee80211_hw *hw) struct mt76x02_dev *dev = hw->priv; int ret; - ret = mt76x0_mac_start(dev); + ret = mt76x02u_mac_start(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index 98329debc033..a57dcc8820aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -8,6 +8,7 @@ #include "mt76x02.h" +int mt76x02u_mac_start(struct mt76x02_dev *dev); void mt76x02u_init_mcu(struct mt76_dev *dev); void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev); int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 78dfc1e7f27b..203420087ac4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -23,6 +23,27 @@ void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, } EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb); +int mt76x02u_mac_start(struct mt76x02_dev *dev) +{ + mt76x02_mac_reset_counters(dev); + + mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) + return -ETIMEDOUT; + + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); + + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); + + if (!mt76x02_wait_for_wpdma(&dev->mt76, 50)) + return -ETIMEDOUT; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02u_mac_start); + int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) { struct sk_buff *iter, *last = skb; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h index c876bac43751..f9d37c6cf1f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -24,7 +24,6 @@ void mt76x2u_cleanup(struct mt76x02_dev *dev); void mt76x2u_stop_hw(struct mt76x02_dev *dev); int mt76x2u_mac_reset(struct mt76x02_dev *dev); -int mt76x2u_mac_start(struct mt76x02_dev *dev); int mt76x2u_mac_stop(struct mt76x02_dev *dev); int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c index 95eb85653bbd..59cbe826188a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -92,23 +92,6 @@ int mt76x2u_mac_reset(struct mt76x02_dev *dev) return 0; } -int mt76x2u_mac_start(struct mt76x02_dev *dev) -{ - mt76x02_mac_reset_counters(dev); - - mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - mt76x02_wait_for_wpdma(&dev->mt76, 1000); - usleep_range(50, 100); - - mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); - - mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | - MT_MAC_SYS_CTRL_ENABLE_RX); - - return 0; -} - int mt76x2u_mac_stop(struct mt76x02_dev *dev) { int i, count = 0, val; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index eb73cb856c81..1e6f78760dd8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -4,13 +4,14 @@ */ #include "mt76x2u.h" +#include "../mt76x02_usb.h" static int mt76x2u_start(struct ieee80211_hw *hw) { struct mt76x02_dev *dev = hw->priv; int ret; - ret = mt76x2u_mac_start(dev); + ret = mt76x02u_mac_start(dev); if (ret) return ret; From 0b82a8e8024b34cf99094105a44ae959c21b7534 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:50 +0200 Subject: [PATCH 12/56] mt76: move queue debugfs entry to driver specific code Move queue debugfs entry to driver specific code since mt7615 devices rely on a different queue layout Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 5 ++--- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index d95b73fd0d2b..d2202acb8dc6 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -25,8 +25,7 @@ mt76_reg_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); -static int -mt76_queues_read(struct seq_file *s, void *data) +int mt76_queues_read(struct seq_file *s, void *data) { struct mt76_dev *dev = dev_get_drvdata(s->private); int i; @@ -45,6 +44,7 @@ mt76_queues_read(struct seq_file *s, void *data) return 0; } +EXPORT_SYMBOL_GPL(mt76_queues_read); void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len) @@ -90,7 +90,6 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom); if (dev->otp.data) debugfs_create_blob("otp", 0400, dir, &dev->otp); - debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read); debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir, mt76_read_rate_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 09544a4efd12..888dfc58546d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -624,6 +624,7 @@ void mt76_unregister_device(struct mt76_dev *dev); void mt76_free_device(struct mt76_dev *dev); struct dentry *mt76_register_debugfs(struct mt76_dev *dev); +int mt76_queues_read(struct seq_file *s, void *data); void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c index 5942fe76c6e9..45eb24862240 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c @@ -77,6 +77,8 @@ void mt7603_init_debugfs(struct mt7603_dev *dev) if (!dir) return; + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt76_queues_read); debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca); debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test); debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c index 0cb2a7b35fe5..186838128c55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c @@ -143,6 +143,8 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev) if (!dir) return; + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt76_queues_read); debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp); debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc); From 25990ed3816e0d47f56b5430bb9415d631e313a7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:51 +0200 Subject: [PATCH 13/56] mt76: mt7615: add queue entry in debugfs Introduce mt7615_queues_read routine to dump hw queue related info. Add hw ac queues statistics in mt7615 debugfs Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7615/debugfs.c | 61 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/regs.h | 11 ++++ 2 files changed, 72 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 2428a4659a1c..1dc68d4aee57 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -61,6 +61,63 @@ static int mt7615_read_temperature(struct seq_file *s, void *data) return 0; } +static int +mt7615_queues_acq(struct seq_file *s, void *data) +{ + struct mt7615_dev *dev = dev_get_drvdata(s->private); + int i; + + for (i = 0; i < 16; i++) { + int j, acs = i / 4, index = i % 4; + u32 ctrl, val, qlen = 0; + + val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); + ctrl = BIT(31) | BIT(15) | (acs << 8); + + for (j = 0; j < 32; j++) { + if (val & BIT(j)) + continue; + + mt76_wr(dev, MT_PLE_FL_Q0_CTRL, + ctrl | (j + (index << 5))); + qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, + GENMASK(11, 0)); + } + seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); + } + + return 0; +} + +static int +mt7615_queues_read(struct seq_file *s, void *data) +{ + struct mt7615_dev *dev = dev_get_drvdata(s->private); + static const struct { + char *queue; + int id; + } queue_map[] = { + { "PDMA0", MT_TXQ_BE }, + { "MCUQ", MT_TXQ_MCU }, + { "MCUFWQ", MT_TXQ_FWDL }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) { + struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id]; + + if (!q->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); + } + + return 0; +} + int mt7615_init_debugfs(struct mt7615_dev *dev) { struct dentry *dir; @@ -69,6 +126,10 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) if (!dir) return -ENOMEM; + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt7615_queues_read); + debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, + mt7615_queues_acq); debugfs_create_file("scs", 0600, dir, dev, &fops_scs); debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir, mt7615_radio_read); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 8ecefcb19354..43676736a807 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -65,6 +65,17 @@ #define MT_WPDMA_ABT_CFG MT_HIF(0x530) #define MT_WPDMA_ABT_CFG1 MT_HIF(0x534) +#define MT_PLE_BASE 0x8000 +#define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) + +#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) +#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) +#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) +#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc) + +#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \ + ((n) << 2)) + #define MT_WF_PHY_BASE 0x10000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) From d7b47bbdd71cbd769501bf181d57e9ff12efc30b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:52 +0200 Subject: [PATCH 14/56] mt76: move aggr_stats array in mt76_dev Move aggr_stats array from mt76x02_dev to mt76_dev in order to be reused adding aggregation stats for mt7603/mt7615 drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 -- drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 888dfc58546d..b3e776ef9469 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -461,6 +461,8 @@ struct mt76_dev { u32 rev; unsigned long state; + u32 aggr_stats[32]; + u8 antenna_mask; u16 chainmask; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index e858bba8c8ff..50b0131f85bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -92,8 +92,6 @@ struct mt76x02_dev { const struct mt76x02_beacon_ops *beacon_ops; - u32 aggr_stats[32]; - struct sk_buff *beacons[8]; u8 beacon_data_mask; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c index 186838128c55..68b40d63a46d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c @@ -19,7 +19,8 @@ mt76x02_ampdu_stat_read(struct seq_file *file, void *data) seq_puts(file, "\n"); seq_puts(file, "Count: "); for (j = 0; j < 8; j++) - seq_printf(file, "%8d | ", dev->aggr_stats[i * 8 + j]); + seq_printf(file, "%8d | ", + dev->mt76.aggr_stats[i * 8 + j]); seq_puts(file, "\n"); seq_puts(file, "--------"); for (j = 0; j < 8; j++) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index c681601f9114..0d000906b2e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -24,7 +24,7 @@ void mt76x02_mac_reset_counters(struct mt76x02_dev *dev) for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_STAT_FIFO); - memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); + memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); } EXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters); @@ -1119,8 +1119,8 @@ void mt76x02_mac_work(struct work_struct *work) for (i = 0, idx = 0; i < 16; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); - dev->aggr_stats[idx++] += val & 0xffff; - dev->aggr_stats[idx++] += val >> 16; + dev->mt76.aggr_stats[idx++] += val & 0xffff; + dev->mt76.aggr_stats[idx++] += val >> 16; } if (!dev->mt76.beacon_mask) From 75601194a1c80f4d2a830ce36b9c3e3abfd8d006 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:53 +0200 Subject: [PATCH 15/56] mt76: mt7615: collect aggregation stats Introduce ampdu_stat entry in mt7615 debugfs in order to dump 802.11 aggr cumulative statistics Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7615/debugfs.c | 39 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/mac.c | 18 +++++++++ .../net/wireless/mediatek/mt76/mt7615/main.c | 2 + .../wireless/mediatek/mt76/mt7615/mt7615.h | 1 + .../net/wireless/mediatek/mt76/mt7615/regs.h | 6 +++ 5 files changed, 66 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 1dc68d4aee57..f6b75f832e6a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -36,6 +36,44 @@ mt7615_scs_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_scs, mt7615_scs_get, mt7615_scs_set, "%lld\n"); +static int +mt7615_ampdu_stat_read(struct seq_file *file, void *data) +{ + struct mt7615_dev *dev = file->private; + int bound[7], i, range; + + range = mt76_rr(dev, MT_AGG_ASRCR0); + for (i = 0; i < 4; i++) + bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1; + range = mt76_rr(dev, MT_AGG_ASRCR1); + for (i = 0; i < 3; i++) + bound[i + 4] = MT_AGG_ASRCR_RANGE(range, i) + 1; + + seq_printf(file, "Length: %8d | ", bound[0]); + for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) + seq_printf(file, "%3d -%3d | ", + bound[i], bound[i + 1]); + seq_puts(file, "\nCount: "); + for (i = 0; i < ARRAY_SIZE(bound); i++) + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); + seq_puts(file, "\n"); + + 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, +}; + static int mt7615_radio_read(struct seq_file *s, void *data) { @@ -130,6 +168,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) mt7615_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("scs", 0600, dir, dev, &fops_scs); debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir, mt7615_radio_read); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index e07ce2c10013..237d15521e18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -41,6 +41,16 @@ static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev, return &sta->vif->sta.wcid; } +void mt7615_mac_reset_counters(struct mt7615_dev *dev) +{ + int i; + + for (i = 0; i < 4; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); +} + int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -1261,6 +1271,7 @@ void mt7615_update_channel(struct mt76_dev *mdev) void mt7615_mac_work(struct work_struct *work) { struct mt7615_dev *dev; + int i, idx; dev = (struct mt7615_dev *)container_of(work, struct mt76_dev, mac_work.work); @@ -1271,6 +1282,13 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mac_scs_check(dev); dev->mac_work_count = 0; } + + for (i = 0, idx = 0; i < 4; i++) { + u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); + + dev->mt76.aggr_stats[idx++] += val & 0xffff; + dev->mt76.aggr_stats[idx++] += val >> 16; + } mutex_unlock(&dev->mt76.mutex); mt76_tx_status_check(&dev->mt76, NULL, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 7252423a89fa..6949cda9df0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -16,6 +16,8 @@ static int mt7615_start(struct ieee80211_hw *hw) { struct mt7615_dev *dev = hw->priv; + mt7615_mac_reset_counters(dev); + dev->mt76.survey_time = ktime_get_boottime(); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 7963e302d705..efb8be29c392 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -229,6 +229,7 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask) } void mt7615_update_channel(struct mt76_dev *mdev); +void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev); void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 43676736a807..643b8bd17850 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -136,6 +136,10 @@ MT_AGG_ARxCR_LIMIT_SHIFT(_n), \ MT_AGG_ARxCR_LIMIT_SHIFT(_n)) +#define MT_AGG_ASRCR0 MT_WF_AGG(0x060) +#define MT_AGG_ASRCR1 MT_WF_AGG(0x064) +#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0)) + #define MT_AGG_ACR0 MT_WF_AGG(0x070) #define MT_AGG_ACR1 MT_WF_AGG(0x170) #define MT_AGG_ACR_NO_BA_RULE BIT(0) @@ -285,6 +289,8 @@ #define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9)) #define MT_MIB_BUSY_MASK GENMASK(23, 0) +#define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2)) + #define MT_EFUSE_BASE 0x81070000 #define MT_EFUSE_BASE_CTRL 0x000 #define MT_EFUSE_BASE_CTRL_EMPTY BIT(30) From 5a8d4678e02bb3ab89191336b505dd7a7212c4e3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:54 +0200 Subject: [PATCH 16/56] mt76: mt7603: collect aggregation stats Introduce ampdu_stat entry in mt7603 debugfs in order to dump 802.11 aggr cumulative statistics Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7603/debugfs.c | 36 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7603/mac.c | 18 ++++++++++ .../net/wireless/mediatek/mt76/mt7603/main.c | 1 + .../wireless/mediatek/mt76/mt7603/mt7603.h | 1 + .../net/wireless/mediatek/mt76/mt7603/regs.h | 5 +++ 5 files changed, 61 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c index 45eb24862240..47c85a9fac28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c @@ -69,6 +69,41 @@ mt7603_edcca_get(void *data, u64 *val) 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) +{ + struct mt7603_dev *dev = file->private; + int bound[3], i, range; + + range = mt76_rr(dev, MT_AGG_ASRCR); + for (i = 0; i < ARRAY_SIZE(bound); i++) + bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1; + + seq_printf(file, "Length: %8d | ", bound[0]); + for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) + seq_printf(file, "%3d -%3d | ", + bound[i], bound[i + 1]); + seq_puts(file, "\nCount: "); + for (i = 0; i < ARRAY_SIZE(bound); i++) + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); + seq_puts(file, "\n"); + + 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, +}; + void mt7603_init_debugfs(struct mt7603_dev *dev) { struct dentry *dir; @@ -77,6 +112,7 @@ void mt7603_init_debugfs(struct mt7603_dev *dev) if (!dir) return; + debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, mt76_queues_read); debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index c328192307c4..c52c4bf5597e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -31,6 +31,16 @@ mt76_start_tx_ac(struct mt7603_dev *dev, u32 mask) mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask)); } +void mt7603_mac_reset_counters(struct mt7603_dev *dev) +{ + int i; + + for (i = 0; i < 2; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); +} + void mt7603_mac_set_timing(struct mt7603_dev *dev) { u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | @@ -1677,6 +1687,7 @@ void mt7603_mac_work(struct work_struct *work) struct mt7603_dev *dev = container_of(work, struct mt7603_dev, mt76.mac_work.work); bool reset = false; + int i, idx; mt76_tx_status_check(&dev->mt76, NULL, false); @@ -1686,6 +1697,13 @@ void mt7603_mac_work(struct work_struct *work) mt7603_update_channel(&dev->mt76); mt7603_edcca_check(dev); + for (i = 0, idx = 0; i < 2; i++) { + u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); + + dev->mt76.aggr_stats[idx++] += val & 0xffff; + dev->mt76.aggr_stats[idx++] += val >> 16; + } + if (dev->mac_work_count == 10) mt7603_false_cca_check(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 4b3217b43a04..9c378f017877 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -13,6 +13,7 @@ mt7603_start(struct ieee80211_hw *hw) { struct mt7603_dev *dev = hw->priv; + mt7603_mac_reset_counters(dev); mt7603_mac_start(dev); dev->mt76.survey_time = ktime_get_boottime(); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 257300fec4f8..fb10adca17f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -191,6 +191,7 @@ static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask) mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } +void mt7603_mac_reset_counters(struct mt7603_dev *dev); void mt7603_mac_dma_start(struct mt7603_dev *dev); void mt7603_mac_start(struct mt7603_dev *dev); void mt7603_mac_stop(struct mt7603_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h index eb9eefe8e125..6e23ed3dfdff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h @@ -212,6 +212,9 @@ #define MT_AGG_PCR_RTS_THR GENMASK(19, 0) #define MT_AGG_PCR_RTS_PKT_THR GENMASK(31, 25) +#define MT_AGG_ASRCR MT_WF_AGG(0x060) +#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0)) + #define MT_AGG_CONTROL MT_WF_AGG(0x070) #define MT_AGG_CONTROL_NO_BA_RULE BIT(0) #define MT_AGG_CONTROL_NO_BA_AR_RULE BIT(1) @@ -555,6 +558,8 @@ enum { #define MT_MIB_STAT_PSCCA MT_MIB_STAT(16) #define MT_MIB_STAT_PSCCA_MASK GENMASK(23, 0) +#define MT_TX_AGG_CNT(n) MT_MIB(0xa8 + ((n) << 2)) + #define MT_MIB_STAT_ED MT_MIB_STAT(18) #define MT_MIB_STAT_ED_MASK GENMASK(23, 0) From 055da6cfd0dc5c87f8999f747cc9dce75b390419 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 28 Aug 2019 11:07:39 +0200 Subject: [PATCH 17/56] mt76: mt7603: remove q_rx field from struct mt7603_dev It is no longer used Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index fb10adca17f3..17176de4fb23 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -118,8 +118,6 @@ struct mt7603_dev { ktime_t ed_time; - struct mt76_queue q_rx; - spinlock_t ps_lock; u8 mac_work_count; From d515fdca46e7290547547f7a5e1a30c608eeb0ac Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 28 Aug 2019 11:28:36 +0200 Subject: [PATCH 18/56] mt76: report rx a-mpdu subframe status This can be used in monitor mode to figure out which subframes were sent as part of which A-MPDU Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + drivers/net/wireless/mediatek/mt76/mt76.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 14 ++++++++++++++ .../net/wireless/mediatek/mt76/mt7603/mt7603.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 14 ++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 15 +++++++++++++++ 7 files changed, 50 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 1a2c143b34d0..cc301216e527 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -502,6 +502,7 @@ static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) status->band = mstat.band; status->signal = mstat.signal; status->chains = mstat.chains; + status->ampdu_reference = mstat.ampdu_ref; BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); BUILD_BUG_ON(sizeof(status->chain_signal) != diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b3e776ef9469..187c3e8998d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -438,6 +438,7 @@ struct mt76_dev { spinlock_t rx_lock; struct napi_struct napi[__MT_RXQ_MAX]; struct sk_buff_head rx_skb[__MT_RXQ_MAX]; + u32 ampdu_ref; struct list_head txwi_cache; struct mt76_sw_queue q_tx[__MT_TXQ_MAX]; @@ -514,6 +515,8 @@ struct mt76_rx_status { unsigned long reorder_time; + u32 ampdu_ref; + u8 iv[6]; u8 aggr:1; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index c52c4bf5597e..44d093943588 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -445,6 +445,20 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } + if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | + MT_RXD2_NORMAL_NON_AMPDU))) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (dev->rx_ampdu_ts != rxd[12]) { + if (!++dev->mt76.ampdu_ref) + dev->mt76.ampdu_ref++; + } + dev->rx_ampdu_ts = rxd[12]; + + status->ampdu_ref = dev->mt76.ampdu_ref; + } + remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 17176de4fb23..01b933538c25 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -109,6 +109,7 @@ struct mt7603_dev { u32 false_cca_ofdm, false_cca_cck; unsigned long last_cca_adj; + __le32 rx_ampdu_ts; u8 rssi_offset[3]; u8 slottime; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 237d15521e18..88271524fb83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -93,6 +93,20 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } + if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | + MT_RXD2_NORMAL_NON_AMPDU))) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (dev->rx_ampdu_ts != rxd[12]) { + if (!++dev->mt76.ampdu_ref) + dev->mt76.ampdu_ref++; + } + dev->rx_ampdu_ts = rxd[12]; + + status->ampdu_ref = dev->mt76.ampdu_ref; + } + remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index efb8be29c392..fa8f2f1ed040 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -81,6 +81,8 @@ struct mt7615_dev { u32 vif_mask; u32 omac_mask; + __le32 rx_ampdu_ts; + struct { u8 n_pulses; u32 period; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 0d000906b2e1..9d2795c1e943 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -789,6 +789,21 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) status->aggr = true; + if (rxinfo & MT_RXINFO_AMPDU) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + status->ampdu_ref = dev->mt76.ampdu_ref; + + /* + * When receiving an A-MPDU subframe and RSSI info is not valid, + * we can assume that more subframes belonging to the same A-MPDU + * are coming. The last one will have valid RSSI info + */ + if (!(rxinfo & MT_RXINFO_RSSI)) { + if (!++dev->mt76.ampdu_ref) + dev->mt76.ampdu_ref++; + } + } + if (WARN_ON_ONCE(len > skb->len)) return -EINVAL; From 9ec0b821b815243d60235220c45250805398147b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 31 Aug 2019 12:41:59 +0200 Subject: [PATCH 19/56] mt76: rename mt76_driver_ops txwi_flags to drv_flags and include tx aligned4 This reduces the struct size and is useful for adding more flags later Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76.h | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 8f69d00bd940..6442a45ba303 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -166,7 +166,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush) dev->drv->tx_complete_skb(dev, qid, &entry); if (entry.txwi) { - if (!(dev->drv->txwi_flags & MT_TXWI_NO_FREE)) + if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE)) mt76_put_txwi(dev, entry.txwi); wake = !flush; } @@ -301,7 +301,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, txwi = mt76_get_txwi_ptr(dev, t); skb->prev = skb->next = NULL; - if (dev->drv->tx_aligned4_skbs) + if (dev->drv->drv_flags & MT_DRV_TX_ALIGNED4_SKBS) mt76_insert_hdr_pad(skb); len = skb_headlen(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 187c3e8998d6..daf2b640e4d4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -280,11 +280,11 @@ struct mt76_hw_cap { bool has_5ghz; }; -#define MT_TXWI_NO_FREE BIT(0) +#define MT_DRV_TXWI_NO_FREE BIT(0) +#define MT_DRV_TX_ALIGNED4_SKBS BIT(1) struct mt76_driver_ops { - bool tx_aligned4_skbs; - u32 txwi_flags; + u32 drv_flags; u16 txwi_size; void (*update_survey)(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index e250607e0a80..73744563a573 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -72,7 +72,7 @@ static int mt7615_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 mt7615_txp), - .txwi_flags = MT_TXWI_NO_FREE, + .drv_flags = MT_DRV_TXWI_NO_FREE, .tx_prepare_skb = mt7615_tx_prepare_skb, .tx_complete_skb = mt7615_tx_complete_skb, .rx_skb = mt7615_queue_rx_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 7705e55aa3d1..d20fd40418a7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -155,7 +155,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), - .tx_aligned4_skbs = true, + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index cf611d1b817c..3d8408d11f0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -21,7 +21,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), - .tx_aligned4_skbs = true, + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, From 0fd0eb54bfe09afc1c0fd5da2893338c215de276 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 5 Sep 2019 16:58:08 +0200 Subject: [PATCH 20/56] mt76: store current channel survey_state in struct mt76_dev Move mt76_channel_state() from mt76.h to mac80211.c Preparation for updating channel state from more places in the drivers/core Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 24 +++++++++++++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 16 +------------ .../net/wireless/mediatek/mt76/mt7603/mac.c | 2 +- .../net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 2 +- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index cc301216e527..aefdd22d74ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -180,6 +180,7 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, sband->bitrates = rates; sband->n_bitrates = n_rates; dev->chandef.chan = &sband->channels[0]; + dev->chan_state = &msband->chan[0]; ht_cap = &sband->ht_cap; ht_cap->ht_supported = true; @@ -398,11 +399,25 @@ bool mt76_has_tx_pending(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_has_tx_pending); +static struct mt76_channel_state * +mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) +{ + struct mt76_sband *msband; + int idx; + + if (c->band == NL80211_BAND_2GHZ) + msband = &dev->sband_2g; + else + msband = &dev->sband_5g; + + idx = c - &msband->sband.channels[0]; + return &msband->chan[idx]; +} + void mt76_set_channel(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; struct cfg80211_chan_def *chandef = &hw->conf.chandef; - struct mt76_channel_state *state; bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; int timeout = HZ / 5; @@ -412,14 +427,13 @@ void mt76_set_channel(struct mt76_dev *dev) dev->drv->update_survey(dev); dev->chandef = *chandef; + dev->chan_state = mt76_channel_state(dev, chandef->chan); if (!offchannel) dev->main_chan = chandef->chan; - if (chandef->chan != dev->main_chan) { - state = mt76_channel_state(dev, chandef->chan); - memset(state, 0, sizeof(*state)); - } + if (chandef->chan != dev->main_chan) + memset(dev->chan_state, 0, sizeof(*dev->chan_state)); } EXPORT_SYMBOL_GPL(mt76_set_channel); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index daf2b640e4d4..f26b51f94437 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -424,6 +424,7 @@ struct mt76_dev { struct cfg80211_chan_def chandef; struct ieee80211_channel *main_chan; + struct mt76_channel_state *chan_state; spinlock_t lock; spinlock_t cc_lock; @@ -605,21 +606,6 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) -static inline struct mt76_channel_state * -mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) -{ - struct mt76_sband *msband; - int idx; - - if (c->band == NL80211_BAND_2GHZ) - msband = &dev->sband_2g; - else - msband = &dev->sband_5g; - - idx = c - &msband->sband.channels[0]; - return &msband->chan[idx]; -} - struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size, const struct ieee80211_ops *ops, const struct mt76_driver_ops *drv_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 44d093943588..3d160230d929 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1491,7 +1491,7 @@ void mt7603_update_channel(struct mt76_dev *mdev) if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) return; - state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); + state = mdev->chan_state; busy = mt76_rr(dev, MT_MIB_STAT_PSCCA); spin_lock_bh(&dev->mt76.cc_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 88271524fb83..9189a86d7825 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1269,7 +1269,7 @@ void mt7615_update_channel(struct mt76_dev *mdev) if (!test_bit(MT76_STATE_RUNNING, &mdev->state)) return; - state = mt76_channel_state(mdev, mdev->chandef.chan); + state = mdev->chan_state; /* TODO: add DBDC support */ busy = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 9d2795c1e943..f73ec17e5f47 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -986,7 +986,7 @@ void mt76x02_update_channel(struct mt76_dev *mdev) struct mt76_channel_state *state; u32 active, busy; - state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); + state = mdev->chan_state; busy = mt76_rr(dev, MT_CH_BUSY); active = busy + mt76_rr(dev, MT_CH_IDLE); From 5ce09c1a79074f613326f626f4781d21fc557296 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 4 Sep 2019 17:45:02 +0200 Subject: [PATCH 21/56] mt76: track rx airtime for airtime fairness and survey Report total rx airtime for valid stations as BSS rx time in survey mt7615 is left out for now, it will be supported later by reading hardware counters instead of calculating airtime in software Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/airtime.c | 278 ++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mac80211.c | 110 ++++++- drivers/net/wireless/mediatek/mt76/mt76.h | 64 ++-- .../net/wireless/mediatek/mt76/mt7603/init.c | 1 + .../net/wireless/mediatek/mt76/mt7603/mac.c | 2 +- .../net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 3 +- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 1 + .../net/wireless/mediatek/mt76/mt76x02_mac.c | 4 +- .../net/wireless/mediatek/mt76/mt76x2/pci.c | 3 +- .../net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + 12 files changed, 434 insertions(+), 37 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/airtime.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index d7a1ddc9e407..99bbc74acda8 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o mt76-y := \ mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ - tx.o agg-rx.o mcu.o + tx.o agg-rx.o mcu.o airtime.o mt76-$(CONFIG_PCI) += pci.o diff --git a/drivers/net/wireless/mediatek/mt76/airtime.c b/drivers/net/wireless/mediatek/mt76/airtime.c new file mode 100644 index 000000000000..d5bc4d713a88 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/airtime.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2019 Felix Fietkau + */ + +#include "mt76.h" + +#define AVG_PKT_SIZE 1024 + +/* Number of bits for an average sized packet */ +#define MCS_NBITS (AVG_PKT_SIZE << 3) + +/* Number of symbols for a packet with (bps) bits per symbol */ +#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps)) + +/* Transmission time (1024 usec) for a packet containing (syms) * symbols */ +#define MCS_SYMBOL_TIME(sgi, syms) \ + (sgi ? \ + ((syms) * 18 * 1024 + 4 * 1024) / 5 : /* syms * 3.6 us */ \ + ((syms) * 1024) << 2 /* syms * 4 us */ \ + ) + +/* Transmit duration for the raw data part of an average sized packet */ +#define MCS_DURATION(streams, sgi, bps) \ + MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) + +#define BW_20 0 +#define BW_40 1 +#define BW_80 2 + +/* + * Define group sort order: HT40 -> SGI -> #streams + */ +#define MT_MAX_STREAMS 4 +#define MT_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ +#define MT_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ + +#define MT_HT_GROUPS_NB (MT_MAX_STREAMS * \ + MT_HT_STREAM_GROUPS) +#define MT_VHT_GROUPS_NB (MT_MAX_STREAMS * \ + MT_VHT_STREAM_GROUPS) +#define MT_GROUPS_NB (MT_HT_GROUPS_NB + \ + MT_VHT_GROUPS_NB) + +#define MT_HT_GROUP_0 0 +#define MT_VHT_GROUP_0 (MT_HT_GROUP_0 + MT_HT_GROUPS_NB) + +#define MCS_GROUP_RATES 10 + +#define HT_GROUP_IDX(_streams, _sgi, _ht40) \ + MT_HT_GROUP_0 + \ + MT_MAX_STREAMS * 2 * _ht40 + \ + MT_MAX_STREAMS * _sgi + \ + _streams - 1 + +#define _MAX(a, b) (((a)>(b))?(a):(b)) + +#define GROUP_SHIFT(duration) \ + _MAX(0, 16 - __builtin_clz(duration)) + +/* MCS rate information for an MCS group */ +#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \ + [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \ + .shift = _s, \ + .duration = { \ + MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s \ + } \ +} + +#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \ + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26)) + +#define MCS_GROUP(_streams, _sgi, _ht40) \ + __MCS_GROUP(_streams, _sgi, _ht40, \ + MCS_GROUP_SHIFT(_streams, _sgi, _ht40)) + +#define VHT_GROUP_IDX(_streams, _sgi, _bw) \ + (MT_VHT_GROUP_0 + \ + MT_MAX_STREAMS * 2 * (_bw) + \ + MT_MAX_STREAMS * (_sgi) + \ + (_streams) - 1) + +#define BW2VBPS(_bw, r3, r2, r1) \ + (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) + +#define __VHT_GROUP(_streams, _sgi, _bw, _s) \ + [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ + .shift = _s, \ + .duration = { \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 117, 54, 26)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 234, 108, 52)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 351, 162, 78)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 468, 216, 104)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 702, 324, 156)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 936, 432, 208)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1053, 486, 234)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1170, 540, 260)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1404, 648, 312)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1560, 720, 346)) >> _s \ + } \ +} + +#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \ + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 117, 54, 26))) + +#define VHT_GROUP(_streams, _sgi, _bw) \ + __VHT_GROUP(_streams, _sgi, _bw, \ + VHT_GROUP_SHIFT(_streams, _sgi, _bw)) + +struct mcs_group { + u8 shift; + u16 duration[MCS_GROUP_RATES]; +}; + +static const struct mcs_group airtime_mcs_groups[] = { + MCS_GROUP(1, 0, BW_20), + MCS_GROUP(2, 0, BW_20), + MCS_GROUP(3, 0, BW_20), + MCS_GROUP(4, 0, BW_20), + + MCS_GROUP(1, 1, BW_20), + MCS_GROUP(2, 1, BW_20), + MCS_GROUP(3, 1, BW_20), + MCS_GROUP(4, 1, BW_20), + + MCS_GROUP(1, 0, BW_40), + MCS_GROUP(2, 0, BW_40), + MCS_GROUP(3, 0, BW_40), + MCS_GROUP(4, 0, BW_40), + + MCS_GROUP(1, 1, BW_40), + MCS_GROUP(2, 1, BW_40), + MCS_GROUP(3, 1, BW_40), + MCS_GROUP(4, 1, BW_40), + + VHT_GROUP(1, 0, BW_20), + VHT_GROUP(2, 0, BW_20), + VHT_GROUP(3, 0, BW_20), + VHT_GROUP(4, 0, BW_20), + + VHT_GROUP(1, 1, BW_20), + VHT_GROUP(2, 1, BW_20), + VHT_GROUP(3, 1, BW_20), + VHT_GROUP(4, 1, BW_20), + + VHT_GROUP(1, 0, BW_40), + VHT_GROUP(2, 0, BW_40), + VHT_GROUP(3, 0, BW_40), + VHT_GROUP(4, 0, BW_40), + + VHT_GROUP(1, 1, BW_40), + VHT_GROUP(2, 1, BW_40), + VHT_GROUP(3, 1, BW_40), + VHT_GROUP(4, 1, BW_40), + + VHT_GROUP(1, 0, BW_80), + VHT_GROUP(2, 0, BW_80), + VHT_GROUP(3, 0, BW_80), + VHT_GROUP(4, 0, BW_80), + + VHT_GROUP(1, 1, BW_80), + VHT_GROUP(2, 1, BW_80), + VHT_GROUP(3, 1, BW_80), + VHT_GROUP(4, 1, BW_80), +}; + +static u32 +mt76_calc_legacy_rate_duration(const struct ieee80211_rate *rate, bool short_pre, + int len) +{ + u32 duration; + + switch (rate->hw_value >> 8) { + case MT_PHY_TYPE_CCK: + duration = 144 + 48; /* preamble + PLCP */ + if (short_pre) + duration >>= 1; + + duration += 10; /* SIFS */ + break; + case MT_PHY_TYPE_OFDM: + duration = 20 + 16; /* premable + SIFS */ + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + len <<= 3; + duration += (len * 10) / rate->bitrate; + + return duration; +} + +u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status, + int len) +{ + struct ieee80211_supported_band *sband; + const struct ieee80211_rate *rate; + bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI; + bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE; + int bw, streams; + u32 duration; + int group, idx; + + switch (status->bw) { + case RATE_INFO_BW_20: + bw = BW_20; + break; + case RATE_INFO_BW_40: + bw = BW_40; + break; + case RATE_INFO_BW_80: + bw = BW_80; + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + switch (status->encoding) { + case RX_ENC_LEGACY: + if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ)) + return 0; + + sband = dev->hw->wiphy->bands[status->band]; + if (!sband || status->rate_idx > sband->n_bitrates) + return 0; + + rate = &sband->bitrates[status->rate_idx]; + + return mt76_calc_legacy_rate_duration(rate, sp, len); + case RX_ENC_VHT: + streams = status->nss; + idx = status->rate_idx; + group = VHT_GROUP_IDX(streams, sgi, bw); + break; + case RX_ENC_HT: + streams = ((status->rate_idx >> 3) & 3) + 1; + idx = status->rate_idx & 7; + group = HT_GROUP_IDX(streams, sgi, bw); + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + if (WARN_ON_ONCE(streams > 4)) + return 0; + + duration = airtime_mcs_groups[group].duration[idx]; + duration <<= airtime_mcs_groups[group].shift; + duration *= len; + duration /= AVG_PKT_SIZE; + duration /= 1024; + + duration += 36 + (streams << 2); + + return duration; +} diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index aefdd22d74ef..c6076c66cd37 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -414,6 +414,25 @@ mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) return &msband->chan[idx]; } +void mt76_update_survey(struct mt76_dev *dev) +{ + struct mt76_channel_state *state; + + if (dev->drv->update_survey) + dev->drv->update_survey(dev); + + if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { + state = mt76_channel_state(dev, dev->chandef.chan); + spin_lock_bh(&dev->rx_lock); + spin_lock(&dev->cc_lock); + state->cc_bss_rx += dev->cur_cc_bss_rx; + dev->cur_cc_bss_rx = 0; + spin_unlock(&dev->cc_lock); + spin_unlock_bh(&dev->rx_lock); + } +} +EXPORT_SYMBOL_GPL(mt76_update_survey); + void mt76_set_channel(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; @@ -422,9 +441,7 @@ void mt76_set_channel(struct mt76_dev *dev) int timeout = HZ / 5; wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout); - - if (dev->drv->update_survey) - dev->drv->update_survey(dev); + mt76_update_survey(dev); dev->chandef = *chandef; dev->chan_state = mt76_channel_state(dev, chandef->chan); @@ -447,7 +464,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, int ret = 0; if (idx == 0 && dev->drv->update_survey) - dev->drv->update_survey(dev); + mt76_update_survey(dev); sband = &dev->sband_2g; if (idx >= sband->sband.n_channels) { @@ -464,12 +481,17 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, memset(survey, 0, sizeof(*survey)); survey->channel = chan; survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; - if (chan == dev->main_chan) + if (chan == dev->main_chan) { survey->filled |= SURVEY_INFO_IN_USE; + if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) + survey->filled |= SURVEY_INFO_TIME_BSS_RX; + } + spin_lock_bh(&dev->cc_lock); survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); + survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); spin_unlock_bh(&dev->cc_lock); return ret; @@ -566,6 +588,82 @@ mt76_check_ccmp_pn(struct sk_buff *skb) return 0; } +static void +mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, + int len) +{ + struct mt76_wcid *wcid = status->wcid; + struct ieee80211_sta *sta; + u32 airtime; + + airtime = mt76_calc_rx_airtime(dev, status, len); + dev->cur_cc_bss_rx += airtime; + + if (!wcid || !wcid->sta) + return; + + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); + ieee80211_sta_register_airtime(sta, status->tid, 0, airtime); +} + +static void +mt76_airtime_flush_ampdu(struct mt76_dev *dev) +{ + struct mt76_wcid *wcid; + int wcid_idx; + + if (!dev->rx_ampdu_len) + return; + + wcid_idx = dev->rx_ampdu_status.wcid_idx; + if (dev->rx_ampdu_status.wcid_idx != 0xff) + wcid = rcu_dereference(dev->wcid[wcid_idx]); + else + wcid = NULL; + dev->rx_ampdu_status.wcid = wcid; + + mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); + + dev->rx_ampdu_len = 0; + dev->rx_ampdu_ref = 0; +} + +static void +mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct mt76_wcid *wcid = status->wcid; + + if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) + return; + + if (!wcid || !wcid->sta) { + if (!ether_addr_equal(hdr->addr1, dev->macaddr)) + return; + + wcid = NULL; + } + + if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || + status->ampdu_ref != dev->rx_ampdu_ref) + mt76_airtime_flush_ampdu(dev); + + if (status->flag & RX_FLAG_AMPDU_DETAILS) { + if (!dev->rx_ampdu_len || + status->ampdu_ref != dev->rx_ampdu_ref) { + dev->rx_ampdu_status = *status; + dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; + dev->rx_ampdu_ref = status->ampdu_ref; + } + + dev->rx_ampdu_len += skb->len; + return; + } + + mt76_airtime_report(dev, status, skb->len); +} + static void mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) { @@ -582,6 +680,8 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; } + mt76_airtime_check(dev, skb); + if (!wcid || !wcid->sta) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f26b51f94437..048b7ebbc46d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -282,6 +282,7 @@ struct mt76_hw_cap { #define MT_DRV_TXWI_NO_FREE BIT(0) #define MT_DRV_TX_ALIGNED4_SKBS BIT(1) +#define MT_DRV_SW_RX_AIRTIME BIT(2) struct mt76_driver_ops { u32 drv_flags; @@ -320,6 +321,7 @@ struct mt76_driver_ops { struct mt76_channel_state { u64 cc_active; u64 cc_busy; + u64 cc_bss_rx; }; struct mt76_sband { @@ -419,6 +421,34 @@ struct mt76_mmio { u32 irqmask; }; +struct mt76_rx_status { + union { + struct mt76_wcid *wcid; + u8 wcid_idx; + }; + + unsigned long reorder_time; + + u32 ampdu_ref; + + u8 iv[6]; + + u8 aggr:1; + u8 tid; + u16 seqno; + + u16 freq; + u32 flag; + u8 enc_flags; + u8 encoding:2, bw:3; + u8 rate_idx; + u8 nss; + u8 band; + s8 signal; + u8 chains; + s8 chain_signal[IEEE80211_MAX_CHAINS]; +}; + struct mt76_dev { struct ieee80211_hw *hw; struct cfg80211_chan_def chandef; @@ -428,6 +458,12 @@ struct mt76_dev { spinlock_t lock; spinlock_t cc_lock; + u32 cur_cc_bss_rx; + + struct mt76_rx_status rx_ampdu_status; + u32 rx_ampdu_len; + u32 rx_ampdu_ref; + struct mutex mutex; const struct mt76_bus_ops *bus; @@ -511,31 +547,6 @@ enum mt76_phy_type { MT_PHY_TYPE_VHT, }; -struct mt76_rx_status { - struct mt76_wcid *wcid; - - unsigned long reorder_time; - - u32 ampdu_ref; - - u8 iv[6]; - - u8 aggr:1; - u8 tid; - u16 seqno; - - u16 freq; - u32 flag; - u8 enc_flags; - u8 encoding:2, bw:3; - u8 rate_idx; - u8 nss; - u8 band; - s8 signal; - u8 chains; - s8 chain_signal[IEEE80211_MAX_CHAINS]; -}; - #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) #define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__) #define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__) @@ -708,6 +719,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, bool more_data); bool mt76_has_tx_pending(struct mt76_dev *dev); void mt76_set_channel(struct mt76_dev *dev); +void mt76_update_survey(struct mt76_dev *dev); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void mt76_set_stream_caps(struct mt76_dev *dev, bool vht); @@ -768,6 +780,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 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); +u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status, + int len); /* usb */ static inline bool mt76u_urb_error(struct urb *urb) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index ad2ccdbe7258..a68533684b18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -7,6 +7,7 @@ const struct mt76_driver_ops mt7603_drv_ops = { .txwi_size = MT_TXD_SIZE, + .drv_flags = MT_DRV_SW_RX_AIRTIME, .tx_prepare_skb = mt7603_tx_prepare_skb, .tx_complete_skb = mt7603_tx_complete_skb, .rx_skb = mt7603_queue_rx_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 3d160230d929..0212384d0d56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1708,7 +1708,7 @@ void mt7603_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); dev->mac_work_count++; - mt7603_update_channel(&dev->mt76); + mt76_update_survey(&dev->mt76); mt7603_edcca_check(dev); for (i = 0, idx = 0; i < 2; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 9189a86d7825..81f45c4ccc26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1291,7 +1291,7 @@ void mt7615_mac_work(struct work_struct *work) mac_work.work); mutex_lock(&dev->mt76.mutex); - mt7615_update_channel(&dev->mt76); + mt76_update_survey(&dev->mt76); if (++dev->mac_work_count == 5) { mt7615_mac_scs_check(dev); dev->mac_work_count = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index d20fd40418a7..f42450b4319c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -155,7 +155,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), - .drv_flags = MT_DRV_TX_ALIGNED4_SKBS, + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | + MT_DRV_SW_RX_AIRTIME, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 4c2b66b53533..54f9c0cc881f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -211,6 +211,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { + .drv_flags = MT_DRV_SW_RX_AIRTIME, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index f73ec17e5f47..c987e57db0b4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -798,7 +798,7 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, * we can assume that more subframes belonging to the same A-MPDU * are coming. The last one will have valid RSSI info */ - if (!(rxinfo & MT_RXINFO_RSSI)) { + if (rxinfo & MT_RXINFO_RSSI) { if (!++dev->mt76.ampdu_ref) dev->mt76.ampdu_ref++; } @@ -1130,7 +1130,7 @@ void mt76x02_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); - mt76x02_update_channel(&dev->mt76); + mt76_update_survey(&dev->mt76); for (i = 0, idx = 0; i < 16; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 3d8408d11f0e..8f57ef50f35d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -21,7 +21,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), - .drv_flags = MT_DRV_TX_ALIGNED4_SKBS, + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | + MT_DRV_SW_RX_AIRTIME, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index da5e0f9a8bae..81be59c60155 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -25,6 +25,7 @@ static int mt76x2u_probe(struct usb_interface *intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { + .drv_flags = MT_DRV_SW_RX_AIRTIME, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, From ea565833fd7848208eb63fc653d32a6ad3a86d87 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 4 Sep 2019 20:50:14 +0200 Subject: [PATCH 22/56] mt76: mt7603: track tx airtime for airtime fairness and survey Poll per-station hardware counters after tx status events Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 + drivers/net/wireless/mediatek/mt76/mt76.h | 2 + .../net/wireless/mediatek/mt76/mt7603/dma.c | 2 + .../net/wireless/mediatek/mt76/mt7603/init.c | 3 + .../net/wireless/mediatek/mt76/mt7603/mac.c | 86 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7603/main.c | 15 +++- .../wireless/mediatek/mt76/mt7603/mt7603.h | 7 ++ 7 files changed, 116 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index c6076c66cd37..38db311b3ca8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -481,6 +481,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, memset(survey, 0, sizeof(*survey)); survey->channel = chan; survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; + survey->filled |= dev->drv->survey_flags; if (chan == dev->main_chan) { survey->filled |= SURVEY_INFO_IN_USE; @@ -492,6 +493,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); + survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 048b7ebbc46d..322595f4e84e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -286,6 +286,7 @@ struct mt76_hw_cap { struct mt76_driver_ops { u32 drv_flags; + u32 survey_flags; u16 txwi_size; void (*update_survey)(struct mt76_dev *dev); @@ -322,6 +323,7 @@ struct mt76_channel_state { u64 cc_active; u64 cc_busy; u64 cc_bss_rx; + u64 cc_tx; }; struct mt76_sband { diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 24d82a20d046..a6ab73060aad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -152,6 +152,8 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget) for (i = MT_TXQ_MCU; i >= 0; i--) mt76_queue_tx_cleanup(dev, i, false); + mt7603_mac_sta_poll(dev); + tasklet_schedule(&dev->mt76.tx_tasklet); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index a68533684b18..3a2927a524c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -8,6 +8,7 @@ const struct mt76_driver_ops mt7603_drv_ops = { .txwi_size = MT_TXD_SIZE, .drv_flags = MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .tx_prepare_skb = mt7603_tx_prepare_skb, .tx_complete_skb = mt7603_tx_complete_skb, .rx_skb = mt7603_queue_rx_skb, @@ -525,6 +526,8 @@ int mt7603_register_device(struct mt7603_dev *dev) bus_ops->rmw = mt7603_rmw; dev->mt76.bus = bus_ops; + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); spin_lock_init(&dev->ps_lock); INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 0212384d0d56..caa1456adc50 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -160,6 +160,8 @@ void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, addr = mt7603_wtbl4_addr(idx); for (i = 0; i < MT_WTBL4_SIZE; i += 4) mt76_wr(dev, addr + i, 0); + + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); } static void @@ -380,6 +382,84 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val); } +void mt7603_mac_sta_poll(struct mt7603_dev *dev) +{ + static const u8 ac_to_tid[4] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + struct ieee80211_sta *sta; + struct mt7603_sta *msta; + u32 total_airtime = 0; + u32 airtime[4]; + u32 addr; + int i; + + rcu_read_lock(); + + while (1) { + bool clear = false; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&dev->sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + + msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta, + poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + addr = mt7603_wtbl4_addr(msta->wcid.idx); + for (i = 0; i < 4; i++) { + u32 airtime_last = msta->tx_airtime_ac[i]; + + msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8); + airtime[i] = msta->tx_airtime_ac[i] - airtime_last; + airtime[i] *= 32; + total_airtime += airtime[i]; + + if (msta->tx_airtime_ac[i] & BIT(22)) + clear = true; + } + + if (clear) { + mt7603_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->tx_airtime_ac, 0, + sizeof(msta->tx_airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + 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; + u8 qidx = q->hw_idx; + u8 tid = ac_to_tid[i]; + u32 txtime = airtime[qidx]; + + if (!txtime) + continue; + + ieee80211_sta_register_airtime(sta, tid, txtime, 0); + } + } + + rcu_read_unlock(); + + if (!total_airtime) + return; + + spin_lock_bh(&dev->mt76.cc_lock); + dev->mt76.chan_state->cc_tx += total_airtime; + spin_unlock_bh(&dev->mt76.cc_lock); +} + static struct mt76_wcid * mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast) { @@ -1159,6 +1239,12 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data) msta = container_of(wcid, struct mt7603_sta, wcid); sta = wcid_to_sta(wcid); + if (list_empty(&msta->poll_list)) { + spin_lock_bh(&dev->sta_poll_lock); + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data)) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 9c378f017877..31cce1c005c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -66,6 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; dev->vif_mask |= BIT(mvif->idx); + INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; @@ -87,8 +88,9 @@ static void mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; + struct mt7603_sta *msta = &mvif->sta; struct mt7603_dev *dev = hw->priv; - int idx = mvif->sta.wcid.idx; + int idx = msta->wcid.idx; mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), 0); mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), 0); @@ -99,6 +101,11 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 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)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + mutex_lock(&dev->mt76.mutex); dev->vif_mask &= ~BIT(mvif->idx); mutex_unlock(&dev->mt76.mutex); @@ -325,6 +332,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; + INIT_LIST_HEAD(&msta->poll_list); __skb_queue_head_init(&msta->psq); msta->ps = ~0; msta->smps = ~0; @@ -361,6 +369,11 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7603_filter_tx(dev, wcid->idx, true); spin_unlock_bh(&dev->ps_lock); + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + mt7603_wtbl_clear(dev, wcid->idx); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 01b933538c25..ab54b0612e98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -61,6 +61,9 @@ struct mt7603_sta { struct mt7603_vif *vif; + struct list_head poll_list; + u32 tx_airtime_ac[4]; + struct sk_buff_head psq; struct ieee80211_tx_rate rates[4]; @@ -103,6 +106,9 @@ struct mt7603_dev { u8 vif_mask; + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + struct mt7603_sta global_sta; u32 agc0, agc3; @@ -202,6 +208,7 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data); void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid); void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ba_size); +void mt7603_mac_sta_poll(struct mt7603_dev *dev); void mt7603_pse_client_reset(struct mt7603_dev *dev); From dcff8d4dc301c0601625ccae0dffec1bbef83234 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 4 Sep 2019 21:12:10 +0200 Subject: [PATCH 23/56] mt76: mt7603: switch to a different counter for survey busy time MT_MIB_STAT_PSCCA only counts rx CCA busy time, which does not include tx time. MT_MIB_STAT_CCA counts full busy time, including Rx, Tx and NAV Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index caa1456adc50..8e6568d4505b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1578,7 +1578,7 @@ void mt7603_update_channel(struct mt76_dev *mdev) return; state = mdev->chan_state; - busy = mt76_rr(dev, MT_MIB_STAT_PSCCA); + busy = mt76_rr(dev, MT_MIB_STAT_CCA); spin_lock_bh(&dev->mt76.cc_lock); cur_time = ktime_get_boottime(); From aec65e484779c6326116be921cc1bf1aa8e85ecc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 5 Sep 2019 18:29:13 +0200 Subject: [PATCH 24/56] mt76: unify channel survey update code Host time is used to calculate the channel active time on mt7603 and mt7615. Use the same on mt76x02 and move the lock to core code to get rid of some duplicated code. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 16 +++++++++++++-- .../net/wireless/mediatek/mt76/mt7603/mac.c | 15 +------------- .../net/wireless/mediatek/mt76/mt7615/mac.c | 18 +++-------------- .../net/wireless/mediatek/mt76/mt76x0/main.c | 5 +---- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 20 ++++++++++--------- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + .../wireless/mediatek/mt76/mt76x2/pci_main.c | 5 +---- .../wireless/mediatek/mt76/mt76x2/usb_main.c | 5 +---- 8 files changed, 33 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 38db311b3ca8..10d736967fbb 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -416,13 +416,25 @@ mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) void mt76_update_survey(struct mt76_dev *dev) { - struct mt76_channel_state *state; + struct mt76_channel_state *state = dev->chan_state; + ktime_t cur_time; + + if (!test_bit(MT76_STATE_RUNNING, &dev->state)) + return; + + spin_lock_bh(&dev->cc_lock); if (dev->drv->update_survey) dev->drv->update_survey(dev); + cur_time = ktime_get_boottime(); + state->cc_active += ktime_to_us(ktime_sub(cur_time, + dev->survey_time)); + dev->survey_time = cur_time; + + spin_unlock_bh(&dev->cc_lock); + if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { - state = mt76_channel_state(dev, dev->chandef.chan); spin_lock_bh(&dev->rx_lock); spin_lock(&dev->cc_lock); state->cc_bss_rx += dev->cur_cc_bss_rx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 8e6568d4505b..1497d5ec649e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1571,22 +1571,9 @@ void mt7603_update_channel(struct mt76_dev *mdev) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct mt76_channel_state *state; - ktime_t cur_time; - u32 busy; - - if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) - return; state = mdev->chan_state; - busy = mt76_rr(dev, MT_MIB_STAT_CCA); - - spin_lock_bh(&dev->mt76.cc_lock); - cur_time = ktime_get_boottime(); - state->cc_busy += busy; - state->cc_active += ktime_to_us(ktime_sub(cur_time, - dev->mt76.survey_time)); - dev->mt76.survey_time = cur_time; - spin_unlock_bh(&dev->mt76.cc_lock); + state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA); } void diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 81f45c4ccc26..271f36f4acb3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1263,23 +1263,11 @@ void mt7615_update_channel(struct mt76_dev *mdev) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt76_channel_state *state; - ktime_t cur_time; - u32 busy; - if (!test_bit(MT76_STATE_RUNNING, &mdev->state)) - return; - - state = mdev->chan_state; /* TODO: add DBDC support */ - busy = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK); - - spin_lock_bh(&mdev->cc_lock); - cur_time = ktime_get_boottime(); - state->cc_busy += busy; - state->cc_active += ktime_to_us(ktime_sub(cur_time, - mdev->survey_time)); - mdev->survey_time = cur_time; - spin_unlock_bh(&mdev->cc_lock); + state = mdev->chan_state; + state->cc_busy += mt76_get_field(dev, MT_MIB_SDR16(0), + MT_MIB_BUSY_MASK); } void mt7615_mac_work(struct work_struct *work) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index efb7ca93863d..f7682bd2e5a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -19,10 +19,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) mt76_set_channel(&dev->mt76); mt76x0_phy_set_channel(dev, chandef); - /* channel cycle counters read-and-clear */ - mt76_rr(dev, MT_CH_IDLE); - mt76_rr(dev, MT_CH_BUSY); - + mt76x02_mac_cc_reset(dev); mt76x02_edcca_init(dev); if (mt76_is_mmio(dev)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index c987e57db0b4..e49d0136adbc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -984,17 +984,9 @@ void mt76x02_update_channel(struct mt76_dev *mdev) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76_channel_state *state; - u32 active, busy; state = mdev->chan_state; - - busy = mt76_rr(dev, MT_CH_BUSY); - active = busy + mt76_rr(dev, MT_CH_IDLE); - - spin_lock_bh(&dev->mt76.cc_lock); - state->cc_busy += busy; - state->cc_active += active; - spin_unlock_bh(&dev->mt76.cc_lock); + state->cc_busy += mt76_rr(dev, MT_CH_BUSY); } EXPORT_SYMBOL_GPL(mt76x02_update_channel); @@ -1152,6 +1144,16 @@ void mt76x02_mac_work(struct work_struct *work) MT_MAC_WORK_INTERVAL); } +void mt76x02_mac_cc_reset(struct mt76x02_dev *dev) +{ + dev->mt76.survey_time = ktime_get_boottime(); + + /* channel cycle counters read-and-clear */ + mt76_rr(dev, MT_CH_BUSY); + mt76_rr(dev, MT_CH_IDLE); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_cc_reset); + void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) { idx &= 7; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index b687341236c0..48de8eb82856 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -193,6 +193,7 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, void mt76x02_update_channel(struct mt76_dev *mdev); void mt76x02_mac_work(struct work_struct *work); +void mt76x02_mac_cc_reset(struct mt76x02_dev *dev); void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr); int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 385960dca906..1387f3172d7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -52,10 +52,7 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) mt76x2_mac_stop(dev, true); ret = mt76x2_phy_set_channel(dev, chandef); - /* channel cycle counters read-and-clear */ - mt76_rr(dev, MT_CH_IDLE); - mt76_rr(dev, MT_CH_BUSY); - + mt76x02_mac_cc_reset(dev); mt76x02_dfs_init_params(dev); mt76x2_mac_resume(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 1e6f78760dd8..a76a40dcd261 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -49,10 +49,7 @@ mt76x2u_set_channel(struct mt76x02_dev *dev, err = mt76x2u_phy_set_channel(dev, chandef); - /* channel cycle counters read-and-clear */ - mt76_rr(dev, MT_CH_IDLE); - mt76_rr(dev, MT_CH_BUSY); - + mt76x02_mac_cc_reset(dev); mt76x2_mac_resume(dev); clear_bit(MT76_RESET, &dev->mt76.state); From b02f42f4ed2ff5756780da024108866aa87aa528 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 5 Sep 2019 19:30:21 +0200 Subject: [PATCH 25/56] mt76: mt76x02: move MT_CH_TIME_CFG init to mt76x02_mac_cc_reset Reduces code duplication and adds missing bits for USB variants Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 9 --------- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 7 ------- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 9 +++++++++ drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c | 9 --------- drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c | 7 ------- 5 files changed, 9 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index f42450b4319c..9f224f0f7c00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -132,15 +132,6 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) mt76_clear(dev, 0x110, BIT(9)); mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY | - MT_CH_CCA_RC_EN | - FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); - err = mt76x0_register_device(dev); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 54f9c0cc881f..259bd2a55b23 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -165,13 +165,6 @@ static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset) FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) | FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58)); - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY); - return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index e49d0136adbc..d32efc0b100d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1148,6 +1148,15 @@ void mt76x02_mac_cc_reset(struct mt76x02_dev *dev) { dev->mt76.survey_time = ktime_get_boottime(); + mt76_wr(dev, MT_CH_TIME_CFG, + MT_CH_TIME_CFG_TIMER_EN | + MT_CH_TIME_CFG_TX_AS_BUSY | + MT_CH_TIME_CFG_RX_AS_BUSY | + MT_CH_TIME_CFG_NAV_AS_BUSY | + MT_CH_TIME_CFG_EIFS_AS_BUSY | + MT_CH_CCA_RC_EN | + FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); + /* channel cycle counters read-and-clear */ mt76_rr(dev, MT_CH_BUSY); mt76_rr(dev, MT_CH_IDLE); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 3cf54963854a..33fcec9179b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -133,15 +133,6 @@ int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_STAT_FIFO); - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY | - MT_CH_CCA_RC_EN | - FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); - mt76x02_set_tx_ackto(dev); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index e305b374c904..2910068f4e79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -184,13 +184,6 @@ int mt76x2u_init_hardware(struct mt76x02_dev *dev) mt76x02_phy_set_rxpath(dev); mt76x02_phy_set_txdac(dev); - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY); - return mt76x2u_mac_stop(dev); } From 355f8d00c597f944213708d296e86a06f7a9ade8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 6 Sep 2019 10:19:19 +0200 Subject: [PATCH 26/56] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey Estimate by calculating duration for EWMA packet size + estimated A-MPDU length on tx status events Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/airtime.c | 48 ++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 2 + .../net/wireless/mediatek/mt76/mt76x0/pci.c | 1 + .../net/wireless/mediatek/mt76/mt76x0/usb.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 + .../net/wireless/mediatek/mt76/mt76x02_mac.c | 49 ++++++++++++++++--- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 6 +++ .../net/wireless/mediatek/mt76/mt76x02_txrx.c | 10 +++- .../wireless/mediatek/mt76/mt76x02_usb_core.c | 4 +- .../net/wireless/mediatek/mt76/mt76x02_util.c | 1 + .../net/wireless/mediatek/mt76/mt76x2/pci.c | 1 + .../net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + 12 files changed, 116 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/airtime.c b/drivers/net/wireless/mediatek/mt76/airtime.c index d5bc4d713a88..55116f395f9a 100644 --- a/drivers/net/wireless/mediatek/mt76/airtime.c +++ b/drivers/net/wireless/mediatek/mt76/airtime.c @@ -276,3 +276,51 @@ u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status, return duration; } + +u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info, + int len) +{ + struct mt76_rx_status stat = { + .band = info->band, + }; + u32 duration = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) { + struct ieee80211_tx_rate *rate = &info->status.rates[i]; + u32 cur_duration; + + if (rate->idx < 0 || !rate->count) + break; + + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + stat.bw = RATE_INFO_BW_80; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + stat.bw = RATE_INFO_BW_40; + else + stat.bw = RATE_INFO_BW_20; + + stat.enc_flags = 0; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + stat.enc_flags |= RX_ENC_FLAG_SHORTPRE; + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + stat.enc_flags |= RX_ENC_FLAG_SHORT_GI; + + stat.rate_idx = rate->idx; + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + stat.encoding = RX_ENC_VHT; + stat.rate_idx = ieee80211_rate_get_vht_mcs(rate); + stat.nss = ieee80211_rate_get_vht_nss(rate); + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + stat.encoding = RX_ENC_HT; + } else { + stat.encoding = RX_ENC_LEGACY; + } + + cur_duration = mt76_calc_rx_airtime(dev, &stat, len); + duration += cur_duration * rate->count; + } + + return duration; +} +EXPORT_SYMBOL_GPL(mt76_calc_tx_airtime); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 322595f4e84e..8876231d8cdb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -772,6 +772,8 @@ void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac); void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info, + int len); /* internal */ void mt76_tx_free(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 9f224f0f7c00..9621e7b16eaf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -148,6 +148,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) .txwi_size = sizeof(struct mt76x02_txwi), .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 259bd2a55b23..ade6312c7367 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -205,6 +205,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, { static const struct mt76_driver_ops drv_ops = { .drv_flags = MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 50b0131f85bf..0ca0bbfe8769 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -81,6 +81,7 @@ struct mt76x02_dev { u8 txdone_seq; DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); spinlock_t txstatus_fifo_lock; + u32 tx_airtime; struct sk_buff *rx_head; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index d32efc0b100d..38329ebca572 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -483,8 +483,8 @@ mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta, phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate); if (st->pktid & MT_PACKET_ID_HAS_RATE) { - first_rate = st->rate & ~MT_RXWI_RATE_INDEX; - first_rate |= st->pktid & MT_RXWI_RATE_INDEX; + first_rate = st->rate & ~MT_PKTID_RATE; + first_rate |= st->pktid & MT_PKTID_RATE; mt76x02_mac_process_tx_rate(&rate[0], first_rate, dev->mt76.chandef.chan->band); @@ -537,10 +537,20 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, struct ieee80211_tx_status status = { .info = &info }; + static const u8 ac_to_tid[4] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; struct mt76_wcid *wcid = NULL; struct mt76x02_sta *msta = NULL; struct mt76_dev *mdev = &dev->mt76; struct sk_buff_head list; + u32 duration = 0; + u8 cur_pktid; + u32 ac = 0; + int len = 0; if (stat->pktid == MT_PACKET_ID_NO_ACK) return; @@ -570,10 +580,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) { mt76_tx_status_unlock(mdev, &list); - rcu_read_unlock(); - return; + goto out; } + if (msta && stat->aggr && !status.skb) { u32 stat_val, stat_cache; @@ -586,10 +596,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, stat->wcid == msta->status.wcid && msta->n_frames < 32) { msta->n_frames++; mt76_tx_status_unlock(mdev, &list); - rcu_read_unlock(); - return; + goto out; } + cur_pktid = msta->status.pktid; mt76x02_mac_fill_tx_status(dev, msta, status.info, &msta->status, msta->n_frames); @@ -597,16 +607,39 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, msta->n_frames = 1; *update = 0; } else { + cur_pktid = stat->pktid; mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1); *update = 1; } - if (status.skb) + if (status.skb) { + info = *status.info; + len = status.skb->len; + ac = skb_get_queue_mapping(status.skb); mt76_tx_status_skb_done(mdev, status.skb, &list); + } else if (msta) { + len = status.info->status.ampdu_len * ewma_pktlen_read(&msta->pktlen); + ac = FIELD_GET(MT_PKTID_AC, cur_pktid); + } + mt76_tx_status_unlock(mdev, &list); if (!status.skb) ieee80211_tx_status_ext(mt76_hw(dev), &status); + + if (!len) + goto out; + + duration = mt76_calc_tx_airtime(&dev->mt76, &info, len); + + spin_lock_bh(&dev->mt76.cc_lock); + dev->tx_airtime += duration; + spin_unlock_bh(&dev->mt76.cc_lock); + + if (msta) + ieee80211_sta_register_airtime(status.sta, ac_to_tid[ac], duration, 0); + +out: rcu_read_unlock(); } @@ -987,6 +1020,8 @@ void mt76x02_update_channel(struct mt76_dev *mdev) state = mdev->chan_state; state->cc_busy += mt76_rr(dev, MT_CH_BUSY); + state->cc_tx += dev->tx_airtime; + dev->tx_airtime = 0; } EXPORT_SYMBOL_GPL(mt76x02_update_channel); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 48de8eb82856..7d946aa77182 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -23,11 +23,16 @@ struct mt76x02_tx_status { #define MT_VIF_WCID(_n) (254 - ((_n) & 7)) #define MT_MAX_VIFS 8 +#define MT_PKTID_RATE GENMASK(4, 0) +#define MT_PKTID_AC GENMASK(6, 5) + struct mt76x02_vif { struct mt76_wcid group_wcid; /* must be first */ u8 idx; }; +DECLARE_EWMA(pktlen, 8, 8); + struct mt76x02_sta { struct mt76_wcid wcid; /* must be first */ @@ -35,6 +40,7 @@ struct mt76x02_sta { struct mt76x02_tx_status status; int n_frames; + struct ewma_pktlen pktlen; }; #define MT_RXINFO_BA BIT(0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index f27aade34c1e..13825f642087 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -158,7 +158,9 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, /* encode packet rate for no-skb packet id to fix up status reporting */ if (pid == MT_PACKET_ID_NO_SKB) pid = MT_PACKET_ID_HAS_RATE | - (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX); + (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX) | + FIELD_PREP(MT_PKTID_AC, + skb_get_queue_mapping(tx_info->skb)); txwi->pktid = pid; @@ -171,6 +173,12 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) tx_info->info |= MT_TXD_INFO_WIV; + if (sta) { + struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; + + ewma_pktlen_add(&msta->pktlen, tx_info->skb->len); + } + return 0; } EXPORT_SYMBOL_GPL(mt76x02_tx_prepare_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 203420087ac4..4294ffc0478b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -104,7 +104,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, /* encode packet rate for no-skb packet id to fix up status reporting */ if (pid == MT_PACKET_ID_NO_SKB) pid = MT_PACKET_ID_HAS_RATE | - (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX); + (le16_to_cpu(txwi->rate) & MT_PKTID_RATE) | + FIELD_PREP(MT_PKTID_AC, + skb_get_queue_mapping(tx_info->skb)); txwi->pktid = pid; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 414b22399d93..23134bb8690b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -264,6 +264,7 @@ int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->wcid.hw_key_idx = -1; mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); mt76x02_mac_wcid_set_drop(dev, idx, false); + ewma_pktlen_init(&msta->pktlen); if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 8f57ef50f35d..53ca0cedf026 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -23,6 +23,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) .txwi_size = sizeof(struct mt76x02_txwi), .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 81be59c60155..e6d778456e5e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -26,6 +26,7 @@ static int mt76x2u_probe(struct usb_interface *intf, { static const struct mt76_driver_ops drv_ops = { .drv_flags = MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, From 6bfa6e38266d234c845c37e976084e6b524743b1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Sep 2019 12:58:02 +0200 Subject: [PATCH 27/56] mt76: mt7615: report tx_time, bss_rx and busy time to mac80211 Report tx time/rx time and obss time from hw mib counters to fill survey info requested by mac80211 Co-developed-by: Felix Fietkau Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../net/wireless/mediatek/mt76/mt7615/init.c | 2 ++ .../net/wireless/mediatek/mt76/mt7615/mac.c | 26 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7615/main.c | 4 +-- .../net/wireless/mediatek/mt76/mt7615/pci.c | 3 +++ .../net/wireless/mediatek/mt76/mt7615/regs.h | 12 +++++++++ 7 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 10d736967fbb..24b507fb06d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -505,6 +505,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); + survey->time_rx = div_u64(state->cc_rx, 1000); survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8876231d8cdb..f50a12252158 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -322,6 +322,7 @@ struct mt76_driver_ops { struct mt76_channel_state { u64 cc_active; u64 cc_busy; + u64 cc_rx; u64 cc_bss_rx; u64 cc_tx; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index ad94a7ce2e10..05a9e1154dd5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -96,6 +96,8 @@ static void mt7615_mac_init(struct mt7615_dev *dev) FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2); mt76_rmw(dev, MT_DMA_BN0RCFR0, mask, set); mt76_rmw(dev, MT_DMA_BN1RCFR0, mask, set); + + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_EN); } static int mt7615_init_hardware(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 271f36f4acb3..9b113037c4f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -49,6 +49,14 @@ void mt7615_mac_reset_counters(struct mt7615_dev *dev) mt76_rr(dev, MT_TX_AGG_CNT(i)); memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); + + /* TODO: add DBDC support */ + + /* reset airtime counters */ + mt76_rr(dev, MT_MIB_SDR16(0)); + mt76_rr(dev, MT_MIB_SDR36(0)); + mt76_rr(dev, MT_MIB_SDR37(0)); + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) @@ -1263,11 +1271,25 @@ void mt7615_update_channel(struct mt76_dev *mdev) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt76_channel_state *state; + u64 busy_time, tx_time, rx_time, obss_time; /* TODO: add DBDC support */ + busy_time = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK); + tx_time = mt76_get_field(dev, MT_MIB_SDR36(0), + MT_MIB_SDR36_TXTIME_MASK); + rx_time = mt76_get_field(dev, MT_MIB_SDR37(0), + MT_MIB_SDR37_RXTIME_MASK); + obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_TIME5, + MT_MIB_OBSSTIME_MASK); + state = mdev->chan_state; - state->cc_busy += mt76_get_field(dev, MT_MIB_SDR16(0), - MT_MIB_BUSY_MASK); + state->cc_busy += busy_time; + state->cc_tx += tx_time; + state->cc_rx += rx_time + obss_time; + state->cc_bss_rx += rx_time; + + /* reset obss airtime */ + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } void mt7615_mac_work(struct work_struct *work) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 6949cda9df0b..a4fc58fadffd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -153,8 +153,8 @@ static int mt7615_set_channel(struct mt7615_dev *dev) ret = mt7615_dfs_init_radar_detector(dev); mt7615_mac_cca_stats_reset(dev); dev->mt76.survey_time = ktime_get_boottime(); - /* TODO: add DBDC support */ - mt76_rr(dev, MT_MIB_SDR16(0)); + + mt7615_mac_reset_counters(dev); out: clear_bit(MT76_RESET, &dev->mt76.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 73744563a573..1eb1eb659c3f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -73,6 +73,9 @@ static int mt7615_pci_probe(struct pci_dev *pdev, /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7615_txp), .drv_flags = MT_DRV_TXWI_NO_FREE, + .survey_flags = SURVEY_INFO_TIME_TX | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_BSS_RX, .tx_prepare_skb = mt7615_tx_prepare_skb, .tx_complete_skb = mt7615_tx_complete_skb, .rx_skb = mt7615_queue_rx_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 643b8bd17850..9a2ff1f3a68c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -198,6 +198,13 @@ #define MT_WF_RFCR1_DROP_CFEND BIT(7) #define MT_WF_RFCR1_DROP_CFACK BIT(8) +#define MT_WF_RMAC_MIB_TIME0 MT_WF_RMAC(0x03c4) +#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) +#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) + +#define MT_WF_RMAC_MIB_TIME5 MT_WF_RMAC(0x03d8) +#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) + #define MT_WF_DMA_BASE 0x21800 #define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs)) @@ -289,6 +296,11 @@ #define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9)) #define MT_MIB_BUSY_MASK GENMASK(23, 0) +#define MT_MIB_SDR36(n) MT_WF_MIB(0x098 + ((n) << 9)) +#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) +#define MT_MIB_SDR37(n) MT_WF_MIB(0x09c + ((n) << 9)) +#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) + #define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2)) #define MT_EFUSE_BASE 0x81070000 From 29ed2a79de000a7cf48a2aba74f25b59f1bbc36d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 26 Sep 2019 18:23:56 +0200 Subject: [PATCH 28/56] mt76: mt7615: fix survey channel busy time Like on mt7603, MIB status register 16 tracks CCA time, but does not include tx time. Switch to status register 9 to includ NAV and tx time as well. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 9b113037c4f2..f688390bfd3a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -53,7 +53,7 @@ void mt7615_mac_reset_counters(struct mt7615_dev *dev) /* TODO: add DBDC support */ /* reset airtime counters */ - mt76_rr(dev, MT_MIB_SDR16(0)); + mt76_rr(dev, MT_MIB_SDR9(0)); mt76_rr(dev, MT_MIB_SDR36(0)); mt76_rr(dev, MT_MIB_SDR37(0)); mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); @@ -1274,7 +1274,8 @@ void mt7615_update_channel(struct mt76_dev *mdev) u64 busy_time, tx_time, rx_time, obss_time; /* TODO: add DBDC support */ - busy_time = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK); + busy_time = mt76_get_field(dev, MT_MIB_SDR9(0), + MT_MIB_SDR9_BUSY_MASK); tx_time = mt76_get_field(dev, MT_MIB_SDR36(0), MT_MIB_SDR36_TXTIME_MASK); rx_time = mt76_get_field(dev, MT_MIB_SDR37(0), diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 9a2ff1f3a68c..226b9ada89f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -293,8 +293,11 @@ #define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) #define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) -#define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9)) -#define MT_MIB_BUSY_MASK GENMASK(23, 0) +#define MT_MIB_SDR9(n) MT_WF_MIB(0x02c + ((n) << 9)) +#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) + +#define MT_MIB_SDR16(n) MT_WF_MIB(0x048 + ((n) << 9)) +#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) #define MT_MIB_SDR36(n) MT_WF_MIB(0x098 + ((n) << 9)) #define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) From 87d3cdeb28113703d4caac5a6926e5a60ccedbeb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Sep 2019 12:58:03 +0200 Subject: [PATCH 29/56] mt76: mt7615: introduce mt7615_mac_wtbl_update routine Introduce mt7615_mac_wtbl_update utility routine in order to update WTBL update register Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 16 +++++++++++----- .../net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f688390bfd3a..2e36b3289fa6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -492,6 +492,15 @@ static u32 mt7615_mac_wtbl_addr(int wcid) return MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE; } +bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) +{ + mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); + + return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, + 0, 5000); +} + void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) @@ -724,11 +733,8 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, mt76_wr(dev, MT_WTBL_RICR0, w0); mt76_wr(dev, MT_WTBL_RICR1, w1); - mt76_wr(dev, MT_WTBL_UPDATE, - FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid->idx) | - MT_WTBL_UPDATE_RXINFO_UPDATE); - - if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + if (!mt7615_mac_wtbl_update(dev, wcid->idx, + MT_WTBL_UPDATE_RXINFO_UPDATE)) return -ETIMEDOUT; return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index fa8f2f1ed040..857279fda661 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -231,6 +231,7 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask) } void mt7615_update_channel(struct mt76_dev *mdev); +bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev); void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable); From b2c2f029683c4f42265c18dbb7e8ccbe06e6b01d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Sep 2019 12:58:05 +0200 Subject: [PATCH 30/56] mt76: mt7615: track tx/rx airtime for airtime fairness Poll per-station hardware counters available in WTBL after tx/rx status events in order to report tx/rx airtime to mac80211 layer Co-developed-by: Felix Fietkau Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/dma.c | 2 + .../net/wireless/mediatek/mt76/mt7615/init.c | 12 ++- .../net/wireless/mediatek/mt76/mt7615/mac.c | 92 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/main.c | 24 ++++- .../wireless/mediatek/mt76/mt7615/mt7615.h | 7 ++ .../net/wireless/mediatek/mt76/mt7615/regs.h | 3 + 6 files changed, 137 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index fe532cecbbdd..285d4f1d6178 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -110,6 +110,8 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget) for (i = 0; i < ARRAY_SIZE(queue_map); i++) mt76_queue_tx_cleanup(dev, queue_map[i], false); + mt7615_mac_sta_poll(dev); + tasklet_schedule(&dev->mt76.tx_tasklet); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 05a9e1154dd5..1e7723aceee2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -21,6 +21,7 @@ static void mt7615_phy_init(struct mt7615_dev *dev) static void mt7615_mac_init(struct mt7615_dev *dev) { u32 val, mask, set; + int i; /* enable band 0/1 clk */ mt76_set(dev, MT_CFG_CCR, @@ -97,7 +98,12 @@ static void mt7615_mac_init(struct mt7615_dev *dev) mt76_rmw(dev, MT_DMA_BN0RCFR0, mask, set); mt76_rmw(dev, MT_DMA_BN1RCFR0, mask, set); + for (i = 0; i < MT7615_WTBL_SIZE; i++) + mt7615_mac_wtbl_update(dev, i, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_EN); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_EN); } static int mt7615_init_hardware(struct mt7615_dev *dev) @@ -262,12 +268,14 @@ int mt7615_register_device(struct mt7615_dev *dev) struct wiphy *wiphy = hw->wiphy; int ret; + INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work); + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); + ret = mt7615_init_hardware(dev); if (ret) return ret; - INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work); - hw->queues = 4; hw->max_rates = 3; hw->max_report_rates = 7; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 2e36b3289fa6..2b810ba359ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -57,6 +57,7 @@ void mt7615_mac_reset_counters(struct mt7615_dev *dev) mt76_rr(dev, MT_MIB_SDR36(0)); mt76_rr(dev, MT_MIB_SDR37(0)); mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) @@ -80,6 +81,16 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2); status->wcid = mt7615_rx_get_wcid(dev, idx, unicast); + if (status->wcid) { + struct mt7615_sta *msta; + + msta = container_of(status->wcid, struct mt7615_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + /* TODO: properly support DBDC */ status->freq = dev->mt76.chandef.chan->center_freq; status->band = dev->mt76.chandef.chan->band; @@ -501,6 +512,82 @@ bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) 0, 5000); } +void mt7615_mac_sta_poll(struct mt7615_dev *dev) +{ + static const u8 ac_to_tid[4] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [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 mt7615_sta *msta; + u32 addr, tx_time[4], rx_time[4]; + int i; + + rcu_read_lock(); + + while (true) { + bool clear = false; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&dev->sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + msta = list_first_entry(&dev->sta_poll_list, + struct mt7615_sta, poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + addr = mt7615_mac_wtbl_addr(msta->wcid.idx) + 19 * 4; + + for (i = 0; i < 4; i++, addr += 8) { + 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); + tx_time[i] = msta->airtime_ac[i] - tx_last; + rx_time[i] = msta->airtime_ac[i + 4] - rx_last; + + if ((tx_last | rx_last) & BIT(30)) + clear = true; + } + + if (clear) { + mt7615_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); + for (i = 0; i < 4; i++) { + u32 tx_cur = tx_time[i]; + u32 rx_cur = rx_time[hw_queue_map[i]]; + u8 tid = ac_to_tid[i]; + + if (!tx_cur && !rx_cur) + continue; + + ieee80211_sta_register_airtime(sta, tid, tx_cur, + rx_cur); + } + } + + rcu_read_unlock(); +} + void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) @@ -1064,6 +1151,11 @@ void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data) msta = container_of(wcid, struct mt7615_sta, wcid); sta = wcid_to_sta(wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data)) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index a4fc58fadffd..602add1be029 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -99,8 +99,12 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, dev->vif_mask |= BIT(mvif->idx); dev->omac_mask |= BIT(mvif->omac_idx); idx = MT7615_WTBL_RESERVED - mvif->idx; + + INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; + mt7615_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); mtxq = (struct mt76_txq *)vif->txq->drv_priv; @@ -117,8 +121,9 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_sta *msta = &mvif->sta; struct mt7615_dev *dev = hw->priv; - int idx = mvif->sta.wcid.idx; + int idx = msta->wcid.idx; /* TODO: disable beacon for the bss */ @@ -131,6 +136,11 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, dev->vif_mask &= ~BIT(mvif->idx); dev->omac_mask &= ~BIT(mvif->omac_idx); mutex_unlock(&dev->mt76.mutex); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); } static int mt7615_set_channel(struct mt7615_dev *dev) @@ -360,9 +370,12 @@ int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; + INIT_LIST_HEAD(&msta->poll_list); msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; + mt7615_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); mt7615_mcu_add_wtbl(dev, vif, sta); mt7615_mcu_set_sta_rec(dev, vif, sta, 1); @@ -383,9 +396,18 @@ void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; mt7615_mcu_set_sta_rec(dev, vif, sta, 0); mt7615_mcu_del_wtbl(dev, sta); + + mt7615_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); } static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 857279fda661..21486831172c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -56,6 +56,9 @@ struct mt7615_sta { struct mt7615_vif *vif; + struct list_head poll_list; + u32 airtime_ac[8]; + struct ieee80211_tx_rate rates[4]; struct mt7615_rate_set rateset[2]; @@ -83,6 +86,9 @@ struct mt7615_dev { __le32 rx_ampdu_ts; + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + struct { u8 n_pulses; u32 period; @@ -235,6 +241,7 @@ bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev); void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable); +void mt7615_mac_sta_poll(struct mt7615_dev *dev); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int pid, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 226b9ada89f6..99bd5939d33f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -202,6 +202,8 @@ #define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) #define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) +#define MT_WF_RMAC_MIB_AIRTIME0 MT_WF_RMAC(0x0380) + #define MT_WF_RMAC_MIB_TIME5 MT_WF_RMAC(0x03d8) #define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) @@ -236,6 +238,7 @@ #define MT_WTBL_UPDATE MT_WTBL_OFF(0x030) #define MT_WTBL_UPDATE_WLAN_IDX GENMASK(7, 0) #define MT_WTBL_UPDATE_RXINFO_UPDATE BIT(11) +#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) #define MT_WTBL_UPDATE_RATE_UPDATE BIT(13) #define MT_WTBL_UPDATE_TX_COUNT_CLEAR BIT(14) #define MT_WTBL_UPDATE_BUSY BIT(31) From 55857ab857975080d9e400ca85a7c192f7986ab9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 6 Sep 2019 11:29:09 +0200 Subject: [PATCH 31/56] mt76: enable airtime fairness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is supported by all hardware drivers now Signed-off-by: Felix Fietkau Acked-by: Toke Høiland-Jørgensen --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 24b507fb06d8..d493437731b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -307,6 +307,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); wiphy->available_antennas_tx = dev->antenna_mask; wiphy->available_antennas_rx = dev->antenna_mask; From 36f7e2b2bb1de86f0072cd49ca93d82b9e8fd894 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 29 Sep 2019 22:04:37 +0200 Subject: [PATCH 32/56] mt76: do not use devm API for led classdev With the devm API, the unregister happens after the device cleanup is done, after which the struct mt76_dev which contains the led_cdev has already been freed. This leads to a use-after-free bug that can crash the system. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d493437731b8..c4eb00d79ffc 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -105,7 +105,15 @@ static int mt76_led_init(struct mt76_dev *dev) dev->led_al = of_property_read_bool(np, "led-active-low"); } - return devm_led_classdev_register(dev->dev, &dev->led_cdev); + return led_classdev_register(dev->dev, &dev->led_cdev); +} + +static void mt76_led_cleanup(struct mt76_dev *dev) +{ + if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) + return; + + led_classdev_unregister(&dev->led_cdev); } static void mt76_init_stream_cap(struct mt76_dev *dev, @@ -362,6 +370,7 @@ void mt76_unregister_device(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; + mt76_led_cleanup(dev); mt76_tx_status_check(dev, NULL, true); ieee80211_unregister_hw(hw); } From 1a817fa73c3b27a593aadf0029de24db1bbc1a3e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Oct 2019 12:32:14 +0200 Subject: [PATCH 33/56] mt76: add missing locking around ampdu action This is needed primarily to avoid races in dealing with rx aggregation related data structures Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 31cce1c005c6..a0632ca198f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -575,6 +575,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq = (struct mt76_txq *)txq->drv_priv; + mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, @@ -603,6 +604,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } + mutex_unlock(&dev->mt76.mutex); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 602add1be029..7e1e1481219a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -489,6 +489,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq = (struct mt76_txq *)txq->drv_priv; + mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, @@ -518,6 +519,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } + mutex_unlock(&dev->mt76.mutex); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 23134bb8690b..ceb0325e1fd0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -372,6 +372,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq = (struct mt76_txq *)txq->drv_priv; + mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, @@ -400,6 +401,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } + mutex_unlock(&dev->mt76.mutex); return 0; } From fb7d95c6ee4f71ba131c9b3c65d658369ffd1128 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Oct 2019 15:30:18 +0200 Subject: [PATCH 34/56] mt76: drop rcu read lock in mt76_rx_aggr_stop A rcu read locked section is not allowed to sleep, and the rcu lock here isn't actually necessary, because we're holding dev->mutex. Fixes an issue when the tid work item is still running while freeing a station or stopping the aggregation session Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 2276fd4e9ec3..b05d439dca3b 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -277,17 +277,13 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) { - struct mt76_rx_tid *tid; + struct mt76_rx_tid *tid = NULL; - rcu_read_lock(); - - tid = rcu_dereference(wcid->aggr[tidno]); + rcu_swap_protected(wcid->aggr[tidno], tid, + lockdep_is_held(&dev->mutex)); if (tid) { - rcu_assign_pointer(wcid->aggr[tidno], NULL); mt76_rx_aggr_shutdown(dev, tid); kfree_rcu(tid, rcu_head); } - - rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop); From e7aaa72f4728451487d7a3fe54225796d08ab1e5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Oct 2019 12:30:46 +0200 Subject: [PATCH 35/56] mt76: fix aggregation stop issue Cancel the workqueue after the tid has been cleaned up, in order to avoid a possible rescheduling from within the work function. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index b05d439dca3b..53b5a4b2dcc5 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -130,8 +130,10 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) return; spin_lock_bh(&tid->lock); - mt76_rx_aggr_release_frames(tid, frames, seqno); - mt76_rx_aggr_release_head(tid, frames); + if (!tid->stopped) { + mt76_rx_aggr_release_frames(tid, frames, seqno); + mt76_rx_aggr_release_head(tid, frames); + } spin_unlock_bh(&tid->lock); } @@ -257,8 +259,6 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) u8 size = tid->size; int i; - cancel_delayed_work_sync(&tid->reorder_work); - spin_lock_bh(&tid->lock); tid->stopped = true; @@ -273,6 +273,8 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) } spin_unlock_bh(&tid->lock); + + cancel_delayed_work_sync(&tid->reorder_work); } void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) From 3e0705acd4de7821d42bea7fb01938ff05fd4d58 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Oct 2019 12:33:39 +0200 Subject: [PATCH 36/56] mt76: avoid enabling interrupt if NAPI poll is still pending if napi_complete() returns false, it means that polling is still pending. Interrupts should not fire until the polling is no longer scheduled Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 6442a45ba303..3de744fb5e7a 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -539,10 +539,8 @@ mt76_dma_rx_poll(struct napi_struct *napi, int budget) rcu_read_unlock(); - if (done < budget) { - napi_complete(napi); + if (done < budget && napi_complete(napi)) dev->drv->rx_poll_complete(dev, qid); - } return done; } From d1bc9bf2072c04e3303339437788fe224a33a7fa Mon Sep 17 00:00:00 2001 From: Pawel Dembicki Date: Fri, 4 Oct 2019 15:23:49 +0200 Subject: [PATCH 37/56] mt76: mt76x0: eeprom: add support for MAC address from OF mt76x0e driver only supports MAC addresses from calibration data eeprom. Many routers however do not have a valid stock address set in this field. This patch makes it possible to take a MAC address from OF (e.g. from mtd). Signed-off-by: Pawel Dembicki [adjusted for kernel submission] Signed-off-by: Adrian Schmutzler Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 96368fac4228..a03e2d01fba7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -343,6 +343,7 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev) version, fae); mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); + mt76_eeprom_override(&dev->mt76); mt76x0_set_chip_cap(dev); mt76x0_set_freq_offset(dev); mt76x0_set_temp_offset(dev); From 237312c5e485804417e0f809f948112c3eb7fc96 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 15 Oct 2019 17:16:43 +0200 Subject: [PATCH 38/56] mt76: refactor cc_lock locking scheme Read busy counters not holding cc_lock spinlock since usb read can't be performed in interrupt context. Move cc_active and cc_rx counters out of cc_lock since they are not modified in interrupt context. Grab cc_lock updating cur_cc_bss_rx in mt76_airtime_report and do not hold rx_lock in mt76_update_survey. Moreover grab mt76 mutex in mt76_get_survey before running mt76_update_survey. This patch fixes the following 'schedule while atomic' [ 291.790866] BUG: scheduling while atomic: iw/2161/0x00000202 [ 291.791002] Preemption disabled at: [ 291.791007] [<0000000000000000>] 0x0 [ 291.791015] CPU: 0 PID: 2161 Comm: iw Tainted: G W 5.4.= 0-rc2-3-ARCH-00104-g9e208aa06c21 #1 [ 291.791017] Hardware name: LENOVO 2349QM6/2349QM6, BIOS G1ETC2WW (2.82=) 08/07/2019 [ 291.791019] Call Trace: [ 291.791042] dump_stack+0x5c/0x80 [ 291.791049] __schedule_bug.cold+0x8e/0x9b [ 291.791055] __schedule+0x5f8/0x770 [ 291.791062] schedule+0x43/0xd0 [ 291.791068] schedule_preempt_disabled+0x14/0x20 [ 291.791074] __mutex_lock.isra.0+0x18a/0x530 [ 291.791099] mt76u_rr+0x1f/0x40 [mt76_usb] [ 291.791113] mt76x02_update_channel+0x22/0x40 [mt76x02_lib] [ 291.791122] mt76_update_survey+0x42/0xe0 [mt76] [ 291.791129] mt76_get_survey+0x2f/0x1b0 [mt76] [ 291.791170] ieee80211_dump_survey+0x5e/0x140 [mac80211] [ 291.791217] nl80211_dump_survey+0x13c/0x2f0 [cfg80211] [ 291.791222] ? __kmalloc_reserve.isra.0+0x2d/0x70 [ 291.791225] ? __alloc_skb+0x96/0x1d0 [ 291.791229] netlink_dump+0x17b/0x370 [ 291.791247] __netlink_dump_start+0x16f/0x1e0 [ 291.791253] genl_family_rcv_msg+0x396/0x410 [ 291.791290] ? nl80211_prepare_wdev_dump+0x1b0/0x1b0 [cfg80211] [ 291.791297] ? _raw_spin_unlock_irqrestore+0x20/0x40 [ 291.791312] ? __wake_up_common_lock+0x8a/0xc0 [ 291.791316] genl_rcv_msg+0x47/0x90 [ 291.791320] ? genl_family_rcv_msg+0x410/0x410 [ 291.791323] netlink_rcv_skb+0x49/0x110 [ 291.791329] genl_rcv+0x24/0x40 [ 291.791333] netlink_unicast+0x171/0x200 [ 291.791340] netlink_sendmsg+0x208/0x3d0 [ 291.791358] sock_sendmsg+0x5e/0x60 [ 291.791361] ___sys_sendmsg+0x2ae/0x330 [ 291.791368] ? filemap_map_pages+0x272/0x390 [ 291.791374] ? _raw_spin_unlock+0x16/0x30 [ 291.791379] ? __handle_mm_fault+0x112f/0x1390 [ 291.791388] __sys_sendmsg+0x59/0xa0 [ 291.791396] do_syscall_64+0x5b/0x1a0 [ 291.791400] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 291.791404] RIP: 0033:0x7f5d0c7f37b7 [ 291.791418] Code: 64 89 02 48 c7 c0 ff ff ff ff eb bb 0f 1f 80 00 00 0= 0 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 2e 00 00 00 0f 05= <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 89 54 24 1c 48 89 74 24 10 [ 291.791421] RSP: 002b:00007ffe8b5d0538 EFLAGS: 00000246 ORIG_RAX: 0000= 00000000002e [ 291.791426] RAX: ffffffffffffffda RBX: 000055a038e6c390 RCX: 00007f5d0= c7f37b7 [ 291.791430] RDX: 0000000000000000 RSI: 00007ffe8b5d0570 RDI: 000000000= 0000003 [ 291.791434] RBP: 000055a038e718c0 R08: 000055a038e6c02a R09: 000000000= 0000002 [ 291.791438] R10: 000055a03808cb00 R11: 0000000000000246 R12: 000055a03= 8e71780 [ 291.791440] R13: 00007ffe8b5d0570 R14: 000055a038e717d0 R15: 000055a03= 8e718c0 [ 291.791480] NOHZ: local_softirq_pending 202 Fixes: 168aea24f4bb ("mt76: mt76x02u: enable survey support") Tested-by: Markus Theil Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 29 ++++++++++--------- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 3 ++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index c4eb00d79ffc..4e6f14ca00f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -432,8 +432,6 @@ void mt76_update_survey(struct mt76_dev *dev) if (!test_bit(MT76_STATE_RUNNING, &dev->state)) return; - spin_lock_bh(&dev->cc_lock); - if (dev->drv->update_survey) dev->drv->update_survey(dev); @@ -442,15 +440,11 @@ void mt76_update_survey(struct mt76_dev *dev) dev->survey_time)); dev->survey_time = cur_time; - spin_unlock_bh(&dev->cc_lock); - if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { - spin_lock_bh(&dev->rx_lock); - spin_lock(&dev->cc_lock); + spin_lock_bh(&dev->cc_lock); state->cc_bss_rx += dev->cur_cc_bss_rx; dev->cur_cc_bss_rx = 0; - spin_unlock(&dev->cc_lock); - spin_unlock_bh(&dev->rx_lock); + spin_unlock_bh(&dev->cc_lock); } } EXPORT_SYMBOL_GPL(mt76_update_survey); @@ -485,6 +479,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct mt76_channel_state *state; int ret = 0; + mutex_lock(&dev->mutex); if (idx == 0 && dev->drv->update_survey) mt76_update_survey(dev); @@ -494,8 +489,10 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, sband = &dev->sband_5g; } - if (idx >= sband->sband.n_channels) - return -ENOENT; + if (idx >= sband->sband.n_channels) { + ret = -ENOENT; + goto out; + } chan = &sband->sband.channels[idx]; state = mt76_channel_state(dev, chan); @@ -511,14 +508,18 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, survey->filled |= SURVEY_INFO_TIME_BSS_RX; } - spin_lock_bh(&dev->cc_lock); - survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); - survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); survey->time_rx = div_u64(state->cc_rx, 1000); + survey->time = div_u64(state->cc_active, 1000); + + spin_lock_bh(&dev->cc_lock); + survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); +out: + mutex_unlock(&dev->mutex); + return ret; } EXPORT_SYMBOL_GPL(mt76_get_survey); @@ -622,7 +623,9 @@ mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, u32 airtime; airtime = mt76_calc_rx_airtime(dev, status, len); + spin_lock(&dev->cc_lock); dev->cur_cc_bss_rx += airtime; + spin_unlock(&dev->cc_lock); if (!wcid || !wcid->sta) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 38329ebca572..4460548f346a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1020,8 +1020,11 @@ void mt76x02_update_channel(struct mt76_dev *mdev) state = mdev->chan_state; state->cc_busy += mt76_rr(dev, MT_CH_BUSY); + + spin_lock_bh(&dev->mt76.cc_lock); state->cc_tx += dev->tx_airtime; dev->tx_airtime = 0; + spin_unlock_bh(&dev->mt76.cc_lock); } EXPORT_SYMBOL_GPL(mt76x02_update_channel); From bf5238b25ac373cb2a544fe8554fd66fc9e04efc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 10 Oct 2019 21:59:46 +0200 Subject: [PATCH 39/56] mt76: add sanity check for a-mpdu rx wcid index Avoid dereferencing invalid ids Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 4e6f14ca00f2..a3975e3795ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -644,7 +644,7 @@ mt76_airtime_flush_ampdu(struct mt76_dev *dev) return; wcid_idx = dev->rx_ampdu_status.wcid_idx; - if (dev->rx_ampdu_status.wcid_idx != 0xff) + if (wcid_idx < ARRAY_SIZE(dev->wcid)) wcid = rcu_dereference(dev->wcid[wcid_idx]); else wcid = NULL; From 3473750cd412e5506213e773e9fdd0729d1affe5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 14 Oct 2019 12:01:09 +0200 Subject: [PATCH 40/56] mt76: remove obsolete .add_buf() from struct mt76_queue_ops It hasn't been used in a while Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f50a12252158..4bdf8c44c6d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -152,10 +152,6 @@ struct mt76_queue_ops { int idx, int n_desc, int bufsize, u32 ring_base); - int (*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); - int (*tx_queue_skb)(struct mt76_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta); From b86b173f634f9d53ae226c8e7e8af9e163f759c0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Oct 2019 00:50:04 +0200 Subject: [PATCH 41/56] mt76: mt76x02u: update ewma pkt len in mt76x02u_tx_prepare_skb Update ewma packet length in mt76x02u_tx_prepare_skb as it is done for pci counterpart in order to properly estimate tx time on current channel Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 4294ffc0478b..d03d3c8e296c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -120,6 +120,12 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) flags |= MT_TXD_INFO_WIV; + if (sta) { + struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; + + ewma_pktlen_add(&msta->pktlen, tx_info->skb->len); + } + return mt76x02u_skb_dma_info(tx_info->skb, WLAN_PORT, flags); } EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb); From 2ec1e82bbf92c3031307beb89b59b589206c318c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Oct 2019 23:31:23 +0200 Subject: [PATCH 42/56] mt76: mt76x0: remove 350ms delay in mt76x0_phy_calibrate Since mt76x0 does not save the phy calibration data it is not necessary to wait 350ms in mt76x0_phy_calibrate Tested-by: Sid Hayn Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 711a352dfd5c..61e1a086f3cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -899,7 +899,6 @@ void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on) } mt76x02_mcu_calibrate(dev, MCU_CAL_FULL, val); - msleep(350); mt76x02_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz); usleep_range(15000, 20000); From 5d1ad7d7bab0e9519c6f2a75fde6ab193279c5b3 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 25 Oct 2019 17:16:16 +0800 Subject: [PATCH 43/56] mt76: mt7615: remove unneeded semicolon remove unneeded semicolon. This is detected by coccinelle. Signed-off-by: YueHaibing Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 7e1e1481219a..4f7cdb4f08fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -60,7 +60,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask) default: WARN_ON(1); break; - }; + } return -1; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 842cd81704db..164619f8a9ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1076,7 +1076,7 @@ int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif, default: WARN_ON(1); break; - }; + } if (en) { req.basic.conn_state = CONN_STATE_PORT_SECURE; From 80df01f4dc79abbed724bbe0851cab3fe8ad9d99 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 28 Oct 2019 16:21:41 +0100 Subject: [PATCH 44/56] mt76: mt76u: rely on usb_interface instead of usb_dev usb drivers are supposed to communicate using usb_interface instead mt76x{0,2}u is now registering through usb_device. Fix it by passing usb_intf device to mt76_alloc_device routine. Fixes: 112f980ac8926 ("mt76usb: use usb_dev private data") Signed-off-by: Lorenzo Bianconi Tested-By: Zero_Chaos Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/usb.c | 12 +++++++++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 4bdf8c44c6d2..ac439fd4f312 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -804,7 +804,8 @@ static inline int mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len, int timeout) { - struct usb_device *udev = to_usb_device(dev->dev); + struct usb_interface *uintf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(uintf); struct mt76_usb *usb = &dev->usb; unsigned int pipe; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index ade6312c7367..b9fd41433106 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -221,7 +221,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, u32 mac_rev; int ret; - mdev = mt76_alloc_device(&usb_dev->dev, sizeof(*dev), &mt76x0u_ops, + mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), &mt76x0u_ops, &drv_ops); if (!mdev) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index e6d778456e5e..48b9017813b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -41,7 +41,7 @@ static int mt76x2u_probe(struct usb_interface *intf, struct mt76_dev *mdev; int err; - mdev = mt76_alloc_device(&udev->dev, sizeof(*dev), &mt76x2u_ops, + mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops, &drv_ops); if (!mdev) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index cac058fc41ef..be19038ea7dd 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -19,7 +19,8 @@ static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len) { - struct usb_device *udev = to_usb_device(dev->dev); + struct usb_interface *uintf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(uintf); unsigned int pipe; int i, ret; @@ -234,7 +235,8 @@ mt76u_rd_rp(struct mt76_dev *dev, u32 base, static bool mt76u_check_sg(struct mt76_dev *dev) { - struct usb_device *udev = to_usb_device(dev->dev); + struct usb_interface *uintf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(uintf); return (!disable_usb_sg && udev->bus->sg_tablesize > 0 && (udev->bus->no_sg_constraint || @@ -369,7 +371,8 @@ mt76u_fill_bulk_urb(struct mt76_dev *dev, int dir, int index, struct urb *urb, usb_complete_t complete_fn, void *context) { - struct usb_device *udev = to_usb_device(dev->dev); + struct usb_interface *uintf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(uintf); unsigned int pipe; if (dir == USB_DIR_IN) @@ -951,6 +954,7 @@ int mt76u_init(struct mt76_dev *dev, .rd_rp = mt76u_rd_rp, .type = MT76_BUS_USB, }; + struct usb_device *udev = interface_to_usbdev(intf); struct mt76_usb *usb = &dev->usb; tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev); @@ -964,6 +968,8 @@ int mt76u_init(struct mt76_dev *dev, dev->bus = &mt76u_ops; dev->queue_ops = &usb_queue_ops; + dev_set_drvdata(&udev->dev, dev); + usb->sg_en = mt76u_check_sg(dev); return mt76u_set_endpoints(intf, usb); From 284efb473ef5f02a7f2c13fdf8d516ecc589bdf1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 28 Oct 2019 17:38:05 +0100 Subject: [PATCH 45/56] mt76: mt76u: rely on a dedicated stats workqueue rate controller and throughput are very sensitive to tx status timing. In order to improve performances when the system is heavily loaded, substitute stat_work delayed_work with a regular work_struct and create a mt76u dedicated workqueue for tx status reporting Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 2 ++ .../net/wireless/mediatek/mt76/mt76x2/usb.c | 2 ++ drivers/net/wireless/mediatek/mt76/usb.c | 27 ++++++++++++------- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ac439fd4f312..a65890cebf0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -387,7 +387,8 @@ struct mt76_usb { }; struct tasklet_struct rx_tasklet; - struct delayed_work stat_work; + struct workqueue_struct *stat_wq; + struct work_struct stat_work; u8 out_ep[__MT_EP_OUT_MAX]; u8 in_ep[__MT_EP_IN_MAX]; @@ -823,6 +824,7 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req, void mt76u_single_wr(struct mt76_dev *dev, const u8 req, const u16 offset, const u32 val); int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf); +void mt76u_deinit(struct mt76_dev *dev); int mt76u_alloc_queues(struct mt76_dev *dev); void mt76u_stop_tx(struct mt76_dev *dev); void mt76u_stop_rx(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index b9fd41433106..a8ab8df075c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -273,6 +273,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, err: usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); + mt76u_deinit(&dev->mt76); ieee80211_free_hw(mdev->hw); return ret; @@ -292,6 +293,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); + mt76u_deinit(&dev->mt76); ieee80211_free_hw(dev->mt76.hw); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 48b9017813b5..b64ad816cc25 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -73,6 +73,7 @@ static int mt76x2u_probe(struct usb_interface *intf, err: ieee80211_free_hw(mt76_hw(dev)); + mt76u_deinit(&dev->mt76); usb_set_intfdata(intf, NULL); usb_put_dev(udev); @@ -88,6 +89,7 @@ static void mt76x2u_disconnect(struct usb_interface *intf) set_bit(MT76_REMOVED, &dev->mt76.state); ieee80211_unregister_hw(hw); mt76x2u_cleanup(dev); + mt76u_deinit(&dev->mt76); ieee80211_free_hw(hw); usb_set_intfdata(intf, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index be19038ea7dd..d6d47081e281 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -697,10 +697,7 @@ static void mt76u_tx_tasklet(unsigned long data) mt76_txq_schedule(dev, i); if (!test_and_set_bit(MT76_READING_STATS, &dev->state)) - ieee80211_queue_delayed_work(dev->hw, - &dev->usb.stat_work, - msecs_to_jiffies(10)); - + queue_work(dev->usb.stat_wq, &dev->usb.stat_work); if (wake) ieee80211_wake_queue(dev->hw, i); } @@ -713,7 +710,7 @@ static void mt76u_tx_status_data(struct work_struct *work) u8 update = 1; u16 count = 0; - usb = container_of(work, struct mt76_usb, stat_work.work); + usb = container_of(work, struct mt76_usb, stat_work); dev = container_of(usb, struct mt76_dev, usb); while (true) { @@ -726,8 +723,7 @@ static void mt76u_tx_status_data(struct work_struct *work) } if (count && test_bit(MT76_STATE_RUNNING, &dev->state)) - ieee80211_queue_delayed_work(dev->hw, &usb->stat_work, - msecs_to_jiffies(10)); + queue_work(usb->stat_wq, &usb->stat_work); else clear_bit(MT76_READING_STATS, &dev->state); } @@ -908,7 +904,7 @@ void mt76u_stop_tx(struct mt76_dev *dev) } } - cancel_delayed_work_sync(&dev->usb.stat_work); + cancel_work_sync(&dev->usb.stat_work); clear_bit(MT76_READING_STATS, &dev->state); mt76_tx_status_check(dev, NULL, true); @@ -959,9 +955,13 @@ int mt76u_init(struct mt76_dev *dev, tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev); tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev); - INIT_DELAYED_WORK(&usb->stat_work, mt76u_tx_status_data); + INIT_WORK(&usb->stat_work, mt76u_tx_status_data); skb_queue_head_init(&dev->rx_skb[MT_RXQ_MAIN]); + usb->stat_wq = alloc_workqueue("mt76u", WQ_UNBOUND, 0); + if (!usb->stat_wq) + return -ENOMEM; + mutex_init(&usb->mcu.mutex); mutex_init(&usb->usb_ctrl_mtx); @@ -976,5 +976,14 @@ int mt76u_init(struct mt76_dev *dev, } EXPORT_SYMBOL_GPL(mt76u_init); +void mt76u_deinit(struct mt76_dev *dev) +{ + if (dev->usb.stat_wq) { + destroy_workqueue(dev->usb.stat_wq); + dev->usb.stat_wq = NULL; + } +} +EXPORT_SYMBOL_GPL(mt76u_deinit); + MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_LICENSE("Dual BSD/GPL"); From cc53b52daa091ee875372d843255728c3ec941e4 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 29 Oct 2019 12:48:39 +0800 Subject: [PATCH 46/56] mt76: Remove set but not used variable 'idx' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/mediatek/mt76/dma.c: In function mt76_dma_rx_fill: drivers/net/wireless/mediatek/mt76/dma.c:377:6: warning: variable idx set but not used [-Wunused-but-set-variable] It is not used since commit 17f1de56df05 ("mt76: add common code shared between multiple chipsets") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 3de744fb5e7a..6173c80189ba 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -365,7 +365,6 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) int frames = 0; int len = SKB_WITH_OVERHEAD(q->buf_size); int offset = q->buf_offset; - int idx; spin_lock_bh(&q->lock); @@ -384,7 +383,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) qbuf.addr = addr + offset; qbuf.len = len - offset; - idx = mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL); + mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL); frames++; } From 61c51a74a4e58673e28e79447f44279b0a52686b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 29 Oct 2019 14:34:44 +0100 Subject: [PATCH 47/56] mt76: use mt76_dev in mt76_is_{mmio,usb} Convert mt76_is_mmio and mt76_is_usb to rely on mt76_dev instead of mt76x02_dev since this is a property not strictly related to hw chipset and it will be more reusable Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 12 ++++++------ drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 6 +++--- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a65890cebf0f..881b91c19ec3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -49,8 +49,8 @@ struct mt76_bus_ops { enum mt76_bus_type type; }; -#define mt76_is_usb(dev) ((dev)->mt76.bus->type == MT76_BUS_USB) -#define mt76_is_mmio(dev) ((dev)->mt76.bus->type == MT76_BUS_MMIO) +#define mt76_is_usb(dev) ((dev)->bus->type == MT76_BUS_USB) +#define mt76_is_mmio(dev) ((dev)->bus->type == MT76_BUS_MMIO) enum mt76_txq_id { MT_TXQ_VO = IEEE80211_AC_VO, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index f7682bd2e5a8..b2ccf50512dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -13,7 +13,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { cancel_delayed_work_sync(&dev->cal_work); mt76x02_pre_tbtt_enable(dev, false); - if (mt76_is_mmio(dev)) + if (mt76_is_mmio(&dev->mt76)) tasklet_disable(&dev->dfs_pd.dfs_tasklet); mt76_set_channel(&dev->mt76); @@ -22,7 +22,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) mt76x02_mac_cc_reset(dev); mt76x02_edcca_init(dev); - if (mt76_is_mmio(dev)) { + if (mt76_is_mmio(&dev->mt76)) { mt76x02_dfs_init_params(dev); tasklet_enable(&dev->dfs_pd.dfs_tasklet); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 82f5b481b723..6953f253a28a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -30,7 +30,7 @@ static inline bool is_mt7610e(struct mt76x02_dev *dev) { - if (!mt76_is_mmio(dev)) + if (!mt76_is_mmio(&dev->mt76)) return false; return mt76_chip(&dev->mt76) == 0x7610; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 61e1a086f3cb..2ecd45f8af90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -102,7 +102,7 @@ static int mt76x0_rf_csr_rr(struct mt76x02_dev *dev, u32 offset) static int mt76x0_rf_wr(struct mt76x02_dev *dev, u32 offset, u8 val) { - if (mt76_is_usb(dev)) { + if (mt76_is_usb(&dev->mt76)) { struct mt76_reg_pair pair = { .reg = offset, .value = val, @@ -121,7 +121,7 @@ static int mt76x0_rf_rr(struct mt76x02_dev *dev, u32 offset) int ret; u32 val; - if (mt76_is_usb(dev)) { + if (mt76_is_usb(&dev->mt76)) { struct mt76_reg_pair pair = { .reg = offset, }; @@ -176,7 +176,7 @@ mt76x0_phy_rf_csr_wr_rp(struct mt76x02_dev *dev, } #define RF_RANDOM_WRITE(dev, tab) do { \ - if (mt76_is_mmio(dev)) \ + if (mt76_is_mmio(&dev->mt76)) \ mt76x0_phy_rf_csr_wr_rp(dev, tab, ARRAY_SIZE(tab)); \ else \ mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));\ @@ -744,7 +744,7 @@ mt76x0_phy_get_delta_power(struct mt76x02_dev *dev, u8 tx_mode, if (!tx_mode) { data = mt76_rr(dev, MT_BBP(CORE, 1)); - if (is_mt7630(dev) && mt76_is_mmio(dev)) { + if (is_mt7630(dev) && mt76_is_mmio(&dev->mt76)) { int offset; /* 2.3 * 8192 or 1.5 * 8192 */ @@ -966,7 +966,7 @@ void mt76x0_phy_set_channel(struct mt76x02_dev *dev, break; } - if (mt76_is_usb(dev)) { + if (mt76_is_usb(&dev->mt76)) { mt76x0_phy_bbp_set_bw(dev, chandef->width); } else { if (chandef->width == NL80211_CHAN_WIDTH_80 || @@ -1122,7 +1122,7 @@ static void mt76x0_rf_patch_reg_array(struct mt76x02_dev *dev, switch (reg) { case MT_RF(0, 3): - if (mt76_is_mmio(dev)) { + if (mt76_is_mmio(&dev->mt76)) { if (is_mt7630(dev)) val = 0x70; else diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index 4be7a24097cc..6274b6a24b07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -114,7 +114,7 @@ int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param) .id = cpu_to_le32(type), .value = cpu_to_le32(param), }; - bool is_mt76x2e = mt76_is_mmio(dev) && is_mt76x2(dev); + bool is_mt76x2e = mt76_is_mmio(&dev->mt76) && is_mt76x2(dev); int ret; if (is_mt76x2e) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index ceb0325e1fd0..50401ea0b82d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -161,7 +161,7 @@ void mt76x02_init_device(struct mt76x02_dev *dev) #endif BIT(NL80211_IFTYPE_ADHOC); - if (mt76_is_usb(dev)) { + if (mt76_is_usb(&dev->mt76)) { hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; wiphy->iface_combinations = mt76x02u_if_comb; @@ -445,7 +445,7 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * data registers and sent via HW beacons engine, they require to * be already encrypted. */ - if (mt76_is_usb(dev) && + if (mt76_is_usb(&dev->mt76) && vif->type == NL80211_IFTYPE_AP && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; @@ -626,7 +626,7 @@ void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, int idx = msta->wcid.idx; mt76_stop_tx_queues(&dev->mt76, sta, true); - if (mt76_is_mmio(dev)) + if (mt76_is_mmio(mdev)) mt76x02_mac_wcid_set_drop(dev, idx, ps); } EXPORT_SYMBOL_GPL(mt76x02_sta_ps); From 19d0affadd6e6122742381813809f2d9f5c49eca Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 31 Oct 2019 09:15:09 +0100 Subject: [PATCH 48/56] mt76: move SUPPORTS_REORDERING_BUFFER hw property in mt76_register_device Move SUPPORTS_REORDERING_BUFFER hw property configuration from chip specific code to mt76_register_device since it is supported by all mt76 drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + drivers/net/wireless/mediatek/mt76/mt7603/init.c | 1 - drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index a3975e3795ee..070c96e983df 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -337,6 +337,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); + ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index 3a2927a524c3..50c6a2828c18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -556,7 +556,6 @@ int mt7603_register_device(struct mt7603_dev *dev) wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); /* init led callbacks */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 1e7723aceee2..537b1b5ba128 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -289,7 +289,6 @@ int mt7615_register_device(struct mt7615_dev *dev) wiphy->reg_notifier = mt7615_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 50401ea0b82d..1cb323091c76 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -190,7 +190,6 @@ void mt76x02_init_device(struct mt76x02_dev *dev) hw->vif_data_size = sizeof(struct mt76x02_vif); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); dev->mt76.global_wcid.idx = 255; dev->mt76.global_wcid.hw_key_idx = -1; From 7f4b7920318b601bcea353b71d569a21846ffac5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 8 Oct 2019 00:49:00 +0200 Subject: [PATCH 49/56] mt76: mt7615: add ibss support Enable IFTYPE_ADHOC support on 7615 devices. The feature has been tested using a mt76x2 device as wireless peer. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 537b1b5ba128..888ca8bbdef0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -177,6 +177,9 @@ static struct ieee80211_rate mt7615_rates[] = { static const struct ieee80211_iface_limit if_limits[] = { { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { .max = MT7615_MAX_INTERFACES, .types = BIT(NL80211_IFTYPE_AP) | #ifdef CONFIG_MAC80211_MESH @@ -289,6 +292,8 @@ int mt7615_register_device(struct mt7615_dev *dev) wiphy->reg_notifier = mt7615_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; @@ -303,6 +308,7 @@ int mt7615_register_device(struct mt7615_dev *dev) dev->dfs_state = -1; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 4f7cdb4f08fb..982e578df4ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -41,6 +41,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask) switch (type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: /* ap use hw bssid 0 and ext bssid */ if (~mask & BIT(HW_BSSID_0)) return HW_BSSID_0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 164619f8a9ed..8371387ca772 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -848,6 +848,11 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, conn_type = CONNECTION_INFRA_STA; break; } + case NL80211_IFTYPE_ADHOC: + conn_type = CONNECTION_IBSS_ADHOC; + tx_wlan_idx = mvif->sta.wcid.idx; + net_type = NETWORK_IBSS; + break; default: WARN_ON(1); break; @@ -1073,6 +1078,9 @@ int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif, case NL80211_IFTYPE_STATION: req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); break; + case NL80211_IFTYPE_ADHOC: + req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + break; default: WARN_ON(1); break; From 0eb8c104fd8dfc2a8636b09b3f908170f7c9d037 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 31 Oct 2019 11:03:12 +0100 Subject: [PATCH 50/56] mt76: move interface_modes definition in mt76_core module Move interface modes declaration in common code since now mt76 chipsets support all modes (NL80211_IFTYPE_STATION, NL80211_IFTYPE_AP, NL80211_IFTYPE_MESH_POINT and NL80211_IFTYPE_ADHOC) Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt7603/init.c | 9 --------- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 7 ------- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 8 -------- 4 files changed, 7 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 070c96e983df..bbe38caca71a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -340,6 +340,13 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_ADHOC); if (dev->cap.has_2ghz) { ret = mt76_init_sband_2g(dev, rates, n_rates); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index 50c6a2828c18..0696dbf28c5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -564,16 +564,7 @@ int mt7603_register_device(struct mt7603_dev *dev) dev->mt76.led_cdev.blink_set = mt7603_led_set_blink; } - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC); - wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - wiphy->reg_notifier = mt7603_regd_notifier; ret = mt76_register_device(&dev->mt76, true, mt7603_rates, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 888ca8bbdef0..128a6ee1fa6d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -307,13 +307,6 @@ int mt7615_register_device(struct mt7615_dev *dev) dev->mt76.antenna_mask = 0xf; dev->dfs_state = -1; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_AP); - ret = mt76_register_device(&dev->mt76, true, mt7615_rates, ARRAY_SIZE(mt7615_rates)); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 1cb323091c76..bdc83838d346 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -153,14 +153,6 @@ void mt76x02_init_device(struct mt76x02_dev *dev) hw->max_rate_tries = 1; hw->extra_tx_headroom = 2; - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC); - if (mt76_is_usb(&dev->mt76)) { hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; From 2b5d1b91e1741c48f00682dec7b1a0845f9792f3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 1 Nov 2019 23:21:07 +0100 Subject: [PATCH 51/56] mt76: mt7615: disable radar pattern detector during scanning Set switch_reason to CH_SWITCH_SCAN_BYPASS_DPD during frequency scanning in order to disable radar pattern detector Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 8371387ca772..f229c9ce9f65 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1305,8 +1305,10 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev) }; int ret; - 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; From 45876d6ebbd26d2df178d1d5410642e73a289f67 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 5 Nov 2019 11:00:32 +0100 Subject: [PATCH 52/56] Revert "mt76: mt76x0e: don't use hw encryption for MT7630E" This reverts commit 34b0e9b767bfa09ae233ca0d6ceb299bf2e24600. Since commit 7bd0650be63c ("mt76: dma: fix buffer unmap with non-linear skbs") is no longer necessary to disable HW encryption for MT7630E. Disabling HW encryption helped previously because somehow fragmented skb's are not created if mac80211 encrypt frames, so buffer unmap bug of non-linear skbs was not triggered. Now since this bug is properly fixed by commit 7bd0650be63c ("mt76: dma: fix buffer unmap with non-linear skbs") , we can enable HW encryption back. Signed-off-by: Stanislaw Gruszka Acked-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 9621e7b16eaf..5605056dfbe2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -51,19 +51,6 @@ static void mt76x0e_stop(struct ieee80211_hw *hw) mt76x0e_stop_hw(dev); } -static int -mt76x0e_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct mt76x02_dev *dev = hw->priv; - - if (is_mt7630(dev)) - return -EOPNOTSUPP; - - return mt76x02_set_key(hw, cmd, vif, sta, key); -} - static void mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) @@ -80,7 +67,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, .sta_state = mt76_sta_state, - .set_key = mt76x0e_set_key, + .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, From e8b970c8e367e85fab9b8ac4f36080e5d653c38e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 7 Nov 2019 01:01:58 +0200 Subject: [PATCH 53/56] mt76: fix possible out-of-bound access in mt7615_fill_txs/mt7603_fill_txs Fix possible out-of-bound access of status rates array in mt7615_fill_txs/mt7603_fill_txs routines Fixes: c5211e997eca ("mt76: mt7603: rework and fix tx status reporting") Fixes: 4af81f02b49c ("mt76: mt7615: sync with mt7603 rate control changes") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 1497d5ec649e..812d081ad943 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1136,8 +1136,10 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta, if (idx && (cur_rate->idx != info->status.rates[i].idx || cur_rate->flags != info->status.rates[i].flags)) { i++; - if (i == ARRAY_SIZE(info->status.rates)) + if (i == ARRAY_SIZE(info->status.rates)) { + i--; break; + } info->status.rates[i] = *cur_rate; info->status.rates[i].count = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 2b810ba359ae..c77adc5d2552 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1039,8 +1039,10 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, if (idx && (cur_rate->idx != info->status.rates[i].idx || cur_rate->flags != info->status.rates[i].flags)) { i++; - if (i == ARRAY_SIZE(info->status.rates)) + if (i == ARRAY_SIZE(info->status.rates)) { + i--; break; + } info->status.rates[i] = *cur_rate; info->status.rates[i].count = 0; From e49c76d455a93b6cc978ae9e9fab2a1e551c147e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 14 Nov 2019 17:12:07 +0200 Subject: [PATCH 54/56] mt76: move mt76_get_antenna in mt76_core module Move mt76_get_antenna in mac80211.c in order to be reused by all drivers. Initialize .get_antenna function pointer for mt76x0, mt7603, mt7615 and mt76x2u drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 13 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7603/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 + .../net/wireless/mediatek/mt76/mt76x2/pci_main.c | 15 +-------------- .../net/wireless/mediatek/mt76/mt76x2/usb_main.c | 1 + 8 files changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index bbe38caca71a..b9f2a401041a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1037,3 +1037,16 @@ void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) clear_bit(MT76_SCANNING, &dev->state); } EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); + +int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct mt76_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + *tx_ant = dev->antenna_mask; + *rx_ant = dev->antenna_mask; + mutex_unlock(&dev->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_get_antenna); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 881b91c19ec3..afdbcfb96cba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -761,6 +761,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76_csa_check(struct mt76_dev *dev); void mt76_csa_finish(struct mt76_dev *dev); +int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id); int mt76_get_rate(struct mt76_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index a0632ca198f1..281387c3f4f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -691,6 +691,7 @@ const struct ieee80211_ops mt7603_ops = { .set_coverage_class = mt7603_set_coverage_class, .set_tim = mt76_set_tim, .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, }; MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 982e578df4ba..240dab919327 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -547,4 +547,5 @@ const struct ieee80211_ops mt7615_ops = { .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7615_channel_switch_beacon, .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 5605056dfbe2..e2974e0ae1fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -81,6 +81,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .release_buffered_frames = mt76_release_buffered_frames, .set_coverage_class = mt76x02_set_coverage_class, .set_rts_threshold = mt76x02_set_rts_threshold, + .get_antenna = mt76_get_antenna, }; static int mt76x0e_register_device(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index a8ab8df075c3..65ba9fc6ea0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -138,6 +138,7 @@ static const struct ieee80211_ops mt76x0u_ops = { .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .release_buffered_frames = mt76_release_buffered_frames, + .get_antenna = mt76_get_antenna, }; static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 1387f3172d7f..cfe8905ce73f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -135,19 +135,6 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, return 0; } -static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, - u32 *rx_ant) -{ - struct mt76x02_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - *tx_ant = dev->mt76.antenna_mask; - *rx_ant = dev->mt76.antenna_mask; - mutex_unlock(&dev->mt76.mutex); - - return 0; -} - const struct ieee80211_ops mt76x2_ops = { .tx = mt76x02_tx, .start = mt76x2_start, @@ -172,7 +159,7 @@ const struct ieee80211_ops mt76x2_ops = { .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .set_antenna = mt76x2_set_antenna, - .get_antenna = mt76x2_get_antenna, + .get_antenna = mt76_get_antenna, .set_rts_threshold = mt76x02_set_rts_threshold, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index a76a40dcd261..9e97204841f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -119,4 +119,5 @@ const struct ieee80211_ops mt76x2u_ops = { .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .release_buffered_frames = mt76_release_buffered_frames, + .get_antenna = mt76_get_antenna, }; From acf5457fd99db6c9a42ef280494dfee949ee1e09 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 14 Nov 2019 22:21:11 +0200 Subject: [PATCH 55/56] mt76: mt7615: read {tx,rx} mask from eeprom Parse configured {tx,rx} mask from eeprom data instead of just setting it to four tx-rx streams Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/eeprom.c | 18 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/eeprom.h | 3 +++ .../net/wireless/mediatek/mt76/mt7615/init.c | 2 -- .../net/wireless/mediatek/mt76/mt7615/regs.h | 2 ++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 515bb58e19fd..eccad4987ac8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -93,6 +93,7 @@ static int mt7615_check_eeprom(struct mt76_dev *dev) static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) { u8 val, *eeprom = dev->mt76.eeprom.data; + u8 tx_mask, rx_mask, max_nss; val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL, eeprom[MT_EE_WIFI_CONF]); @@ -108,6 +109,23 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) dev->mt76.cap.has_5ghz = true; break; } + + /* read tx-rx mask from eeprom */ + val = mt76_rr(dev, MT_TOP_STRAP_STA); + max_nss = val & MT_TOP_3NSS ? 3 : 4; + + rx_mask = FIELD_GET(MT_EE_NIC_CONF_RX_MASK, + eeprom[MT_EE_NIC_CONF_0]); + if (!rx_mask || rx_mask > max_nss) + rx_mask = max_nss; + + tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK, + eeprom[MT_EE_NIC_CONF_0]); + if (!tx_mask || tx_mask > max_nss) + tx_mask = max_nss; + + dev->mt76.chainmask = tx_mask << 8 | rx_mask; + dev->mt76.antenna_mask = BIT(tx_mask) - 1; } int mt7615_eeprom_get_power_index(struct mt7615_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h index f4a4280768d2..c3bc69ac210e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h @@ -24,6 +24,9 @@ enum mt7615_eeprom_field { __MT_EE_MAX = 0x3bf }; +#define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4) +#define MT_EE_NIC_CONF_RX_MASK GENMASK(3, 0) + #define MT_EE_NIC_CONF_TSSI_2G BIT(5) #define MT_EE_NIC_CONF_TSSI_5G BIT(6) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 128a6ee1fa6d..553bd4d988f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -303,8 +303,6 @@ int mt7615_register_device(struct mt7615_dev *dev) IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; - dev->mt76.chainmask = 0x404; - dev->mt76.antenna_mask = 0xf; dev->dfs_state = -1; ret = mt76_register_device(&dev->mt76, true, mt7615_rates, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 99bd5939d33f..61a4aa9ac6e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -6,6 +6,8 @@ #define MT_HW_REV 0x1000 #define MT_HW_CHIPID 0x1008 +#define MT_TOP_STRAP_STA 0x1010 +#define MT_TOP_3NSS BIT(24) #define MT_TOP_MISC2 0x1134 #define MT_TOP_MISC2_FW_STATE GENMASK(2, 0) From 23cb16d2ccb5f819d7acff602e5a153157bf2884 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 17 Nov 2019 14:26:14 +0200 Subject: [PATCH 56/56] mt76: mt76u: fix endpoint definition order Even if they are not currently used fix BK/BE endpoint definition order. Fixes: b40b15e1521f ("mt76: add usb support to mt76 layer") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index afdbcfb96cba..fb077760347a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -366,8 +366,8 @@ enum mt76u_in_ep { enum mt76u_out_ep { MT_EP_OUT_INBAND_CMD, - MT_EP_OUT_AC_BK, MT_EP_OUT_AC_BE, + MT_EP_OUT_AC_BK, MT_EP_OUT_AC_VI, MT_EP_OUT_AC_VO, MT_EP_OUT_HCCA,