linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev
@ 2019-09-26 17:47 Felix Fietkau
  2019-09-26 17:47 ` [PATCH 02/15] mt76: report rx a-mpdu subframe status Felix Fietkau
                   ` (13 more replies)
  0 siblings, 14 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

It is no longer used

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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;
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 02/15] mt76: report rx a-mpdu subframe status
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 03/15] mt76: rename mt76_driver_ops txwi_flags to drv_flags and include tx aligned4 Felix Fietkau
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

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 <nbd@nbd.name>
---
 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 331de7c44b6c..173d158d7018 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -437,6 +437,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];
@@ -513,6 +514,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 8a6142637bfd..fe084555754b 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;
 
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 03/15] mt76: rename mt76_driver_ops txwi_flags to drv_flags and include tx aligned4
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
  2019-09-26 17:47 ` [PATCH 02/15] mt76: report rx a-mpdu subframe status Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 04/15] mt76: store current channel survey_state in struct mt76_dev Felix Fietkau
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

This reduces the struct size and is useful for adding more flags later

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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 c747eb24581c..e2ce59b260c1 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -164,7 +164,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;
 		}
@@ -299,7 +299,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 173d158d7018..af71773c2d55 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -279,11 +279,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 73c3104f8858..f7a1f82d8320 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,
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 04/15] mt76: store current channel survey_state in struct mt76_dev
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
  2019-09-26 17:47 ` [PATCH 02/15] mt76: report rx a-mpdu subframe status Felix Fietkau
  2019-09-26 17:47 ` [PATCH 03/15] mt76: rename mt76_driver_ops txwi_flags to drv_flags and include tx aligned4 Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 05/15] mt76: track rx airtime for airtime fairness and survey Felix Fietkau
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

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 <nbd@nbd.name>
---
 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 af71773c2d55..3e4ababcae9b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -423,6 +423,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;
 
@@ -603,21 +604,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);
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 05/15] mt76: track rx airtime for airtime fairness and survey
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (2 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 04/15] mt76: store current channel survey_state in struct mt76_dev Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-27  8:35   ` Toke Høiland-Jørgensen
  2019-09-26 17:47 ` [PATCH 06/15] mt76: mt7603: track tx " Felix Fietkau
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

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 <nbd@nbd.name>
---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 drivers/net/wireless/mediatek/mt76/airtime.c  | 278 ++++++++++++++++++
 drivers/net/wireless/mediatek/mt76/mac80211.c | 109 ++++++-
 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, 433 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 4d03596e891f..181af60e32db 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-usb-y := usb.o usb_trace.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 <nbd@nbd.name>
+ */
+
+#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..aab181bc6eb2 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,81 @@ 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 (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 +679,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 3e4ababcae9b..911347bd272c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -281,6 +281,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;
@@ -319,6 +320,7 @@ struct mt76_driver_ops {
 struct mt76_channel_state {
 	u64 cc_active;
 	u64 cc_busy;
+	u64 cc_bss_rx;
 };
 
 struct mt76_sband {
@@ -418,6 +420,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;
@@ -427,6 +457,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;
@@ -510,31 +546,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__)
@@ -706,6 +717,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);
@@ -766,6 +778,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 f7a1f82d8320..5304b6ecda26 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,
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 06/15] mt76: mt7603: track tx airtime for airtime fairness and survey
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (3 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 05/15] mt76: track rx airtime for airtime fairness and survey Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 07/15] mt76: mt7603: switch to a different counter for survey busy time Felix Fietkau
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

Poll per-station hardware counters after tx status events

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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  |  7 ++
 .../wireless/mediatek/mt76/mt7603/mt7603.h    |  7 ++
 7 files changed, 109 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index aab181bc6eb2..5fcadd712f89 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 911347bd272c..4f3849b4f677 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -285,6 +285,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);
@@ -321,6 +322,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 e7b57f20b629..180eb6bb781a 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;
 
@@ -325,6 +326,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 +363,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);
 
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 07/15] mt76: mt7603: switch to a different counter for survey busy time
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (4 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 06/15] mt76: mt7603: track tx " Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 08/15] mt76: unify channel survey update code Felix Fietkau
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

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 <nbd@nbd.name>
---
 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();
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 08/15] mt76: unify channel survey update code
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (5 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 07/15] mt76: mt7603: switch to a different counter for survey busy time Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 09/15] mt76: mt76x02: move MT_CH_TIME_CFG init to mt76x02_mac_cc_reset Felix Fietkau
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

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 <nbd@nbd.name>
---
 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 5fcadd712f89..5aba8bc0b086 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);
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 09/15] mt76: mt76x02: move MT_CH_TIME_CFG init to mt76x02_mac_cc_reset
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (6 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 08/15] mt76: unify channel survey update code Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey Felix Fietkau
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

Reduces code duplication and adds missing bits for USB variants

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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);
 }
 
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (7 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 09/15] mt76: mt76x02: move MT_CH_TIME_CFG init to mt76x02_mac_cc_reset Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-27  7:45   ` Toke Høiland-Jørgensen
  2019-09-26 17:47 ` [PATCH 11/15] mt76: mt7615: report tx_time, bss_rx and busy time to mac80211 Felix Fietkau
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

Estimate by calculating duration for EWMA packet size + estimated A-MPDU
length on tx status events

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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, 117 insertions(+), 8 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 4f3849b4f677..49511bd06fd9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -770,6 +770,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..d4f37140fede 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;
 
 	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,6 +607,7 @@ 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;
 	}
@@ -607,6 +618,30 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
 
 	if (!status.skb)
 		ieee80211_tx_status_ext(mt76_hw(dev), &status);
+
+	if (status.skb) {
+		len = status.skb->len;
+		ac = skb_get_queue_mapping(status.skb);
+	} else if (msta) {
+		len = status.info->status.ampdu_len * ewma_pktlen_read(&msta->pktlen);
+		ac = FIELD_GET(MT_PKTID_AC, cur_pktid);
+	} else {
+		goto out;
+	}
+
+	if (!len)
+		goto out;
+
+	duration = mt76_calc_tx_airtime(&dev->mt76, status.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 +1022,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 aec73a0295e8..f5695ebdb225 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 5304b6ecda26..6253ec5fbd72 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,
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 11/15] mt76: mt7615: report tx_time, bss_rx and busy time to mac80211
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (8 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 12/15] mt76: mt7615: fix survey channel busy time Felix Fietkau
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

From: Lorenzo Bianconi <lorenzo@kernel.org>

Report tx time/rx time and obss time from hw mib counters to fill survey
info requested by mac80211

Co-developed-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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 5aba8bc0b086..fd64172ca785 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 49511bd06fd9..8bcc7f21e83c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -321,6 +321,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 61df2988ca10..9707fa8b5485 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
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 12/15] mt76: mt7615: fix survey channel busy time
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (9 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 11/15] mt76: mt7615: report tx_time, bss_rx and busy time to mac80211 Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 13/15] mt76: mt7615: introduce mt7615_mac_wtbl_update routine Felix Fietkau
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

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 <nbd@nbd.name>
---
 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)
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 13/15] mt76: mt7615: introduce mt7615_mac_wtbl_update routine
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (10 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 12/15] mt76: mt7615: fix survey channel busy time Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 14/15] mt76: mt7615: track tx/rx airtime for airtime fairness Felix Fietkau
  2019-09-26 17:47 ` [PATCH 15/15] mt76: enable " Felix Fietkau
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

From: Lorenzo Bianconi <lorenzo@kernel.org>

Introduce mt7615_mac_wtbl_update utility routine in order to update
WTBL update register

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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 fe084555754b..070afba63e43 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);
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 14/15] mt76: mt7615: track tx/rx airtime for airtime fairness
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (11 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 13/15] mt76: mt7615: introduce mt7615_mac_wtbl_update routine Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-26 17:47 ` [PATCH 15/15] mt76: enable " Felix Fietkau
  13 siblings, 0 replies; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

From: Lorenzo Bianconi <lorenzo@kernel.org>

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 <nbd@nbd.name>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 .../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  | 16 ++++
 .../wireless/mediatek/mt76/mt7615/mt7615.h    |  7 ++
 .../net/wireless/mediatek/mt76/mt7615/regs.h  |  3 +
 6 files changed, 130 insertions(+), 2 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 9707fa8b5485..942076b6d1ad 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;
@@ -360,9 +364,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 +390,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 070afba63e43..d537f68c5531 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)
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 15/15] mt76: enable airtime fairness
  2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
                   ` (12 preceding siblings ...)
  2019-09-26 17:47 ` [PATCH 14/15] mt76: mt7615: track tx/rx airtime for airtime fairness Felix Fietkau
@ 2019-09-26 17:47 ` Felix Fietkau
  2019-09-27  7:46   ` Toke Høiland-Jørgensen
  13 siblings, 1 reply; 26+ messages in thread
From: Felix Fietkau @ 2019-09-26 17:47 UTC (permalink / raw)
  To: linux-wireless

It is supported by all hardware drivers now

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 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 fd64172ca785..9a59a1b54c97 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;
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
  2019-09-26 17:47 ` [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey Felix Fietkau
@ 2019-09-27  7:45   ` Toke Høiland-Jørgensen
  2019-09-27  8:11     ` Felix Fietkau
  0 siblings, 1 reply; 26+ messages in thread
From: Toke Høiland-Jørgensen @ 2019-09-27  7:45 UTC (permalink / raw)
  To: Felix Fietkau, linux-wireless

Felix Fietkau <nbd@nbd.name> writes:

> Estimate by calculating duration for EWMA packet size + estimated A-MPDU
> length on tx status events

Would it make sense to move some of this code into mac80211? If we're
going to do airtime estimation for queue limiting it may make sense to
use this instead of the simplistic estimate I used in my RFC patch?

-Toke


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 15/15] mt76: enable airtime fairness
  2019-09-26 17:47 ` [PATCH 15/15] mt76: enable " Felix Fietkau
@ 2019-09-27  7:46   ` Toke Høiland-Jørgensen
  0 siblings, 0 replies; 26+ messages in thread
From: Toke Høiland-Jørgensen @ 2019-09-27  7:46 UTC (permalink / raw)
  To: Felix Fietkau, linux-wireless

Felix Fietkau <nbd@nbd.name> writes:

> It is supported by all hardware drivers now
>
> Signed-off-by: Felix Fietkau <nbd@nbd.name>

Very happy to see this! Emphatically:

Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
  2019-09-27  7:45   ` Toke Høiland-Jørgensen
@ 2019-09-27  8:11     ` Felix Fietkau
  2019-09-27  8:37       ` Toke Høiland-Jørgensen
  0 siblings, 1 reply; 26+ messages in thread
From: Felix Fietkau @ 2019-09-27  8:11 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, linux-wireless

On 2019-09-27 09:45, Toke Høiland-Jørgensen wrote:
> Felix Fietkau <nbd@nbd.name> writes:
> 
>> Estimate by calculating duration for EWMA packet size + estimated A-MPDU
>> length on tx status events
> 
> Would it make sense to move some of this code into mac80211? If we're
> going to do airtime estimation for queue limiting it may make sense to
> use this instead of the simplistic estimate I used in my RFC patch?
Sure. I mainly put it in the driver because I wanted to get it working,
tested and merged first without having to wait for a mac80211-next ->
wireless-drivers-next merge.

If we move it to mac80211, we can also make ath9k use it. My
implementation should be faster than the ath9k duration calculation.

- Felix

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 05/15] mt76: track rx airtime for airtime fairness and survey
  2019-09-26 17:47 ` [PATCH 05/15] mt76: track rx airtime for airtime fairness and survey Felix Fietkau
@ 2019-09-27  8:35   ` Toke Høiland-Jørgensen
  2019-09-27  8:46     ` Felix Fietkau
  0 siblings, 1 reply; 26+ messages in thread
From: Toke Høiland-Jørgensen @ 2019-09-27  8:35 UTC (permalink / raw)
  To: Felix Fietkau, linux-wireless

Felix Fietkau <nbd@nbd.name> writes:

> 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 <nbd@nbd.name>
> ---
>  drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
>  drivers/net/wireless/mediatek/mt76/airtime.c  | 278 ++++++++++++++++++
>  drivers/net/wireless/mediatek/mt76/mac80211.c | 109 ++++++-
>  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, 433 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 4d03596e891f..181af60e32db 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-usb-y := usb.o usb_trace.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 <nbd@nbd.name>
> + */
> +
> +#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;

On an earlier patch of mine you expressed concern over divisions in the
fast path. Does this mean this is no longer a concern? Or is the
compiler doing fancy things with the constant division here? :)

-Toke


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
  2019-09-27  8:11     ` Felix Fietkau
@ 2019-09-27  8:37       ` Toke Høiland-Jørgensen
  2019-09-27  8:47         ` Felix Fietkau
  0 siblings, 1 reply; 26+ messages in thread
From: Toke Høiland-Jørgensen @ 2019-09-27  8:37 UTC (permalink / raw)
  To: Felix Fietkau, linux-wireless

Felix Fietkau <nbd@nbd.name> writes:

> On 2019-09-27 09:45, Toke Høiland-Jørgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>> 
>>> Estimate by calculating duration for EWMA packet size + estimated A-MPDU
>>> length on tx status events
>> 
>> Would it make sense to move some of this code into mac80211? If we're
>> going to do airtime estimation for queue limiting it may make sense to
>> use this instead of the simplistic estimate I used in my RFC patch?
> Sure. I mainly put it in the driver because I wanted to get it working,
> tested and merged first without having to wait for a mac80211-next ->
> wireless-drivers-next merge.

Right, OK. So that means another patch set on top of this to move it
afterwards? Don't suppose you can be convinced to take care of that as
well? :)

> If we move it to mac80211, we can also make ath9k use it. My
> implementation should be faster than the ath9k duration calculation.

SGTM!

-Toke


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 05/15] mt76: track rx airtime for airtime fairness and survey
  2019-09-27  8:35   ` Toke Høiland-Jørgensen
@ 2019-09-27  8:46     ` Felix Fietkau
  2019-09-27  9:04       ` Toke Høiland-Jørgensen
  0 siblings, 1 reply; 26+ messages in thread
From: Felix Fietkau @ 2019-09-27  8:46 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, linux-wireless

On 2019-09-27 10:35, Toke Høiland-Jørgensen wrote:
> Felix Fietkau <nbd@nbd.name> writes:
>> +	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;
> 
> On an earlier patch of mine you expressed concern over divisions in the
> fast path. Does this mean this is no longer a concern? Or is the
> compiler doing fancy things with the constant division here? :)
I made the constants power-of-2, so that the compiler can turn them into
bit shifts. I verified the disassembly: no divisions left in the code.

- Felix

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
  2019-09-27  8:37       ` Toke Høiland-Jørgensen
@ 2019-09-27  8:47         ` Felix Fietkau
  2019-09-27  9:07           ` Toke Høiland-Jørgensen
  0 siblings, 1 reply; 26+ messages in thread
From: Felix Fietkau @ 2019-09-27  8:47 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, linux-wireless

On 2019-09-27 10:37, Toke Høiland-Jørgensen wrote:
> Felix Fietkau <nbd@nbd.name> writes:
> 
>> On 2019-09-27 09:45, Toke Høiland-Jørgensen wrote:
>>> Felix Fietkau <nbd@nbd.name> writes:
>>> 
>>>> Estimate by calculating duration for EWMA packet size + estimated A-MPDU
>>>> length on tx status events
>>> 
>>> Would it make sense to move some of this code into mac80211? If we're
>>> going to do airtime estimation for queue limiting it may make sense to
>>> use this instead of the simplistic estimate I used in my RFC patch?
>> Sure. I mainly put it in the driver because I wanted to get it working,
>> tested and merged first without having to wait for a mac80211-next ->
>> wireless-drivers-next merge.
> 
> Right, OK. So that means another patch set on top of this to move it
> afterwards? Don't suppose you can be convinced to take care of that as
> well? :)
I could, but I don't know when I will have time for it, since my plate
is pretty full at the moment.

- Felix

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 05/15] mt76: track rx airtime for airtime fairness and survey
  2019-09-27  8:46     ` Felix Fietkau
@ 2019-09-27  9:04       ` Toke Høiland-Jørgensen
  0 siblings, 0 replies; 26+ messages in thread
From: Toke Høiland-Jørgensen @ 2019-09-27  9:04 UTC (permalink / raw)
  To: Felix Fietkau, linux-wireless

Felix Fietkau <nbd@nbd.name> writes:

> On 2019-09-27 10:35, Toke Høiland-Jørgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>>> +	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;
>> 
>> On an earlier patch of mine you expressed concern over divisions in the
>> fast path. Does this mean this is no longer a concern? Or is the
>> compiler doing fancy things with the constant division here? :)
> I made the constants power-of-2, so that the compiler can turn them into
> bit shifts. I verified the disassembly: no divisions left in the code.

I see. Neat :)

There's still a regular division in the legacy rate calc further up,
though, right? But I guess that doesn't happen so often?

-Toke


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
  2019-09-27  8:47         ` Felix Fietkau
@ 2019-09-27  9:07           ` Toke Høiland-Jørgensen
  2019-09-27  9:17             ` Felix Fietkau
  0 siblings, 1 reply; 26+ messages in thread
From: Toke Høiland-Jørgensen @ 2019-09-27  9:07 UTC (permalink / raw)
  To: Felix Fietkau, linux-wireless

Felix Fietkau <nbd@nbd.name> writes:

> On 2019-09-27 10:37, Toke Høiland-Jørgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>> 
>>> On 2019-09-27 09:45, Toke Høiland-Jørgensen wrote:
>>>> Felix Fietkau <nbd@nbd.name> writes:
>>>> 
>>>>> Estimate by calculating duration for EWMA packet size + estimated A-MPDU
>>>>> length on tx status events
>>>> 
>>>> Would it make sense to move some of this code into mac80211? If we're
>>>> going to do airtime estimation for queue limiting it may make sense to
>>>> use this instead of the simplistic estimate I used in my RFC patch?
>>> Sure. I mainly put it in the driver because I wanted to get it working,
>>> tested and merged first without having to wait for a mac80211-next ->
>>> wireless-drivers-next merge.
>> 
>> Right, OK. So that means another patch set on top of this to move it
>> afterwards? Don't suppose you can be convinced to take care of that as
>> well? :)
> I could, but I don't know when I will have time for it, since my plate
> is pretty full at the moment.

Heh, I was afraid you'd say that. That makes two of us; guess we'll see
who gets around to it first, then :)

Is there anything in your new airtime.c that is mt76-specific apart from
the struct mt76_dev and struct mt76_rx_status parameters?

-Toke


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
  2019-09-27  9:07           ` Toke Høiland-Jørgensen
@ 2019-09-27  9:17             ` Felix Fietkau
  2019-09-28 10:31               ` Toke Høiland-Jørgensen
  0 siblings, 1 reply; 26+ messages in thread
From: Felix Fietkau @ 2019-09-27  9:17 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, linux-wireless

On 2019-09-27 11:07, Toke Høiland-Jørgensen wrote:
> Felix Fietkau <nbd@nbd.name> writes:
> 
>> On 2019-09-27 10:37, Toke Høiland-Jørgensen wrote:
>>> Felix Fietkau <nbd@nbd.name> writes:
>>> 
>>>> On 2019-09-27 09:45, Toke Høiland-Jørgensen wrote:
>>>>> Felix Fietkau <nbd@nbd.name> writes:
>>>>> 
>>>>>> Estimate by calculating duration for EWMA packet size + estimated A-MPDU
>>>>>> length on tx status events
>>>>> 
>>>>> Would it make sense to move some of this code into mac80211? If we're
>>>>> going to do airtime estimation for queue limiting it may make sense to
>>>>> use this instead of the simplistic estimate I used in my RFC patch?
>>>> Sure. I mainly put it in the driver because I wanted to get it working,
>>>> tested and merged first without having to wait for a mac80211-next ->
>>>> wireless-drivers-next merge.
>>> 
>>> Right, OK. So that means another patch set on top of this to move it
>>> afterwards? Don't suppose you can be convinced to take care of that as
>>> well? :)
>> I could, but I don't know when I will have time for it, since my plate
>> is pretty full at the moment.
> 
> Heh, I was afraid you'd say that. That makes two of us; guess we'll see
> who gets around to it first, then :)
> 
> Is there anything in your new airtime.c that is mt76-specific apart from
> the struct mt76_dev and struct mt76_rx_status parameters?
No, I made it as generic as possible to make it easy to move to
mac80211. mt76_rx_status mirrors ieee80211_rx_status very closely, and
going from mt76_dev to ieee80211_hw is easy as well.

- Felix

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
  2019-09-27  9:17             ` Felix Fietkau
@ 2019-09-28 10:31               ` Toke Høiland-Jørgensen
  0 siblings, 0 replies; 26+ messages in thread
From: Toke Høiland-Jørgensen @ 2019-09-28 10:31 UTC (permalink / raw)
  To: Felix Fietkau, linux-wireless

Felix Fietkau <nbd@nbd.name> writes:

> On 2019-09-27 11:07, Toke Høiland-Jørgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>> 
>>> On 2019-09-27 10:37, Toke Høiland-Jørgensen wrote:
>>>> Felix Fietkau <nbd@nbd.name> writes:
>>>> 
>>>>> On 2019-09-27 09:45, Toke Høiland-Jørgensen wrote:
>>>>>> Felix Fietkau <nbd@nbd.name> writes:
>>>>>> 
>>>>>>> Estimate by calculating duration for EWMA packet size + estimated A-MPDU
>>>>>>> length on tx status events
>>>>>> 
>>>>>> Would it make sense to move some of this code into mac80211? If we're
>>>>>> going to do airtime estimation for queue limiting it may make sense to
>>>>>> use this instead of the simplistic estimate I used in my RFC patch?
>>>>> Sure. I mainly put it in the driver because I wanted to get it working,
>>>>> tested and merged first without having to wait for a mac80211-next ->
>>>>> wireless-drivers-next merge.
>>>> 
>>>> Right, OK. So that means another patch set on top of this to move it
>>>> afterwards? Don't suppose you can be convinced to take care of that as
>>>> well? :)
>>> I could, but I don't know when I will have time for it, since my plate
>>> is pretty full at the moment.
>> 
>> Heh, I was afraid you'd say that. That makes two of us; guess we'll see
>> who gets around to it first, then :)
>> 
>> Is there anything in your new airtime.c that is mt76-specific apart from
>> the struct mt76_dev and struct mt76_rx_status parameters?
> No, I made it as generic as possible to make it easy to move to
> mac80211. mt76_rx_status mirrors ieee80211_rx_status very closely, and
> going from mt76_dev to ieee80211_hw is easy as well.

Awesome, thanks!

-Toke


^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2019-09-28 10:31 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-26 17:47 [PATCH 01/15] mt76: mt7603: remove q_rx field from struct mt7603_dev Felix Fietkau
2019-09-26 17:47 ` [PATCH 02/15] mt76: report rx a-mpdu subframe status Felix Fietkau
2019-09-26 17:47 ` [PATCH 03/15] mt76: rename mt76_driver_ops txwi_flags to drv_flags and include tx aligned4 Felix Fietkau
2019-09-26 17:47 ` [PATCH 04/15] mt76: store current channel survey_state in struct mt76_dev Felix Fietkau
2019-09-26 17:47 ` [PATCH 05/15] mt76: track rx airtime for airtime fairness and survey Felix Fietkau
2019-09-27  8:35   ` Toke Høiland-Jørgensen
2019-09-27  8:46     ` Felix Fietkau
2019-09-27  9:04       ` Toke Høiland-Jørgensen
2019-09-26 17:47 ` [PATCH 06/15] mt76: mt7603: track tx " Felix Fietkau
2019-09-26 17:47 ` [PATCH 07/15] mt76: mt7603: switch to a different counter for survey busy time Felix Fietkau
2019-09-26 17:47 ` [PATCH 08/15] mt76: unify channel survey update code Felix Fietkau
2019-09-26 17:47 ` [PATCH 09/15] mt76: mt76x02: move MT_CH_TIME_CFG init to mt76x02_mac_cc_reset Felix Fietkau
2019-09-26 17:47 ` [PATCH 10/15] mt76: mt76x02: track approximate tx airtime for airtime fairness and survey Felix Fietkau
2019-09-27  7:45   ` Toke Høiland-Jørgensen
2019-09-27  8:11     ` Felix Fietkau
2019-09-27  8:37       ` Toke Høiland-Jørgensen
2019-09-27  8:47         ` Felix Fietkau
2019-09-27  9:07           ` Toke Høiland-Jørgensen
2019-09-27  9:17             ` Felix Fietkau
2019-09-28 10:31               ` Toke Høiland-Jørgensen
2019-09-26 17:47 ` [PATCH 11/15] mt76: mt7615: report tx_time, bss_rx and busy time to mac80211 Felix Fietkau
2019-09-26 17:47 ` [PATCH 12/15] mt76: mt7615: fix survey channel busy time Felix Fietkau
2019-09-26 17:47 ` [PATCH 13/15] mt76: mt7615: introduce mt7615_mac_wtbl_update routine Felix Fietkau
2019-09-26 17:47 ` [PATCH 14/15] mt76: mt7615: track tx/rx airtime for airtime fairness Felix Fietkau
2019-09-26 17:47 ` [PATCH 15/15] mt76: enable " Felix Fietkau
2019-09-27  7:46   ` Toke Høiland-Jørgensen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).