Skip to contentSkip to conversation

mt76: introduce connac3_mac support

PATCH Superseded Lorenzo Bianconi 6 participants 27 messages Jun 9, 2023 – Jun 12, 2023 2 messages not in the archive

Subsystems (2)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

Lorenzo Bianconi

author maintainer
#0 lore raw

v2 cover mt76: introduce connac3_mac support

Introduce connac3_mac in mt76_connac library to reuse mac code shared between WiFi7 chipsets.
Move the following common mac fields in mt76_struct/mt76_wcid:
- sta_poll_list
- sta_poll_lock
- poll_list
- ampdu_state

Move the following routines in mt76-connac lib since they are shared between mt7915 and mt7921:
- mt76_connac2_tx_check_aggr
- mt76_connac2_txwi_free
- mt76_connac2_tx_token_put

Changes since v1:
- rebase on top wireless-next tree
- fix connac3_mac library
- fix compilation warnings

Lorenzo Bianconi (15):
wifi: mt76: mt7915: move sta_poll_list and sta_poll_lock in mt76_dev
wifi: mt76: mt7603: rely on shared sta_poll_list and sta_poll_lock
wifi: mt76: mt7615: rely on shared sta_poll_list and sta_poll_lock
wifi: mt76: mt7996: rely on shared sta_poll_list and sta_poll_lock
wifi: mt76: mt7921: rely on shared sta_poll_list and sta_poll_lock
wifi: mt76: mt7915: move poll_list in mt76_wcid
wifi: mt76: mt7603: rely on shared poll_list field
wifi: mt76: mt7615: rely on shared poll_list field
wifi: mt76: mt7996: rely on shared poll_list field
wifi: mt76: mt7921: rely on shared poll_list field
wifi: mt76: move ampdu_state in mt76_wcid
mt76: connac: move more mt7921/mt7915 mac shared code in connac lib
wifi: mt76: move rate info in mt76_vif
wifi: mt76: connac: move connac3 definitions in mt76_connac3_mac.h
wifi: mt76: connac: add connac3 mac library

 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 drivers/net/wireless/mediatek/mt76/mac80211.c |   2 +
 drivers/net/wireless/mediatek/mt76/mt76.h     |   9 +
 .../net/wireless/mediatek/mt76/mt7603/init.c  |   2 -
 .../net/wireless/mediatek/mt76/mt7603/mac.c   |  22 +-
 .../net/wireless/mediatek/mt76/mt7603/main.c  |  20 +-
 .../wireless/mediatek/mt76/mt7603/mt7603.h    |   4 -
 .../net/wireless/mediatek/mt76/mt7615/init.c  |   2 -
 .../net/wireless/mediatek/mt76/mt7615/mac.c   |  31 +-
 .../net/wireless/mediatek/mt76/mt7615/main.c  |  20 +-
 .../wireless/mediatek/mt76/mt7615/mt7615.h    |   4 -
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  24 +
 .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742 ++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h | 343 ++++++++
 .../wireless/mediatek/mt76/mt76_connac_mac.c  |  82 ++
 .../net/wireless/mediatek/mt76/mt7915/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 140 +--
 .../net/wireless/mediatek/mt76/mt7915/main.c  |  30 +-
 .../wireless/mediatek/mt76/mt7915/mt7915.h    |   5 -
 .../net/wireless/mediatek/mt76/mt7921/init.c  |   2 -
 .../net/wireless/mediatek/mt76/mt7921/mac.c   | 104 +--
 .../net/wireless/mediatek/mt76/mt7921/main.c  |  26 +-
 .../wireless/mediatek/mt76/mt7921/mt7921.h    |   9 -
 .../net/wireless/mediatek/mt76/mt7921/pci.c   |   2 +-
 .../wireless/mediatek/mt76/mt7921/pci_mac.c   |  16 +-
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   6 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 803 +-----------------
 .../net/wireless/mediatek/mt76/mt7996/mac.h   | 315 +------
 .../net/wireless/mediatek/mt76/mt7996/main.c  |  42 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |  11 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  36 +-
 31 files changed, 1403 insertions(+), 1457 deletions(-)
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
Signature · 1 line
2.40.1
author maintainer
#1 lore raw

PATCH v2 1/15 wifi: mt76: mt7915: move sta_poll_list and sta_poll_lock in mt76_dev

sta_poll_list and sta_poll_lock are used by most of the drivers, so move them in mt76_dev structure.

---
 drivers/net/wireless/mediatek/mt76/mac80211.c |  2 +
 drivers/net/wireless/mediatek/mt76/mt76.h     |  3 ++
 .../net/wireless/mediatek/mt76/mt7915/init.c  |  2 -
 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 47 ++++++++++---------
 .../net/wireless/mediatek/mt76/mt7915/main.c  | 12 ++---
 .../wireless/mediatek/mt76/mt7915/mt7915.h    |  2 -
 6 files changed, 36 insertions(+), 32 deletions(-)
drivers/net/wireless/mediatek/mt76/mac80211.c +2 -0
index 467afef98ba2..952f4cbd3ce8 100644
@@ -660,6 +660,8 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
 	idr_init(&dev->rx_token);
 
 	INIT_LIST_HEAD(&dev->wcid_list);
+	INIT_LIST_HEAD(&dev->sta_poll_list);
+	spin_lock_init(&dev->sta_poll_lock);
 
 	INIT_LIST_HEAD(&dev->txwi_cache);
 	INIT_LIST_HEAD(&dev->rxwi_cache);
drivers/net/wireless/mediatek/mt76/mt76.h +3 -0
index 6b07b8fafec2..5eae2e666ff6 100644
@@ -823,6 +823,9 @@ struct mt76_dev {
 	struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
 	struct list_head wcid_list;
 
+	struct list_head sta_poll_list;
+	spinlock_t sta_poll_lock;
+
 	u32 rev;
 
 	struct tasklet_struct pre_tbtt_tasklet;
drivers/net/wireless/mediatek/mt76/mt7915/init.c +0 -2
index ac2049f49bb3..90c883c7fe05 100644
@@ -1177,9 +1177,7 @@ int mt7915_register_device(struct mt7915_dev *dev)
 	INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
 	INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
 	INIT_LIST_HEAD(&dev->sta_rc_list);
-	INIT_LIST_HEAD(&dev->sta_poll_list);
 	INIT_LIST_HEAD(&dev->twt_list);
-	spin_lock_init(&dev->sta_poll_lock);
 
 	init_waitqueue_head(&dev->reset_wait);
 	INIT_WORK(&dev->reset_work, mt7915_mac_reset_work);
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +25 -22

113 lines not on this page · raw message

drivers/net/wireless/mediatek/mt76/mt7915/main.c +6 -6
index 2ada2806de66..805b4522a813 100644
@@ -308,10 +308,10 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
 	phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
 	mutex_unlock(&dev->mt76.mutex);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
 }
@@ -715,12 +715,12 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
 		mt7915_mac_twt_teardown_flow(dev, msta, i);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&mdev->sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
 	if (!list_empty(&msta->rc_list))
 		list_del_init(&msta->rc_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&mdev->sta_poll_lock);
 }
 
 static void mt7915_tx(struct ieee80211_hw *hw,
@@ -1074,11 +1074,11 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
 	struct mt7915_dev *dev = msta->vif->phy->dev;
 	u32 *changed = data;
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	msta->changed |= *changed;
 	if (list_empty(&msta->rc_list))
 		list_add_tail(&msta->rc_list, &dev->sta_rc_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 }
 
 static void mt7915_sta_rc_update(struct ieee80211_hw *hw,
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +0 -2
index b3ead3530740..f8ff190e9c4e 100644
@@ -328,9 +328,7 @@ struct mt7915_dev {
 #endif
 
 	struct list_head sta_rc_list;
-	struct list_head sta_poll_list;
 	struct list_head twt_list;
-	spinlock_t sta_poll_lock;
 
 	u32 hw_pattern;
 
Signature · 1 line
2.40.1
author maintainer
#2 lore raw

PATCH v2 2/15 wifi: mt76: mt7603: rely on shared sta_poll_list and sta_poll_lock

In reply to Lorenzo Bianconi

Rely on sta_poll_list and sta_poll_lock fields in mt76_dev structure and get rid of private copies.

---
 .../net/wireless/mediatek/mt76/mt7603/init.c   |  2 --
 .../net/wireless/mediatek/mt76/mt7603/mac.c    | 18 +++++++++---------
 .../net/wireless/mediatek/mt76/mt7603/main.c   |  8 ++++----
 .../net/wireless/mediatek/mt76/mt7603/mt7603.h |  3 ---
 4 files changed, 13 insertions(+), 18 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7603/init.c +0 -2
index 9a2e632d577a..0762de3ce5ac 100644
@@ -500,8 +500,6 @@ 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->mphy.mac_work, mt7603_mac_work);
drivers/net/wireless/mediatek/mt76/mt7603/mac.c +9 -9
index 12e0af52082a..ac8a67e10a4d 100644
@@ -412,16 +412,16 @@ void mt7603_mac_sta_poll(struct mt7603_dev *dev)
 	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);
+		spin_lock_bh(&dev->mt76.sta_poll_lock);
+		if (list_empty(&dev->mt76.sta_poll_list)) {
+			spin_unlock_bh(&dev->mt76.sta_poll_lock);
 			break;
 		}
 
-		msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta,
-					poll_list);
+		msta = list_first_entry(&dev->mt76.sta_poll_list,
+					struct mt7603_sta, poll_list);
 		list_del_init(&msta->poll_list);
-		spin_unlock_bh(&dev->sta_poll_lock);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		addr = mt7603_wtbl4_addr(msta->wcid.idx);
 		for (i = 0; i < 4; i++) {
@@ -1268,9 +1268,9 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
 	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);
+		spin_lock_bh(&dev->mt76.sta_poll_lock);
+		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
 
 	if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data))
drivers/net/wireless/mediatek/mt76/mt7603/main.c +4 -4
index ca50feb0b3a9..2affa62caf2b 100644
@@ -100,10 +100,10 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
 	rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mutex_lock(&dev->mt76.mutex);
 	dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx);
@@ -388,10 +388,10 @@ 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);
+	spin_lock_bh(&mdev->sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&mdev->sta_poll_lock);
 
 	mt7603_wtbl_clear(dev, wcid->idx);
 }
drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +0 -3
index 7c3be596da09..689922d133e7 100644
@@ -110,9 +110,6 @@ struct mt7603_dev {
 
 	u32 rxfilter;
 
-	struct list_head sta_poll_list;
-	spinlock_t sta_poll_lock;
-
 	struct mt7603_sta global_sta;
 
 	u32 agc0, agc3;
Signature · 1 line
2.40.1
author maintainer
#3 lore raw

PATCH v2 3/15 wifi: mt76: mt7615: rely on shared sta_poll_list and sta_poll_lock

In reply to Lorenzo Bianconi

Rely on sta_poll_list and sta_poll_lock fields in mt76_dev structure and get rid of private copies.

---
 .../net/wireless/mediatek/mt76/mt7615/init.c  |  2 --
 .../net/wireless/mediatek/mt76/mt7615/mac.c   | 23 ++++++++++---------
 .../net/wireless/mediatek/mt76/mt7615/main.c  |  8 +++----
 .../wireless/mediatek/mt76/mt7615/mt7615.h    |  3 ---
 4 files changed, 16 insertions(+), 20 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7615/init.c +0 -2
index 621e69f07e3c..155931978ed8 100644
@@ -626,8 +626,6 @@ void mt7615_init_device(struct mt7615_dev *dev)
 	INIT_DELAYED_WORK(&dev->coredump.work, mt7615_coredump_work);
 	skb_queue_head_init(&dev->phy.scan_event_list);
 	skb_queue_head_init(&dev->coredump.msg_list);
-	INIT_LIST_HEAD(&dev->sta_poll_list);
-	spin_lock_init(&dev->sta_poll_lock);
 	init_waitqueue_head(&dev->reset_wait);
 	init_waitqueue_head(&dev->phy.roc_wait);
 
drivers/net/wireless/mediatek/mt76/mt7615/mac.c +12 -11
index 415b5ff3ee4f..0fc6d7765f83 100644
@@ -387,10 +387,11 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
 		struct mt7615_sta *msta;
 
 		msta = container_of(status->wcid, struct mt7615_sta, wcid);
-		spin_lock_bh(&dev->sta_poll_lock);
+		spin_lock_bh(&dev->mt76.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);
+			list_add_tail(&msta->poll_list,
+				      &dev->mt76.sta_poll_list);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
 
 	if (mt76_is_mmio(&dev->mt76) && (rxd0 & csum_mask) == csum_mask &&
@@ -905,9 +906,9 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev)
 	int i;
 
 	INIT_LIST_HEAD(&sta_poll_list);
-	spin_lock_bh(&dev->sta_poll_lock);
-	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
+	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	while (!list_empty(&sta_poll_list)) {
 		bool clear = false;
@@ -915,9 +916,9 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev)
 		msta = list_first_entry(&sta_poll_list, struct mt7615_sta,
 					poll_list);
 
-		spin_lock_bh(&dev->sta_poll_lock);
+		spin_lock_bh(&dev->mt76.sta_poll_lock);
 		list_del_init(&msta->poll_list);
-		spin_unlock_bh(&dev->sta_poll_lock);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4;
 
@@ -1542,10 +1543,10 @@ static 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);
+	spin_lock_bh(&dev->mt76.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);
+		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
 		goto out;
drivers/net/wireless/mediatek/mt76/mt7615/main.c +4 -4
index ab4c1b4478aa..2a5462bd54c2 100644
@@ -274,10 +274,10 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
 
 	mt7615_mutex_release(dev);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid);
 }
@@ -677,10 +677,10 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
 		mt7615_mcu_add_bss_info(phy, vif, sta, false);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&mdev->sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&mdev->sta_poll_lock);
 
 	mt76_connac_power_save_sched(phy->mt76, &dev->pm);
 }
drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +0 -3
index 0381c53bc96a..7386495f8299 100644
@@ -262,9 +262,6 @@ struct mt7615_dev {
 	wait_queue_head_t reset_wait;
 	u32 reset_state;
 
-	struct list_head sta_poll_list;
-	spinlock_t sta_poll_lock;
-
 	struct {
 		u8 n_pulses;
 		u32 period;
Signature · 1 line
2.40.1
author maintainer
#4 lore raw

PATCH v2 4/15 wifi: mt76: mt7996: rely on shared sta_poll_list and sta_poll_lock

In reply to Lorenzo Bianconi

Rely on sta_poll_list and sta_poll_lock fields in mt76_dev structure and get rid of private copies.

---
 .../net/wireless/mediatek/mt76/mt7996/init.c  |  2 -
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 40 ++++++++++---------
 .../net/wireless/mediatek/mt76/mt7996/main.c  | 12 +++---
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  2 -
 4 files changed, 27 insertions(+), 29 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7996/init.c +0 -2
index f1b48cdda58f..8f3536dbe2bb 100644
@@ -853,9 +853,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
 	INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
 	INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
 	INIT_LIST_HEAD(&dev->sta_rc_list);
-	INIT_LIST_HEAD(&dev->sta_poll_list);
 	INIT_LIST_HEAD(&dev->twt_list);
-	spin_lock_init(&dev->sta_poll_lock);
 
 	init_waitqueue_head(&dev->reset_wait);
 	INIT_WORK(&dev->reset_work, mt7996_mac_reset_work);
drivers/net/wireless/mediatek/mt76/mt7996/mac.c +21 -19
index 740d08e9d5e5..18249572cb2e 100644
@@ -111,9 +111,9 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
 	LIST_HEAD(sta_poll_list);
 	int i;
 
-	spin_lock_bh(&dev->sta_poll_lock);
-	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
+	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	rcu_read_lock();
 
@@ -124,15 +124,15 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
 		s8 rssi[4];
 		u8 bw;
 
-		spin_lock_bh(&dev->sta_poll_lock);
+		spin_lock_bh(&dev->mt76.sta_poll_lock);
 		if (list_empty(&sta_poll_list)) {
-			spin_unlock_bh(&dev->sta_poll_lock);
+			spin_unlock_bh(&dev->mt76.sta_poll_lock);
 			break;
 		}
 		msta = list_first_entry(&sta_poll_list,
 					struct mt7996_sta, poll_list);
 		list_del_init(&msta->poll_list);
-		spin_unlock_bh(&dev->sta_poll_lock);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		idx = msta->wcid.idx;
 
@@ -681,10 +681,11 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
 		struct mt7996_sta *msta;
 
 		msta = container_of(status->wcid, struct mt7996_sta, wcid);
-		spin_lock_bh(&dev->sta_poll_lock);
+		spin_lock_bh(&dev->mt76.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);
+			list_add_tail(&msta->poll_list,
+				      &dev->mt76.sta_poll_list);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
 
 	status->freq = mphy->chandef.chan->center_freq;
@@ -1286,10 +1287,11 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
 				continue;
 
 			msta = container_of(wcid, struct mt7996_sta, wcid);
-			spin_lock_bh(&dev->sta_poll_lock);
+			spin_lock_bh(&mdev->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);
+				list_add_tail(&msta->poll_list,
+					      &mdev->sta_poll_list);
+			spin_unlock_bh(&mdev->sta_poll_lock);
 			continue;
 		}
 
@@ -1494,10 +1496,10 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
 	if (!wcid->sta)
 		goto out;
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.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);
+		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 out:
 	rcu_read_unlock();
@@ -2340,7 +2342,7 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
 	u32 changed;
 	LIST_HEAD(list);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	list_splice_init(&dev->sta_rc_list, &list);
 
 	while (!list_empty(&list)) {
@@ -2348,7 +2350,7 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
 		list_del_init(&msta->rc_list);
 		changed = msta->changed;
 		msta->changed = 0;
-		spin_unlock_bh(&dev->sta_poll_lock);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
 		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
@@ -2360,10 +2362,10 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
 
 		/* TODO: smps change */
 
-		spin_lock_bh(&dev->sta_poll_lock);
+		spin_lock_bh(&dev->mt76.sta_poll_lock);
 	}
 
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 }
 
 void mt7996_mac_work(struct work_struct *work)
drivers/net/wireless/mediatek/mt76/mt7996/main.c +6 -6
index c7917e301c87..ecac04066fda 100644
@@ -262,10 +262,10 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
 	phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
 	mutex_unlock(&dev->mt76.mutex);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
 }
@@ -667,12 +667,12 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
 		mt7996_mac_twt_teardown_flow(dev, msta, i);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&mdev->sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
 	if (!list_empty(&msta->rc_list))
 		list_del_init(&msta->rc_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&mdev->sta_poll_lock);
 }
 
 static void mt7996_tx(struct ieee80211_hw *hw,
@@ -982,11 +982,11 @@ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta)
 	struct mt7996_dev *dev = msta->vif->phy->dev;
 	u32 *changed = data;
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	msta->changed |= *changed;
 	if (list_empty(&msta->rc_list))
 		list_add_tail(&msta->rc_list, &dev->sta_rc_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 }
 
 static void mt7996_sta_rc_update(struct ieee80211_hw *hw,
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +0 -2
index c9f0e541abe4..9be7a5f80f4d 100644
@@ -270,9 +270,7 @@ struct mt7996_dev {
 #endif
 
 	struct list_head sta_rc_list;
-	struct list_head sta_poll_list;
 	struct list_head twt_list;
-	spinlock_t sta_poll_lock;
 
 	u32 hw_pattern;
 
Signature · 1 line
2.40.1
author maintainer
#5 lore raw

PATCH v2 5/15 wifi: mt76: mt7921: rely on shared sta_poll_list and sta_poll_lock

In reply to Lorenzo Bianconi

Rely on sta_poll_list and sta_poll_lock fields in mt76_dev structure and get rid of private copies.

---
 .../net/wireless/mediatek/mt76/mt7921/init.c  |  2 --
 .../net/wireless/mediatek/mt76/mt7921/mac.c   | 32 ++++++++++---------
 .../net/wireless/mediatek/mt76/mt7921/main.c  |  8 ++---
 .../wireless/mediatek/mt76/mt7921/mt7921.h    |  3 --
 4 files changed, 21 insertions(+), 24 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/init.c +0 -2
index e929f6eb65ce..cdb4478f04d0 100644
@@ -392,8 +392,6 @@ int mt7921_register_device(struct mt7921_dev *dev)
 #endif
 	skb_queue_head_init(&dev->phy.scan_event_list);
 	skb_queue_head_init(&dev->coredump.msg_list);
-	INIT_LIST_HEAD(&dev->sta_poll_list);
-	spin_lock_init(&dev->sta_poll_lock);
 
 	INIT_WORK(&dev->reset_work, mt7921_mac_reset_work);
 	INIT_WORK(&dev->init_work, mt7921_init_work);
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +17 -15
index bde73859b5da..d81d78ac5c91 100644
@@ -68,9 +68,9 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
 	s8 rssi[4];
 	int i;
 
-	spin_lock_bh(&dev->sta_poll_lock);
-	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
+	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	while (true) {
 		bool clear = false;
@@ -78,15 +78,15 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
 		u16 idx;
 		u8 bw;
 
-		spin_lock_bh(&dev->sta_poll_lock);
+		spin_lock_bh(&dev->mt76.sta_poll_lock);
 		if (list_empty(&sta_poll_list)) {
-			spin_unlock_bh(&dev->sta_poll_lock);
+			spin_unlock_bh(&dev->mt76.sta_poll_lock);
 			break;
 		}
 		msta = list_first_entry(&sta_poll_list,
 					struct mt7921_sta, poll_list);
 		list_del_init(&msta->poll_list);
-		spin_unlock_bh(&dev->sta_poll_lock);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		idx = msta->wcid.idx;
 		addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_AC0_CTT_OFFSET);
@@ -280,10 +280,11 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
 
 	if (status->wcid) {
 		msta = container_of(status->wcid, struct mt7921_sta, wcid);
-		spin_lock_bh(&dev->sta_poll_lock);
+		spin_lock_bh(&dev->mt76.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);
+			list_add_tail(&msta->poll_list,
+				      &dev->mt76.sta_poll_list);
+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
 
 	mt7921_get_status_freq_info(dev, mphy, status, chfreq);
@@ -566,10 +567,10 @@ void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data)
 	if (!wcid->sta)
 		goto out;
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.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);
+		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 out:
 	rcu_read_unlock();
@@ -647,10 +648,11 @@ static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
 				continue;
 
 			msta = container_of(wcid, struct mt7921_sta, wcid);
-			spin_lock_bh(&dev->sta_poll_lock);
+			spin_lock_bh(&mdev->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);
+				list_add_tail(&msta->poll_list,
+					      &mdev->sta_poll_list);
+			spin_unlock_bh(&mdev->sta_poll_lock);
 			continue;
 		}
 
drivers/net/wireless/mediatek/mt76/mt7921/main.c +4 -4
index 0c9a472bc81a..ffbe48f33d49 100644
@@ -357,10 +357,10 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw,
 	phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
 	mt7921_mutex_release(dev);
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
 }
@@ -843,10 +843,10 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 						    mvif->ctx);
 	}
 
-	spin_lock_bh(&dev->sta_poll_lock);
+	spin_lock_bh(&dev->mt76.sta_poll_lock);
 	if (!list_empty(&msta->poll_list))
 		list_del_init(&msta->poll_list);
-	spin_unlock_bh(&dev->sta_poll_lock);
+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
 }
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +0 -3
index 9640cc033300..ef1fe4d9ab99 100644
@@ -303,9 +303,6 @@ struct mt7921_dev {
 	bool hw_init_done:1;
 	bool fw_assert:1;
 
-	struct list_head sta_poll_list;
-	spinlock_t sta_poll_lock;
-
 	struct work_struct init_work;
 
 	u8 fw_debug;
Signature · 1 line
2.40.1
author maintainer
#6 lore raw

PATCH v2 6/15 wifi: mt76: mt7915: move poll_list in mt76_wcid

In reply to Lorenzo Bianconi

poll_list field is used by most of the drivers, so move it in mt76_wcid structure.

---
 drivers/net/wireless/mediatek/mt76/mt76.h     |  2 ++
 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 20 +++++++++----------
 .../net/wireless/mediatek/mt76/mt7915/main.c  | 12 +++++------
 .../wireless/mediatek/mt76/mt7915/mt7915.h    |  1 -
 4 files changed, 18 insertions(+), 17 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76.h +2 -0
index 5eae2e666ff6..997bd722b045 100644
@@ -336,6 +336,8 @@ struct mt76_wcid {
 	struct idr pktid;
 
 	struct mt76_sta_stats stats;
+
+	struct list_head poll_list;
 };
 
 struct mt76_txq {
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +10 -10
index f29ab70d3ce2..b499ab7d95f8 100644
@@ -124,8 +124,8 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
 			break;
 		}
 		msta = list_first_entry(&sta_poll_list,
-					struct mt7915_sta, poll_list);
-		list_del_init(&msta->poll_list);
+					struct mt7915_sta, wcid.poll_list);
+		list_del_init(&msta->wcid.poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		idx = msta->wcid.idx;
@@ -327,8 +327,8 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
 	if (status->wcid) {
 		msta = container_of(status->wcid, struct mt7915_sta, wcid);
 		spin_lock_bh(&dev->mt76.sta_poll_lock);
-		if (list_empty(&msta->poll_list))
-			list_add_tail(&msta->poll_list,
+		if (list_empty(&msta->wcid.poll_list))
+			list_add_tail(&msta->wcid.poll_list,
 				      &dev->mt76.sta_poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
@@ -894,8 +894,8 @@ mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
 			sta = container_of((void *)msta, struct ieee80211_sta,
 					  drv_priv);
 			spin_lock_bh(&mdev->sta_poll_lock);
-			if (list_empty(&msta->poll_list))
-				list_add_tail(&msta->poll_list,
+			if (list_empty(&msta->wcid.poll_list))
+				list_add_tail(&msta->wcid.poll_list,
 					      &mdev->sta_poll_list);
 			spin_unlock_bh(&mdev->sta_poll_lock);
 		}
@@ -990,8 +990,8 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
 
 			msta = container_of(wcid, struct mt7915_sta, wcid);
 			spin_lock_bh(&mdev->sta_poll_lock);
-			if (list_empty(&msta->poll_list))
-				list_add_tail(&msta->poll_list,
+			if (list_empty(&msta->wcid.poll_list))
+				list_add_tail(&msta->wcid.poll_list,
 					      &mdev->sta_poll_list);
 			spin_unlock_bh(&mdev->sta_poll_lock);
 			continue;
@@ -1085,8 +1085,8 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
 		goto out;
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (list_empty(&msta->poll_list))
-		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+	if (list_empty(&msta->wcid.poll_list))
+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 out:
drivers/net/wireless/mediatek/mt76/mt7915/main.c +6 -6
index 805b4522a813..cf1ed8632925 100644
@@ -248,7 +248,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
 	idx = MT7915_WTBL_RESERVED - mvif->mt76.idx;
 
 	INIT_LIST_HEAD(&mvif->sta.rc_list);
-	INIT_LIST_HEAD(&mvif->sta.poll_list);
+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
 	mvif->sta.wcid.idx = idx;
 	mvif->sta.wcid.phy_idx = ext_phy;
 	mvif->sta.wcid.hw_key_idx = -1;
@@ -309,8 +309,8 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
 	mutex_unlock(&dev->mt76.mutex);
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
@@ -680,7 +680,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 		return -ENOSPC;
 
 	INIT_LIST_HEAD(&msta->rc_list);
-	INIT_LIST_HEAD(&msta->poll_list);
+	INIT_LIST_HEAD(&msta->wcid.poll_list);
 	msta->vif = mvif;
 	msta->wcid.sta = 1;
 	msta->wcid.idx = idx;
@@ -716,8 +716,8 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 		mt7915_mac_twt_teardown_flow(dev, msta, i);
 
 	spin_lock_bh(&mdev->sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	if (!list_empty(&msta->rc_list))
 		list_del_init(&msta->rc_list);
 	spin_unlock_bh(&mdev->sta_poll_lock);
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +0 -1
index f8ff190e9c4e..0ebd44fa5f5f 100644
@@ -129,7 +129,6 @@ struct mt7915_sta {
 
 	struct mt7915_vif *vif;
 
-	struct list_head poll_list;
 	struct list_head rc_list;
 	u32 airtime_ac[8];
 
Signature · 1 line
2.40.1
author maintainer
#7 lore raw

PATCH v2 7/15 wifi: mt76: mt7603: rely on shared poll_list field

In reply to Lorenzo Bianconi

Rely on poll_list field in mt76_wcid structure and get rid of private copy.

---
 drivers/net/wireless/mediatek/mt76/mt7603/mac.c    |  8 ++++----
 drivers/net/wireless/mediatek/mt76/mt7603/main.c   | 12 ++++++------
 drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h |  1 -
 3 files changed, 10 insertions(+), 11 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7603/mac.c +4 -4
index ac8a67e10a4d..de11557eb04c 100644
@@ -419,8 +419,8 @@ void mt7603_mac_sta_poll(struct mt7603_dev *dev)
 		}
 
 		msta = list_first_entry(&dev->mt76.sta_poll_list,
-					struct mt7603_sta, poll_list);
-		list_del_init(&msta->poll_list);
+					struct mt7603_sta, wcid.poll_list);
+		list_del_init(&msta->wcid.poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		addr = mt7603_wtbl4_addr(msta->wcid.idx);
@@ -1267,9 +1267,9 @@ 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)) {
+	if (list_empty(&msta->wcid.poll_list)) {
 		spin_lock_bh(&dev->mt76.sta_poll_lock);
-		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
 
drivers/net/wireless/mediatek/mt76/mt7603/main.c +6 -6
index 2affa62caf2b..36f287bbddd1 100644
@@ -66,7 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
 	idx = MT7603_WTBL_RESERVED - 1 - mvif->idx;
 	dev->mt76.vif_mask |= BIT_ULL(mvif->idx);
-	INIT_LIST_HEAD(&mvif->sta.poll_list);
+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
 	mvif->sta.wcid.idx = idx;
 	mvif->sta.wcid.hw_key_idx = -1;
 	mt76_packet_id_init(&mvif->sta.wcid);
@@ -101,8 +101,8 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 	rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mutex_lock(&dev->mt76.mutex);
@@ -351,7 +351,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	if (idx < 0)
 		return -ENOSPC;
 
-	INIT_LIST_HEAD(&msta->poll_list);
+	INIT_LIST_HEAD(&msta->wcid.poll_list);
 	__skb_queue_head_init(&msta->psq);
 	msta->ps = ~0;
 	msta->smps = ~0;
@@ -389,8 +389,8 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	spin_unlock_bh(&dev->ps_lock);
 
 	spin_lock_bh(&mdev->sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	spin_unlock_bh(&mdev->sta_poll_lock);
 
 	mt7603_wtbl_clear(dev, wcid->idx);
drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +0 -1
index 689922d133e7..354b189862f7 100644
@@ -64,7 +64,6 @@ struct mt7603_sta {
 
 	struct mt7603_vif *vif;
 
-	struct list_head poll_list;
 	u32 tx_airtime_ac[4];
 
 	struct sk_buff_head psq;
Signature · 1 line
2.40.1
author maintainer
#8 lore raw

PATCH v2 8/15 wifi: mt76: mt7615: rely on shared poll_list field

In reply to Lorenzo Bianconi

Rely on poll_list field in mt76_wcid structure and get rid of private copy.

---
 drivers/net/wireless/mediatek/mt76/mt7615/mac.c    | 12 ++++++------
 drivers/net/wireless/mediatek/mt76/mt7615/main.c   | 12 ++++++------
 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h |  1 -
 3 files changed, 12 insertions(+), 13 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7615/mac.c +6 -6
index 0fc6d7765f83..f46b884d2905 100644
@@ -388,8 +388,8 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
 
 		msta = container_of(status->wcid, struct mt7615_sta, wcid);
 		spin_lock_bh(&dev->mt76.sta_poll_lock);
-		if (list_empty(&msta->poll_list))
-			list_add_tail(&msta->poll_list,
+		if (list_empty(&msta->wcid.poll_list))
+			list_add_tail(&msta->wcid.poll_list,
 				      &dev->mt76.sta_poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
@@ -914,10 +914,10 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev)
 		bool clear = false;
 
 		msta = list_first_entry(&sta_poll_list, struct mt7615_sta,
-					poll_list);
+					wcid.poll_list);
 
 		spin_lock_bh(&dev->mt76.sta_poll_lock);
-		list_del_init(&msta->poll_list);
+		list_del_init(&msta->wcid.poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4;
@@ -1544,8 +1544,8 @@ static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
 	sta = wcid_to_sta(wcid);
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (list_empty(&msta->poll_list))
-		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+	if (list_empty(&msta->wcid.poll_list))
+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
drivers/net/wireless/mediatek/mt76/mt7615/main.c +6 -6
index 2a5462bd54c2..5c342d85b8d8 100644
@@ -222,7 +222,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
 
 	idx = MT7615_WTBL_RESERVED - mvif->mt76.idx;
 
-	INIT_LIST_HEAD(&mvif->sta.poll_list);
+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
 	mvif->sta.wcid.idx = idx;
 	mvif->sta.wcid.phy_idx = mvif->mt76.band_idx;
 	mvif->sta.wcid.hw_key_idx = -1;
@@ -275,8 +275,8 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
 	mt7615_mutex_release(dev);
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid);
@@ -629,7 +629,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	if (idx < 0)
 		return -ENOSPC;
 
-	INIT_LIST_HEAD(&msta->poll_list);
+	INIT_LIST_HEAD(&msta->wcid.poll_list);
 	msta->vif = mvif;
 	msta->wcid.sta = 1;
 	msta->wcid.idx = idx;
@@ -678,8 +678,8 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 		mt7615_mcu_add_bss_info(phy, vif, sta, false);
 
 	spin_lock_bh(&mdev->sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	spin_unlock_bh(&mdev->sta_poll_lock);
 
 	mt76_connac_power_save_sched(phy->mt76, &dev->pm);
drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +0 -1
index 7386495f8299..6a7c14dbf72e 100644
@@ -125,7 +125,6 @@ struct mt7615_sta {
 
 	struct mt7615_vif *vif;
 
-	struct list_head poll_list;
 	u32 airtime_ac[8];
 
 	struct ieee80211_tx_rate rates[4];
Signature · 1 line
2.40.1
author maintainer
#9 lore raw

PATCH v2 9/15 wifi: mt76: mt7996: rely on shared poll_list field

In reply to Lorenzo Bianconi

Rely on poll_list field in mt76_wcid structure and get rid of private copy.

---
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c  | 16 ++++++++--------
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 12 ++++++------
 .../net/wireless/mediatek/mt76/mt7996/mt7996.h   |  1 -
 3 files changed, 14 insertions(+), 15 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7996/mac.c +8 -8
index 18249572cb2e..5e1f26d3c5ad 100644
@@ -130,8 +130,8 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
 			break;
 		}
 		msta = list_first_entry(&sta_poll_list,
-					struct mt7996_sta, poll_list);
-		list_del_init(&msta->poll_list);
+					struct mt7996_sta, wcid.poll_list);
+		list_del_init(&msta->wcid.poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		idx = msta->wcid.idx;
@@ -682,8 +682,8 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
 
 		msta = container_of(status->wcid, struct mt7996_sta, wcid);
 		spin_lock_bh(&dev->mt76.sta_poll_lock);
-		if (list_empty(&msta->poll_list))
-			list_add_tail(&msta->poll_list,
+		if (list_empty(&msta->wcid.poll_list))
+			list_add_tail(&msta->wcid.poll_list,
 				      &dev->mt76.sta_poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
@@ -1288,8 +1288,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
 
 			msta = container_of(wcid, struct mt7996_sta, wcid);
 			spin_lock_bh(&mdev->sta_poll_lock);
-			if (list_empty(&msta->poll_list))
-				list_add_tail(&msta->poll_list,
+			if (list_empty(&msta->wcid.poll_list))
+				list_add_tail(&msta->wcid.poll_list,
 					      &mdev->sta_poll_list);
 			spin_unlock_bh(&mdev->sta_poll_lock);
 			continue;
@@ -1497,8 +1497,8 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
 		goto out;
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (list_empty(&msta->poll_list))
-		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+	if (list_empty(&msta->wcid.poll_list))
+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 out:
drivers/net/wireless/mediatek/mt76/mt7996/main.c +6 -6
index ecac04066fda..1a5d646631a6 100644
@@ -200,7 +200,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
 	idx = MT7996_WTBL_RESERVED - mvif->mt76.idx;
 
 	INIT_LIST_HEAD(&mvif->sta.rc_list);
-	INIT_LIST_HEAD(&mvif->sta.poll_list);
+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
 	mvif->sta.wcid.idx = idx;
 	mvif->sta.wcid.phy_idx = band_idx;
 	mvif->sta.wcid.hw_key_idx = -1;
@@ -263,8 +263,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
 	mutex_unlock(&dev->mt76.mutex);
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
@@ -632,7 +632,7 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 		return -ENOSPC;
 
 	INIT_LIST_HEAD(&msta->rc_list);
-	INIT_LIST_HEAD(&msta->poll_list);
+	INIT_LIST_HEAD(&msta->wcid.poll_list);
 	msta->vif = mvif;
 	msta->wcid.sta = 1;
 	msta->wcid.idx = idx;
@@ -668,8 +668,8 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 		mt7996_mac_twt_teardown_flow(dev, msta, i);
 
 	spin_lock_bh(&mdev->sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	if (!list_empty(&msta->rc_list))
 		list_del_init(&msta->rc_list);
 	spin_unlock_bh(&mdev->sta_poll_lock);
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +0 -1
index 9be7a5f80f4d..e1ab38bf9118 100644
@@ -95,7 +95,6 @@ struct mt7996_sta {
 
 	struct mt7996_vif *vif;
 
-	struct list_head poll_list;
 	struct list_head rc_list;
 	u32 airtime_ac[8];
 
Signature · 1 line
2.40.1
author maintainer
#10 lore raw

PATCH v2 10/15 wifi: mt76: mt7921: rely on shared poll_list field

In reply to Lorenzo Bianconi

Rely on poll_list field in mt76_wcid structure and get rid of private copy.

---
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c  | 16 ++++++++--------
 drivers/net/wireless/mediatek/mt76/mt7921/main.c | 12 ++++++------
 .../net/wireless/mediatek/mt76/mt7921/mt7921.h   |  1 -
 3 files changed, 14 insertions(+), 15 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +8 -8
index d81d78ac5c91..561590713e0b 100644
@@ -84,8 +84,8 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
 			break;
 		}
 		msta = list_first_entry(&sta_poll_list,
-					struct mt7921_sta, poll_list);
-		list_del_init(&msta->poll_list);
+					struct mt7921_sta, wcid.poll_list);
+		list_del_init(&msta->wcid.poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 		idx = msta->wcid.idx;
@@ -281,8 +281,8 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
 	if (status->wcid) {
 		msta = container_of(status->wcid, struct mt7921_sta, wcid);
 		spin_lock_bh(&dev->mt76.sta_poll_lock);
-		if (list_empty(&msta->poll_list))
-			list_add_tail(&msta->poll_list,
+		if (list_empty(&msta->wcid.poll_list))
+			list_add_tail(&msta->wcid.poll_list,
 				      &dev->mt76.sta_poll_list);
 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
 	}
@@ -568,8 +568,8 @@ void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data)
 		goto out;
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (list_empty(&msta->poll_list))
-		list_add_tail(&msta->poll_list, &dev->mt76.sta_poll_list);
+	if (list_empty(&msta->wcid.poll_list))
+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 out:
@@ -649,8 +649,8 @@ static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
 
 			msta = container_of(wcid, struct mt7921_sta, wcid);
 			spin_lock_bh(&mdev->sta_poll_lock);
-			if (list_empty(&msta->poll_list))
-				list_add_tail(&msta->poll_list,
+			if (list_empty(&msta->wcid.poll_list))
+				list_add_tail(&msta->wcid.poll_list,
 					      &mdev->sta_poll_list);
 			spin_unlock_bh(&mdev->sta_poll_lock);
 			continue;
drivers/net/wireless/mediatek/mt76/mt7921/main.c +6 -6
index ffbe48f33d49..2512c1c1fb89 100644
@@ -313,7 +313,7 @@ static int mt7921_add_interface(struct ieee80211_hw *hw,
 
 	idx = MT7921_WTBL_RESERVED - mvif->mt76.idx;
 
-	INIT_LIST_HEAD(&mvif->sta.poll_list);
+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
 	mvif->sta.wcid.idx = idx;
 	mvif->sta.wcid.phy_idx = mvif->mt76.band_idx;
 	mvif->sta.wcid.hw_key_idx = -1;
@@ -358,8 +358,8 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw,
 	mt7921_mutex_release(dev);
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
@@ -765,7 +765,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	if (idx < 0)
 		return -ENOSPC;
 
-	INIT_LIST_HEAD(&msta->poll_list);
+	INIT_LIST_HEAD(&msta->wcid.poll_list);
 	msta->vif = mvif;
 	msta->wcid.sta = 1;
 	msta->wcid.idx = idx;
@@ -844,8 +844,8 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	}
 
 	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	if (!list_empty(&msta->poll_list))
-		list_del_init(&msta->poll_list);
+	if (!list_empty(&msta->wcid.poll_list))
+		list_del_init(&msta->wcid.poll_list);
 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
 
 	mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +0 -1
index ef1fe4d9ab99..bd2c4190b77e 100644
@@ -150,7 +150,6 @@ struct mt7921_sta {
 
 	struct mt7921_vif *vif;
 
-	struct list_head poll_list;
 	u32 airtime_ac[8];
 
 	int ack_signal;
Signature · 1 line
2.40.1
author maintainer
#11 lore raw

PATCH v2 11/15 wifi: mt76: move ampdu_state in mt76_wcid

In reply to Lorenzo Bianconi

ampdu_state field is used by most of the drivers, so move it in mt76_wcid structure.

---
 drivers/net/wireless/mediatek/mt76/mt76.h          | 1 +
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c    | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7915/main.c   | 6 +++---
 drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 -
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c    | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7921/main.c   | 6 +++---
 drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 -
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c    | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7996/main.c   | 6 +++---
 drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 1 -
 10 files changed, 13 insertions(+), 15 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76.h +1 -0
index 997bd722b045..878cebb8a4e9 100644
@@ -316,6 +316,7 @@ struct mt76_wcid {
 	int inactive_count;
 
 	struct rate_info rate;
+	unsigned long ampdu_state;
 
 	u16 idx;
 	u8 hw_key_idx;
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +1 -1
index b499ab7d95f8..5c2c054b31fb 100644
@@ -863,7 +863,7 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
 		return;
 
 	msta = (struct mt7915_sta *)sta->drv_priv;
-	if (!test_and_set_bit(tid, &msta->ampdu_state))
+	if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
 		ieee80211_start_tx_ba_session(sta, tid, 0);
 }
 
drivers/net/wireless/mediatek/mt76/mt7915/main.c +3 -3
index cf1ed8632925..f2b4a99bd142 100644
@@ -802,16 +802,16 @@ mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		mtxq->aggr = false;
-		clear_bit(tid, &msta->ampdu_state);
+		clear_bit(tid, &msta->wcid.ampdu_state);
 		ret = mt7915_mcu_add_tx_ba(dev, params, false);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		set_bit(tid, &msta->ampdu_state);
+		set_bit(tid, &msta->wcid.ampdu_state);
 		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
 		break;
 	case IEEE80211_AMPDU_TX_STOP_CONT:
 		mtxq->aggr = false;
-		clear_bit(tid, &msta->ampdu_state);
+		clear_bit(tid, &msta->wcid.ampdu_state);
 		ret = mt7915_mcu_add_tx_ba(dev, params, false);
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +0 -1
index 0ebd44fa5f5f..ca01199afd11 100644
@@ -137,7 +137,6 @@ struct mt7915_sta {
 
 	unsigned long changed;
 	unsigned long jiffies;
-	unsigned long ampdu_state;
 	struct mt76_connac_sta_key_conf bip;
 
 	struct {
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +1 -1
index 561590713e0b..f0e67e62abc2 100644
@@ -531,7 +531,7 @@ static void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
 		return;
 
 	msta = (struct mt7921_sta *)sta->drv_priv;
-	if (!test_and_set_bit(tid, &msta->ampdu_state))
+	if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
 		ieee80211_start_tx_ba_session(sta, tid, 0);
 }
 
drivers/net/wireless/mediatek/mt76/mt7921/main.c +3 -3
index 2512c1c1fb89..ecfa3ef70902 100644
@@ -955,16 +955,16 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		mtxq->aggr = false;
-		clear_bit(tid, &msta->ampdu_state);
+		clear_bit(tid, &msta->wcid.ampdu_state);
 		mt7921_mcu_uni_tx_ba(dev, params, false);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		set_bit(tid, &msta->ampdu_state);
+		set_bit(tid, &msta->wcid.ampdu_state);
 		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
 		break;
 	case IEEE80211_AMPDU_TX_STOP_CONT:
 		mtxq->aggr = false;
-		clear_bit(tid, &msta->ampdu_state);
+		clear_bit(tid, &msta->wcid.ampdu_state);
 		mt7921_mcu_uni_tx_ba(dev, params, false);
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +0 -1
index bd2c4190b77e..d4dfbbdb5f27 100644
@@ -156,7 +156,6 @@ struct mt7921_sta {
 	struct ewma_avg_signal avg_ack_signal;
 
 	unsigned long last_txs;
-	unsigned long ampdu_state;
 
 	struct mt76_connac_sta_key_conf bip;
 };
drivers/net/wireless/mediatek/mt76/mt7996/mac.c +1 -1
index 5e1f26d3c5ad..753e9c7b1199 100644
@@ -1199,7 +1199,7 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
 		return;
 
 	msta = (struct mt7996_sta *)sta->drv_priv;
-	if (!test_and_set_bit(tid, &msta->ampdu_state))
+	if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
 		ieee80211_start_tx_ba_session(sta, tid, 0);
 }
 
drivers/net/wireless/mediatek/mt76/mt7996/main.c +3 -3
index 1a5d646631a6..2d20de7c8916 100644
@@ -752,16 +752,16 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		mtxq->aggr = false;
-		clear_bit(tid, &msta->ampdu_state);
+		clear_bit(tid, &msta->wcid.ampdu_state);
 		ret = mt7996_mcu_add_tx_ba(dev, params, false);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		set_bit(tid, &msta->ampdu_state);
+		set_bit(tid, &msta->wcid.ampdu_state);
 		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
 		break;
 	case IEEE80211_AMPDU_TX_STOP_CONT:
 		mtxq->aggr = false;
-		clear_bit(tid, &msta->ampdu_state);
+		clear_bit(tid, &msta->wcid.ampdu_state);
 		ret = mt7996_mcu_add_tx_ba(dev, params, false);
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +0 -1
index e1ab38bf9118..829973abc28d 100644
@@ -103,7 +103,6 @@ struct mt7996_sta {
 
 	unsigned long changed;
 	unsigned long jiffies;
-	unsigned long ampdu_state;
 
 	struct mt76_connac_sta_key_conf bip;
 
Signature · 1 line
2.40.1
author maintainer
#12 lore raw

PATCH v2 12/15 mt76: connac: move more mt7921/mt7915 mac shared code in connac lib

In reply to Lorenzo Bianconi

Move the following routines in mt76-connac lib since they are shared between mt7915 and mt7921:
- mt76_connac2_tx_check_aggr
- mt76_connac2_txwi_free
- mt76_connac2_tx_token_put

---
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  5 +
 .../wireless/mediatek/mt76/mt76_connac_mac.c  | 82 +++++++++++++++++
 .../net/wireless/mediatek/mt76/mt7915/init.c  |  2 +-
 .../net/wireless/mediatek/mt76/mt7915/mac.c   | 91 +------------------
 .../wireless/mediatek/mt76/mt7915/mt7915.h    |  1 -
 .../net/wireless/mediatek/mt76/mt7921/mac.c   | 62 +------------
 .../wireless/mediatek/mt76/mt7921/mt7921.h    |  4 -
 .../net/wireless/mediatek/mt76/mt7921/pci.c   |  2 +-
 .../wireless/mediatek/mt76/mt7921/pci_mac.c   | 16 +---
 9 files changed, 96 insertions(+), 169 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76_connac.h +5 -0
index 15653b274f83..68bdeada1421 100644
@@ -409,5 +409,10 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
 				  struct mt76_rx_status *status,
 				  struct ieee80211_supported_band *sband,
 				  __le32 *rxv, u8 *mode);
+void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi);
+void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list);
+void mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
 #endif /* __MT76_CONNAC_H */
drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +82 -0

85 lines not on this page · raw message

drivers/net/wireless/mediatek/mt76/mt7915/init.c +1 -1
index 90c883c7fe05..1bb687bee8c8 100644
@@ -1158,7 +1158,7 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
 static void mt7915_stop_hardware(struct mt7915_dev *dev)
 {
 	mt7915_mcu_exit(dev);
-	mt7915_tx_token_put(dev);
+	mt76_connac2_tx_token_put(&dev->mt76);
 	mt7915_dma_cleanup(dev);
 	tasklet_disable(&dev->mt76.irq_tasklet);
 
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +4 -87

127 lines not on this page · raw message

drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +0 -1
index ca01199afd11..ac116ab03690 100644
@@ -608,7 +608,6 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
 			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
 			  struct ieee80211_sta *sta,
 			  struct mt76_tx_info *tx_info);
-void mt7915_tx_token_put(struct mt7915_dev *dev);
 void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
 			 struct sk_buff *skb, u32 *info);
 bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len);
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +2 -60

96 lines not on this page · raw message

drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +0 -4
index d4dfbbdb5f27..16188e2ae691 100644
@@ -471,7 +471,6 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
 			   struct mt76_tx_info *tx_info);
 
 void mt7921_tx_worker(struct mt76_worker *w);
-void mt7921_tx_token_put(struct mt7921_dev *dev);
 bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len);
 void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
 			 struct sk_buff *skb, u32 *info);
@@ -504,9 +503,6 @@ int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			void *data, int len);
 int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
 			 struct netlink_callback *cb, void *data, int len);
-void mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
-		      struct ieee80211_sta *sta, bool clear_status,
-		      struct list_head *free_list);
 int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
 			      struct sk_buff *skb, int seq);
 
drivers/net/wireless/mediatek/mt76/mt7921/pci.c +1 -1
index 1c727870bbdb..6c06d4b5856e 100644
@@ -115,7 +115,7 @@ static void mt7921e_unregister_device(struct mt7921_dev *dev)
 	cancel_work_sync(&pm->wake_work);
 	cancel_work_sync(&dev->reset_work);
 
-	mt7921_tx_token_put(dev);
+	mt76_connac2_tx_token_put(&dev->mt76);
 	__mt7921_mcu_drv_pmctrl(dev);
 	mt7921_dma_cleanup(dev);
 	mt7921_wfsys_reset(dev);
drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +1 -15
index 6053a2556c20..978c90a034cf 100644
@@ -53,20 +53,6 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
 	return 0;
 }
 
-void mt7921_tx_token_put(struct mt7921_dev *dev)
-{
-	struct mt76_txwi_cache *txwi;
-	int id;
-
-	spin_lock_bh(&dev->mt76.token_lock);
-	idr_for_each_entry(&dev->mt76.token, txwi, id) {
-		mt7921_txwi_free(dev, txwi, NULL, false, NULL);
-		dev->mt76.token_count--;
-	}
-	spin_unlock_bh(&dev->mt76.token_lock);
-	idr_destroy(&dev->mt76.token);
-}
-
 int mt7921e_mac_reset(struct mt7921_dev *dev)
 {
 	int i, err;
@@ -91,7 +77,7 @@ int mt7921e_mac_reset(struct mt7921_dev *dev)
 	napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]);
 	napi_disable(&dev->mt76.tx_napi);
 
-	mt7921_tx_token_put(dev);
+	mt76_connac2_tx_token_put(&dev->mt76);
 	idr_init(&dev->mt76.token);
 
 	mt7921_wpdma_reset(dev, true);
Signature · 1 line
2.40.1
author maintainer
#13 lore raw

PATCH v2 13/15 wifi: mt76: move rate info in mt76_vif

In reply to Lorenzo Bianconi

This is a preliminary patch to introduce mt76_connac3 mac library used by WiFi7 chipsets (e.g. mt7996).

---
 drivers/net/wireless/mediatek/mt76/mt76.h          |  3 +++
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c    | 10 +++++-----
 drivers/net/wireless/mediatek/mt76/mt7996/main.c   | 10 +++++-----
 drivers/net/wireless/mediatek/mt76/mt7996/mcu.c    |  2 +-
 drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h |  4 ----
 5 files changed, 14 insertions(+), 15 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76.h +3 -0
index 878cebb8a4e9..d14844d7c5bb 100644
@@ -705,6 +705,9 @@ struct mt76_vif {
 	u8 wmm_idx;
 	u8 scan_seq_num;
 	u8 cipher;
+	u8 basic_rates_idx;
+	u8 mcast_rates_idx;
+	u8 beacon_rates_idx;
 };
 
 struct mt76_phy {
drivers/net/wireless/mediatek/mt76/mt7996/mac.c +5 -5
index 753e9c7b1199..e407fc547e42 100644
@@ -1008,7 +1008,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
 	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
 	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
-	struct mt7996_vif *mvif;
+	struct mt76_vif *mvif;
 	u16 tx_count = 15;
 	u32 val;
 	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
@@ -1016,11 +1016,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
 	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
 					 BSS_CHANGED_FILS_DISCOVERY));
 
-	mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
+	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
 	if (mvif) {
-		omac_idx = mvif->mt76.omac_idx;
-		wmm_idx = mvif->mt76.wmm_idx;
-		band_idx = mvif->mt76.band_idx;
+		omac_idx = mvif->omac_idx;
+		wmm_idx = mvif->wmm_idx;
+		band_idx = mvif->band_idx;
 	}
 
 	if (inband_disc) {
drivers/net/wireless/mediatek/mt76/mt7996/main.c +5 -5
index 2d20de7c8916..ee9e409b8eb9 100644
@@ -221,9 +221,9 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
 	vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
 
 	if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ)
-		mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
+		mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
 	else
-		mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL;
+		mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL;
 
 	mt7996_init_bitrate_mask(vif);
 
@@ -506,7 +506,7 @@ static u8
 mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       bool beacon, bool mcast)
 {
-	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
 	struct mt76_phy *mphy = hw->priv;
 	u16 rate;
 	u8 i, idx, ht;
@@ -518,7 +518,7 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		struct mt7996_dev *dev = mt7996_hw_dev(hw);
 
 		/* must odd index */
-		idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->mt76.idx % 20);
+		idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20);
 		mt7996_mac_set_fixed_rate_table(dev, idx, rate);
 		return idx;
 	}
@@ -536,7 +536,7 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
 				    struct ieee80211_bss_conf *info,
 				    u64 changed)
 {
-	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
 	struct mt7996_phy *phy = mt7996_hw_phy(hw);
 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
 
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +1 -1
index 88e2f9d0e513..6cc87835263a 100644
@@ -600,7 +600,7 @@ static void
 mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
 		       struct mt7996_phy *phy)
 {
-	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
 	struct bss_rate_tlv *bmc;
 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
 	enum nl80211_band band = chandef->chan->band;
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +0 -4
index 829973abc28d..c8e8a04a561e 100644
@@ -120,10 +120,6 @@ struct mt7996_vif {
 
 	struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
 	struct cfg80211_bitrate_mask bitrate_mask;
-
-	u8 basic_rates_idx;
-	u8 mcast_rates_idx;
-	u8 beacon_rates_idx;
 };
 
 /* per-phy stats.  */
Signature · 1 line
2.40.1
author maintainer
#14 lore raw

PATCH v2 14/15 wifi: mt76: connac: move connac3 definitions in mt76_connac3_mac.h

In reply to Lorenzo Bianconi

Connac3 mac definitions are shared between WiFi7 chipsets so move them in mt76_connac3_mac.h

---
 .../wireless/mediatek/mt76/mt76_connac3_mac.h | 325 ++++++++++++++++++
 .../net/wireless/mediatek/mt76/mt7996/mac.h   | 315 +----------------
 2 files changed, 326 insertions(+), 314 deletions(-)
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h new file +325 -0
new file mode 100644
index 000000000000..6663a0b46541
@@ -0,0 +1,325 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#ifndef __MT76_CONNAC3_MAC_H
+#define __MT76_CONNAC3_MAC_H
+
+#define MT_CT_PARSE_LEN			72
+#define MT_CT_DMA_BUF_NUM		2
+
+#define MT_RXD0_LENGTH			GENMASK(15, 0)
+#define MT_RXD0_PKT_FLAG                GENMASK(19, 16)
+#define MT_RXD0_PKT_TYPE		GENMASK(31, 27)
+
+#define MT_RXD0_MESH			BIT(18)
+#define MT_RXD0_MHCP			BIT(19)
+#define MT_RXD0_NORMAL_ETH_TYPE_OFS	GENMASK(22, 16)
+#define MT_RXD0_NORMAL_IP_SUM		BIT(23)
+#define MT_RXD0_NORMAL_UDP_TCP_SUM	BIT(24)
+
+#define MT_RXD0_SW_PKT_TYPE_MASK	GENMASK(31, 16)
+#define MT_RXD0_SW_PKT_TYPE_MAP		0x380F
+#define MT_RXD0_SW_PKT_TYPE_FRAME	0x3801
+
+/* RXD DW1 */
+#define MT_RXD1_NORMAL_WLAN_IDX		GENMASK(11, 0)
+#define MT_RXD1_NORMAL_GROUP_1		BIT(16)
+#define MT_RXD1_NORMAL_GROUP_2		BIT(17)
+#define MT_RXD1_NORMAL_GROUP_3		BIT(18)
+#define MT_RXD1_NORMAL_GROUP_4		BIT(19)
+#define MT_RXD1_NORMAL_GROUP_5		BIT(20)
+#define MT_RXD1_NORMAL_KEY_ID		GENMASK(22, 21)
+#define MT_RXD1_NORMAL_CM		BIT(23)
+#define MT_RXD1_NORMAL_CLM		BIT(24)
+#define MT_RXD1_NORMAL_ICV_ERR		BIT(25)
+#define MT_RXD1_NORMAL_TKIP_MIC_ERR	BIT(26)
+#define MT_RXD1_NORMAL_BAND_IDX		GENMASK(28, 27)
+#define MT_RXD1_NORMAL_SPP_EN		BIT(29)
+#define MT_RXD1_NORMAL_ADD_OM		BIT(30)
+#define MT_RXD1_NORMAL_SEC_DONE		BIT(31)
+
+/* RXD DW2 */
+#define MT_RXD2_NORMAL_BSSID		GENMASK(5, 0)
+#define MT_RXD2_NORMAL_MAC_HDR_LEN	GENMASK(12, 8)
+#define MT_RXD2_NORMAL_HDR_TRANS	BIT(7)
+#define MT_RXD2_NORMAL_HDR_OFFSET	GENMASK(15, 13)
+#define MT_RXD2_NORMAL_SEC_MODE		GENMASK(20, 16)
+#define MT_RXD2_NORMAL_MU_BAR		BIT(21)
+#define MT_RXD2_NORMAL_SW_BIT		BIT(22)
+#define MT_RXD2_NORMAL_AMSDU_ERR	BIT(23)
+#define MT_RXD2_NORMAL_MAX_LEN_ERROR	BIT(24)
+#define MT_RXD2_NORMAL_HDR_TRANS_ERROR	BIT(25)
+#define MT_RXD2_NORMAL_INT_FRAME	BIT(26)
+#define MT_RXD2_NORMAL_FRAG		BIT(27)
+#define MT_RXD2_NORMAL_NULL_FRAME	BIT(28)
+#define MT_RXD2_NORMAL_NDATA		BIT(29)
+#define MT_RXD2_NORMAL_NON_AMPDU	BIT(30)
+#define MT_RXD2_NORMAL_BF_REPORT	BIT(31)
+
+/* RXD DW3 */
+#define MT_RXD3_NORMAL_RXV_SEQ		GENMASK(7, 0)
+#define MT_RXD3_NORMAL_CH_FREQ		GENMASK(15, 8)
+#define MT_RXD3_NORMAL_ADDR_TYPE	GENMASK(17, 16)
+#define MT_RXD3_NORMAL_U2M		BIT(0)
+#define MT_RXD3_NORMAL_HTC_VLD		BIT(18)
+#define MT_RXD3_NORMAL_BEACON_MC	BIT(20)
+#define MT_RXD3_NORMAL_BEACON_UC	BIT(21)
+#define MT_RXD3_NORMAL_CO_ANT		BIT(22)
+#define MT_RXD3_NORMAL_FCS_ERR		BIT(24)
+#define MT_RXD3_NORMAL_VLAN2ETH		BIT(31)
+
+/* RXD DW4 */
+#define MT_RXD4_NORMAL_PAYLOAD_FORMAT	GENMASK(1, 0)
+#define MT_RXD4_FIRST_AMSDU_FRAME	GENMASK(1, 0)
+#define MT_RXD4_MID_AMSDU_FRAME		BIT(1)
+#define MT_RXD4_LAST_AMSDU_FRAME	BIT(0)
+
+#define MT_RXV_HDR_BAND_IDX		BIT(24)
+
+/* RXD GROUP4 */
+#define MT_RXD8_FRAME_CONTROL		GENMASK(15, 0)
+
+#define MT_RXD10_SEQ_CTRL		GENMASK(15, 0)
+#define MT_RXD10_QOS_CTL		GENMASK(31, 16)
+
+#define MT_RXD11_HT_CONTROL		GENMASK(31, 0)
+
+/* P-RXV */
+#define MT_PRXV_TX_RATE			GENMASK(6, 0)
+#define MT_PRXV_TX_DCM			BIT(4)
+#define MT_PRXV_TX_ER_SU_106T		BIT(5)
+#define MT_PRXV_NSTS			GENMASK(10, 7)
+#define MT_PRXV_TXBF			BIT(11)
+#define MT_PRXV_HT_AD_CODE		BIT(12)
+#define MT_PRXV_HE_RU_ALLOC		GENMASK(30, 22)
+#define MT_PRXV_RCPI3			GENMASK(31, 24)
+#define MT_PRXV_RCPI2			GENMASK(23, 16)
+#define MT_PRXV_RCPI1			GENMASK(15, 8)
+#define MT_PRXV_RCPI0			GENMASK(7, 0)
+#define MT_PRXV_HT_SHORT_GI		GENMASK(4, 3)
+#define MT_PRXV_HT_STBC			GENMASK(10, 9)
+#define MT_PRXV_TX_MODE			GENMASK(14, 11)
+#define MT_PRXV_FRAME_MODE		GENMASK(2, 0)
+#define MT_PRXV_DCM			BIT(5)
+
+/* C-RXV */
+#define MT_CRXV_HE_NUM_USER		GENMASK(26, 20)
+#define MT_CRXV_HE_LTF_SIZE		GENMASK(28, 27)
+#define MT_CRXV_HE_LDPC_EXT_SYM		BIT(30)
+
+#define MT_CRXV_HE_PE_DISAMBIG		BIT(1)
+#define MT_CRXV_HE_UPLINK		BIT(2)
+
+#define MT_CRXV_HE_MU_AID		GENMASK(27, 17)
+#define MT_CRXV_HE_BEAM_CHNG		BIT(29)
+
+#define MT_CRXV_HE_DOPPLER		BIT(0)
+#define MT_CRXV_HE_BSS_COLOR		GENMASK(15, 10)
+#define MT_CRXV_HE_TXOP_DUR		GENMASK(19, 17)
+
+#define MT_CRXV_HE_SR_MASK		GENMASK(11, 8)
+#define MT_CRXV_HE_SR1_MASK		GENMASK(16, 12)
+#define MT_CRXV_HE_SR2_MASK             GENMASK(20, 17)
+#define MT_CRXV_HE_SR3_MASK             GENMASK(24, 21)
+
+#define MT_CRXV_HE_RU0			GENMASK(8, 0)
+#define MT_CRXV_HE_RU1			GENMASK(17, 9)
+#define MT_CRXV_HE_RU2			GENMASK(26, 18)
+#define MT_CRXV_HE_RU3_L		GENMASK(31, 27)
+#define MT_CRXV_HE_RU3_H		GENMASK(3, 0)
+
+enum tx_header_format {
+	MT_HDR_FORMAT_802_3,
+	MT_HDR_FORMAT_CMD,
+	MT_HDR_FORMAT_802_11,
+	MT_HDR_FORMAT_802_11_EXT,
+};
+
+enum tx_pkt_type {
+	MT_TX_TYPE_CT,
+	MT_TX_TYPE_SF,
+	MT_TX_TYPE_CMD,
+	MT_TX_TYPE_FW,
+};
+
+enum tx_port_idx {
+	MT_TX_PORT_IDX_LMAC,
+	MT_TX_PORT_IDX_MCU
+};
+
+enum tx_mcu_port_q_idx {
+	MT_TX_MCU_PORT_RX_Q0 = 0x20,
+	MT_TX_MCU_PORT_RX_Q1,
+	MT_TX_MCU_PORT_RX_Q2,
+	MT_TX_MCU_PORT_RX_Q3,
+	MT_TX_MCU_PORT_RX_FWDL = 0x3e
+};
+
+enum tx_mgnt_type {
+	MT_TX_NORMAL,
+	MT_TX_TIMING,
+	MT_TX_ADDBA,
+};
+
+#define MT_CT_INFO_APPLY_TXD		BIT(0)
+#define MT_CT_INFO_COPY_HOST_TXD_ALL	BIT(1)
+#define MT_CT_INFO_MGMT_FRAME		BIT(2)
+#define MT_CT_INFO_NONE_CIPHER_FRAME	BIT(3)
+#define MT_CT_INFO_HSR2_TX		BIT(4)
+#define MT_CT_INFO_FROM_HOST		BIT(7)
+
+#define MT_TXD_SIZE			(8 * 4)
+
+#define MT_TXD0_Q_IDX			GENMASK(31, 25)
+#define MT_TXD0_PKT_FMT			GENMASK(24, 23)
+#define MT_TXD0_ETH_TYPE_OFFSET		GENMASK(22, 16)
+#define MT_TXD0_TX_BYTES		GENMASK(15, 0)
+
+#define MT_TXD1_FIXED_RATE		BIT(31)
+#define MT_TXD1_OWN_MAC			GENMASK(30, 25)
+#define MT_TXD1_TID			GENMASK(24, 21)
+#define MT_TXD1_BIP			BIT(24)
+#define MT_TXD1_ETH_802_3		BIT(20)
+#define MT_TXD1_HDR_INFO		GENMASK(20, 16)
+#define MT_TXD1_HDR_FORMAT		GENMASK(15, 14)
+#define MT_TXD1_TGID			GENMASK(13, 12)
+#define MT_TXD1_WLAN_IDX		GENMASK(11, 0)
+
+#define MT_TXD2_POWER_OFFSET		GENMASK(31, 26)
+#define MT_TXD2_MAX_TX_TIME		GENMASK(25, 16)
+#define MT_TXD2_FRAG			GENMASK(15, 14)
+#define MT_TXD2_HTC_VLD			BIT(13)
+#define MT_TXD2_DURATION		BIT(12)
+#define MT_TXD2_HDR_PAD			GENMASK(11, 10)
+#define MT_TXD2_RTS			BIT(9)
+#define MT_TXD2_OWN_MAC_MAP		BIT(8)
+#define MT_TXD2_BF_TYPE			GENMASK(6, 7)
+#define MT_TXD2_FRAME_TYPE		GENMASK(5, 4)
+#define MT_TXD2_SUB_TYPE		GENMASK(3, 0)
+
+#define MT_TXD3_SN_VALID		BIT(31)
+#define MT_TXD3_PN_VALID		BIT(30)
+#define MT_TXD3_SW_POWER_MGMT		BIT(29)
+#define MT_TXD3_BA_DISABLE		BIT(28)
+#define MT_TXD3_SEQ			GENMASK(27, 16)
+#define MT_TXD3_REM_TX_COUNT		GENMASK(15, 11)
+#define MT_TXD3_TX_COUNT		GENMASK(10, 6)
+#define MT_TXD3_HW_AMSDU		BIT(5)
+#define MT_TXD3_BCM			BIT(4)
+#define MT_TXD3_EEOSP			BIT(3)
+#define MT_TXD3_EMRD			BIT(2)
+#define MT_TXD3_PROTECT_FRAME		BIT(1)
+#define MT_TXD3_NO_ACK			BIT(0)
+
+#define MT_TXD4_PN_LOW			GENMASK(31, 0)
+
+#define MT_TXD5_PN_HIGH			GENMASK(31, 16)
+#define MT_TXD5_FL			BIT(15)
+#define MT_TXD5_BYPASS_TBB		BIT(14)
+#define MT_TXD5_BYPASS_RBB		BIT(13)
+#define MT_TXD5_BSS_COLOR_ZERO		BIT(12)
+#define MT_TXD5_TX_STATUS_HOST		BIT(10)
+#define MT_TXD5_TX_STATUS_MCU		BIT(9)
+#define MT_TXD5_TX_STATUS_FMT		BIT(8)
+#define MT_TXD5_PID			GENMASK(7, 0)
+
+#define MT_TXD6_TX_SRC			GENMASK(31, 30)
+#define MT_TXD6_VTA			BIT(28)
+#define MT_TXD6_BW			GENMASK(25, 22)
+#define MT_TXD6_TX_RATE			GENMASK(21, 16)
+#define MT_TXD6_TIMESTAMP_OFS_EN	BIT(15)
+#define MT_TXD6_TIMESTAMP_OFS_IDX	GENMASK(14, 10)
+#define MT_TXD6_MSDU_CNT		GENMASK(9, 4)
+#define MT_TXD6_DIS_MAT			BIT(3)
+#define MT_TXD6_DAS			BIT(2)
+#define MT_TXD6_AMSDU_CAP		BIT(1)
+
+#define MT_TXD7_TXD_LEN			GENMASK(31, 30)
+#define MT_TXD7_IP_SUM			BIT(29)
+#define MT_TXD7_DROP_BY_SDO		BIT(28)
+#define MT_TXD7_MAC_TXD			BIT(27)
+#define MT_TXD7_CTXD			BIT(26)
+#define MT_TXD7_CTXD_CNT		GENMASK(25, 22)
+#define MT_TXD7_UDP_TCP_SUM		BIT(15)
+#define MT_TXD7_TX_TIME			GENMASK(9, 0)
+
+#define MT_TX_RATE_STBC			BIT(14)
+#define MT_TX_RATE_NSS			GENMASK(13, 10)
+#define MT_TX_RATE_MODE			GENMASK(9, 6)
+#define MT_TX_RATE_SU_EXT_TONE		BIT(5)
+#define MT_TX_RATE_DCM			BIT(4)
+/* VHT/HE only use bits 0-3 */
+#define MT_TX_RATE_IDX			GENMASK(5, 0)
+
+#define MT_TXFREE0_PKT_TYPE		GENMASK(31, 27)
+#define MT_TXFREE0_MSDU_CNT		GENMASK(25, 16)
+#define MT_TXFREE0_RX_BYTE		GENMASK(15, 0)
+
+#define MT_TXFREE1_VER			GENMASK(18, 16)
+
+#define MT_TXFREE_INFO_PAIR		BIT(31)
+#define MT_TXFREE_INFO_HEADER		BIT(30)
+#define MT_TXFREE_INFO_WLAN_ID		GENMASK(23, 12)
+#define MT_TXFREE_INFO_MSDU_ID		GENMASK(14, 0)
+#define MT_TXFREE_INFO_COUNT		GENMASK(27, 24)
+#define MT_TXFREE_INFO_STAT		GENMASK(29, 28)
+
+#define MT_TXS0_BW			GENMASK(31, 29)
+#define MT_TXS0_TID			GENMASK(28, 26)
+#define MT_TXS0_AMPDU			BIT(25)
+#define MT_TXS0_TXS_FORMAT		GENMASK(24, 23)
+#define MT_TXS0_BA_ERROR		BIT(22)
+#define MT_TXS0_PS_FLAG			BIT(21)
+#define MT_TXS0_TXOP_TIMEOUT		BIT(20)
+#define MT_TXS0_BIP_ERROR		BIT(19)
+
+#define MT_TXS0_QUEUE_TIMEOUT		BIT(18)
+#define MT_TXS0_RTS_TIMEOUT		BIT(17)
+#define MT_TXS0_ACK_TIMEOUT		BIT(16)
+#define MT_TXS0_ACK_ERROR_MASK		GENMASK(18, 16)
+
+#define MT_TXS0_TX_STATUS_HOST		BIT(15)
+#define MT_TXS0_TX_STATUS_MCU		BIT(14)
+#define MT_TXS0_TX_RATE			GENMASK(13, 0)
+
+#define MT_TXS1_SEQNO			GENMASK(31, 20)
+#define MT_TXS1_RESP_RATE		GENMASK(19, 16)
+#define MT_TXS1_RXV_SEQNO		GENMASK(15, 8)
+#define MT_TXS1_TX_POWER_DBM		GENMASK(7, 0)
+
+#define MT_TXS2_BF_STATUS		GENMASK(31, 30)
+#define MT_TXS2_BAND			GENMASK(29, 28)
+#define MT_TXS2_WCID			GENMASK(27, 16)
+#define MT_TXS2_TX_DELAY		GENMASK(15, 0)
+
+#define MT_TXS3_PID			GENMASK(31, 24)
+#define MT_TXS3_RATE_STBC		BIT(7)
+#define MT_TXS3_FIXED_RATE		BIT(6)
+#define MT_TXS3_SRC			GENMASK(5, 4)
+#define MT_TXS3_SHARED_ANTENNA		BIT(3)
+#define MT_TXS3_LAST_TX_RATE		GENMASK(2, 0)
+
+#define MT_TXS4_TIMESTAMP		GENMASK(31, 0)
+
+#define MT_TXS5_F0_FINAL_MPDU		BIT(31)
+#define MT_TXS5_F0_QOS			BIT(30)
+#define MT_TXS5_F0_TX_COUNT		GENMASK(29, 25)
+#define MT_TXS5_F0_FRONT_TIME		GENMASK(24, 0)
+#define MT_TXS5_F1_MPDU_TX_COUNT	GENMASK(31, 24)
+#define MT_TXS5_F1_MPDU_TX_BYTES	GENMASK(23, 0)
+
+#define MT_TXS6_F0_NOISE_3		GENMASK(31, 24)
+#define MT_TXS6_F0_NOISE_2		GENMASK(23, 16)
+#define MT_TXS6_F0_NOISE_1		GENMASK(15, 8)
+#define MT_TXS6_F0_NOISE_0		GENMASK(7, 0)
+#define MT_TXS6_F1_MPDU_FAIL_COUNT	GENMASK(31, 24)
+#define MT_TXS6_F1_MPDU_FAIL_BYTES	GENMASK(23, 0)
+
+#define MT_TXS7_F0_RCPI_3		GENMASK(31, 24)
+#define MT_TXS7_F0_RCPI_2		GENMASK(23, 16)
+#define MT_TXS7_F0_RCPI_1		GENMASK(15, 8)
+#define MT_TXS7_F0_RCPI_0		GENMASK(7, 0)
+#define MT_TXS7_F1_MPDU_RETRY_COUNT	GENMASK(31, 24)
+#define MT_TXS7_F1_MPDU_RETRY_BYTES	GENMASK(23, 0)
+
+#endif /* __MT76_CONNAC3_MAC_H */
drivers/net/wireless/mediatek/mt76/mt7996/mac.h +1 -314

321 lines not on this page · raw message

Signature · 1 line
2.40.1
author maintainer
#15 lore raw

PATCH v2 15/15 wifi: mt76: connac: add connac3 mac library

In reply to Lorenzo Bianconi

Introduce connac3_mac in mt76_connac library to reuse mac code shared between WiFi7 chipsets.

---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +
 .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742 +++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +-----------------
 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-)
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c
drivers/net/wireless/mediatek/mt76/Makefile +1 -1
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
 
 mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o mt76_connac3_mac.o
 
 obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
 obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
drivers/net/wireless/mediatek/mt76/mt76_connac.h +19 -0
index 68bdeada1421..20111678537b 100644
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
 			    struct list_head *free_list);
 void mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv,
+					 u8 mode);
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band *sband,
+				  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
+				 struct sk_buff *skb, struct mt76_wcid *wcid,
+				 struct ieee80211_key_conf *key, int pid,
+				 enum mt76_txq_id qid, u32 changed);
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list);
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +742 -0

742 lines not on this page · raw message

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +18 -0
index 6663a0b46541..bcc1d976b2b0 100644
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
+/* NOTE: used to map mt76_rates. idx may change if firmware expands table */
+#define MT76_CONNAC3_BASIC_RATES_TBL	11
+#define MT76_CONNAC3_BEACON_RATES_TBL	25
+
+enum {
+	MT_CTX0,
+	MT_HIF0 = 0x0,
+
+	MT_LMAC_AC00 = 0x0,
+	MT_LMAC_AC01,
+	MT_LMAC_AC02,
+	MT_LMAC_AC03,
+	MT_LMAC_ALTX0 = 0x10,
+	MT_LMAC_BMC0,
+	MT_LMAC_BCN0,
+	MT_LMAC_PSMP0,
+};
+
 #define MT_CT_PARSE_LEN			72
 #define MT_CT_DMA_BUF_NUM		2
 
drivers/net/wireless/mediatek/mt76/mt7996/init.c +2 -2
index 8f3536dbe2bb..b4a2ae00d7e0 100644
@@ -262,7 +262,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
 
 	for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) {
 		u16 rate = mt76_rates[i].hw_value;
-		u16 idx = MT7996_BASIC_RATES_TBL + i;
+		u16 idx = MT76_CONNAC3_BASIC_RATES_TBL + i;
 
 		rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) |
 		       FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0));
@@ -903,7 +903,7 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
 	mt7996_coredump_unregister(dev);
 	mt76_unregister_device(&dev->mt76);
 	mt7996_mcu_exit(dev);
-	mt7996_tx_token_put(dev);
+	mt76_connac3_tx_token_put(&dev->mt76);
 	mt7996_dma_cleanup(dev);
 	tasklet_disable(&dev->mt76.irq_tasklet);
 
drivers/net/wireless/mediatek/mt76/mt7996/mac.c +12 -749

851 lines not on this page · raw message

drivers/net/wireless/mediatek/mt76/mt7996/main.c +4 -4
index ee9e409b8eb9..6aef12e5dfe4 100644
@@ -221,9 +221,9 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
 	vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
 
 	if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ)
-		mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
+		mvif->mt76.basic_rates_idx = MT76_CONNAC3_BASIC_RATES_TBL + 4;
 	else
-		mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL;
+		mvif->mt76.basic_rates_idx = MT76_CONNAC3_BASIC_RATES_TBL;
 
 	mt7996_init_bitrate_mask(vif);
 
@@ -518,7 +518,7 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		struct mt7996_dev *dev = mt7996_hw_dev(hw);
 
 		/* must odd index */
-		idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20);
+		idx = MT76_CONNAC3_BEACON_RATES_TBL + 2 * (mvif->idx % 20);
 		mt7996_mac_set_fixed_rate_table(dev, idx, rate);
 		return idx;
 	}
@@ -526,7 +526,7 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	idx = FIELD_GET(MT_TX_RATE_IDX, rate);
 	for (i = 0; i < ARRAY_SIZE(mt76_rates); i++)
 		if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx)
-			return MT7996_BASIC_RATES_TBL + i;
+			return MT76_CONNAC3_BASIC_RATES_TBL + i;
 
 	return mvif->basic_rates_idx;
 }
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +5 -4
index 6cc87835263a..d0ba58c58760 100644
@@ -1912,8 +1912,8 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif,
 	}
 
 	buf = (u8 *)bcn + sizeof(*bcn) - MAX_BEACON_SIZE;
-	mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0,
-			      BSS_CHANGED_BEACON);
+	mt76_connac3_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, NULL,
+				    0, 0, BSS_CHANGED_BEACON);
 
 	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
 }
@@ -2024,7 +2024,8 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
 
 	buf = (u8 *)tlv + sizeof(*discov) - MAX_INBAND_FRAME_SIZE;
 
-	mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, changed);
+	mt76_connac3_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid,
+				    NULL, 0, 0, changed);
 
 	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
 
@@ -2575,7 +2576,7 @@ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif)
 
 		e = (struct edca *)tlv;
 		e->set = WMM_PARAM_SET;
-		e->queue = ac + mvif->mt76.wmm_idx * MT7996_MAX_WMM_SETS;
+		e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS;
 		e->aifs = q->aifs;
 		e->txop = cpu_to_le16(q->txop);
 
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +4 -24
index c8e8a04a561e..1de85e0a8b32 100644
@@ -12,7 +12,6 @@
 #include "regs.h"
 
 #define MT7996_MAX_INTERFACES		19	/* per-band */
-#define MT7996_MAX_WMM_SETS		4
 #define MT7996_WTBL_RESERVED		(mt7996_wtbl_size(dev) - 1)
 #define MT7996_WTBL_STA			(MT7996_WTBL_RESERVED - \
 					 mt7996_max_interface_num(dev))
@@ -43,10 +42,6 @@
 #define MT7996_MAX_STA_TWT_AGRT		8
 #define MT7996_MAX_QUEUE		(__MT_RXQ_MAX +	__MT_MCUQ_MAX + 3)
 
-/* NOTE: used to map mt76_rates. idx may change if firmware expands table */
-#define MT7996_BASIC_RATES_TBL		11
-#define MT7996_BEACON_RATES_TBL		25
-
 struct mt7996_vif;
 struct mt7996_sta;
 struct mt7996_dfs_pulse;
@@ -300,20 +295,6 @@ enum {
 	__MT_WFDMA_MAX,
 };
 
-enum {
-	MT_CTX0,
-	MT_HIF0 = 0x0,
-
-	MT_LMAC_AC00 = 0x0,
-	MT_LMAC_AC01,
-	MT_LMAC_AC02,
-	MT_LMAC_AC03,
-	MT_LMAC_ALTX0 = 0x10,
-	MT_LMAC_BMC0,
-	MT_LMAC_BCN0,
-	MT_LMAC_PSMP0,
-};
-
 enum {
 	MT_RX_SEL0,
 	MT_RX_SEL1,
@@ -505,10 +486,10 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
 			      struct ieee80211_vif *vif, bool enable);
 void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
 				     u8 tbl_idx, u16 rate_idx);
-void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
-			   struct sk_buff *skb, struct mt76_wcid *wcid,
-			   struct ieee80211_key_conf *key, int pid,
-			   enum mt76_txq_id qid, u32 changed);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
+				 struct sk_buff *skb, struct mt76_wcid *wcid,
+				 struct ieee80211_key_conf *key, int pid,
+				 enum mt76_txq_id qid, u32 changed);
 void mt7996_mac_set_timing(struct mt7996_phy *phy);
 int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta);
@@ -529,7 +510,6 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
 			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
 			  struct ieee80211_sta *sta,
 			  struct mt76_tx_info *tx_info);
-void mt7996_tx_token_put(struct mt7996_dev *dev);
 void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
 			 struct sk_buff *skb, u32 *info);
 bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len);
Signature · 1 line
2.40.1
maintainer
#16 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

Quoted 882 lines · Lorenzo Bianconi

External email : Please do not click links or open attachments until you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse mac code
shared
between WiFi7 chipsets.

---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +
 .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +---------------
--
 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-)
 create mode 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/Makefile +1 -1
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o
 mt76x02_mcu.o \
 
 mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o

mt76_connac3_mac.o

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
index 68bdeada1421..20111678537b 100644
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct mt76_dev
 *dev, struct mt76_txwi_cache *t,
 			    struct list_head *free_list);
 void mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta, __le32

*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +4 -0
+					 u8 mode);
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+				  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
+				 struct sk_buff *skb, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct ieee80211_key_conf *key, int

pid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+				 enum mt76_txq_id qid, u32 changed);
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list);
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
new file mode 100644
index 000000000000..4b745bb74ca0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
+#define HE_PREP(f, m, v)	le16_encode_bits(le32_get_bits(v,

MT_CRXV_HE_##m),\

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+						 IEEE80211_RADIOTAP_HE_

##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta, __le32

*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+{
+	struct mt76_wcid *wcid;
+	u16 fc, tid;
+	u32 val;
+
+	if (!sta ||
+	    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+	if (tid >= 6) /* skip VO queue */
+		return;
+
+	val = le32_to_cpu(txwi[2]);
+	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+	if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	wcid = (struct mt76_wcid *)sta->drv_priv;
+	if (!test_and_set_bit(tid, &wcid->ampdu_state))
+		ieee80211_start_tx_ba_session(sta, tid, 0);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				       struct ieee80211_radiotap_he

*he,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +39 -0
+				       __le32 *rxv)
+{
+	u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0;
+
+	status->bw = RATE_INFO_BW_HE_RU;
+
+	switch (ru) {
+	case 0 ... 36:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+		offs = ru;
+		break;
+	case 37 ... 52:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+		offs = ru - 37;
+		break;
+	case 53 ... 60:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+		offs = ru - 53;
+		break;
+	case 61 ... 64:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+		offs = ru - 61;
+		break;
+	case 65 ... 66:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+		offs = ru - 65;
+		break;
+	case 67:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+		break;
+	case 68:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+		break;
+	}
+
+	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+		     le16_encode_bits(offs,
+				      IEEE80211_RADIOTAP_HE_DATA2_RU_OF

FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+}
+
+#define MU_PREP(f, v)	le16_encode_bits(v,

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32

*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb-
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+	static const struct ieee80211_radiotap_he_mu mu_known = {
+		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
+		.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+	};
+	struct ieee80211_radiotap_he_mu *he_mu;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+	he_mu = skb_push(skb, sizeof(mu_known));
+	memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
+	if (status->he_dcm)
+		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status-
Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
+			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+				 le32_get_bits(rxv[4],

MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) &

0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+	if (status->bw >= RATE_INFO_BW_40) {
+		he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+		he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+	}
+
+	if (status->bw >= RATE_INFO_BW_80) {
+		u32 ru_h, ru_l;
+
+		he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+
+		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
+		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
+		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+	}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32

*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+					 u8 mode)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb-
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +28 -0
+	static const struct ieee80211_radiotap_he known = {
+		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
+			 HE_BITS(DATA1_STBC_KNOWN) |
+			 HE_BITS(DATA1_CODING_KNOWN) |
+			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+			 HE_BITS(DATA1_DOPPLER_KNOWN) |
+			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
+		.data2 = HE_BITS(DATA2_GI_KNOWN) |
+			 HE_BITS(DATA2_TXBF_KNOWN) |
+			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+			 HE_BITS(DATA2_TXOP_KNOWN),
+	};
+	u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
+	struct ieee80211_radiotap_he *he;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE;
+
+	he = skb_push(skb, sizeof(known));
+	memcpy(he, &known, sizeof(known));
+
+	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
+		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
+	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
+	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
+		    le16_encode_bits(ltf_size,
+				     IEEE80211_RADIOTAP_HE_DATA5_LTF_SI

ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+		he->data5 |= HE_BITS(DATA5_TXBF);
+	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+	switch (mode) {
+	case MT_PHY_TYPE_HE_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG,

rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		break;
+	case MT_PHY_TYPE_HE_EXT_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		break;
+	case MT_PHY_TYPE_HE_MU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+		mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
+		break;
+	case MT_PHY_TYPE_HE_TB:
+		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK,

rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +119 -0
+				  __le32 *rxv, u8 *mode)
+{
+	u8 stbc, gi, bw, dcm, nss;
+	bool cck = false;
+	u32 v0, v2;
+	int i, idx;
+
+	v0 = le32_to_cpu(rxv[0]);
+	v2 = le32_to_cpu(rxv[2]);
+
+	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+	i = idx;
+	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+	dcm = FIELD_GET(MT_PRXV_DCM, v2);
+	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+	switch (*mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		i = mt76_get_rate(dev, sband, i, cck);
+		break;
+	case MT_PHY_TYPE_HT_GF:
+	case MT_PHY_TYPE_HT:
+		status->encoding = RX_ENC_HT;
+		if (gi)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (i > 31)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_VHT:
+		status->nss = nss;
+		status->encoding = RX_ENC_VHT;
+		if (gi)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (i > 11)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_HE_MU:
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+		status->nss = nss;
+		status->encoding = RX_ENC_HE;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+			status->he_gi = gi;
+
+		status->he_dcm = dcm;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		status->nss = nss;
+		status->encoding = RX_ENC_EHT;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+			status->eht.gi = gi;
+		break;
+	default:
+		return -EINVAL;
+	}
+	status->rate_idx = i;
+
+	switch (bw) {
+	case IEEE80211_STA_RX_BW_20:
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+		    (idx & MT_PRXV_TX_ER_SU_106T)) {
+			status->bw = RATE_INFO_BW_HE_RU;
+			status->he_ru =
+				NL80211_RATE_INFO_HE_RU_ALLOC_106;
+		} else {
+			status->bw = RATE_INFO_BW_40;
+		}
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		status->bw = RATE_INFO_BW_80;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		status->bw = RATE_INFO_BW_160;
+		break;
+	case IEEE80211_STA_RX_BW_320:
+		status->bw = RATE_INFO_BW_320;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+	if (*mode < MT_PHY_TYPE_HE_SU && gi)
+		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,
+				 struct mt76_wcid *wcid)
+{
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	u8 fc_type, fc_stype;
+	u16 ethertype;
+	bool wmm = false;
+	u32 val;
+
+	if (wcid->sta) {
+		struct ieee80211_sta *sta;
+
+		sta = container_of((void *)wcid, struct ieee80211_sta,

drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +23 -0
+		wmm = sta->wme;
+	}
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	ethertype = get_unaligned_be16(&skb->data[12]);
+	if (ethertype >= ETH_P_802_3_MIN)
+		val |= MT_TXD1_ETH_802_3;
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = IEEE80211_FTYPE_DATA >> 2;
+	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev, __le32

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+				  struct sk_buff *skb,
+				  struct ieee80211_key_conf *key)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb-
Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	bool multicast = is_multicast_ether_addr(hdr->addr1);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	__le16 fc = hdr->frame_control;
+	u8 fc_type, fc_stype;
+	u32 val;
+
+	if (ieee80211_is_action(fc) &&
+	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+	    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +47 -0
+		tid = MT_TX_ADDBA;
+	else if (ieee80211_is_mgmt(hdr->frame_control))
+		tid = MT_TX_NORMAL;
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
+	      FIELD_PREP(MT_TXD1_HDR_INFO,
+			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	if (!ieee80211_is_data(fc) || multicast ||
+	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+		val |= MT_TXD1_FIXED_RATE;
+
+	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
+	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		val |= MT_TXD1_BIP;
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+	}
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
+	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+
+	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
+	if (ieee80211_is_beacon(fc)) {
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+		if (ieee80211_is_back_req(hdr->frame_control)) {
+			struct ieee80211_bar *bar;
+
+			bar = (struct ieee80211_bar *)skb->data;
+			seqno = le16_to_cpu(bar->start_seq_num);
+		}
+
+		val = MT_TXD3_SN_VALID |
+		      FIELD_PREP(MT_TXD3_SEQ,

IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+		txwi[3] |= cpu_to_le32(val);
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+	}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
+				 struct sk_buff *skb, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct ieee80211_key_conf *key, int

pid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+				 enum mt76_txq_id qid, u32 changed)
+{
+	u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :

MT_SDIO_TXD_SIZE;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = info->control.vif;
+	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+	struct mt76_vif *mvif;
+	u16 tx_count = 15;
+	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+				    BSS_CHANGED_BEACON_ENABLED));
+	bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+					 BSS_CHANGED_FILS_DISCOVERY));
+
+	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+	if (mvif) {
+		omac_idx = mvif->omac_idx;
+		wmm_idx = mvif->wmm_idx;
+		band_idx = mvif->band_idx;
+	}
+
+	if (inband_disc) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_ALTX0;
+	} else if (beacon) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_BCN0;
+	} else if (qid >= MT_TXQ_PSD) {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+		q_idx = MT_LMAC_ALTX0;
+	} else {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+			mt76_connac_lmac_mapping(skb_get_queue_mapping(

skb));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +45 -0
+	}
+
+	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
+	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+	txwi[0] = cpu_to_le32(val);
+
+	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+	if (band_idx)
+		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+	txwi[1] = cpu_to_le32(val);
+	txwi[2] = 0;
+
+	val = MT_TXD3_SW_POWER_MGMT |
+	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+	if (key)
+		val |= MT_TXD3_PROTECT_FRAME;
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		val |= MT_TXD3_NO_ACK;
+	if (wcid->amsdu)
+		val |= MT_TXD3_HW_AMSDU;
+
+	txwi[3] = cpu_to_le32(val);
+	txwi[4] = 0;
+
+	val = FIELD_PREP(MT_TXD5_PID, pid);
+	if (pid >= MT_PACKET_ID_FIRST)
+		val |= MT_TXD5_TX_STATUS_HOST;
+	txwi[5] = cpu_to_le32(val);
+
+	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+	txwi[6] = cpu_to_le32(val);
+	txwi[7] = 0;
+
+	if (is_8023)
+		mt76_connac3_mac_write_txwi_8023(txwi, skb, wcid);
+	else
+		mt76_connac3_mac_write_txwi_80211(dev, txwi, skb, key);
+
+	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +14 -0
+		bool mcast = ieee80211_is_data(hdr->frame_control) &&
+			     is_multicast_ether_addr(hdr->addr1);
+		u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+		if (mvif) {
+			if (mcast && mvif->mcast_rates_idx)
+				idx = mvif->mcast_rates_idx;
+			else if (beacon && mvif->beacon_rates_idx)
+				idx = mvif->beacon_rates_idx;
+			else
+				idx = mvif->basic_rates_idx;
+		}
+
+		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,

idx));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list)
+{
+	__le32 *txwi;
+	u16 wcid_idx;
+
+	mt76_connac_txp_skb_unmap(dev, t);
+	if (!t->skb)
+		goto out;
+
+	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+	if (sta) {
+		struct mt76_wcid *wcid = (struct mt76_wcid *)sta-
Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+
+		wcid_idx = wcid->idx;
+		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+			mt76_connac3_tx_check_aggr(sta, txwi);
+	} else {
+		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+	}
+
+	__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
+out:
+	t->skb = NULL;
+	mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +58 -0
+			     int pid, __le32 *txs_data)
+{
+	struct mt76_sta_stats *stats = &wcid->stats;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_tx_info *info;
+	u32 txrate, txs, mode, stbc;
+	struct rate_info rate = {};
+	struct sk_buff_head list;
+	struct mt76_phy *mphy;
+	struct sk_buff *skb;
+	bool cck = false;
+
+	mt76_tx_status_lock(dev, &list);
+	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+	if (!skb)
+		goto out_no_skb;
+
+	txs = le32_to_cpu(txs_data[0]);
+
+	info = IEEE80211_SKB_CB(skb);
+	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	info->status.ampdu_len = 1;
+	info->status.ampdu_ack_len = !!(info->flags &
+					IEEE80211_TX_STAT_ACK);
+	info->status.rates[0].idx = -1;
+
+	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+	if (stbc && rate.nss > 1)
+		rate.nss >>= 1;
+
+	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+		stats->tx_nss[rate.nss - 1]++;
+	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+		stats->tx_mcs[rate.mcs]++;
+
+	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+	switch (mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+			sband = &mphy->sband_5g.sband;
+		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
+			sband = &mphy->sband_6g.sband;
+		else
+			sband = &mphy->sband_2g.sband;
+
+		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs,

cck);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +130 -0
+		rate.legacy = sband->bitrates[rate.mcs].bitrate;
+		break;
+	case MT_PHY_TYPE_HT:
+	case MT_PHY_TYPE_HT_GF:
+		if (rate.mcs > 31)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_MCS;
+		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		break;
+	case MT_PHY_TYPE_VHT:
+		if (rate.mcs > 9)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+		break;
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+	case MT_PHY_TYPE_HE_MU:
+		if (rate.mcs > 11)
+			goto out;
+
+		rate.he_gi = wcid->rate.he_gi;
+		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
+		rate.flags = RATE_INFO_FLAGS_HE_MCS;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		if (rate.mcs > 13)
+			goto out;
+
+		rate.eht_gi = wcid->rate.eht_gi;
+		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+		break;
+	default:
+		goto out;
+	}
+
+	stats->tx_mode[mode]++;
+
+	switch (FIELD_GET(MT_TXS0_BW, txs)) {
+	case IEEE80211_STA_RX_BW_320:
+		rate.bw = RATE_INFO_BW_320;
+		stats->tx_bw[4]++;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		rate.bw = RATE_INFO_BW_160;
+		stats->tx_bw[3]++;
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		rate.bw = RATE_INFO_BW_80;
+		stats->tx_bw[2]++;
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		rate.bw = RATE_INFO_BW_40;
+		stats->tx_bw[1]++;
+		break;
+	default:
+		rate.bw = RATE_INFO_BW_20;
+		stats->tx_bw[0]++;
+		break;
+	}
+	wcid->rate = rate;
+
+out:
+	mt76_tx_status_skb_done(dev, skb, &list);
+
+out_no_skb:
+	mt76_tx_status_unlock(dev, &list);
+
+	return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size)
+{
+	struct mt76_wcid *wcid;
+	__le32 *txs_data = data;
+	u16 wcidx;
+	u8 pid;
+
+	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
+		return;
+
+	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+	if (pid < MT_PACKET_ID_FIRST)
+		return;
+
+	if (wcidx >= max_wtbl_size)
+		return;
+
+	rcu_read_lock();
+
+	wcid = rcu_dereference(dev->wcid[wcidx]);
+	if (!wcid)
+		goto out;
+
+	mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
+	if (!wcid->sta)
+		goto out;
+
+	spin_lock_bh(&dev->sta_poll_lock);
+	if (list_empty(&wcid->poll_list))
+		list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
+	spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *txwi;
+	int id;
+
+	spin_lock_bh(&dev->token_lock);
+	idr_for_each_entry(&dev->token, txwi, id) {
+		mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+		dev->token_count--;
+	}
+	spin_unlock_bh(&dev->token_lock);
+	idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +1 -0
index 6663a0b46541..bcc1d976b2b0 100644
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
+/* NOTE: used to map mt76_rates. idx may change if firmware expands

table */

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h line 9

Quoted 2 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL	11
+#define MT76_CONNAC3_BEACON_RATES_TBL	25

Different devices may have different defined value.

I'm thinking if it's too early to create this patch for just moving mt7996 to connac3_lib?

Ryder

#17 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

Quoted 880 lines · Ryder Lee
Quoted 879 lines · Lorenzo Bianconi

External email : Please do not click links or open attachments until you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse mac code
shared
between WiFi7 chipsets.

---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +
 .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +---------------
--
 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-)
 create mode 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/Makefile +1 -1
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o
 mt76x02_mcu.o \
 
 mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o

mt76_connac3_mac.o

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
index 68bdeada1421..20111678537b 100644
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct mt76_dev
 *dev, struct mt76_txwi_cache *t,
 			    struct list_head *free_list);
 void mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta, __le32

*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +4 -0
+					 u8 mode);
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+				  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
+				 struct sk_buff *skb, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct ieee80211_key_conf *key, int

pid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+				 enum mt76_txq_id qid, u32 changed);
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list);
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
new file mode 100644
index 000000000000..4b745bb74ca0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
+#define HE_PREP(f, m, v)	le16_encode_bits(le32_get_bits(v,

MT_CRXV_HE_##m),\

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+						 IEEE80211_RADIOTAP_HE_

##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta, __le32

*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+{
+	struct mt76_wcid *wcid;
+	u16 fc, tid;
+	u32 val;
+
+	if (!sta ||
+	    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+	if (tid >= 6) /* skip VO queue */
+		return;
+
+	val = le32_to_cpu(txwi[2]);
+	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+	if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	wcid = (struct mt76_wcid *)sta->drv_priv;
+	if (!test_and_set_bit(tid, &wcid->ampdu_state))
+		ieee80211_start_tx_ba_session(sta, tid, 0);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				       struct ieee80211_radiotap_he

*he,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +39 -0
+				       __le32 *rxv)
+{
+	u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0;
+
+	status->bw = RATE_INFO_BW_HE_RU;
+
+	switch (ru) {
+	case 0 ... 36:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+		offs = ru;
+		break;
+	case 37 ... 52:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+		offs = ru - 37;
+		break;
+	case 53 ... 60:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+		offs = ru - 53;
+		break;
+	case 61 ... 64:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+		offs = ru - 61;
+		break;
+	case 65 ... 66:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+		offs = ru - 65;
+		break;
+	case 67:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+		break;
+	case 68:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+		break;
+	}
+
+	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+		     le16_encode_bits(offs,
+				      IEEE80211_RADIOTAP_HE_DATA2_RU_OF

FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+}
+
+#define MU_PREP(f, v)	le16_encode_bits(v,

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32

*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb-
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+	static const struct ieee80211_radiotap_he_mu mu_known = {
+		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
+		.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+	};
+	struct ieee80211_radiotap_he_mu *he_mu;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+	he_mu = skb_push(skb, sizeof(mu_known));
+	memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
+	if (status->he_dcm)
+		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status-
Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
+			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+				 le32_get_bits(rxv[4],

MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) &

0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+	if (status->bw >= RATE_INFO_BW_40) {
+		he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+		he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+	}
+
+	if (status->bw >= RATE_INFO_BW_80) {
+		u32 ru_h, ru_l;
+
+		he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+
+		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
+		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
+		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+	}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32

*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+					 u8 mode)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb-
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +28 -0
+	static const struct ieee80211_radiotap_he known = {
+		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
+			 HE_BITS(DATA1_STBC_KNOWN) |
+			 HE_BITS(DATA1_CODING_KNOWN) |
+			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+			 HE_BITS(DATA1_DOPPLER_KNOWN) |
+			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
+		.data2 = HE_BITS(DATA2_GI_KNOWN) |
+			 HE_BITS(DATA2_TXBF_KNOWN) |
+			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+			 HE_BITS(DATA2_TXOP_KNOWN),
+	};
+	u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
+	struct ieee80211_radiotap_he *he;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE;
+
+	he = skb_push(skb, sizeof(known));
+	memcpy(he, &known, sizeof(known));
+
+	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
+		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
+	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
+	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
+		    le16_encode_bits(ltf_size,
+				     IEEE80211_RADIOTAP_HE_DATA5_LTF_SI

ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+		he->data5 |= HE_BITS(DATA5_TXBF);
+	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+	switch (mode) {
+	case MT_PHY_TYPE_HE_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG,

rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		break;
+	case MT_PHY_TYPE_HE_EXT_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		break;
+	case MT_PHY_TYPE_HE_MU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+		mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
+		break;
+	case MT_PHY_TYPE_HE_TB:
+		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK,

rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +119 -0
+				  __le32 *rxv, u8 *mode)
+{
+	u8 stbc, gi, bw, dcm, nss;
+	bool cck = false;
+	u32 v0, v2;
+	int i, idx;
+
+	v0 = le32_to_cpu(rxv[0]);
+	v2 = le32_to_cpu(rxv[2]);
+
+	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+	i = idx;
+	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+	dcm = FIELD_GET(MT_PRXV_DCM, v2);
+	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+	switch (*mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		i = mt76_get_rate(dev, sband, i, cck);
+		break;
+	case MT_PHY_TYPE_HT_GF:
+	case MT_PHY_TYPE_HT:
+		status->encoding = RX_ENC_HT;
+		if (gi)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (i > 31)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_VHT:
+		status->nss = nss;
+		status->encoding = RX_ENC_VHT;
+		if (gi)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (i > 11)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_HE_MU:
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+		status->nss = nss;
+		status->encoding = RX_ENC_HE;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+			status->he_gi = gi;
+
+		status->he_dcm = dcm;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		status->nss = nss;
+		status->encoding = RX_ENC_EHT;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+			status->eht.gi = gi;
+		break;
+	default:
+		return -EINVAL;
+	}
+	status->rate_idx = i;
+
+	switch (bw) {
+	case IEEE80211_STA_RX_BW_20:
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+		    (idx & MT_PRXV_TX_ER_SU_106T)) {
+			status->bw = RATE_INFO_BW_HE_RU;
+			status->he_ru =
+				NL80211_RATE_INFO_HE_RU_ALLOC_106;
+		} else {
+			status->bw = RATE_INFO_BW_40;
+		}
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		status->bw = RATE_INFO_BW_80;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		status->bw = RATE_INFO_BW_160;
+		break;
+	case IEEE80211_STA_RX_BW_320:
+		status->bw = RATE_INFO_BW_320;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+	if (*mode < MT_PHY_TYPE_HE_SU && gi)
+		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,
+				 struct mt76_wcid *wcid)
+{
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	u8 fc_type, fc_stype;
+	u16 ethertype;
+	bool wmm = false;
+	u32 val;
+
+	if (wcid->sta) {
+		struct ieee80211_sta *sta;
+
+		sta = container_of((void *)wcid, struct ieee80211_sta,

drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +23 -0
+		wmm = sta->wme;
+	}
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	ethertype = get_unaligned_be16(&skb->data[12]);
+	if (ethertype >= ETH_P_802_3_MIN)
+		val |= MT_TXD1_ETH_802_3;
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = IEEE80211_FTYPE_DATA >> 2;
+	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev, __le32

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+				  struct sk_buff *skb,
+				  struct ieee80211_key_conf *key)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb-
Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	bool multicast = is_multicast_ether_addr(hdr->addr1);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	__le16 fc = hdr->frame_control;
+	u8 fc_type, fc_stype;
+	u32 val;
+
+	if (ieee80211_is_action(fc) &&
+	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+	    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +47 -0
+		tid = MT_TX_ADDBA;
+	else if (ieee80211_is_mgmt(hdr->frame_control))
+		tid = MT_TX_NORMAL;
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
+	      FIELD_PREP(MT_TXD1_HDR_INFO,
+			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	if (!ieee80211_is_data(fc) || multicast ||
+	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+		val |= MT_TXD1_FIXED_RATE;
+
+	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
+	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		val |= MT_TXD1_BIP;
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+	}
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
+	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+
+	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
+	if (ieee80211_is_beacon(fc)) {
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+		if (ieee80211_is_back_req(hdr->frame_control)) {
+			struct ieee80211_bar *bar;
+
+			bar = (struct ieee80211_bar *)skb->data;
+			seqno = le16_to_cpu(bar->start_seq_num);
+		}
+
+		val = MT_TXD3_SN_VALID |
+		      FIELD_PREP(MT_TXD3_SEQ,

IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+		txwi[3] |= cpu_to_le32(val);
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+	}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
+				 struct sk_buff *skb, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct ieee80211_key_conf *key, int

pid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+				 enum mt76_txq_id qid, u32 changed)
+{
+	u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :

MT_SDIO_TXD_SIZE;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = info->control.vif;
+	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+	struct mt76_vif *mvif;
+	u16 tx_count = 15;
+	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+				    BSS_CHANGED_BEACON_ENABLED));
+	bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+					 BSS_CHANGED_FILS_DISCOVERY));
+
+	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+	if (mvif) {
+		omac_idx = mvif->omac_idx;
+		wmm_idx = mvif->wmm_idx;
+		band_idx = mvif->band_idx;
+	}
+
+	if (inband_disc) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_ALTX0;
+	} else if (beacon) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_BCN0;
+	} else if (qid >= MT_TXQ_PSD) {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+		q_idx = MT_LMAC_ALTX0;
+	} else {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+			mt76_connac_lmac_mapping(skb_get_queue_mapping(

skb));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +45 -0
+	}
+
+	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
+	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+	txwi[0] = cpu_to_le32(val);
+
+	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+	if (band_idx)
+		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+	txwi[1] = cpu_to_le32(val);
+	txwi[2] = 0;
+
+	val = MT_TXD3_SW_POWER_MGMT |
+	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+	if (key)
+		val |= MT_TXD3_PROTECT_FRAME;
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		val |= MT_TXD3_NO_ACK;
+	if (wcid->amsdu)
+		val |= MT_TXD3_HW_AMSDU;
+
+	txwi[3] = cpu_to_le32(val);
+	txwi[4] = 0;
+
+	val = FIELD_PREP(MT_TXD5_PID, pid);
+	if (pid >= MT_PACKET_ID_FIRST)
+		val |= MT_TXD5_TX_STATUS_HOST;
+	txwi[5] = cpu_to_le32(val);
+
+	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+	txwi[6] = cpu_to_le32(val);
+	txwi[7] = 0;
+
+	if (is_8023)
+		mt76_connac3_mac_write_txwi_8023(txwi, skb, wcid);
+	else
+		mt76_connac3_mac_write_txwi_80211(dev, txwi, skb, key);
+
+	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +14 -0
+		bool mcast = ieee80211_is_data(hdr->frame_control) &&
+			     is_multicast_ether_addr(hdr->addr1);
+		u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+		if (mvif) {
+			if (mcast && mvif->mcast_rates_idx)
+				idx = mvif->mcast_rates_idx;
+			else if (beacon && mvif->beacon_rates_idx)
+				idx = mvif->beacon_rates_idx;
+			else
+				idx = mvif->basic_rates_idx;
+		}
+
+		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,

idx));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list)
+{
+	__le32 *txwi;
+	u16 wcid_idx;
+
+	mt76_connac_txp_skb_unmap(dev, t);
+	if (!t->skb)
+		goto out;
+
+	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+	if (sta) {
+		struct mt76_wcid *wcid = (struct mt76_wcid *)sta-
Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+
+		wcid_idx = wcid->idx;
+		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+			mt76_connac3_tx_check_aggr(sta, txwi);
+	} else {
+		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+	}
+
+	__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
+out:
+	t->skb = NULL;
+	mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +58 -0
+			     int pid, __le32 *txs_data)
+{
+	struct mt76_sta_stats *stats = &wcid->stats;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_tx_info *info;
+	u32 txrate, txs, mode, stbc;
+	struct rate_info rate = {};
+	struct sk_buff_head list;
+	struct mt76_phy *mphy;
+	struct sk_buff *skb;
+	bool cck = false;
+
+	mt76_tx_status_lock(dev, &list);
+	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+	if (!skb)
+		goto out_no_skb;
+
+	txs = le32_to_cpu(txs_data[0]);
+
+	info = IEEE80211_SKB_CB(skb);
+	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	info->status.ampdu_len = 1;
+	info->status.ampdu_ack_len = !!(info->flags &
+					IEEE80211_TX_STAT_ACK);
+	info->status.rates[0].idx = -1;
+
+	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+	if (stbc && rate.nss > 1)
+		rate.nss >>= 1;
+
+	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+		stats->tx_nss[rate.nss - 1]++;
+	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+		stats->tx_mcs[rate.mcs]++;
+
+	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+	switch (mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+			sband = &mphy->sband_5g.sband;
+		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
+			sband = &mphy->sband_6g.sband;
+		else
+			sband = &mphy->sband_2g.sband;
+
+		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs,

cck);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +130 -0
+		rate.legacy = sband->bitrates[rate.mcs].bitrate;
+		break;
+	case MT_PHY_TYPE_HT:
+	case MT_PHY_TYPE_HT_GF:
+		if (rate.mcs > 31)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_MCS;
+		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		break;
+	case MT_PHY_TYPE_VHT:
+		if (rate.mcs > 9)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+		break;
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+	case MT_PHY_TYPE_HE_MU:
+		if (rate.mcs > 11)
+			goto out;
+
+		rate.he_gi = wcid->rate.he_gi;
+		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
+		rate.flags = RATE_INFO_FLAGS_HE_MCS;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		if (rate.mcs > 13)
+			goto out;
+
+		rate.eht_gi = wcid->rate.eht_gi;
+		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+		break;
+	default:
+		goto out;
+	}
+
+	stats->tx_mode[mode]++;
+
+	switch (FIELD_GET(MT_TXS0_BW, txs)) {
+	case IEEE80211_STA_RX_BW_320:
+		rate.bw = RATE_INFO_BW_320;
+		stats->tx_bw[4]++;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		rate.bw = RATE_INFO_BW_160;
+		stats->tx_bw[3]++;
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		rate.bw = RATE_INFO_BW_80;
+		stats->tx_bw[2]++;
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		rate.bw = RATE_INFO_BW_40;
+		stats->tx_bw[1]++;
+		break;
+	default:
+		rate.bw = RATE_INFO_BW_20;
+		stats->tx_bw[0]++;
+		break;
+	}
+	wcid->rate = rate;
+
+out:
+	mt76_tx_status_skb_done(dev, skb, &list);
+
+out_no_skb:
+	mt76_tx_status_unlock(dev, &list);
+
+	return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size)
+{
+	struct mt76_wcid *wcid;
+	__le32 *txs_data = data;
+	u16 wcidx;
+	u8 pid;
+
+	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
+		return;
+
+	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+	if (pid < MT_PACKET_ID_FIRST)
+		return;
+
+	if (wcidx >= max_wtbl_size)
+		return;
+
+	rcu_read_lock();
+
+	wcid = rcu_dereference(dev->wcid[wcidx]);
+	if (!wcid)
+		goto out;
+
+	mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
+	if (!wcid->sta)
+		goto out;
+
+	spin_lock_bh(&dev->sta_poll_lock);
+	if (list_empty(&wcid->poll_list))
+		list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
+	spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *txwi;
+	int id;
+
+	spin_lock_bh(&dev->token_lock);
+	idr_for_each_entry(&dev->token, txwi, id) {
+		mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+		dev->token_count--;
+	}
+	spin_unlock_bh(&dev->token_lock);
+	idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +0 -0
index 6663a0b46541..bcc1d976b2b0 100644
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
Quoted 7 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h line 9

Quoted 5 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +1 -0
+/* NOTE: used to map mt76_rates. idx may change if firmware expands

table */

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL	11
+#define MT76_CONNAC3_BEACON_RATES_TBL	25

Different devices may have different defined value.

The other WiFi7 device I am working on relies on the values I moved in mt76_connac3_mac.h (in common with mt7996). Moreover you can still have per-device values in mt7996/mac.h (I have not removed it).

Quoted 3 lines

I'm thinking if it's too early to create this patch for just moving mt7996 to connac3_lib?

The code I moved is used by the other device as well. This series is a preliminary series to support it.

Regards,
Lorenzo

Quoted 3 lines

Ryder

maintainer
#18 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

Quoted 910 lines · On Fri, 2023-06-09 at 18:34 +0200, [email protected] wrote:
Quoted 900 lines · Ryder Lee
Quoted 899 lines · Lorenzo Bianconi

External email : Please do not click links or open attachments until
you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse mac code
shared
between WiFi7 chipsets.

---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +
 .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +-----------
----
--
 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-)
 create mode 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/Makefile +1 -1
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o
 mt76x02_mcu.o \
 
 mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o

mt76_connac3_mac.o

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
index 68bdeada1421..20111678537b 100644
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct mt76_dev
 *dev, struct mt76_txwi_cache *t,
 			    struct list_head *free_list);
 void mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32
*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +4 -0
+					 u8 mode);
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+				  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct sk_buff *skb, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct ieee80211_key_conf *key, int

pid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+				 enum mt76_txq_id qid, u32 changed);
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list);
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file mode 100644
index 000000000000..4b745bb74ca0

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_

HE_##f)
+#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v,
MT_CRXV_HE_##m),\

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+						 IEEE80211_RADIOTAP_HE_

##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+{
+	struct mt76_wcid *wcid;
+	u16 fc, tid;
+	u32 val;
+
+	if (!sta ||
+	    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+	if (tid >= 6) /* skip VO queue */
+		return;
+
+	val = le32_to_cpu(txwi[2]);
+	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+	if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	wcid = (struct mt76_wcid *)sta->drv_priv;
+	if (!test_and_set_bit(tid, &wcid->ampdu_state))
+		ieee80211_start_tx_ba_session(sta, tid, 0);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				       struct ieee80211_radiotap_he

*he,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +39 -0
+				       __le32 *rxv)
+{
+	u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0;
+
+	status->bw = RATE_INFO_BW_HE_RU;
+
+	switch (ru) {
+	case 0 ... 36:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+		offs = ru;
+		break;
+	case 37 ... 52:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+		offs = ru - 37;
+		break;
+	case 53 ... 60:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+		offs = ru - 53;
+		break;
+	case 61 ... 64:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+		offs = ru - 61;
+		break;
+	case 65 ... 66:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+		offs = ru - 65;
+		break;
+	case 67:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+		break;
+	case 68:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+		break;
+	}
+
+	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+		     le16_encode_bits(offs,
+				      IEEE80211_RADIOTAP_HE_DATA2_RU_OF

FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+}
+
+#define MU_PREP(f, v)	le16_encode_bits(v,

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb,

__le32
*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb-
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+	static const struct ieee80211_radiotap_he_mu mu_known = {
+		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
+		.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+	};
+	struct ieee80211_radiotap_he_mu *he_mu;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+	he_mu = skb_push(skb, sizeof(mu_known));
+	memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
+	if (status->he_dcm)
+		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status-
Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
+			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+				 le32_get_bits(rxv[4],

MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) &

0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+	if (status->bw >= RATE_INFO_BW_40) {
+		he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+		he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+	}
+
+	if (status->bw >= RATE_INFO_BW_80) {
+		u32 ru_h, ru_l;
+
+		he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+
+		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
+		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
+		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+	}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb,

__le32
*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+					 u8 mode)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb-
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +28 -0
+	static const struct ieee80211_radiotap_he known = {
+		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
+			 HE_BITS(DATA1_STBC_KNOWN) |
+			 HE_BITS(DATA1_CODING_KNOWN) |
+			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+			 HE_BITS(DATA1_DOPPLER_KNOWN) |
+			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
+		.data2 = HE_BITS(DATA2_GI_KNOWN) |
+			 HE_BITS(DATA2_TXBF_KNOWN) |
+			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+			 HE_BITS(DATA2_TXOP_KNOWN),
+	};
+	u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
+	struct ieee80211_radiotap_he *he;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE;
+
+	he = skb_push(skb, sizeof(known));
+	memcpy(he, &known, sizeof(known));
+
+	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
+		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
+	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
+	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
+		    le16_encode_bits(ltf_size,
+				     IEEE80211_RADIOTAP_HE_DATA5_LTF_SI

ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+		he->data5 |= HE_BITS(DATA5_TXBF);
+	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+	switch (mode) {
+	case MT_PHY_TYPE_HE_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG,

rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		break;
+	case MT_PHY_TYPE_HE_EXT_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		break;
+	case MT_PHY_TYPE_HE_MU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+		mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
+		break;
+	case MT_PHY_TYPE_HE_TB:
+		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK,

rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +107 -0
+				  __le32 *rxv, u8 *mode)
+{
+	u8 stbc, gi, bw, dcm, nss;
+	bool cck = false;
+	u32 v0, v2;
+	int i, idx;
+
+	v0 = le32_to_cpu(rxv[0]);
+	v2 = le32_to_cpu(rxv[2]);
+
+	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+	i = idx;
+	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+	dcm = FIELD_GET(MT_PRXV_DCM, v2);
+	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+	switch (*mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		i = mt76_get_rate(dev, sband, i, cck);
+		break;
+	case MT_PHY_TYPE_HT_GF:
+	case MT_PHY_TYPE_HT:
+		status->encoding = RX_ENC_HT;
+		if (gi)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (i > 31)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_VHT:
+		status->nss = nss;
+		status->encoding = RX_ENC_VHT;
+		if (gi)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (i > 11)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_HE_MU:
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+		status->nss = nss;
+		status->encoding = RX_ENC_HE;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+			status->he_gi = gi;
+
+		status->he_dcm = dcm;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		status->nss = nss;
+		status->encoding = RX_ENC_EHT;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+			status->eht.gi = gi;
+		break;
+	default:
+		return -EINVAL;
+	}
+	status->rate_idx = i;
+
+	switch (bw) {
+	case IEEE80211_STA_RX_BW_20:
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+		    (idx & MT_PRXV_TX_ER_SU_106T)) {
+			status->bw = RATE_INFO_BW_HE_RU;
+			status->he_ru =
+				NL80211_RATE_INFO_HE_RU_ALLOC_106;
+		} else {
+			status->bw = RATE_INFO_BW_40;
+		}
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		status->bw = RATE_INFO_BW_80;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		status->bw = RATE_INFO_BW_160;
+		break;
+	case IEEE80211_STA_RX_BW_320:
+		status->bw = RATE_INFO_BW_320;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+	if (*mode < MT_PHY_TYPE_HE_SU && gi)
+		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct sk_buff

*skb,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +12 -0
+				 struct mt76_wcid *wcid)
+{
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	u8 fc_type, fc_stype;
+	u16 ethertype;
+	bool wmm = false;
+	u32 val;
+
+	if (wcid->sta) {
+		struct ieee80211_sta *sta;
+
+		sta = container_of((void *)wcid, struct ieee80211_sta,

drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +23 -0
+		wmm = sta->wme;
+	}
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	ethertype = get_unaligned_be16(&skb->data[12]);
+	if (ethertype >= ETH_P_802_3_MIN)
+		val |= MT_TXD1_ETH_802_3;
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = IEEE80211_FTYPE_DATA >> 2;
+	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev, __le32

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+				  struct sk_buff *skb,
+				  struct ieee80211_key_conf *key)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb-
Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	bool multicast = is_multicast_ether_addr(hdr->addr1);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	__le16 fc = hdr->frame_control;
+	u8 fc_type, fc_stype;
+	u32 val;
+
+	if (ieee80211_is_action(fc) &&
+	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+	    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +47 -0
+		tid = MT_TX_ADDBA;
+	else if (ieee80211_is_mgmt(hdr->frame_control))
+		tid = MT_TX_NORMAL;
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
+	      FIELD_PREP(MT_TXD1_HDR_INFO,
+			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	if (!ieee80211_is_data(fc) || multicast ||
+	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+		val |= MT_TXD1_FIXED_RATE;
+
+	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
+	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		val |= MT_TXD1_BIP;
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+	}
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
+	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+
+	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
+	if (ieee80211_is_beacon(fc)) {
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+		if (ieee80211_is_back_req(hdr->frame_control)) {
+			struct ieee80211_bar *bar;
+
+			bar = (struct ieee80211_bar *)skb->data;
+			seqno = le16_to_cpu(bar->start_seq_num);
+		}
+
+		val = MT_TXD3_SN_VALID |
+		      FIELD_PREP(MT_TXD3_SEQ,

IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(val);
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+	}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct sk_buff *skb, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct ieee80211_key_conf *key, int

pid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+				 enum mt76_txq_id qid, u32 changed)
+{
+	u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :

MT_SDIO_TXD_SIZE;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = info->control.vif;
+	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+	struct mt76_vif *mvif;
+	u16 tx_count = 15;
+	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+				    BSS_CHANGED_BEACON_ENABLED));
+	bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+					 BSS_CHANGED_FILS_DISCOVERY));
+
+	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+	if (mvif) {
+		omac_idx = mvif->omac_idx;
+		wmm_idx = mvif->wmm_idx;
+		band_idx = mvif->band_idx;
+	}
+
+	if (inband_disc) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_ALTX0;
+	} else if (beacon) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_BCN0;
+	} else if (qid >= MT_TXQ_PSD) {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+		q_idx = MT_LMAC_ALTX0;
+	} else {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+			mt76_connac_lmac_mapping(skb_get_queue_mapping(

skb));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +45 -0
+	}
+
+	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
+	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+	txwi[0] = cpu_to_le32(val);
+
+	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+	if (band_idx)
+		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+	txwi[1] = cpu_to_le32(val);
+	txwi[2] = 0;
+
+	val = MT_TXD3_SW_POWER_MGMT |
+	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+	if (key)
+		val |= MT_TXD3_PROTECT_FRAME;
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		val |= MT_TXD3_NO_ACK;
+	if (wcid->amsdu)
+		val |= MT_TXD3_HW_AMSDU;
+
+	txwi[3] = cpu_to_le32(val);
+	txwi[4] = 0;
+
+	val = FIELD_PREP(MT_TXD5_PID, pid);
+	if (pid >= MT_PACKET_ID_FIRST)
+		val |= MT_TXD5_TX_STATUS_HOST;
+	txwi[5] = cpu_to_le32(val);
+
+	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+	txwi[6] = cpu_to_le32(val);
+	txwi[7] = 0;
+
+	if (is_8023)
+		mt76_connac3_mac_write_txwi_8023(txwi, skb, wcid);
+	else
+		mt76_connac3_mac_write_txwi_80211(dev, txwi, skb, key);
+
+	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +14 -0
+		bool mcast = ieee80211_is_data(hdr->frame_control) &&
+			     is_multicast_ether_addr(hdr->addr1);
+		u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+		if (mvif) {
+			if (mcast && mvif->mcast_rates_idx)
+				idx = mvif->mcast_rates_idx;
+			else if (beacon && mvif->beacon_rates_idx)
+				idx = mvif->beacon_rates_idx;
+			else
+				idx = mvif->basic_rates_idx;
+		}
+
+		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,

idx));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list)
+{
+	__le32 *txwi;
+	u16 wcid_idx;
+
+	mt76_connac_txp_skb_unmap(dev, t);
+	if (!t->skb)
+		goto out;
+
+	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+	if (sta) {
+		struct mt76_wcid *wcid = (struct mt76_wcid *)sta-
Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+
+		wcid_idx = wcid->idx;
+		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+			mt76_connac3_tx_check_aggr(sta, txwi);
+	} else {
+		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+	}
+
+	__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
+out:
+	t->skb = NULL;
+	mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +58 -0
+			     int pid, __le32 *txs_data)
+{
+	struct mt76_sta_stats *stats = &wcid->stats;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_tx_info *info;
+	u32 txrate, txs, mode, stbc;
+	struct rate_info rate = {};
+	struct sk_buff_head list;
+	struct mt76_phy *mphy;
+	struct sk_buff *skb;
+	bool cck = false;
+
+	mt76_tx_status_lock(dev, &list);
+	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+	if (!skb)
+		goto out_no_skb;
+
+	txs = le32_to_cpu(txs_data[0]);
+
+	info = IEEE80211_SKB_CB(skb);
+	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	info->status.ampdu_len = 1;
+	info->status.ampdu_ack_len = !!(info->flags &
+					IEEE80211_TX_STAT_ACK);
+	info->status.rates[0].idx = -1;
+
+	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+	if (stbc && rate.nss > 1)
+		rate.nss >>= 1;
+
+	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+		stats->tx_nss[rate.nss - 1]++;
+	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+		stats->tx_mcs[rate.mcs]++;
+
+	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+	switch (mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+			sband = &mphy->sband_5g.sband;
+		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
+			sband = &mphy->sband_6g.sband;
+		else
+			sband = &mphy->sband_2g.sband;
+
+		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs,

cck);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +130 -0
+		rate.legacy = sband->bitrates[rate.mcs].bitrate;
+		break;
+	case MT_PHY_TYPE_HT:
+	case MT_PHY_TYPE_HT_GF:
+		if (rate.mcs > 31)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_MCS;
+		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		break;
+	case MT_PHY_TYPE_VHT:
+		if (rate.mcs > 9)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+		break;
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+	case MT_PHY_TYPE_HE_MU:
+		if (rate.mcs > 11)
+			goto out;
+
+		rate.he_gi = wcid->rate.he_gi;
+		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
+		rate.flags = RATE_INFO_FLAGS_HE_MCS;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		if (rate.mcs > 13)
+			goto out;
+
+		rate.eht_gi = wcid->rate.eht_gi;
+		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+		break;
+	default:
+		goto out;
+	}
+
+	stats->tx_mode[mode]++;
+
+	switch (FIELD_GET(MT_TXS0_BW, txs)) {
+	case IEEE80211_STA_RX_BW_320:
+		rate.bw = RATE_INFO_BW_320;
+		stats->tx_bw[4]++;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		rate.bw = RATE_INFO_BW_160;
+		stats->tx_bw[3]++;
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		rate.bw = RATE_INFO_BW_80;
+		stats->tx_bw[2]++;
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		rate.bw = RATE_INFO_BW_40;
+		stats->tx_bw[1]++;
+		break;
+	default:
+		rate.bw = RATE_INFO_BW_20;
+		stats->tx_bw[0]++;
+		break;
+	}
+	wcid->rate = rate;
+
+out:
+	mt76_tx_status_skb_done(dev, skb, &list);
+
+out_no_skb:
+	mt76_tx_status_unlock(dev, &list);
+
+	return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size)
+{
+	struct mt76_wcid *wcid;
+	__le32 *txs_data = data;
+	u16 wcidx;
+	u8 pid;
+
+	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
+		return;
+
+	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+	if (pid < MT_PACKET_ID_FIRST)
+		return;
+
+	if (wcidx >= max_wtbl_size)
+		return;
+
+	rcu_read_lock();
+
+	wcid = rcu_dereference(dev->wcid[wcidx]);
+	if (!wcid)
+		goto out;
+
+	mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
+	if (!wcid->sta)
+		goto out;
+
+	spin_lock_bh(&dev->sta_poll_lock);
+	if (list_empty(&wcid->poll_list))
+		list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
+	spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *txwi;
+	int id;
+
+	spin_lock_bh(&dev->token_lock);
+	idr_for_each_entry(&dev->token, txwi, id) {
+		mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+		dev->token_count--;
+	}
+	spin_unlock_bh(&dev->token_lock);
+	idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 6663a0b46541..bcc1d976b2b0 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +0 -0
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h line 9

Quoted 6 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +1 -0
+/* NOTE: used to map mt76_rates. idx may change if firmware

expands
table */

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL	11
+#define MT76_CONNAC3_BEACON_RATES_TBL	25

Different devices may have different defined value.

Quoted 5 lines

The other WiFi7 device I am working on relies on the values I moved in
mt76_connac3_mac.h (in common with mt7996). Moreover you can still have per-device values in mt7996/mac.h (I have not removed it).

Please double check with the mtk folk you work with. The 11 and 25 is the value I discussed with firmware folks to avoid overlapping the tbl mt7996 use (MU/other algo in fw), or it causes something hardly solving issue

Quoted 14 lines
Quoted 3 lines

I'm thinking if it's too early to create this patch for just moving mt7996 to connac3_lib?

The code I moved is used by the other device as well. This series is a
preliminary series to support it.

Regards,
Lorenzo

Quoted 3 lines

Ryder

author maintainer
#19 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

Quoted 917 lines · On Fri, 2023-06-09 at 18:34 +0200, [email protected] wrote:
Quoted 910 lines · Ryder Lee
Quoted 900 lines · Lorenzo Bianconi
Quoted 899 lines

External email : Please do not click links or open attachments until
you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse mac code
shared
between WiFi7 chipsets.

---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +
 .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +-----------
----
--
 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-)
 create mode 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/Makefile +1 -1
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o
 mt76x02_mcu.o \
 
 mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o

mt76_connac3_mac.o

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
index 68bdeada1421..20111678537b 100644
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct mt76_dev
 *dev, struct mt76_txwi_cache *t,
 			    struct list_head *free_list);
 void mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32
*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +4 -0
+					 u8 mode);
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+				  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct sk_buff *skb, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct ieee80211_key_conf *key, int

pid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+				 enum mt76_txq_id qid, u32 changed);
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list);
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file mode 100644
index 000000000000..4b745bb74ca0

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_

HE_##f)
+#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v,
MT_CRXV_HE_##m),\

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+						 IEEE80211_RADIOTAP_HE_

##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+{
+	struct mt76_wcid *wcid;
+	u16 fc, tid;
+	u32 val;
+
+	if (!sta ||
+	    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+	if (tid >= 6) /* skip VO queue */
+		return;
+
+	val = le32_to_cpu(txwi[2]);
+	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+	if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	wcid = (struct mt76_wcid *)sta->drv_priv;
+	if (!test_and_set_bit(tid, &wcid->ampdu_state))
+		ieee80211_start_tx_ba_session(sta, tid, 0);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				       struct ieee80211_radiotap_he

*he,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +39 -0
+				       __le32 *rxv)
+{
+	u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0;
+
+	status->bw = RATE_INFO_BW_HE_RU;
+
+	switch (ru) {
+	case 0 ... 36:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+		offs = ru;
+		break;
+	case 37 ... 52:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+		offs = ru - 37;
+		break;
+	case 53 ... 60:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+		offs = ru - 53;
+		break;
+	case 61 ... 64:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+		offs = ru - 61;
+		break;
+	case 65 ... 66:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+		offs = ru - 65;
+		break;
+	case 67:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+		break;
+	case 68:
+		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+		break;
+	}
+
+	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+		     le16_encode_bits(offs,
+				      IEEE80211_RADIOTAP_HE_DATA2_RU_OF

FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+}
+
+#define MU_PREP(f, v)	le16_encode_bits(v,

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb,

__le32
*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb-
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+	static const struct ieee80211_radiotap_he_mu mu_known = {
+		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
+		.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+	};
+	struct ieee80211_radiotap_he_mu *he_mu;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+	he_mu = skb_push(skb, sizeof(mu_known));
+	memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
+	if (status->he_dcm)
+		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status-
Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
+			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+				 le32_get_bits(rxv[4],

MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) &

0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+	if (status->bw >= RATE_INFO_BW_40) {
+		he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+		he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+	}
+
+	if (status->bw >= RATE_INFO_BW_80) {
+		u32 ru_h, ru_l;
+
+		he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+
+		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
+		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
+		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+	}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb,

__le32
*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+					 u8 mode)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb-
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +28 -0
+	static const struct ieee80211_radiotap_he known = {
+		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
+			 HE_BITS(DATA1_STBC_KNOWN) |
+			 HE_BITS(DATA1_CODING_KNOWN) |
+			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+			 HE_BITS(DATA1_DOPPLER_KNOWN) |
+			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
+		.data2 = HE_BITS(DATA2_GI_KNOWN) |
+			 HE_BITS(DATA2_TXBF_KNOWN) |
+			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+			 HE_BITS(DATA2_TXOP_KNOWN),
+	};
+	u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
+	struct ieee80211_radiotap_he *he;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE;
+
+	he = skb_push(skb, sizeof(known));
+	memcpy(he, &known, sizeof(known));
+
+	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
+		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
+	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
+	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
+		    le16_encode_bits(ltf_size,
+				     IEEE80211_RADIOTAP_HE_DATA5_LTF_SI

ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+		he->data5 |= HE_BITS(DATA5_TXBF);
+	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+	switch (mode) {
+	case MT_PHY_TYPE_HE_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG,

rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		break;
+	case MT_PHY_TYPE_HE_EXT_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		break;
+	case MT_PHY_TYPE_HE_MU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+		mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
+		break;
+	case MT_PHY_TYPE_HE_TB:
+		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK,

rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK,

rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status *status,
+				  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +107 -0
+				  __le32 *rxv, u8 *mode)
+{
+	u8 stbc, gi, bw, dcm, nss;
+	bool cck = false;
+	u32 v0, v2;
+	int i, idx;
+
+	v0 = le32_to_cpu(rxv[0]);
+	v2 = le32_to_cpu(rxv[2]);
+
+	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+	i = idx;
+	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+	dcm = FIELD_GET(MT_PRXV_DCM, v2);
+	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+	switch (*mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		i = mt76_get_rate(dev, sband, i, cck);
+		break;
+	case MT_PHY_TYPE_HT_GF:
+	case MT_PHY_TYPE_HT:
+		status->encoding = RX_ENC_HT;
+		if (gi)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (i > 31)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_VHT:
+		status->nss = nss;
+		status->encoding = RX_ENC_VHT;
+		if (gi)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (i > 11)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_HE_MU:
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+		status->nss = nss;
+		status->encoding = RX_ENC_HE;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+			status->he_gi = gi;
+
+		status->he_dcm = dcm;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		status->nss = nss;
+		status->encoding = RX_ENC_EHT;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+			status->eht.gi = gi;
+		break;
+	default:
+		return -EINVAL;
+	}
+	status->rate_idx = i;
+
+	switch (bw) {
+	case IEEE80211_STA_RX_BW_20:
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+		    (idx & MT_PRXV_TX_ER_SU_106T)) {
+			status->bw = RATE_INFO_BW_HE_RU;
+			status->he_ru =
+				NL80211_RATE_INFO_HE_RU_ALLOC_106;
+		} else {
+			status->bw = RATE_INFO_BW_40;
+		}
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		status->bw = RATE_INFO_BW_80;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		status->bw = RATE_INFO_BW_160;
+		break;
+	case IEEE80211_STA_RX_BW_320:
+		status->bw = RATE_INFO_BW_320;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+	if (*mode < MT_PHY_TYPE_HE_SU && gi)
+		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct sk_buff

*skb,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +12 -0
+				 struct mt76_wcid *wcid)
+{
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	u8 fc_type, fc_stype;
+	u16 ethertype;
+	bool wmm = false;
+	u32 val;
+
+	if (wcid->sta) {
+		struct ieee80211_sta *sta;
+
+		sta = container_of((void *)wcid, struct ieee80211_sta,

drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +23 -0
+		wmm = sta->wme;
+	}
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	ethertype = get_unaligned_be16(&skb->data[12]);
+	if (ethertype >= ETH_P_802_3_MIN)
+		val |= MT_TXD1_ETH_802_3;
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = IEEE80211_FTYPE_DATA >> 2;
+	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev, __le32

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+				  struct sk_buff *skb,
+				  struct ieee80211_key_conf *key)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb-
Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	bool multicast = is_multicast_ether_addr(hdr->addr1);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	__le16 fc = hdr->frame_control;
+	u8 fc_type, fc_stype;
+	u32 val;
+
+	if (ieee80211_is_action(fc) &&
+	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+	    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +47 -0
+		tid = MT_TX_ADDBA;
+	else if (ieee80211_is_mgmt(hdr->frame_control))
+		tid = MT_TX_NORMAL;
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
+	      FIELD_PREP(MT_TXD1_HDR_INFO,
+			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	if (!ieee80211_is_data(fc) || multicast ||
+	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+		val |= MT_TXD1_FIXED_RATE;
+
+	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
+	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		val |= MT_TXD1_BIP;
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+	}
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
+	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+
+	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
+	if (ieee80211_is_beacon(fc)) {
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+		if (ieee80211_is_back_req(hdr->frame_control)) {
+			struct ieee80211_bar *bar;
+
+			bar = (struct ieee80211_bar *)skb->data;
+			seqno = le16_to_cpu(bar->start_seq_num);
+		}
+
+		val = MT_TXD3_SN_VALID |
+		      FIELD_PREP(MT_TXD3_SEQ,

IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(val);
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+	}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct sk_buff *skb, struct mt76_wcid

*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct ieee80211_key_conf *key, int

pid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+				 enum mt76_txq_id qid, u32 changed)
+{
+	u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :

MT_SDIO_TXD_SIZE;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = info->control.vif;
+	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+	struct mt76_vif *mvif;
+	u16 tx_count = 15;
+	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+				    BSS_CHANGED_BEACON_ENABLED));
+	bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+					 BSS_CHANGED_FILS_DISCOVERY));
+
+	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+	if (mvif) {
+		omac_idx = mvif->omac_idx;
+		wmm_idx = mvif->wmm_idx;
+		band_idx = mvif->band_idx;
+	}
+
+	if (inband_disc) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_ALTX0;
+	} else if (beacon) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_BCN0;
+	} else if (qid >= MT_TXQ_PSD) {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+		q_idx = MT_LMAC_ALTX0;
+	} else {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+			mt76_connac_lmac_mapping(skb_get_queue_mapping(

skb));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +45 -0
+	}
+
+	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
+	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+	txwi[0] = cpu_to_le32(val);
+
+	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+	if (band_idx)
+		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+	txwi[1] = cpu_to_le32(val);
+	txwi[2] = 0;
+
+	val = MT_TXD3_SW_POWER_MGMT |
+	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+	if (key)
+		val |= MT_TXD3_PROTECT_FRAME;
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		val |= MT_TXD3_NO_ACK;
+	if (wcid->amsdu)
+		val |= MT_TXD3_HW_AMSDU;
+
+	txwi[3] = cpu_to_le32(val);
+	txwi[4] = 0;
+
+	val = FIELD_PREP(MT_TXD5_PID, pid);
+	if (pid >= MT_PACKET_ID_FIRST)
+		val |= MT_TXD5_TX_STATUS_HOST;
+	txwi[5] = cpu_to_le32(val);
+
+	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+	txwi[6] = cpu_to_le32(val);
+	txwi[7] = 0;
+
+	if (is_8023)
+		mt76_connac3_mac_write_txwi_8023(txwi, skb, wcid);
+	else
+		mt76_connac3_mac_write_txwi_80211(dev, txwi, skb, key);
+
+	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +14 -0
+		bool mcast = ieee80211_is_data(hdr->frame_control) &&
+			     is_multicast_ether_addr(hdr->addr1);
+		u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+		if (mvif) {
+			if (mcast && mvif->mcast_rates_idx)
+				idx = mvif->mcast_rates_idx;
+			else if (beacon && mvif->beacon_rates_idx)
+				idx = mvif->beacon_rates_idx;
+			else
+				idx = mvif->basic_rates_idx;
+		}
+
+		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,

idx));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list)
+{
+	__le32 *txwi;
+	u16 wcid_idx;
+
+	mt76_connac_txp_skb_unmap(dev, t);
+	if (!t->skb)
+		goto out;
+
+	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+	if (sta) {
+		struct mt76_wcid *wcid = (struct mt76_wcid *)sta-
Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+
+		wcid_idx = wcid->idx;
+		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+			mt76_connac3_tx_check_aggr(sta, txwi);
+	} else {
+		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+	}
+
+	__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
+out:
+	t->skb = NULL;
+	mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +58 -0
+			     int pid, __le32 *txs_data)
+{
+	struct mt76_sta_stats *stats = &wcid->stats;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_tx_info *info;
+	u32 txrate, txs, mode, stbc;
+	struct rate_info rate = {};
+	struct sk_buff_head list;
+	struct mt76_phy *mphy;
+	struct sk_buff *skb;
+	bool cck = false;
+
+	mt76_tx_status_lock(dev, &list);
+	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+	if (!skb)
+		goto out_no_skb;
+
+	txs = le32_to_cpu(txs_data[0]);
+
+	info = IEEE80211_SKB_CB(skb);
+	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	info->status.ampdu_len = 1;
+	info->status.ampdu_ack_len = !!(info->flags &
+					IEEE80211_TX_STAT_ACK);
+	info->status.rates[0].idx = -1;
+
+	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+	if (stbc && rate.nss > 1)
+		rate.nss >>= 1;
+
+	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+		stats->tx_nss[rate.nss - 1]++;
+	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+		stats->tx_mcs[rate.mcs]++;
+
+	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+	switch (mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+			sband = &mphy->sband_5g.sband;
+		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
+			sband = &mphy->sband_6g.sband;
+		else
+			sband = &mphy->sband_2g.sband;
+
+		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs,

cck);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +130 -0
+		rate.legacy = sband->bitrates[rate.mcs].bitrate;
+		break;
+	case MT_PHY_TYPE_HT:
+	case MT_PHY_TYPE_HT_GF:
+		if (rate.mcs > 31)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_MCS;
+		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		break;
+	case MT_PHY_TYPE_VHT:
+		if (rate.mcs > 9)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+		break;
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+	case MT_PHY_TYPE_HE_MU:
+		if (rate.mcs > 11)
+			goto out;
+
+		rate.he_gi = wcid->rate.he_gi;
+		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
+		rate.flags = RATE_INFO_FLAGS_HE_MCS;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		if (rate.mcs > 13)
+			goto out;
+
+		rate.eht_gi = wcid->rate.eht_gi;
+		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+		break;
+	default:
+		goto out;
+	}
+
+	stats->tx_mode[mode]++;
+
+	switch (FIELD_GET(MT_TXS0_BW, txs)) {
+	case IEEE80211_STA_RX_BW_320:
+		rate.bw = RATE_INFO_BW_320;
+		stats->tx_bw[4]++;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		rate.bw = RATE_INFO_BW_160;
+		stats->tx_bw[3]++;
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		rate.bw = RATE_INFO_BW_80;
+		stats->tx_bw[2]++;
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		rate.bw = RATE_INFO_BW_40;
+		stats->tx_bw[1]++;
+		break;
+	default:
+		rate.bw = RATE_INFO_BW_20;
+		stats->tx_bw[0]++;
+		break;
+	}
+	wcid->rate = rate;
+
+out:
+	mt76_tx_status_skb_done(dev, skb, &list);
+
+out_no_skb:
+	mt76_tx_status_unlock(dev, &list);
+
+	return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+			      u32 max_wtbl_size)
+{
+	struct mt76_wcid *wcid;
+	__le32 *txs_data = data;
+	u16 wcidx;
+	u8 pid;
+
+	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
+		return;
+
+	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+	if (pid < MT_PACKET_ID_FIRST)
+		return;
+
+	if (wcidx >= max_wtbl_size)
+		return;
+
+	rcu_read_lock();
+
+	wcid = rcu_dereference(dev->wcid[wcidx]);
+	if (!wcid)
+		goto out;
+
+	mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
+	if (!wcid->sta)
+		goto out;
+
+	spin_lock_bh(&dev->sta_poll_lock);
+	if (list_empty(&wcid->poll_list))
+		list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
+	spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *txwi;
+	int id;
+
+	spin_lock_bh(&dev->token_lock);
+	idr_for_each_entry(&dev->token, txwi, id) {
+		mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+		dev->token_count--;
+	}
+	spin_unlock_bh(&dev->token_lock);
+	idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 6663a0b46541..bcc1d976b2b0 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +0 -0
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h line 9

Quoted 6 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +1 -0
+/* NOTE: used to map mt76_rates. idx may change if firmware

expands
table */

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL	11
+#define MT76_CONNAC3_BEACON_RATES_TBL	25

Different devices may have different defined value.

Quoted 5 lines

The other WiFi7 device I am working on relies on the values I moved in
mt76_connac3_mac.h (in common with mt7996). Moreover you can still have per-device values in mt7996/mac.h (I have not removed it).

Quoted 4 lines

Please double check with the mtk folk you work with. The 11 and 25 is the value I discussed with firmware folks to avoid overlapping the tbl mt7996 use (MU/other algo in fw), or it causes something hardly solving issue

sure, thx for pointing this out.
@Deren: can you please double check?

Regards,
Lorenzo

Quoted 15 lines
Quoted 15 lines
Quoted 4 lines

I'm thinking if it's too early to create this patch for just moving mt7996 to connac3_lib?

The code I moved is used by the other device as well. This series is a
preliminary series to support it.

Regards,
Lorenzo

Quoted 3 lines

Ryder

#22 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

In reply to a message not in the archive
Quoted 28 lines · Shayne Chen
Quoted 6 lines
Quoted 1 line

On Fri, 2023-06-09 at 18:34 +0200, [email protected]

Quoted 3 lines · wrote:
Quoted 3 lines · Ryder Lee
Quoted 2 lines · Lorenzo Bianconi
Quoted 1 line
Quoted 10 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

External email : Please do not click links or open

attachments

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

until you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse mac

code

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

shared between WiFi7 chipsets.

Hi Lorenzo,

I don't think it's a good idea to start sharing mac or mcu functions for all WiFi7 chipsets at such early stage.

The driver is still under many processes of bug fixing, performance tuning, and new features development.
Chipsets that mainly used for AP or STA segment have different designs
and should face different problems.

Quoted 8 lines

Start sharing the code at early stage will break the independence, make
it more hard to develop and do verifications, since many changes will affect chipsets of both segments.

Thanks,
Shayne

(Resend for missing CC)

Quoted 1,001 lines
Quoted 1,001 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +  
.../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +-----

--

----

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

----
--

 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-

) create

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

drivers/net/wireless/mediatek/mt76/Makefile mt76x02-lib-y := mt76x02_util.o

Quoted 9 lines

mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/Makefile +0 -0
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o

mt76x02_mac.o

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/wireless/mediatek/mt76/Makefile +1 -1
 mt76x02_mcu.o \
 
 mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o

mt76_connac3_mac.o

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h void mt76_connac2_txwi_free(struct

Quoted 8 lines

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ diff --git
a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 68bdeada1421..20111678537b 100644

drivers/net/wireless/mediatek/mt76/mt76_connac.h +0 -0
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct

mt76_dev

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
 *dev, struct mt76_txwi_cache *t,
     struct list_head *free_list);  void 
 mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff

*skb,

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 9 lines

__le32
*rxv,
+ u8 mode);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+  struct mt76_rx_status *status,
+  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32

Quoted 69 lines
Quoted 69 lines
Quoted 69 lines
Quoted 69 lines

*txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key, int
pid,
+ enum mt76_txq_id qid, u32 changed); void +mt76_connac3_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+    struct ieee80211_sta *sta,
+    struct list_head *free_list); void 
+mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file mode 100644
index 000000000000..4b745bb74ca0

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)cpu_to_le16(IEEE80211_RADIOTAP_

HE_##f)
+#define HE_PREP(f, m, v)le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
+ IEEE80211_RADIOTAP_HE_
##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+{
+struct mt76_wcid *wcid;
+u16 fc, tid;
+u32 val;
+
+if (!sta ||
+    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+return;
+
+tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+if (tid >= 6) /* skip VO queue */
+return;
+
+val = le32_to_cpu(txwi[2]);
+fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+return;
+
+wcid = (struct mt76_wcid *)sta->drv_priv;
+if (!test_and_set_bit(tid, &wcid->ampdu_state))
+ieee80211_start_tx_ba_session(sta, tid, 0); } 
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

mt76_rx_status
*status,
+ struct ieee80211_radiotap_he
*he,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+       __le32 *rxv)
+{
+u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs

=

0;

Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +36 -0
+
+status->bw = RATE_INFO_BW_HE_RU;
+
+switch (ru) {
+case 0 ... 36:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+offs = ru;
+break;
+case 37 ... 52:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+offs = ru - 37;
+break;
+case 53 ... 60:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+offs = ru - 53;
+break;
+case 61 ... 64:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+offs = ru - 61;
+break;
+case 65 ... 66:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+offs = ru - 65;
+break;
+case 67:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+break;
+case 68:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+break;
+}
+
+he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+     le16_encode_bits(offs,
+      IEEE80211_RADIOTAP_HE_DATA2_RU_OF

FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+}
+
+#define MU_PREP(f, v)le16_encode_bits(v,
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff

*skb,
__le32
*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 46 lines
Quoted 17 lines
Quoted 17 lines
Quoted 7 lines
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+static const struct ieee80211_radiotap_he_mu mu_known = {
+.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+};
+struct ieee80211_radiotap_he_mu *he_mu;
+
+status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+he_mu = skb_push(skb, sizeof(mu_known));
+memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status-

rate_idx);

Quoted 6 lines
Quoted 6 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 6 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+if (status->he_dcm)
+he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status-
Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status-

bw) |

Quoted 19 lines
Quoted 19 lines
Quoted 19 lines

+ MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+ le32_get_bits(rxv[4],
MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0)

&
0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+if (status->bw >= RATE_INFO_BW_40) {
+he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+}
+
+if (status->bw >= RATE_INFO_BW_80) {
+u32 ru_h, ru_l;
+
+he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+
+ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
+ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
+he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff

*skb,

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 5 lines

__le32
*rxv,
+ u8 mode)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 8 lines
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+static const struct ieee80211_radiotap_he known = {
+.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+ HE_BITS(DATA1_DATA_DCM_KNOWN) |
+ HE_BITS(DATA1_STBC_KNOWN) |
+ HE_BITS(DATA1_CODING_KNOWN) |
+ HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+ HE_BITS(DATA1_DOPPLER_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+ HE_BITS(DATA1_BSS_COLOR_KNOWN),
+.data2 = HE_BITS(DATA2_GI_KNOWN) |
+ HE_BITS(DATA2_TXBF_KNOWN) |
+ HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+ HE_BITS(DATA2_TXOP_KNOWN),
+};
+u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE)
+

1;

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+struct ieee80211_radiotap_he *he;
+
+status->flag |= RX_FLAG_RADIOTAP_HE;
+
+he = skb_push(skb, sizeof(known));
+memcpy(he, &known, sizeof(known));
+
+he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
+    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
+he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK,

rxv[13]);

Quoted 166 lines
Quoted 166 lines
Quoted 166 lines
Quoted 166 lines

+he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5])

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+    le16_encode_bits(ltf_size,
+     IEEE80211_RADIOTAP_HE_DATA5_LTF_SI

ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+he->data5 |= HE_BITS(DATA5_TXBF);
+he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+switch (mode) {
+case MT_PHY_TYPE_HE_SU:
+he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+     HE_BITS(DATA1_UL_DL_KNOWN) |
+     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG,

rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+break;
+case MT_PHY_TYPE_HE_EXT_SU:
+he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+     HE_BITS(DATA1_UL_DL_KNOWN) |
+     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+break;
+case MT_PHY_TYPE_HE_MU:
+he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+     HE_BITS(DATA1_UL_DL_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
+
+mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
+break;
+case MT_PHY_TYPE_HE_TB:
+he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK,

rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK,
rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK,
rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK,
rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+break;
+default:
+break;
+}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+  struct mt76_rx_status *status,
+  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +99 -0
+  __le32 *rxv, u8 *mode)
+{
+u8 stbc, gi, bw, dcm, nss;
+bool cck = false;
+u32 v0, v2;
+int i, idx;
+
+v0 = le32_to_cpu(rxv[0]);
+v2 = le32_to_cpu(rxv[2]);
+
+idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+i = idx;
+nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+dcm = FIELD_GET(MT_PRXV_DCM, v2);
+bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+switch (*mode) {
+case MT_PHY_TYPE_CCK:
+cck = true;
+fallthrough;
+case MT_PHY_TYPE_OFDM:
+i = mt76_get_rate(dev, sband, i, cck);
+break;
+case MT_PHY_TYPE_HT_GF:
+case MT_PHY_TYPE_HT:
+status->encoding = RX_ENC_HT;
+if (gi)
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+if (i > 31)
+return -EINVAL;
+break;
+case MT_PHY_TYPE_VHT:
+status->nss = nss;
+status->encoding = RX_ENC_VHT;
+if (gi)
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+if (i > 11)
+return -EINVAL;
+break;
+case MT_PHY_TYPE_HE_MU:
+case MT_PHY_TYPE_HE_SU:
+case MT_PHY_TYPE_HE_EXT_SU:
+case MT_PHY_TYPE_HE_TB:
+status->nss = nss;
+status->encoding = RX_ENC_HE;
+i &= GENMASK(3, 0);
+
+if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+status->he_gi = gi;
+
+status->he_dcm = dcm;
+break;
+case MT_PHY_TYPE_EHT_SU:
+case MT_PHY_TYPE_EHT_TRIG:
+case MT_PHY_TYPE_EHT_MU:
+status->nss = nss;
+status->encoding = RX_ENC_EHT;
+i &= GENMASK(3, 0);
+
+if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+status->eht.gi = gi;
+break;
+default:
+return -EINVAL;
+}
+status->rate_idx = i;
+
+switch (bw) {
+case IEEE80211_STA_RX_BW_20:
+break;
+case IEEE80211_STA_RX_BW_40:
+if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+    (idx & MT_PRXV_TX_ER_SU_106T)) {
+status->bw = RATE_INFO_BW_HE_RU;
+status->he_ru =
+NL80211_RATE_INFO_HE_RU_ALLOC_106;
+} else {
+status->bw = RATE_INFO_BW_40;
+}
+break;
+case IEEE80211_STA_RX_BW_80:
+status->bw = RATE_INFO_BW_80;
+break;
+case IEEE80211_STA_RX_BW_160:
+status->bw = RATE_INFO_BW_160;
+break;
+case IEEE80211_STA_RX_BW_320:
+status->bw = RATE_INFO_BW_320;
+break;
+default:
+return -EINVAL;
+}
+
+status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+if (*mode < MT_PHY_TYPE_HE_SU && gi)
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct

sk_buff

Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines

*skb,
+ struct mt76_wcid *wcid)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +11 -0
+{
+u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+u8 fc_type, fc_stype;
+u16 ethertype;
+bool wmm = false;
+u32 val;
+
+if (wcid->sta) {
+struct ieee80211_sta *sta;
+
+sta = container_of((void *)wcid, struct ieee80211_sta,

drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+wmm = sta->wme;
+}
+
+val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3)

|

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +11 -0
+      FIELD_PREP(MT_TXD1_TID, tid);
+
+ethertype = get_unaligned_be16(&skb->data[12]);
+if (ethertype >= ETH_P_802_3_MIN)
+val |= MT_TXD1_ETH_802_3;
+
+txwi[1] |= cpu_to_le32(val);
+
+fc_type = IEEE80211_FTYPE_DATA >> 2;
+fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev,

__le32

Quoted 29 lines
Quoted 4 lines
Quoted 4 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 4 lines

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+  struct sk_buff *skb,
+  struct ieee80211_key_conf *key) {
+struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb-

data;

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines

+struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb-

Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+bool multicast = is_multicast_ether_addr(hdr->addr1);
+u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+__le16 fc = hdr->frame_control;
+u8 fc_type, fc_stype;
+u32 val;
+
+if (ieee80211_is_action(fc) &&
+    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+tid = MT_TX_ADDBA;
+else if (ieee80211_is_mgmt(hdr->frame_control))
+tid = MT_TX_NORMAL;
+
+val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11)

|
+ FIELD_PREP(MT_TXD1_HDR_INFO,
+ ieee80211_get_hdrlen_from_skb(skb) / 2) |

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+      FIELD_PREP(MT_TXD1_TID, tid);
+
+if (!ieee80211_is_data(fc) || multicast ||
+    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+val |= MT_TXD1_FIXED_RATE;
+
+if (key && multicast &&

ieee80211_is_robust_mgmt_frame(skb)

&&

Quoted 33 lines
Quoted 33 lines
Quoted 33 lines
Quoted 33 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +16 -0
+    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+val |= MT_TXD1_BIP;
+txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+}
+
+txwi[1] |= cpu_to_le32(val);
+
+fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
+fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
+
+val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+txwi[2] |= cpu_to_le32(val);
+
+txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM,

multicast));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +16 -0
+if (ieee80211_is_beacon(fc)) {
+txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+}
+
+if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+if (ieee80211_is_back_req(hdr->frame_control)) {
+struct ieee80211_bar *bar;
+
+bar = (struct ieee80211_bar *)skb->data;
+seqno = le16_to_cpu(bar->start_seq_num);
+}
+
+val = MT_TXD3_SN_VALID |
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines

+ FIELD_PREP(MT_TXD3_SEQ,
IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+txwi[3] |= cpu_to_le32(val);
+txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

*txwi,
+ struct sk_buff *skb, struct mt76_wcid
*wcid,
+ struct ieee80211_key_conf *key, int
pid,
+ enum mt76_txq_id qid, u32 changed)

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :

MT_SDIO_TXD_SIZE;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+struct ieee80211_vif *vif = info->control.vif;
+u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+bool is_8023 = info->flags &

IEEE80211_TX_CTL_HW_80211_ENCAP;

Quoted 261 lines
Quoted 261 lines
Quoted 261 lines
Quoted 261 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+struct mt76_vif *mvif;
+u16 tx_count = 15;
+bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+    BSS_CHANGED_BEACON_ENABLED));
+bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+ BSS_CHANGED_FILS_DISCOVERY));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +16 -0
+
+mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+if (mvif) {
+omac_idx = mvif->omac_idx;
+wmm_idx = mvif->wmm_idx;
+band_idx = mvif->band_idx;
+}
+
+if (inband_disc) {
+p_fmt = MT_TX_TYPE_FW;
+q_idx = MT_LMAC_ALTX0;
+} else if (beacon) {
+p_fmt = MT_TX_TYPE_FW;
+q_idx = MT_LMAC_BCN0;
+} else if (qid >= MT_TXQ_PSD) {
+p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+q_idx = MT_LMAC_ALTX0;
+} else {
+p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+mt76_connac_lmac_mapping(skb_get_queue_mapping(

skb));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +45 -0
+}
+
+val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
+      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+txwi[0] = cpu_to_le32(val);
+
+val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+if (band_idx)
+val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+txwi[1] = cpu_to_le32(val);
+txwi[2] = 0;
+
+val = MT_TXD3_SW_POWER_MGMT |
+      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+if (key)
+val |= MT_TXD3_PROTECT_FRAME;
+if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+val |= MT_TXD3_NO_ACK;
+if (wcid->amsdu)
+val |= MT_TXD3_HW_AMSDU;
+
+txwi[3] = cpu_to_le32(val);
+txwi[4] = 0;
+
+val = FIELD_PREP(MT_TXD5_PID, pid);
+if (pid >= MT_PACKET_ID_FIRST)
+val |= MT_TXD5_TX_STATUS_HOST;
+txwi[5] = cpu_to_le32(val);
+
+val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+txwi[6] = cpu_to_le32(val);
+txwi[7] = 0;
+
+if (is_8023)
+mt76_connac3_mac_write_txwi_8023(txwi, skb, wcid);
+else
+mt76_connac3_mac_write_txwi_80211(dev, txwi, skb, key);
+
+if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +14 -0
+bool mcast = ieee80211_is_data(hdr->frame_control) &&
+     is_multicast_ether_addr(hdr->addr1);
+u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+if (mvif) {
+if (mcast && mvif->mcast_rates_idx)
+idx = mvif->mcast_rates_idx;
+else if (beacon && mvif->beacon_rates_idx)
+idx = mvif->beacon_rates_idx;
+else
+idx = mvif->basic_rates_idx;
+}
+
+txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,

idx));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+    struct ieee80211_sta *sta,
+    struct list_head *free_list)
+{
+__le32 *txwi;
+u16 wcid_idx;
+
+mt76_connac_txp_skb_unmap(dev, t);
+if (!t->skb)
+goto out;
+
+txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+if (sta) {
+struct mt76_wcid *wcid = (struct mt76_wcid *)sta-
Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+
+wcid_idx = wcid->idx;
+if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+mt76_connac3_tx_check_aggr(sta, txwi);
+} else {
+wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+}
+
+__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
+out:
+t->skb = NULL;
+mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +58 -0
+     int pid, __le32 *txs_data)
+{
+struct mt76_sta_stats *stats = &wcid->stats;
+struct ieee80211_supported_band *sband;
+struct ieee80211_tx_info *info;
+u32 txrate, txs, mode, stbc;
+struct rate_info rate = {};
+struct sk_buff_head list;
+struct mt76_phy *mphy;
+struct sk_buff *skb;
+bool cck = false;
+
+mt76_tx_status_lock(dev, &list);
+skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+if (!skb)
+goto out_no_skb;
+
+txs = le32_to_cpu(txs_data[0]);
+
+info = IEEE80211_SKB_CB(skb);
+if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+info->flags |= IEEE80211_TX_STAT_ACK;
+
+info->status.ampdu_len = 1;
+info->status.ampdu_ack_len = !!(info->flags &
+IEEE80211_TX_STAT_ACK);
+info->status.rates[0].idx = -1;
+
+txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+if (stbc && rate.nss > 1)
+rate.nss >>= 1;
+
+if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+stats->tx_nss[rate.nss - 1]++;
+if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+stats->tx_mcs[rate.mcs]++;
+
+mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+switch (mode) {
+case MT_PHY_TYPE_CCK:
+cck = true;
+fallthrough;
+case MT_PHY_TYPE_OFDM:
+mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+sband = &mphy->sband_5g.sband;
+else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
+sband = &mphy->sband_6g.sband;
+else
+sband = &mphy->sband_2g.sband;
+
+rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs,

cck);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +69 -0
+rate.legacy = sband->bitrates[rate.mcs].bitrate;
+break;
+case MT_PHY_TYPE_HT:
+case MT_PHY_TYPE_HT_GF:
+if (rate.mcs > 31)
+goto out;
+
+rate.flags = RATE_INFO_FLAGS_MCS;
+if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+break;
+case MT_PHY_TYPE_VHT:
+if (rate.mcs > 9)
+goto out;
+
+rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+break;
+case MT_PHY_TYPE_HE_SU:
+case MT_PHY_TYPE_HE_EXT_SU:
+case MT_PHY_TYPE_HE_TB:
+case MT_PHY_TYPE_HE_MU:
+if (rate.mcs > 11)
+goto out;
+
+rate.he_gi = wcid->rate.he_gi;
+rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
+rate.flags = RATE_INFO_FLAGS_HE_MCS;
+break;
+case MT_PHY_TYPE_EHT_SU:
+case MT_PHY_TYPE_EHT_TRIG:
+case MT_PHY_TYPE_EHT_MU:
+if (rate.mcs > 13)
+goto out;
+
+rate.eht_gi = wcid->rate.eht_gi;
+rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+break;
+default:
+goto out;
+}
+
+stats->tx_mode[mode]++;
+
+switch (FIELD_GET(MT_TXS0_BW, txs)) {
+case IEEE80211_STA_RX_BW_320:
+rate.bw = RATE_INFO_BW_320;
+stats->tx_bw[4]++;
+break;
+case IEEE80211_STA_RX_BW_160:
+rate.bw = RATE_INFO_BW_160;
+stats->tx_bw[3]++;
+break;
+case IEEE80211_STA_RX_BW_80:
+rate.bw = RATE_INFO_BW_80;
+stats->tx_bw[2]++;
+break;
+case IEEE80211_STA_RX_BW_40:
+rate.bw = RATE_INFO_BW_40;
+stats->tx_bw[1]++;
+break;
+default:
+rate.bw = RATE_INFO_BW_20;
+stats->tx_bw[0]++;
+break;
+}
+wcid->rate = rate;
+
+out:
+mt76_tx_status_skb_done(dev, skb, &list);
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+
+out_no_skb:
+mt76_tx_status_unlock(dev, &list);
+
+return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void

*data,

Quoted 73 lines
Quoted 73 lines
Quoted 72 lines
Quoted 68 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +53 -0
+      u32 max_wtbl_size)
+{
+struct mt76_wcid *wcid;
+__le32 *txs_data = data;
+u16 wcidx;
+u8 pid;
+
+if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
+return;
+
+wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+if (pid < MT_PACKET_ID_FIRST)
+return;
+
+if (wcidx >= max_wtbl_size)
+return;
+
+rcu_read_lock();
+
+wcid = rcu_dereference(dev->wcid[wcidx]);
+if (!wcid)
+goto out;
+
+mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
+if (!wcid->sta)
+goto out;
+
+spin_lock_bh(&dev->sta_poll_lock);
+if (list_empty(&wcid->poll_list))
+list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
+spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+struct mt76_txwi_cache *txwi;
+int id;
+
+spin_lock_bh(&dev->token_lock);
+idr_for_each_entry(&dev->token, txwi, id) {
+mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+dev->token_count--;
+}
+spin_unlock_bh(&dev->token_lock);
+idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 6663a0b46541..bcc1d976b2b0 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +1 -0
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
+/* NOTE: used to map mt76_rates. idx may change if

firmware
expands
table */

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h

Quoted 2 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL11
+#define MT76_CONNAC3_BEACON_RATES_TBL25

Different devices may have different defined value.

Quoted 1 line
Quoted 1 line

The other WiFi7 device I am working on relies on the values I

moved

Quoted 2 lines
Quoted 2 lines

in
mt76_connac3_mac.h (in common with mt7996). Moreover you can

still

Quoted 5 lines
Quoted 2 lines

have per-device values in mt7996/mac.h (I have not removed it).

Please double check with the mtk folk you work with. The 11 and 25

is

Quoted 2 lines

the value I discussed with firmware folks to avoid overlapping the

tbl

Quoted 1 line

mt7996 use (MU/other algo in fw), or it causes something hardly

solving

Quoted 1 line

issue

sure, thx for pointing this out.
@Deren: can you please double check?

Regards,
Lorenzo

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

I'm thinking if it's too early to create this patch for just

moving

Quoted 4 lines
Quoted 4 lines
Quoted 1 line

mt7996 to connac3_lib?

The code I moved is used by the other device as well. This series

is

Quoted 9 lines
Quoted 9 lines

a
preliminary series to support it.

Regards,
Lorenzo

Quoted 3 lines

Ryder

#26 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

In reply to [email protected]
Quoted 1,033 lines · On Fri, 2023-06-09 at 18:45 +0200, [email protected] wrote:
Quoted 1,025 lines
Quoted 1,015 lines · On Fri, 2023-06-09 at 18:34 +0200, [email protected] wrote:
Quoted 1,005 lines · Ryder Lee
Quoted 1,004 lines · Lorenzo Bianconi

External email : Please do not click links or open attachments
until
you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse mac
code
shared
between WiFi7 chipsets.

---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +
 .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +-------
----
----
--
 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-)
 create mode 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/Makefile +0 -0
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o

mt76x02_mac.o
mt76x02_mcu.o \

mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o

drivers/net/wireless/mediatek/mt76/Makefile +1 -1
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o

mt76_connac3_mac.o

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/

drivers/net/wireless/mediatek/mt76/mt76_connac.h +0 -0
index 68bdeada1421..20111678537b 100644
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct

mt76_dev
*dev, struct mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
 			    struct list_head *free_list);
 void mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb,
__le32
*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+					 u8 mode);
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				  struct

ieee80211_supported_band
*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+				  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32
*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct sk_buff *skb, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct ieee80211_key_conf

*key, int
pid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 enum mt76_txq_id qid, u32

changed);
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list);
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void

*data,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+			      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file mode 100644
index 000000000000..4b745bb74ca0

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_

HE_##f)
+#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(
v,
MT_CRXV_HE_##m),\

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+						 IEEE80211_RADI

OTAP_HE_
##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+{
+	struct mt76_wcid *wcid;
+	u16 fc, tid;
+	u32 val;
+
+	if (!sta ||
+	    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+	if (tid >= 6) /* skip VO queue */
+		return;
+
+	val = le32_to_cpu(txwi[2]);
+	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+	if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	wcid = (struct mt76_wcid *)sta->drv_priv;
+	if (!test_and_set_bit(tid, &wcid->ampdu_state))
+		ieee80211_start_tx_ba_session(sta, tid, 0);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				       struct

ieee80211_radiotap_he
*he,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+				       __le32 *rxv)
+{
+	u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC),

offs = 0;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+
+	status->bw = RATE_INFO_BW_HE_RU;
+
+	switch (ru) {
+	case 0 ... 36:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_26;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru;
+		break;
+	case 37 ... 52:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_52;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru - 37;
+		break;
+	case 53 ... 60:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_106;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru - 53;
+		break;
+	case 61 ... 64:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_242;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru - 61;
+		break;
+	case 65 ... 66:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_484;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru - 65;
+		break;
+	case 67:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_996;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+		break;
+	case 68:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_2x996;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+		break;
+	}
+
+	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+		     le16_encode_bits(offs,
+				      IEEE80211_RADIOTAP_HE_DAT

A2_RU_OF
FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+}
+
+#define MU_PREP(f, v)	le16_encode_bits(v,

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb,

__le32
*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	static const struct ieee80211_radiotap_he_mu mu_known =

{

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KN

OWN),

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		.flags2 =

HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+	};
+	struct ieee80211_radiotap_he_mu *he_mu;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+	he_mu = skb_push(skb, sizeof(mu_known));
+	memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status-
Quoted 1 line

rate_idx);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+	if (status->he_dcm)
+		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM,

status-

Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW,

status->bw) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+				 le32_get_bits(rxv[4],

MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+	he_mu->ru_ch1[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU0) &
0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+
+	if (status->bw >= RATE_INFO_BW_40) {
+		he_mu->flags1 |=

HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+	}
+
+	if (status->bw >= RATE_INFO_BW_80) {
+		u32 ru_h, ru_l;
+
+		he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		ru_l = le32_get_bits(rxv[16],

MT_CRXV_HE_RU3_L);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H)

& 0x7;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+	}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff

*skb,
__le32
*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+					 u8 mode)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +15 -0
+	static const struct ieee80211_radiotap_he known = {
+		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
+			 HE_BITS(DATA1_STBC_KNOWN) |
+			 HE_BITS(DATA1_CODING_KNOWN) |
+			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+			 HE_BITS(DATA1_DOPPLER_KNOWN) |
+			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
+		.data2 = HE_BITS(DATA2_GI_KNOWN) |
+			 HE_BITS(DATA2_TXBF_KNOWN) |
+			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+			 HE_BITS(DATA2_TXOP_KNOWN),
+	};
+	u32 ltf_size = le32_get_bits(rxv[4],

MT_CRXV_HE_LTF_SIZE) + 1;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+	struct ieee80211_radiotap_he *he;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE;
+
+	he = skb_push(skb, sizeof(known));
+	memcpy(he, &known, sizeof(known));
+
+	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9])

|

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM,

rxv[4]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK,

rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG,

rxv[5]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+		    le16_encode_bits(ltf_size,
+				     IEEE80211_RADIOTAP_HE_DATA

5_LTF_SI
ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+		he->data5 |= HE_BITS(DATA5_TXBF);
+	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+	switch (mode) {
+	case MT_PHY_TYPE_HE_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE,

BEAM_CHNG,
rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA3_UL_DL, UPLINK,

rxv[5]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+		break;
+	case MT_PHY_TYPE_HE_EXT_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK,

rxv[5]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		break;
+	case MT_PHY_TYPE_HE_MU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK,

rxv[5]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID,

rxv[8]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status,

he,
rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		mt76_connac3_mac_decode_he_mu_radiotap(skb,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+		break;
+	case MT_PHY_TYPE_HE_TB:
+		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1,

SR_MASK,
rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE2,

SR1_MASK,
rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE3,

SR2_MASK,
rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE4,

SR3_MASK,
rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status,

he,
rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				  struct

ieee80211_supported_band
*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +32 -0
+				  __le32 *rxv, u8 *mode)
+{
+	u8 stbc, gi, bw, dcm, nss;
+	bool cck = false;
+	u32 v0, v2;
+	int i, idx;
+
+	v0 = le32_to_cpu(rxv[0]);
+	v2 = le32_to_cpu(rxv[2]);
+
+	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+	i = idx;
+	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+	dcm = FIELD_GET(MT_PRXV_DCM, v2);
+	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+	switch (*mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		i = mt76_get_rate(dev, sband, i, cck);
+		break;
+	case MT_PHY_TYPE_HT_GF:
+	case MT_PHY_TYPE_HT:
+		status->encoding = RX_ENC_HT;
+		if (gi)
+			status->enc_flags |=

RX_ENC_FLAG_SHORT_GI;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+		if (i > 31)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_VHT:
+		status->nss = nss;
+		status->encoding = RX_ENC_VHT;
+		if (gi)
+			status->enc_flags |=

RX_ENC_FLAG_SHORT_GI;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +40 -0
+		if (i > 11)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_HE_MU:
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+		status->nss = nss;
+		status->encoding = RX_ENC_HE;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+			status->he_gi = gi;
+
+		status->he_dcm = dcm;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		status->nss = nss;
+		status->encoding = RX_ENC_EHT;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+			status->eht.gi = gi;
+		break;
+	default:
+		return -EINVAL;
+	}
+	status->rate_idx = i;
+
+	switch (bw) {
+	case IEEE80211_STA_RX_BW_20:
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+		    (idx & MT_PRXV_TX_ER_SU_106T)) {
+			status->bw = RATE_INFO_BW_HE_RU;
+			status->he_ru =
+				NL80211_RATE_INFO_HE_RU_ALLOC_1

06;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +27 -0
+		} else {
+			status->bw = RATE_INFO_BW_40;
+		}
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		status->bw = RATE_INFO_BW_80;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		status->bw = RATE_INFO_BW_160;
+		break;
+	case IEEE80211_STA_RX_BW_320:
+		status->bw = RATE_INFO_BW_320;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+	if (*mode < MT_PHY_TYPE_HE_SU && gi)
+		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct

sk_buff
*skb,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +12 -0
+				 struct mt76_wcid *wcid)
+{
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	u8 fc_type, fc_stype;
+	u16 ethertype;
+	bool wmm = false;
+	u32 val;
+
+	if (wcid->sta) {
+		struct ieee80211_sta *sta;
+
+		sta = container_of((void *)wcid, struct

ieee80211_sta,
drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		wmm = sta->wme;
+	}
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT,

MT_HDR_FORMAT_802_3) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +19 -0
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	ethertype = get_unaligned_be16(&skb->data[12]);
+	if (ethertype >= ETH_P_802_3_MIN)
+		val |= MT_TXD1_ETH_802_3;
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = IEEE80211_FTYPE_DATA >> 2;
+	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev,

__le32
*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+				  struct sk_buff *skb,
+				  struct ieee80211_key_conf

*key)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt

*)skb-

Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	bool multicast = is_multicast_ether_addr(hdr->addr1);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	__le16 fc = hdr->frame_control;
+	u8 fc_type, fc_stype;
+	u32 val;
+
+	if (ieee80211_is_action(fc) &&
+	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+	    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+		tid = MT_TX_ADDBA;
+	else if (ieee80211_is_mgmt(hdr->frame_control))
+		tid = MT_TX_NORMAL;
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT,

MT_HDR_FORMAT_802_11) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+	      FIELD_PREP(MT_TXD1_HDR_INFO,
+			 ieee80211_get_hdrlen_from_skb(skb) /

2) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	if (!ieee80211_is_data(fc) || multicast ||
+	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+		val |= MT_TXD1_FIXED_RATE;
+
+	if (key && multicast &&

ieee80211_is_robust_mgmt_frame(skb) &&

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		val |= MT_TXD1_BIP;
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+	}
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >>

2;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >>

4;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+
+	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM,

multicast));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+	if (ieee80211_is_beacon(fc)) {
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+		if (ieee80211_is_back_req(hdr->frame_control))

{

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+			struct ieee80211_bar *bar;
+
+			bar = (struct ieee80211_bar *)skb-
Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			seqno = le16_to_cpu(bar-
Quoted 1 line

start_seq_num);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		}
+
+		val = MT_TXD3_SN_VALID |
+		      FIELD_PREP(MT_TXD3_SEQ,

IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(val);
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+	}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32
*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct sk_buff *skb, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct ieee80211_key_conf

*key, int
pid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 enum mt76_txq_id qid, u32

changed)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :

MT_SDIO_TXD_SIZE;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = info->control.vif;
+	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >>

2;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+	bool is_8023 = info->flags &

IEEE80211_TX_CTL_HW_80211_ENCAP;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+	struct mt76_vif *mvif;
+	u16 tx_count = 15;
+	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+				    BSS_CHANGED_BEACON_ENABLED)

);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+					 BSS_CHANGED_FILS_DISCO

VERY));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +16 -0
+
+	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+	if (mvif) {
+		omac_idx = mvif->omac_idx;
+		wmm_idx = mvif->wmm_idx;
+		band_idx = mvif->band_idx;
+	}
+
+	if (inband_disc) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_ALTX0;
+	} else if (beacon) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_BCN0;
+	} else if (qid >= MT_TXQ_PSD) {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+		q_idx = MT_LMAC_ALTX0;
+	} else {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+			mt76_connac_lmac_mapping(skb_get_queue_

mapping(
skb));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +40 -0
+	}
+
+	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
+	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+	txwi[0] = cpu_to_le32(val);
+
+	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+	if (band_idx)
+		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+	txwi[1] = cpu_to_le32(val);
+	txwi[2] = 0;
+
+	val = MT_TXD3_SW_POWER_MGMT |
+	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+	if (key)
+		val |= MT_TXD3_PROTECT_FRAME;
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		val |= MT_TXD3_NO_ACK;
+	if (wcid->amsdu)
+		val |= MT_TXD3_HW_AMSDU;
+
+	txwi[3] = cpu_to_le32(val);
+	txwi[4] = 0;
+
+	val = FIELD_PREP(MT_TXD5_PID, pid);
+	if (pid >= MT_PACKET_ID_FIRST)
+		val |= MT_TXD5_TX_STATUS_HOST;
+	txwi[5] = cpu_to_le32(val);
+
+	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+	txwi[6] = cpu_to_le32(val);
+	txwi[7] = 0;
+
+	if (is_8023)
+		mt76_connac3_mac_write_txwi_8023(txwi, skb,

wcid);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+	else
+		mt76_connac3_mac_write_txwi_80211(dev, txwi,

skb, key);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+
+	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+		struct ieee80211_hdr *hdr = (struct

ieee80211_hdr
*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		bool mcast = ieee80211_is_data(hdr-
Quoted 1 line

frame_control) &&

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     is_multicast_ether_addr(hdr-
Quoted 1 line

addr1);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+		if (mvif) {
+			if (mcast && mvif->mcast_rates_idx)
+				idx = mvif->mcast_rates_idx;
+			else if (beacon && mvif-
Quoted 1 line

beacon_rates_idx)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+				idx = mvif->beacon_rates_idx;
+			else
+				idx = mvif->basic_rates_idx;
+		}
+
+		txwi[6] |=

cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,
idx));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list)
+{
+	__le32 *txwi;
+	u16 wcid_idx;
+
+	mt76_connac_txp_skb_unmap(dev, t);
+	if (!t->skb)
+		goto out;
+
+	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+	if (sta) {
+		struct mt76_wcid *wcid = (struct mt76_wcid

*)sta-

Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+
+		wcid_idx = wcid->idx;
+		if (likely(t->skb->protocol !=

cpu_to_be16(ETH_P_PAE)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+			mt76_connac3_tx_check_aggr(sta, txwi);
+	} else {
+		wcid_idx = le32_get_bits(txwi[1],

MT_TXD1_WLAN_IDX);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+	}
+
+	__mt76_tx_complete_skb(dev, wcid_idx, t->skb,

free_list);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+out:
+	t->skb = NULL;
+	mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +51 -0
+			     int pid, __le32 *txs_data)
+{
+	struct mt76_sta_stats *stats = &wcid->stats;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_tx_info *info;
+	u32 txrate, txs, mode, stbc;
+	struct rate_info rate = {};
+	struct sk_buff_head list;
+	struct mt76_phy *mphy;
+	struct sk_buff *skb;
+	bool cck = false;
+
+	mt76_tx_status_lock(dev, &list);
+	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+	if (!skb)
+		goto out_no_skb;
+
+	txs = le32_to_cpu(txs_data[0]);
+
+	info = IEEE80211_SKB_CB(skb);
+	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	info->status.ampdu_len = 1;
+	info->status.ampdu_ack_len = !!(info->flags &
+					IEEE80211_TX_STAT_ACK);
+	info->status.rates[0].idx = -1;
+
+	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+	if (stbc && rate.nss > 1)
+		rate.nss >>= 1;
+
+	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+		stats->tx_nss[rate.nss - 1]++;
+	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+		stats->tx_mcs[rate.mcs]++;
+
+	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+	switch (mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+		if (mphy->chandef.chan->band ==

NL80211_BAND_5GHZ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+			sband = &mphy->sband_5g.sband;
+		else if (mphy->chandef.chan->band ==

NL80211_BAND_6GHZ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+			sband = &mphy->sband_6g.sband;
+		else
+			sband = &mphy->sband_2g.sband;
+
+		rate.mcs = mt76_get_rate(mphy->dev, sband,

rate.mcs,
cck);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		rate.legacy = sband-
Quoted 1 line

bitrates[rate.mcs].bitrate;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+		break;
+	case MT_PHY_TYPE_HT:
+	case MT_PHY_TYPE_HT_GF:
+		if (rate.mcs > 31)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_MCS;
+		if (wcid->rate.flags &

RATE_INFO_FLAGS_SHORT_GI)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		break;
+	case MT_PHY_TYPE_VHT:
+		if (rate.mcs > 9)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+		break;
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+	case MT_PHY_TYPE_HE_MU:
+		if (rate.mcs > 11)
+			goto out;
+
+		rate.he_gi = wcid->rate.he_gi;
+		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM,

txrate);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +51 -0
+		rate.flags = RATE_INFO_FLAGS_HE_MCS;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		if (rate.mcs > 13)
+			goto out;
+
+		rate.eht_gi = wcid->rate.eht_gi;
+		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+		break;
+	default:
+		goto out;
+	}
+
+	stats->tx_mode[mode]++;
+
+	switch (FIELD_GET(MT_TXS0_BW, txs)) {
+	case IEEE80211_STA_RX_BW_320:
+		rate.bw = RATE_INFO_BW_320;
+		stats->tx_bw[4]++;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		rate.bw = RATE_INFO_BW_160;
+		stats->tx_bw[3]++;
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		rate.bw = RATE_INFO_BW_80;
+		stats->tx_bw[2]++;
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		rate.bw = RATE_INFO_BW_40;
+		stats->tx_bw[1]++;
+		break;
+	default:
+		rate.bw = RATE_INFO_BW_20;
+		stats->tx_bw[0]++;
+		break;
+	}
+	wcid->rate = rate;
+
+out:
+	mt76_tx_status_skb_done(dev, skb, &list);
+
+out_no_skb:
+	mt76_tx_status_unlock(dev, &list);
+
+	return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void

*data,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +32 -0
+			      u32 max_wtbl_size)
+{
+	struct mt76_wcid *wcid;
+	__le32 *txs_data = data;
+	u16 wcidx;
+	u8 pid;
+
+	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
+		return;
+
+	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+	if (pid < MT_PACKET_ID_FIRST)
+		return;
+
+	if (wcidx >= max_wtbl_size)
+		return;
+
+	rcu_read_lock();
+
+	wcid = rcu_dereference(dev->wcid[wcidx]);
+	if (!wcid)
+		goto out;
+
+	mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
+	if (!wcid->sta)
+		goto out;
+
+	spin_lock_bh(&dev->sta_poll_lock);
+	if (list_empty(&wcid->poll_list))
+		list_add_tail(&wcid->poll_list, &dev-
Quoted 1 line

sta_poll_list);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +21 -0
+	spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *txwi;
+	int id;
+
+	spin_lock_bh(&dev->token_lock);
+	idr_for_each_entry(&dev->token, txwi, id) {
+		mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+		dev->token_count--;
+	}
+	spin_unlock_bh(&dev->token_lock);
+	idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 6663a0b46541..bcc1d976b2b0 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +0 -0
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h line 9

Quoted 6 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +1 -0
+/* NOTE: used to map mt76_rates. idx may change if firmware

expands
table */

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL	11
+#define MT76_CONNAC3_BEACON_RATES_TBL	25

Different devices may have different defined value.

Quoted 7 lines

The other WiFi7 device I am working on relies on the values I moved
in
mt76_connac3_mac.h (in common with mt7996). Moreover you can still
have per-device values in mt7996/mac.h (I have not removed it).

Quoted 7 lines

Please double check with the mtk folk you work with. The 11 and 25 is
the value I discussed with firmware folks to avoid overlapping the tbl
mt7996 use (MU/other algo in fw), or it causes something hardly solving
issue

Quoted 6 lines

sure, thx for pointing this out.
@Deren: can you please double check?

Regards,
Lorenzo

The idx is defined by different flow in fw and may be changed in next stage development. I think it's better to keep them in per-chip header.

Regards,
Deren

Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
Quoted 5 lines

I'm thinking if it's too early to create this patch for just moving
mt7996 to connac3_lib?

The code I moved is used by the other device as well. This series is
a
preliminary series to support it.

Regards,
Lorenzo

Quoted 3 lines

Ryder

author maintainer
#27 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

Quoted 1,034 lines · Deren Wu
Quoted 1,033 lines · On Fri, 2023-06-09 at 18:45 +0200, [email protected] wrote:
Quoted 1,032 lines
Quoted 1,015 lines · On Fri, 2023-06-09 at 18:34 +0200, [email protected] wrote:
Quoted 1,005 lines · Ryder Lee
Quoted 1,004 lines · Lorenzo Bianconi

External email : Please do not click links or open attachments
until
you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse mac
code
shared
between WiFi7 chipsets.

---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +
 .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +-------
----
----
--
 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-)
 create mode 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/Makefile +0 -0
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o

mt76x02_mac.o
mt76x02_mcu.o \

mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o

drivers/net/wireless/mediatek/mt76/Makefile +1 -1
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o

mt76_connac3_mac.o

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/

drivers/net/wireless/mediatek/mt76/mt76_connac.h +0 -0
index 68bdeada1421..20111678537b 100644
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct

mt76_dev
*dev, struct mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
 			    struct list_head *free_list);
 void mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb,
__le32
*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+					 u8 mode);
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				  struct

ieee80211_supported_band
*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+				  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32
*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct sk_buff *skb, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 struct ieee80211_key_conf

*key, int
pid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
+				 enum mt76_txq_id qid, u32

changed);
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list);
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void

*data,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+			      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file mode 100644
index 000000000000..4b745bb74ca0

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_

HE_##f)
+#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(
v,
MT_CRXV_HE_##m),\

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+						 IEEE80211_RADI

OTAP_HE_
##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+{
+	struct mt76_wcid *wcid;
+	u16 fc, tid;
+	u32 val;
+
+	if (!sta ||
+	    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+	if (tid >= 6) /* skip VO queue */
+		return;
+
+	val = le32_to_cpu(txwi[2]);
+	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+	if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+		return;
+
+	wcid = (struct mt76_wcid *)sta->drv_priv;
+	if (!test_and_set_bit(tid, &wcid->ampdu_state))
+		ieee80211_start_tx_ba_session(sta, tid, 0);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				       struct

ieee80211_radiotap_he
*he,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+				       __le32 *rxv)
+{
+	u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC),

offs = 0;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+
+	status->bw = RATE_INFO_BW_HE_RU;
+
+	switch (ru) {
+	case 0 ... 36:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_26;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru;
+		break;
+	case 37 ... 52:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_52;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru - 37;
+		break;
+	case 53 ... 60:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_106;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru - 53;
+		break;
+	case 61 ... 64:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_242;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru - 61;
+		break;
+	case 65 ... 66:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_484;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		offs = ru - 65;
+		break;
+	case 67:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_996;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+		break;
+	case 68:
+		status->he_ru =

NL80211_RATE_INFO_HE_RU_ALLOC_2x996;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+		break;
+	}
+
+	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+		     le16_encode_bits(offs,
+				      IEEE80211_RADIOTAP_HE_DAT

A2_RU_OF
FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+}
+
+#define MU_PREP(f, v)	le16_encode_bits(v,

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb,

__le32
*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	static const struct ieee80211_radiotap_he_mu mu_known =

{

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KN

OWN),

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		.flags2 =

HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+	};
+	struct ieee80211_radiotap_he_mu *he_mu;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+	he_mu = skb_push(skb, sizeof(mu_known));
+	memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status-
Quoted 1 line

rate_idx);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+	if (status->he_dcm)
+		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM,

status-

Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW,

status->bw) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+				 le32_get_bits(rxv[4],

MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+	he_mu->ru_ch1[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU0) &
0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+
+	if (status->bw >= RATE_INFO_BW_40) {
+		he_mu->flags1 |=

HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+	}
+
+	if (status->bw >= RATE_INFO_BW_80) {
+		u32 ru_h, ru_l;
+
+		he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		ru_l = le32_get_bits(rxv[16],

MT_CRXV_HE_RU3_L);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H)

& 0x7;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+	}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff

*skb,
__le32
*rxv,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+					 u8 mode)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +15 -0
+	static const struct ieee80211_radiotap_he known = {
+		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
+			 HE_BITS(DATA1_STBC_KNOWN) |
+			 HE_BITS(DATA1_CODING_KNOWN) |
+			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+			 HE_BITS(DATA1_DOPPLER_KNOWN) |
+			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
+		.data2 = HE_BITS(DATA2_GI_KNOWN) |
+			 HE_BITS(DATA2_TXBF_KNOWN) |
+			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+			 HE_BITS(DATA2_TXOP_KNOWN),
+	};
+	u32 ltf_size = le32_get_bits(rxv[4],

MT_CRXV_HE_LTF_SIZE) + 1;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+	struct ieee80211_radiotap_he *he;
+
+	status->flag |= RX_FLAG_RADIOTAP_HE;
+
+	he = skb_push(skb, sizeof(known));
+	memcpy(he, &known, sizeof(known));
+
+	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9])

|

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM,

rxv[4]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK,

rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG,

rxv[5]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+		    le16_encode_bits(ltf_size,
+				     IEEE80211_RADIOTAP_HE_DATA

5_LTF_SI
ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+		he->data5 |= HE_BITS(DATA5_TXBF);
+	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+	switch (mode) {
+	case MT_PHY_TYPE_HE_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE,

BEAM_CHNG,
rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA3_UL_DL, UPLINK,

rxv[5]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+		break;
+	case MT_PHY_TYPE_HE_EXT_SU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN) |
+			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK,

rxv[5]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		break;
+	case MT_PHY_TYPE_HE_MU:
+		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+			     HE_BITS(DATA1_UL_DL_KNOWN);
+
+		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK,

rxv[5]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID,

rxv[8]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status,

he,
rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		mt76_connac3_mac_decode_he_mu_radiotap(skb,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+		break;
+	case MT_PHY_TYPE_HE_TB:
+		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1,

SR_MASK,
rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE2,

SR1_MASK,
rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE3,

SR2_MASK,
rxv[13]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     HE_PREP(DATA4_TB_SPTL_REUSE4,

SR3_MASK,
rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+		mt76_connac3_mac_decode_he_radiotap_ru(status,

he,
rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+				  struct mt76_rx_status

*status,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				  struct

ieee80211_supported_band
*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +32 -0
+				  __le32 *rxv, u8 *mode)
+{
+	u8 stbc, gi, bw, dcm, nss;
+	bool cck = false;
+	u32 v0, v2;
+	int i, idx;
+
+	v0 = le32_to_cpu(rxv[0]);
+	v2 = le32_to_cpu(rxv[2]);
+
+	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+	i = idx;
+	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+	dcm = FIELD_GET(MT_PRXV_DCM, v2);
+	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+	switch (*mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		i = mt76_get_rate(dev, sband, i, cck);
+		break;
+	case MT_PHY_TYPE_HT_GF:
+	case MT_PHY_TYPE_HT:
+		status->encoding = RX_ENC_HT;
+		if (gi)
+			status->enc_flags |=

RX_ENC_FLAG_SHORT_GI;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+		if (i > 31)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_VHT:
+		status->nss = nss;
+		status->encoding = RX_ENC_VHT;
+		if (gi)
+			status->enc_flags |=

RX_ENC_FLAG_SHORT_GI;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +40 -0
+		if (i > 11)
+			return -EINVAL;
+		break;
+	case MT_PHY_TYPE_HE_MU:
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+		status->nss = nss;
+		status->encoding = RX_ENC_HE;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+			status->he_gi = gi;
+
+		status->he_dcm = dcm;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		status->nss = nss;
+		status->encoding = RX_ENC_EHT;
+		i &= GENMASK(3, 0);
+
+		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+			status->eht.gi = gi;
+		break;
+	default:
+		return -EINVAL;
+	}
+	status->rate_idx = i;
+
+	switch (bw) {
+	case IEEE80211_STA_RX_BW_20:
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+		    (idx & MT_PRXV_TX_ER_SU_106T)) {
+			status->bw = RATE_INFO_BW_HE_RU;
+			status->he_ru =
+				NL80211_RATE_INFO_HE_RU_ALLOC_1

06;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +27 -0
+		} else {
+			status->bw = RATE_INFO_BW_40;
+		}
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		status->bw = RATE_INFO_BW_80;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		status->bw = RATE_INFO_BW_160;
+		break;
+	case IEEE80211_STA_RX_BW_320:
+		status->bw = RATE_INFO_BW_320;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+	if (*mode < MT_PHY_TYPE_HE_SU && gi)
+		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct

sk_buff
*skb,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +12 -0
+				 struct mt76_wcid *wcid)
+{
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	u8 fc_type, fc_stype;
+	u16 ethertype;
+	bool wmm = false;
+	u32 val;
+
+	if (wcid->sta) {
+		struct ieee80211_sta *sta;
+
+		sta = container_of((void *)wcid, struct

ieee80211_sta,
drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		wmm = sta->wme;
+	}
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT,

MT_HDR_FORMAT_802_3) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +19 -0
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	ethertype = get_unaligned_be16(&skb->data[12]);
+	if (ethertype >= ETH_P_802_3_MIN)
+		val |= MT_TXD1_ETH_802_3;
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = IEEE80211_FTYPE_DATA >> 2;
+	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev,

__le32
*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+				  struct sk_buff *skb,
+				  struct ieee80211_key_conf

*key)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt

*)skb-

Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	bool multicast = is_multicast_ether_addr(hdr->addr1);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+	__le16 fc = hdr->frame_control;
+	u8 fc_type, fc_stype;
+	u32 val;
+
+	if (ieee80211_is_action(fc) &&
+	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+	    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+		tid = MT_TX_ADDBA;
+	else if (ieee80211_is_mgmt(hdr->frame_control))
+		tid = MT_TX_NORMAL;
+
+	val = FIELD_PREP(MT_TXD1_HDR_FORMAT,

MT_HDR_FORMAT_802_11) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+	      FIELD_PREP(MT_TXD1_HDR_INFO,
+			 ieee80211_get_hdrlen_from_skb(skb) /

2) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+	      FIELD_PREP(MT_TXD1_TID, tid);
+
+	if (!ieee80211_is_data(fc) || multicast ||
+	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+		val |= MT_TXD1_FIXED_RATE;
+
+	if (key && multicast &&

ieee80211_is_robust_mgmt_frame(skb) &&

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		val |= MT_TXD1_BIP;
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+	}
+
+	txwi[1] |= cpu_to_le32(val);
+
+	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >>

2;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >>

4;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+	txwi[2] |= cpu_to_le32(val);
+
+	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM,

multicast));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+	if (ieee80211_is_beacon(fc)) {
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+		if (ieee80211_is_back_req(hdr->frame_control))

{

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+			struct ieee80211_bar *bar;
+
+			bar = (struct ieee80211_bar *)skb-
Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			seqno = le16_to_cpu(bar-
Quoted 1 line

start_seq_num);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+		}
+
+		val = MT_TXD3_SN_VALID |
+		      FIELD_PREP(MT_TXD3_SEQ,

IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(val);
+		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+	}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32
*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct sk_buff *skb, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 struct ieee80211_key_conf

*key, int
pid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+				 enum mt76_txq_id qid, u32

changed)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+	u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :

MT_SDIO_TXD_SIZE;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = info->control.vif;
+	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >>

2;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+	bool is_8023 = info->flags &

IEEE80211_TX_CTL_HW_80211_ENCAP;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+	struct mt76_vif *mvif;
+	u16 tx_count = 15;
+	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+				    BSS_CHANGED_BEACON_ENABLED)

);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+	bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+					 BSS_CHANGED_FILS_DISCO

VERY));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +16 -0
+
+	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+	if (mvif) {
+		omac_idx = mvif->omac_idx;
+		wmm_idx = mvif->wmm_idx;
+		band_idx = mvif->band_idx;
+	}
+
+	if (inband_disc) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_ALTX0;
+	} else if (beacon) {
+		p_fmt = MT_TX_TYPE_FW;
+		q_idx = MT_LMAC_BCN0;
+	} else if (qid >= MT_TXQ_PSD) {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+		q_idx = MT_LMAC_ALTX0;
+	} else {
+		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+			mt76_connac_lmac_mapping(skb_get_queue_

mapping(
skb));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +40 -0
+	}
+
+	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
+	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+	txwi[0] = cpu_to_le32(val);
+
+	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+	if (band_idx)
+		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+	txwi[1] = cpu_to_le32(val);
+	txwi[2] = 0;
+
+	val = MT_TXD3_SW_POWER_MGMT |
+	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+	if (key)
+		val |= MT_TXD3_PROTECT_FRAME;
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		val |= MT_TXD3_NO_ACK;
+	if (wcid->amsdu)
+		val |= MT_TXD3_HW_AMSDU;
+
+	txwi[3] = cpu_to_le32(val);
+	txwi[4] = 0;
+
+	val = FIELD_PREP(MT_TXD5_PID, pid);
+	if (pid >= MT_PACKET_ID_FIRST)
+		val |= MT_TXD5_TX_STATUS_HOST;
+	txwi[5] = cpu_to_le32(val);
+
+	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+	txwi[6] = cpu_to_le32(val);
+	txwi[7] = 0;
+
+	if (is_8023)
+		mt76_connac3_mac_write_txwi_8023(txwi, skb,

wcid);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+	else
+		mt76_connac3_mac_write_txwi_80211(dev, txwi,

skb, key);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+
+	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+		struct ieee80211_hdr *hdr = (struct

ieee80211_hdr
*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		bool mcast = ieee80211_is_data(hdr-
Quoted 1 line

frame_control) &&

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+			     is_multicast_ether_addr(hdr-
Quoted 1 line

addr1);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+		if (mvif) {
+			if (mcast && mvif->mcast_rates_idx)
+				idx = mvif->mcast_rates_idx;
+			else if (beacon && mvif-
Quoted 1 line

beacon_rates_idx)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+				idx = mvif->beacon_rates_idx;
+			else
+				idx = mvif->basic_rates_idx;
+		}
+
+		txwi[6] |=

cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,
idx));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+			    struct ieee80211_sta *sta,
+			    struct list_head *free_list)
+{
+	__le32 *txwi;
+	u16 wcid_idx;
+
+	mt76_connac_txp_skb_unmap(dev, t);
+	if (!t->skb)
+		goto out;
+
+	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+	if (sta) {
+		struct mt76_wcid *wcid = (struct mt76_wcid

*)sta-

Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+
+		wcid_idx = wcid->idx;
+		if (likely(t->skb->protocol !=

cpu_to_be16(ETH_P_PAE)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+			mt76_connac3_tx_check_aggr(sta, txwi);
+	} else {
+		wcid_idx = le32_get_bits(txwi[1],

MT_TXD1_WLAN_IDX);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+	}
+
+	__mt76_tx_complete_skb(dev, wcid_idx, t->skb,

free_list);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+out:
+	t->skb = NULL;
+	mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +51 -0
+			     int pid, __le32 *txs_data)
+{
+	struct mt76_sta_stats *stats = &wcid->stats;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_tx_info *info;
+	u32 txrate, txs, mode, stbc;
+	struct rate_info rate = {};
+	struct sk_buff_head list;
+	struct mt76_phy *mphy;
+	struct sk_buff *skb;
+	bool cck = false;
+
+	mt76_tx_status_lock(dev, &list);
+	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+	if (!skb)
+		goto out_no_skb;
+
+	txs = le32_to_cpu(txs_data[0]);
+
+	info = IEEE80211_SKB_CB(skb);
+	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	info->status.ampdu_len = 1;
+	info->status.ampdu_ack_len = !!(info->flags &
+					IEEE80211_TX_STAT_ACK);
+	info->status.rates[0].idx = -1;
+
+	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+	if (stbc && rate.nss > 1)
+		rate.nss >>= 1;
+
+	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+		stats->tx_nss[rate.nss - 1]++;
+	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+		stats->tx_mcs[rate.mcs]++;
+
+	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+	switch (mode) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		fallthrough;
+	case MT_PHY_TYPE_OFDM:
+		mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+		if (mphy->chandef.chan->band ==

NL80211_BAND_5GHZ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+			sband = &mphy->sband_5g.sband;
+		else if (mphy->chandef.chan->band ==

NL80211_BAND_6GHZ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+			sband = &mphy->sband_6g.sband;
+		else
+			sband = &mphy->sband_2g.sband;
+
+		rate.mcs = mt76_get_rate(mphy->dev, sband,

rate.mcs,
cck);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +1 -0
+		rate.legacy = sband-
Quoted 1 line

bitrates[rate.mcs].bitrate;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+		break;
+	case MT_PHY_TYPE_HT:
+	case MT_PHY_TYPE_HT_GF:
+		if (rate.mcs > 31)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_MCS;
+		if (wcid->rate.flags &

RATE_INFO_FLAGS_SHORT_GI)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		break;
+	case MT_PHY_TYPE_VHT:
+		if (rate.mcs > 9)
+			goto out;
+
+		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+		break;
+	case MT_PHY_TYPE_HE_SU:
+	case MT_PHY_TYPE_HE_EXT_SU:
+	case MT_PHY_TYPE_HE_TB:
+	case MT_PHY_TYPE_HE_MU:
+		if (rate.mcs > 11)
+			goto out;
+
+		rate.he_gi = wcid->rate.he_gi;
+		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM,

txrate);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +51 -0
+		rate.flags = RATE_INFO_FLAGS_HE_MCS;
+		break;
+	case MT_PHY_TYPE_EHT_SU:
+	case MT_PHY_TYPE_EHT_TRIG:
+	case MT_PHY_TYPE_EHT_MU:
+		if (rate.mcs > 13)
+			goto out;
+
+		rate.eht_gi = wcid->rate.eht_gi;
+		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+		break;
+	default:
+		goto out;
+	}
+
+	stats->tx_mode[mode]++;
+
+	switch (FIELD_GET(MT_TXS0_BW, txs)) {
+	case IEEE80211_STA_RX_BW_320:
+		rate.bw = RATE_INFO_BW_320;
+		stats->tx_bw[4]++;
+		break;
+	case IEEE80211_STA_RX_BW_160:
+		rate.bw = RATE_INFO_BW_160;
+		stats->tx_bw[3]++;
+		break;
+	case IEEE80211_STA_RX_BW_80:
+		rate.bw = RATE_INFO_BW_80;
+		stats->tx_bw[2]++;
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		rate.bw = RATE_INFO_BW_40;
+		stats->tx_bw[1]++;
+		break;
+	default:
+		rate.bw = RATE_INFO_BW_20;
+		stats->tx_bw[0]++;
+		break;
+	}
+	wcid->rate = rate;
+
+out:
+	mt76_tx_status_skb_done(dev, skb, &list);
+
+out_no_skb:
+	mt76_tx_status_unlock(dev, &list);
+
+	return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void

*data,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +32 -0
+			      u32 max_wtbl_size)
+{
+	struct mt76_wcid *wcid;
+	__le32 *txs_data = data;
+	u16 wcidx;
+	u8 pid;
+
+	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
+		return;
+
+	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+	if (pid < MT_PACKET_ID_FIRST)
+		return;
+
+	if (wcidx >= max_wtbl_size)
+		return;
+
+	rcu_read_lock();
+
+	wcid = rcu_dereference(dev->wcid[wcidx]);
+	if (!wcid)
+		goto out;
+
+	mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
+	if (!wcid->sta)
+		goto out;
+
+	spin_lock_bh(&dev->sta_poll_lock);
+	if (list_empty(&wcid->poll_list))
+		list_add_tail(&wcid->poll_list, &dev-
Quoted 1 line

sta_poll_list);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +21 -0
+	spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *txwi;
+	int id;
+
+	spin_lock_bh(&dev->token_lock);
+	idr_for_each_entry(&dev->token, txwi, id) {
+		mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+		dev->token_count--;
+	}
+	spin_unlock_bh(&dev->token_lock);
+	idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 6663a0b46541..bcc1d976b2b0 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +0 -0
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h line 9

Quoted 6 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +1 -0
+/* NOTE: used to map mt76_rates. idx may change if firmware

expands
table */

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL	11
+#define MT76_CONNAC3_BEACON_RATES_TBL	25

Different devices may have different defined value.

Quoted 7 lines

The other WiFi7 device I am working on relies on the values I moved
in
mt76_connac3_mac.h (in common with mt7996). Moreover you can still
have per-device values in mt7996/mac.h (I have not removed it).

Please double check with the mtk folk you work with. The 11 and 25 is
the value I discussed with firmware folks to avoid overlapping the tbl
mt7996 use (MU/other algo in fw), or it causes something hardly solving
issue

Quoted 8 lines
Quoted 6 lines

sure, thx for pointing this out.
@Deren: can you please double check?

Regards,
Lorenzo

The idx is defined by different flow in fw and may be changed in next stage development. I think it's better to keep them in per-chip header.

ack, I will fix it.

Regards,
Lorenzo

Quoted 21 lines

Regards,
Deren

Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
Quoted 5 lines

I'm thinking if it's too early to create this patch for just moving
mt7996 to connac3_lib?

The code I moved is used by the other device as well. This series is
a
preliminary series to support it.

Regards,
Lorenzo

Quoted 3 lines

Ryder

author maintainer
#23 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

In reply to [email protected]
Quoted 13 lines · Shayne Chen
Quoted 12 lines
Quoted 12 lines
Quoted 1 line

On Fri, 2023-06-09 at 18:34 +0200, [email protected]

Quoted 4 lines · wrote:
Quoted 4 lines · Ryder Lee
Quoted 3 lines · Lorenzo Bianconi
Quoted 2 lines

External email : Please do not click links or open

attachments

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

until you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse mac

Quoted 6 lines
Quoted 6 lines
Quoted 4 lines

code

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

shared between WiFi7 chipsets.

Hi Lorenzo,

Hi Shayne,

Quoted 10 lines
Quoted 10 lines

I don't think it's a good idea to start sharing mac or mcu functions for all WiFi7 chipsets at such early stage.

The driver is still under many processes of bug fixing, performance tuning, and new features development.
Chipsets that mainly used for AP or STA segment have different designs
and should face different problems.

Quoted 4 lines
Quoted 4 lines

Start sharing the code at early stage will break the independence, make
it more hard to develop and do verifications, since many changes will affect chipsets of both segments.

my goal is to share the code that hardly will be changed (or that will have very few changes in the future, i.e. I have not changed mcu codebase). If you consider for example the routines below:

- mt76_connac*_mac_write_txwi_8023()
- mt76_connac*_mac_write_txwi_80211()
- mt76_connac*_mac_add_txs_skb()
- mt76_connac*_txwi_free()
- ...

they are the same for mt7615/mt7663, mt7921/mt7915, mt7996/.. , what is changing is just register map between versions (e.g. mt7615/mt7663 and mt7915/mt7921). I think it is not a good idea to copy-paste the code because it will just make the code much harder to maintain, and this will be more difficult to address in the future.
If you consider the commit below:

commit ead449023d3acb1424886d7b8cc672ed69bdd27e

Author: Lorenzo Bianconi <[email protected]>
Date:   Sun May 28 12:28:49 2023 +0200

wifi: mt76: mt7996: fix possible NULL pointer dereference in mt7996_mac_write_txwi()

Fix possible NULL pointer dereference on mvif pointer in mt7996_mac_write_txwi routine.

Deren will needs to monitor the ML and apply the same fix for the other WiFi7 chipset too.

Moreover I kept mt7996/mac.{c,h} to put the per-chipset codebase. If you think MT76_CONNAC3_BASIC_RATES_TBL11 and MT76_CONNAC3_BEACON_RATES_TBL25 are sensible, we can put them in mt7996/mac.h

Regards,
Lorenzo

Quoted 1,007 lines
Quoted 4 lines

Thanks,
Shayne

(Resend for missing CC)

Quoted 1,001 lines
Quoted 1,001 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +  
.../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +-----

--

----

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

----
--

 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-

) create

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

drivers/net/wireless/mediatek/mt76/Makefile mt76x02-lib-y := mt76x02_util.o

Quoted 9 lines

mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/Makefile +0 -0
index 84c99b7e57f9..d8e8079c8b54 100644
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o

mt76x02_mac.o

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/wireless/mediatek/mt76/Makefile +1 -1
 mt76x02_mcu.o \
 
 mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o

mt76_connac3_mac.o

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h void mt76_connac2_txwi_free(struct

Quoted 8 lines

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ diff --git
a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 68bdeada1421..20111678537b 100644

drivers/net/wireless/mediatek/mt76/mt76_connac.h +0 -0
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct

mt76_dev

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
 *dev, struct mt76_txwi_cache *t,
     struct list_head *free_list);  void 
 mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff

*skb,

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 9 lines

__le32
*rxv,
+ u8 mode);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+  struct mt76_rx_status *status,
+  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32

Quoted 69 lines
Quoted 69 lines
Quoted 69 lines
Quoted 69 lines

*txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key, int
pid,
+ enum mt76_txq_id qid, u32 changed); void +mt76_connac3_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+    struct ieee80211_sta *sta,
+    struct list_head *free_list); void 
+mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
+      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file mode 100644
index 000000000000..4b745bb74ca0

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)cpu_to_le16(IEEE80211_RADIOTAP_

HE_##f)
+#define HE_PREP(f, m, v)le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
+ IEEE80211_RADIOTAP_HE_
##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta,

__le32
*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+{
+struct mt76_wcid *wcid;
+u16 fc, tid;
+u32 val;
+
+if (!sta ||
+    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+return;
+
+tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+if (tid >= 6) /* skip VO queue */
+return;
+
+val = le32_to_cpu(txwi[2]);
+fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+return;
+
+wcid = (struct mt76_wcid *)sta->drv_priv;
+if (!test_and_set_bit(tid, &wcid->ampdu_state))
+ieee80211_start_tx_ba_session(sta, tid, 0); } 
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

mt76_rx_status
*status,
+ struct ieee80211_radiotap_he
*he,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+       __le32 *rxv)
+{
+u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs

=

0;

Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +36 -0
+
+status->bw = RATE_INFO_BW_HE_RU;
+
+switch (ru) {
+case 0 ... 36:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+offs = ru;
+break;
+case 37 ... 52:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+offs = ru - 37;
+break;
+case 53 ... 60:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+offs = ru - 53;
+break;
+case 61 ... 64:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+offs = ru - 61;
+break;
+case 65 ... 66:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+offs = ru - 65;
+break;
+case 67:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+break;
+case 68:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+break;
+}
+
+he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+     le16_encode_bits(offs,
+      IEEE80211_RADIOTAP_HE_DATA2_RU_OF

FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+}
+
+#define MU_PREP(f, v)le16_encode_bits(v,
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff

*skb,
__le32
*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 46 lines
Quoted 17 lines
Quoted 17 lines
Quoted 7 lines
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+static const struct ieee80211_radiotap_he_mu mu_known = {
+.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+};
+struct ieee80211_radiotap_he_mu *he_mu;
+
+status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+he_mu = skb_push(skb, sizeof(mu_known));
+memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status-

rate_idx);

Quoted 6 lines
Quoted 6 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 6 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+if (status->he_dcm)
+he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status-
Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status-

bw) |

Quoted 19 lines
Quoted 19 lines
Quoted 19 lines

+ MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+ le32_get_bits(rxv[4],
MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0)

&
0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+
+if (status->bw >= RATE_INFO_BW_40) {
+he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+}
+
+if (status->bw >= RATE_INFO_BW_80) {
+u32 ru_h, ru_l;
+
+he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+
+ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
+ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
+he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff

*skb,

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 5 lines

__le32
*rxv,
+ u8 mode)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 8 lines
Quoted 1 line

cb;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+static const struct ieee80211_radiotap_he known = {
+.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+ HE_BITS(DATA1_DATA_DCM_KNOWN) |
+ HE_BITS(DATA1_STBC_KNOWN) |
+ HE_BITS(DATA1_CODING_KNOWN) |
+ HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+ HE_BITS(DATA1_DOPPLER_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+ HE_BITS(DATA1_BSS_COLOR_KNOWN),
+.data2 = HE_BITS(DATA2_GI_KNOWN) |
+ HE_BITS(DATA2_TXBF_KNOWN) |
+ HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+ HE_BITS(DATA2_TXOP_KNOWN),
+};
+u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE)
+

1;

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+struct ieee80211_radiotap_he *he;
+
+status->flag |= RX_FLAG_RADIOTAP_HE;
+
+he = skb_push(skb, sizeof(known));
+memcpy(he, &known, sizeof(known));
+
+he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
+    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
+he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK,

rxv[13]);

Quoted 166 lines
Quoted 166 lines
Quoted 166 lines
Quoted 166 lines

+he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5])

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+    le16_encode_bits(ltf_size,
+     IEEE80211_RADIOTAP_HE_DATA5_LTF_SI

ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+he->data5 |= HE_BITS(DATA5_TXBF);
+he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+switch (mode) {
+case MT_PHY_TYPE_HE_SU:
+he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+     HE_BITS(DATA1_UL_DL_KNOWN) |
+     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG,

rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+break;
+case MT_PHY_TYPE_HE_EXT_SU:
+he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+     HE_BITS(DATA1_UL_DL_KNOWN) |
+     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+break;
+case MT_PHY_TYPE_HE_MU:
+he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+     HE_BITS(DATA1_UL_DL_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
+
+mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +9 -0
+mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
+break;
+case MT_PHY_TYPE_HE_TB:
+he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK,

rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK,
rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK,
rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK,
rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+
+mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+break;
+default:
+break;
+}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
+  struct mt76_rx_status *status,
+  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +99 -0
+  __le32 *rxv, u8 *mode)
+{
+u8 stbc, gi, bw, dcm, nss;
+bool cck = false;
+u32 v0, v2;
+int i, idx;
+
+v0 = le32_to_cpu(rxv[0]);
+v2 = le32_to_cpu(rxv[2]);
+
+idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+i = idx;
+nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+dcm = FIELD_GET(MT_PRXV_DCM, v2);
+bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+switch (*mode) {
+case MT_PHY_TYPE_CCK:
+cck = true;
+fallthrough;
+case MT_PHY_TYPE_OFDM:
+i = mt76_get_rate(dev, sband, i, cck);
+break;
+case MT_PHY_TYPE_HT_GF:
+case MT_PHY_TYPE_HT:
+status->encoding = RX_ENC_HT;
+if (gi)
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+if (i > 31)
+return -EINVAL;
+break;
+case MT_PHY_TYPE_VHT:
+status->nss = nss;
+status->encoding = RX_ENC_VHT;
+if (gi)
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+if (i > 11)
+return -EINVAL;
+break;
+case MT_PHY_TYPE_HE_MU:
+case MT_PHY_TYPE_HE_SU:
+case MT_PHY_TYPE_HE_EXT_SU:
+case MT_PHY_TYPE_HE_TB:
+status->nss = nss;
+status->encoding = RX_ENC_HE;
+i &= GENMASK(3, 0);
+
+if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+status->he_gi = gi;
+
+status->he_dcm = dcm;
+break;
+case MT_PHY_TYPE_EHT_SU:
+case MT_PHY_TYPE_EHT_TRIG:
+case MT_PHY_TYPE_EHT_MU:
+status->nss = nss;
+status->encoding = RX_ENC_EHT;
+i &= GENMASK(3, 0);
+
+if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+status->eht.gi = gi;
+break;
+default:
+return -EINVAL;
+}
+status->rate_idx = i;
+
+switch (bw) {
+case IEEE80211_STA_RX_BW_20:
+break;
+case IEEE80211_STA_RX_BW_40:
+if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+    (idx & MT_PRXV_TX_ER_SU_106T)) {
+status->bw = RATE_INFO_BW_HE_RU;
+status->he_ru =
+NL80211_RATE_INFO_HE_RU_ALLOC_106;
+} else {
+status->bw = RATE_INFO_BW_40;
+}
+break;
+case IEEE80211_STA_RX_BW_80:
+status->bw = RATE_INFO_BW_80;
+break;
+case IEEE80211_STA_RX_BW_160:
+status->bw = RATE_INFO_BW_160;
+break;
+case IEEE80211_STA_RX_BW_320:
+status->bw = RATE_INFO_BW_320;
+break;
+default:
+return -EINVAL;
+}
+
+status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+if (*mode < MT_PHY_TYPE_HE_SU && gi)
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct

sk_buff

Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines

*skb,
+ struct mt76_wcid *wcid)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +11 -0
+{
+u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+u8 fc_type, fc_stype;
+u16 ethertype;
+bool wmm = false;
+u32 val;
+
+if (wcid->sta) {
+struct ieee80211_sta *sta;
+
+sta = container_of((void *)wcid, struct ieee80211_sta,

drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +4 -0
+wmm = sta->wme;
+}
+
+val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3)

|

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +11 -0
+      FIELD_PREP(MT_TXD1_TID, tid);
+
+ethertype = get_unaligned_be16(&skb->data[12]);
+if (ethertype >= ETH_P_802_3_MIN)
+val |= MT_TXD1_ETH_802_3;
+
+txwi[1] |= cpu_to_le32(val);
+
+fc_type = IEEE80211_FTYPE_DATA >> 2;
+fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev,

__le32

Quoted 29 lines
Quoted 4 lines
Quoted 4 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 4 lines

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+  struct sk_buff *skb,
+  struct ieee80211_key_conf *key) {
+struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb-

data;

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines

+struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb-

Quoted 1 line

data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +10 -0
+struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+bool multicast = is_multicast_ether_addr(hdr->addr1);
+u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+__le16 fc = hdr->frame_control;
+u8 fc_type, fc_stype;
+u32 val;
+
+if (ieee80211_is_action(fc) &&
+    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+tid = MT_TX_ADDBA;
+else if (ieee80211_is_mgmt(hdr->frame_control))
+tid = MT_TX_NORMAL;
+
+val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11)

|
+ FIELD_PREP(MT_TXD1_HDR_INFO,
+ ieee80211_get_hdrlen_from_skb(skb) / 2) |

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +7 -0
+      FIELD_PREP(MT_TXD1_TID, tid);
+
+if (!ieee80211_is_data(fc) || multicast ||
+    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+val |= MT_TXD1_FIXED_RATE;
+
+if (key && multicast &&

ieee80211_is_robust_mgmt_frame(skb)

&&

Quoted 33 lines
Quoted 33 lines
Quoted 33 lines
Quoted 33 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +16 -0
+    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+val |= MT_TXD1_BIP;
+txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+}
+
+txwi[1] |= cpu_to_le32(val);
+
+fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
+fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
+
+val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+txwi[2] |= cpu_to_le32(val);
+
+txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM,

multicast));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +16 -0
+if (ieee80211_is_beacon(fc)) {
+txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+}
+
+if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+if (ieee80211_is_back_req(hdr->frame_control)) {
+struct ieee80211_bar *bar;
+
+bar = (struct ieee80211_bar *)skb->data;
+seqno = le16_to_cpu(bar->start_seq_num);
+}
+
+val = MT_TXD3_SN_VALID |
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines

+ FIELD_PREP(MT_TXD3_SEQ,
IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+txwi[3] |= cpu_to_le32(val);
+txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

*txwi,
+ struct sk_buff *skb, struct mt76_wcid
*wcid,
+ struct ieee80211_key_conf *key, int
pid,
+ enum mt76_txq_id qid, u32 changed)

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+{
+u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :

MT_SDIO_TXD_SIZE;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+struct ieee80211_vif *vif = info->control.vif;
+u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+bool is_8023 = info->flags &

IEEE80211_TX_CTL_HW_80211_ENCAP;

Quoted 261 lines
Quoted 261 lines
Quoted 261 lines
Quoted 261 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +5 -0
+struct mt76_vif *mvif;
+u16 tx_count = 15;
+bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+    BSS_CHANGED_BEACON_ENABLED));
+bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+ BSS_CHANGED_FILS_DISCOVERY));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +16 -0
+
+mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+if (mvif) {
+omac_idx = mvif->omac_idx;
+wmm_idx = mvif->wmm_idx;
+band_idx = mvif->band_idx;
+}
+
+if (inband_disc) {
+p_fmt = MT_TX_TYPE_FW;
+q_idx = MT_LMAC_ALTX0;
+} else if (beacon) {
+p_fmt = MT_TX_TYPE_FW;
+q_idx = MT_LMAC_BCN0;
+} else if (qid >= MT_TXQ_PSD) {
+p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +3 -0
+q_idx = MT_LMAC_ALTX0;
+} else {
+p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +2 -0
+q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+mt76_connac_lmac_mapping(skb_get_queue_mapping(

skb));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +45 -0
+}
+
+val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
+      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+txwi[0] = cpu_to_le32(val);
+
+val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+if (band_idx)
+val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+txwi[1] = cpu_to_le32(val);
+txwi[2] = 0;
+
+val = MT_TXD3_SW_POWER_MGMT |
+      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+if (key)
+val |= MT_TXD3_PROTECT_FRAME;
+if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+val |= MT_TXD3_NO_ACK;
+if (wcid->amsdu)
+val |= MT_TXD3_HW_AMSDU;
+
+txwi[3] = cpu_to_le32(val);
+txwi[4] = 0;
+
+val = FIELD_PREP(MT_TXD5_PID, pid);
+if (pid >= MT_PACKET_ID_FIRST)
+val |= MT_TXD5_TX_STATUS_HOST;
+txwi[5] = cpu_to_le32(val);
+
+val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+txwi[6] = cpu_to_le32(val);
+txwi[7] = 0;
+
+if (is_8023)
+mt76_connac3_mac_write_txwi_8023(txwi, skb, wcid);
+else
+mt76_connac3_mac_write_txwi_80211(dev, txwi, skb, key);
+
+if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +14 -0
+bool mcast = ieee80211_is_data(hdr->frame_control) &&
+     is_multicast_ether_addr(hdr->addr1);
+u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+if (mvif) {
+if (mcast && mvif->mcast_rates_idx)
+idx = mvif->mcast_rates_idx;
+else if (beacon && mvif->beacon_rates_idx)
+idx = mvif->beacon_rates_idx;
+else
+idx = mvif->basic_rates_idx;
+}
+
+txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,

idx));

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +6 -0
+txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev, struct

mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +13 -0
+    struct ieee80211_sta *sta,
+    struct list_head *free_list)
+{
+__le32 *txwi;
+u16 wcid_idx;
+
+mt76_connac_txp_skb_unmap(dev, t);
+if (!t->skb)
+goto out;
+
+txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+if (sta) {
+struct mt76_wcid *wcid = (struct mt76_wcid *)sta-
Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +17 -0
+
+wcid_idx = wcid->idx;
+if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+mt76_connac3_tx_check_aggr(sta, txwi);
+} else {
+wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+}
+
+__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
+out:
+t->skb = NULL;
+mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct

mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +58 -0
+     int pid, __le32 *txs_data)
+{
+struct mt76_sta_stats *stats = &wcid->stats;
+struct ieee80211_supported_band *sband;
+struct ieee80211_tx_info *info;
+u32 txrate, txs, mode, stbc;
+struct rate_info rate = {};
+struct sk_buff_head list;
+struct mt76_phy *mphy;
+struct sk_buff *skb;
+bool cck = false;
+
+mt76_tx_status_lock(dev, &list);
+skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+if (!skb)
+goto out_no_skb;
+
+txs = le32_to_cpu(txs_data[0]);
+
+info = IEEE80211_SKB_CB(skb);
+if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+info->flags |= IEEE80211_TX_STAT_ACK;
+
+info->status.ampdu_len = 1;
+info->status.ampdu_ack_len = !!(info->flags &
+IEEE80211_TX_STAT_ACK);
+info->status.rates[0].idx = -1;
+
+txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+if (stbc && rate.nss > 1)
+rate.nss >>= 1;
+
+if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+stats->tx_nss[rate.nss - 1]++;
+if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+stats->tx_mcs[rate.mcs]++;
+
+mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+switch (mode) {
+case MT_PHY_TYPE_CCK:
+cck = true;
+fallthrough;
+case MT_PHY_TYPE_OFDM:
+mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+sband = &mphy->sband_5g.sband;
+else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
+sband = &mphy->sband_6g.sband;
+else
+sband = &mphy->sband_2g.sband;
+
+rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs,

cck);

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +69 -0
+rate.legacy = sband->bitrates[rate.mcs].bitrate;
+break;
+case MT_PHY_TYPE_HT:
+case MT_PHY_TYPE_HT_GF:
+if (rate.mcs > 31)
+goto out;
+
+rate.flags = RATE_INFO_FLAGS_MCS;
+if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+break;
+case MT_PHY_TYPE_VHT:
+if (rate.mcs > 9)
+goto out;
+
+rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+break;
+case MT_PHY_TYPE_HE_SU:
+case MT_PHY_TYPE_HE_EXT_SU:
+case MT_PHY_TYPE_HE_TB:
+case MT_PHY_TYPE_HE_MU:
+if (rate.mcs > 11)
+goto out;
+
+rate.he_gi = wcid->rate.he_gi;
+rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
+rate.flags = RATE_INFO_FLAGS_HE_MCS;
+break;
+case MT_PHY_TYPE_EHT_SU:
+case MT_PHY_TYPE_EHT_TRIG:
+case MT_PHY_TYPE_EHT_MU:
+if (rate.mcs > 13)
+goto out;
+
+rate.eht_gi = wcid->rate.eht_gi;
+rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+break;
+default:
+goto out;
+}
+
+stats->tx_mode[mode]++;
+
+switch (FIELD_GET(MT_TXS0_BW, txs)) {
+case IEEE80211_STA_RX_BW_320:
+rate.bw = RATE_INFO_BW_320;
+stats->tx_bw[4]++;
+break;
+case IEEE80211_STA_RX_BW_160:
+rate.bw = RATE_INFO_BW_160;
+stats->tx_bw[3]++;
+break;
+case IEEE80211_STA_RX_BW_80:
+rate.bw = RATE_INFO_BW_80;
+stats->tx_bw[2]++;
+break;
+case IEEE80211_STA_RX_BW_40:
+rate.bw = RATE_INFO_BW_40;
+stats->tx_bw[1]++;
+break;
+default:
+rate.bw = RATE_INFO_BW_20;
+stats->tx_bw[0]++;
+break;
+}
+wcid->rate = rate;
+
+out:
+mt76_tx_status_skb_done(dev, skb, &list);
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +8 -0
+
+out_no_skb:
+mt76_tx_status_unlock(dev, &list);
+
+return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void

*data,

Quoted 73 lines
Quoted 73 lines
Quoted 72 lines
Quoted 68 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file +53 -0
+      u32 max_wtbl_size)
+{
+struct mt76_wcid *wcid;
+__le32 *txs_data = data;
+u16 wcidx;
+u8 pid;
+
+if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
+return;
+
+wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+if (pid < MT_PACKET_ID_FIRST)
+return;
+
+if (wcidx >= max_wtbl_size)
+return;
+
+rcu_read_lock();
+
+wcid = rcu_dereference(dev->wcid[wcidx]);
+if (!wcid)
+goto out;
+
+mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
+if (!wcid->sta)
+goto out;
+
+spin_lock_bh(&dev->sta_poll_lock);
+if (list_empty(&wcid->poll_list))
+list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
+spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+struct mt76_txwi_cache *txwi;
+int id;
+
+spin_lock_bh(&dev->token_lock);
+idr_for_each_entry(&dev->token, txwi, id) {
+mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+dev->token_count--;
+}
+spin_unlock_bh(&dev->token_lock);
+idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 6663a0b46541..bcc1d976b2b0 100644

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +1 -0
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
+/* NOTE: used to map mt76_rates. idx may change if

firmware
expands
table */

drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h

Quoted 2 lines
drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL11
+#define MT76_CONNAC3_BEACON_RATES_TBL25

Different devices may have different defined value.

Quoted 1 line
Quoted 1 line

The other WiFi7 device I am working on relies on the values I

moved

Quoted 2 lines
Quoted 2 lines

in
mt76_connac3_mac.h (in common with mt7996). Moreover you can

still

Quoted 5 lines
Quoted 2 lines

have per-device values in mt7996/mac.h (I have not removed it).

Please double check with the mtk folk you work with. The 11 and 25

is

Quoted 2 lines

the value I discussed with firmware folks to avoid overlapping the

tbl

Quoted 1 line

mt7996 use (MU/other algo in fw), or it causes something hardly

solving

Quoted 1 line

issue

sure, thx for pointing this out.
@Deren: can you please double check?

Regards,
Lorenzo

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

I'm thinking if it's too early to create this patch for just

moving

Quoted 4 lines
Quoted 4 lines
Quoted 1 line

mt7996 to connac3_lib?

The code I moved is used by the other device as well. This series

is

Quoted 9 lines
Quoted 9 lines

a
preliminary series to support it.

Regards,
Lorenzo

Quoted 3 lines

Ryder

#24 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

Quoted 16 lines · On Sat, 2023-06-10 at 12:06 +0200, [email protected] wrote:
Quoted 16 lines · Shayne Chen
Quoted 15 lines
Quoted 15 lines
Quoted 2 lines

On Fri, 2023-06-09 at 18:34 +0200,
[email protected]

Quoted 5 lines · wrote:
Quoted 5 lines · Ryder Lee
Quoted 4 lines
Quoted 2 lines · Lorenzo Bianconi

External email : Please do not click links or open

attachments

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

until you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to reuse
mac

Quoted 9 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines

code

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

shared between WiFi7 chipsets.

Hi Lorenzo,

Hi Shayne,

Hi Lorenzo,

Quoted 51 lines
Quoted 12 lines
Quoted 12 lines

I don't think it's a good idea to start sharing mac or mcu functions
for all WiFi7 chipsets at such early stage.

The driver is still under many processes of bug fixing, performance
tuning, and new features development.
Chipsets that mainly used for AP or STA segment have different designs
and should face different problems.

Quoted 6 lines
Quoted 6 lines

Start sharing the code at early stage will break the independence,
make
it more hard to develop and do verifications, since many changes will
affect chipsets of both segments.

my goal is to share the code that hardly will be changed (or that will have
very few changes in the future, i.e. I have not changed mcu codebase).
If you consider for example the routines below:

- mt76_connac*_mac_write_txwi_8023()
- mt76_connac*_mac_write_txwi_80211()
- mt76_connac*_mac_add_txs_skb()
- mt76_connac*_txwi_free()
- ...

they are the same for mt7615/mt7663, mt7921/mt7915, mt7996/.. , what is
changing is just register map between versions (e.g. mt7615/mt7663 and
mt7915/mt7921). I think it is not a good idea to copy-paste the code because it will just make the code much harder to maintain, and this will be
more difficult to address in the future.
If you consider the commit below:

commit ead449023d3acb1424886d7b8cc672ed69bdd27e

Author: Lorenzo Bianconi <[email protected]>
Date:   Sun May 28 12:28:49 2023 +0200

wifi: mt76: mt7996: fix possible NULL pointer dereference in
mt7996_mac_write_txwi()

Fix possible NULL pointer dereference on mvif pointer in mt7996_mac_write_txwi routine.

Quoted 8 lines

Deren will needs to monitor the ML and apply the same fix for the other WiFi7
chipset too.

Moreover I kept mt7996/mac.{c,h} to put the per-chipset codebase. If you think MT76_CONNAC3_BASIC_RATES_TBL11 and MT76_CONNAC3_BEACON_RATES_TBL25
are sensible, we can put them in mt7996/mac.h

I understand your concern, but if the code starts to be shared at early stage, we may need to add several is_mt7996() to split different parts temporarily or permanently, since we have different development procedure and focusing, on devices of different segements.

Below are some examples I concern:
- We're doing some tests about switching all TXS to PPDU TXS, and the code in mac_add_txs_skb() needs to be changed. If devices of STA segement don't want to change or won't switch in short time, we may need to add is_mt7996() to split.

- When adding MLO support, there will be many changes in mac_write_txwi() and txwi_free(), compared to previous chipsets. To prevent from adding side effects to other devices, we may also need to add is_mt7996() to split code at least for temporary.

I would like to know is it fine with you to add some is_mt7996() to the shared code for the above examples?
I think this could help to balance the trade off between sharing code and assuring the driver stability on different segements.

Thanks,
Shayne

Quoted 1,063 lines

Regards,
Lorenzo

Quoted 1,059 lines
Quoted 4 lines

Thanks,
Shayne

(Resend for missing CC)

Quoted 1,052 lines
Quoted 1,052 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
---
 drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
 .../net/wireless/mediatek/mt76/mt76_connac.h  |  19
+  
.../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
+++++++++++++++++
 .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
 .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +-

----
--

----

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

----
--

 .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
 9 files changed, 807 insertions(+), 784 deletions(-

) create

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

drivers/net/wireless/mediatek/mt76/Makefile mt76x02-lib-y := mt76x02_util.o

Quoted 10 lines

mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

diff --git
a/drivers/net/wireless/mediatek/mt76/Makefile
b/drivers/net/wireless/mediatek/mt76/Makefile
index 84c99b7e57f9..d8e8079c8b54 100644

drivers/net/wireless/mediatek/mt76/Makefile +0 -0
@@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o

mt76x02_mac.o

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
drivers/net/wireless/mediatek/mt76/Makefile +0 -1
 mt76x02_mcu.o \
 
 mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 
-mt76-connac-lib-y := mt76_connac_mcu.o

mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o
mt76_connac_mac.o
mt76_connac3_mac.o

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h void mt76_connac2_txwi_free(struct

Quoted 8 lines

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ diff --git
a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 68bdeada1421..20111678537b 100644

drivers/net/wireless/mediatek/mt76/mt76_connac.h +0 -0
@@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct

mt76_dev

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
 *dev, struct mt76_txwi_cache *t,
     struct list_head *free_list);  void 
 mt76_connac2_tx_token_put(struct mt76_dev *dev);
 
+/* connac3 */
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta

*sta,
__le32
*txwi);
+void mt76_connac3_mac_decode_he_radiotap(struct
sk_buff

*skb,

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 10 lines

__le32
*rxv,
+ u8 mode);
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+  struct mt76_rx_status *status,
+  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+  __le32 *rxv, u8 *mode);
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32

Quoted 74 lines
Quoted 74 lines
Quoted 74 lines
Quoted 74 lines

*txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key, int
pid,
+ enum mt76_txq_id qid, u32 changed); void +mt76_connac3_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+    struct ieee80211_sta *sta,
+    struct list_head *free_list); void 
+mt76_connac3_mac_add_txs(struct mt76_dev *dev, void

*data,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+      u32 max_wtbl_size);
+void mt76_connac3_tx_token_put(struct mt76_dev *dev);
+
 #endif /* __MT76_CONNAC_H */

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c new file mode 100644
index 000000000000..4b745bb74ca0
--- /dev/null
+++
b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c

drivers/net/wireless/mediatek/mt76/mt76_connac.h +8 -0
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f)cpu_to_le16(IEEE80211_RADIOTAP_

HE_##f)
+#define HE_PREP(f, m,
v)le16_encode_bits(le32_get_bits(v,
MT_CRXV_HE_##m),\
+ IEEE80211_RADIOTAP_HE_
##f)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+
+void mt76_connac3_tx_check_aggr(struct ieee80211_sta

*sta,
__le32
*txwi)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +7 -0
+{
+struct mt76_wcid *wcid;
+u16 fc, tid;
+u32 val;
+
+if (!sta ||
+    !(sta->deflink.ht_cap.ht_supported || sta-
Quoted 1 line

deflink.he_cap.has_he))

drivers/net/wireless/mediatek/mt76/mt76_connac.h +10 -0
+return;
+
+tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+if (tid >= 6) /* skip VO queue */
+return;
+
+val = le32_to_cpu(txwi[2]);
+fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+if (unlikely(fc != (IEEE80211_FTYPE_DATA |

IEEE80211_STYPE_QOS_DATA)))

drivers/net/wireless/mediatek/mt76/mt76_connac.h +9 -0
+return;
+
+wcid = (struct mt76_wcid *)sta->drv_priv;
+if (!test_and_set_bit(tid, &wcid->ampdu_state))
+ieee80211_start_tx_ba_session(sta, tid, 0); } 
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct

mt76_rx_status

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

*status,
+ struct ieee80211_radiotap_he
*he,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+       __le32 *rxv)
+{
+u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC),

offs
=

0;

Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +36 -0
+
+status->bw = RATE_INFO_BW_HE_RU;
+
+switch (ru) {
+case 0 ... 36:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+offs = ru;
+break;
+case 37 ... 52:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+offs = ru - 37;
+break;
+case 53 ... 60:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+offs = ru - 53;
+break;
+case 61 ... 64:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+offs = ru - 61;
+break;
+case 65 ... 66:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+offs = ru - 65;
+break;
+case 67:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+break;
+case 68:
+status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+break;
+}
+
+he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+     le16_encode_bits(offs,
+      IEEE80211_RADIOTAP_HE_DATA2_RU_OF

FSET);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+}
+
+#define MU_PREP(f, v)le16_encode_bits(v,
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 8 lines

IEEE80211_RADIOTAP_HE_MU_##f)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff

*skb,
__le32
*rxv)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+{
+struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 50 lines
Quoted 18 lines
Quoted 18 lines
Quoted 8 lines
Quoted 1 line

cb;

+static const struct ieee80211_radiotap_he_mu mu_known = {
+.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +10 -0
+.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+};
+struct ieee80211_radiotap_he_mu *he_mu;
+
+status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+he_mu = skb_push(skb, sizeof(mu_known));
+memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status-

rate_idx);

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+if (status->he_dcm)
+he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status-
Quoted 1 line

he_dcm);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+
+he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW,

status-

bw) |

Quoted 21 lines
Quoted 21 lines
Quoted 21 lines

+ MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+ le32_get_bits(rxv[4],
MT_CRXV_HE_NUM_USER));

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+
+he_mu->ru_ch1[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU0)
&
0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +4 -0
+
+if (status->bw >= RATE_INFO_BW_40) {
+he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+he_mu->ru_ch2[0] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU1) & 0xff;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+}
+
+if (status->bw >= RATE_INFO_BW_80) {
+u32 ru_h, ru_l;
+
+he_mu->ru_ch1[1] = le32_get_bits(rxv[16],

MT_CRXV_HE_RU2) & 0xff;
+

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +7 -0
+ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
+ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
+he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+}
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct

sk_buff

*skb,

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 5 lines

__le32
*rxv,
+ u8 mode)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+{
+struct mt76_rx_status *status = (struct mt76_rx_status

*)skb-

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 1 line

cb;

+static const struct ieee80211_radiotap_he known = { +.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+ HE_BITS(DATA1_DATA_DCM_KNOWN) |
+ HE_BITS(DATA1_STBC_KNOWN) |
+ HE_BITS(DATA1_CODING_KNOWN) |
+ HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+ HE_BITS(DATA1_DOPPLER_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+ HE_BITS(DATA1_BSS_COLOR_KNOWN),

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

+.data2 = HE_BITS(DATA2_GI_KNOWN) |
+ HE_BITS(DATA2_TXBF_KNOWN) |
+ HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+ HE_BITS(DATA2_TXOP_KNOWN),

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+};
+u32 ltf_size = le32_get_bits(rxv[4],

MT_CRXV_HE_LTF_SIZE)
+

1;

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 11 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +8 -0
+struct ieee80211_radiotap_he *he;
+
+status->flag |= RX_FLAG_RADIOTAP_HE;
+
+he = skb_push(skb, sizeof(known));
+memcpy(he, &known, sizeof(known));
+
+he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR,

rxv[9]) |

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
+he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK,

rxv[13]);

Quoted 168 lines
Quoted 168 lines
Quoted 168 lines
Quoted 168 lines

+he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5])

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+    le16_encode_bits(ltf_size,
+     IEEE80211_RADIOTAP_HE_DATA5_LTF_SI

ZE);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +13 -0
+if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+he->data5 |= HE_BITS(DATA5_TXBF);
+he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+switch (mode) {
+case MT_PHY_TYPE_HE_SU:
+he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+     HE_BITS(DATA1_UL_DL_KNOWN) |
+     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG,

rxv[8]) |

drivers/net/wireless/mediatek/mt76/mt76_connac.h +17 -0
+     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+break;
+case MT_PHY_TYPE_HE_EXT_SU:
+he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+     HE_BITS(DATA1_UL_DL_KNOWN) |
+     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+break;
+case MT_PHY_TYPE_HE_MU:
+he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+     HE_BITS(DATA1_UL_DL_KNOWN);
+
+he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
+
+mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +9 -0
+mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
+break;
+case MT_PHY_TYPE_HE_TB:
+he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK,

rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK,
rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK,
rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK,
rxv[13]);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+
+mt76_connac3_mac_decode_he_radiotap_ru(status, he,

rxv);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+break;
+default:
+break;
+}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap)

;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+
+int mt76_connac3_mac_fill_rx_rate(struct mt76_dev

*dev,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+  struct mt76_rx_status *status,
+  struct ieee80211_supported_band

*sband,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +99 -0
+  __le32 *rxv, u8 *mode)
+{
+u8 stbc, gi, bw, dcm, nss;
+bool cck = false;
+u32 v0, v2;
+int i, idx;
+
+v0 = le32_to_cpu(rxv[0]);
+v2 = le32_to_cpu(rxv[2]);
+
+idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
+i = idx;
+nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
+
+stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
+gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
+*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
+dcm = FIELD_GET(MT_PRXV_DCM, v2);
+bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
+
+switch (*mode) {
+case MT_PHY_TYPE_CCK:
+cck = true;
+fallthrough;
+case MT_PHY_TYPE_OFDM:
+i = mt76_get_rate(dev, sband, i, cck);
+break;
+case MT_PHY_TYPE_HT_GF:
+case MT_PHY_TYPE_HT:
+status->encoding = RX_ENC_HT;
+if (gi)
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+if (i > 31)
+return -EINVAL;
+break;
+case MT_PHY_TYPE_VHT:
+status->nss = nss;
+status->encoding = RX_ENC_VHT;
+if (gi)
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+if (i > 11)
+return -EINVAL;
+break;
+case MT_PHY_TYPE_HE_MU:
+case MT_PHY_TYPE_HE_SU:
+case MT_PHY_TYPE_HE_EXT_SU:
+case MT_PHY_TYPE_HE_TB:
+status->nss = nss;
+status->encoding = RX_ENC_HE;
+i &= GENMASK(3, 0);
+
+if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
+status->he_gi = gi;
+
+status->he_dcm = dcm;
+break;
+case MT_PHY_TYPE_EHT_SU:
+case MT_PHY_TYPE_EHT_TRIG:
+case MT_PHY_TYPE_EHT_MU:
+status->nss = nss;
+status->encoding = RX_ENC_EHT;
+i &= GENMASK(3, 0);
+
+if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
+status->eht.gi = gi;
+break;
+default:
+return -EINVAL;
+}
+status->rate_idx = i;
+
+switch (bw) {
+case IEEE80211_STA_RX_BW_20:
+break;
+case IEEE80211_STA_RX_BW_40:
+if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
+    (idx & MT_PRXV_TX_ER_SU_106T)) {
+status->bw = RATE_INFO_BW_HE_RU;
+status->he_ru =
+NL80211_RATE_INFO_HE_RU_ALLOC_106;
+} else {
+status->bw = RATE_INFO_BW_40;
+}
+break;
+case IEEE80211_STA_RX_BW_80:
+status->bw = RATE_INFO_BW_80;
+break;
+case IEEE80211_STA_RX_BW_160:
+status->bw = RATE_INFO_BW_160;
+break;
+case IEEE80211_STA_RX_BW_320:
+status->bw = RATE_INFO_BW_320;
+break;
+default:
+return -EINVAL;
+}
+
+status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+if (*mode < MT_PHY_TYPE_HE_SU && gi)
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +8 -0
+status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
+
+static void
+mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct

sk_buff

Quoted 33 lines
Quoted 33 lines
Quoted 33 lines
Quoted 33 lines

*skb,
+ struct mt76_wcid *wcid)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +11 -0
+{
+u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+u8 fc_type, fc_stype;
+u16 ethertype;
+bool wmm = false;
+u32 val;
+
+if (wcid->sta) {
+struct ieee80211_sta *sta;
+
+sta = container_of((void *)wcid, struct ieee80211_sta,

drv_priv);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +4 -0
+wmm = sta->wme;
+}
+
+val = FIELD_PREP(MT_TXD1_HDR_FORMAT,

MT_HDR_FORMAT_802_3)

Quoted 1 line
drivers/net/wireless/mediatek/mt76/mt76_connac.h +12 -0
+      FIELD_PREP(MT_TXD1_TID, tid);
+
+ethertype = get_unaligned_be16(&skb->data[12]);
+if (ethertype >= ETH_P_802_3_MIN)
+val |= MT_TXD1_ETH_802_3;
+
+txwi[1] |= cpu_to_le32(val);
+
+fc_type = IEEE80211_FTYPE_DATA >> 2;
+fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
+val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +7 -0
+      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+txwi[2] |= cpu_to_le32(val);
+}
+
+static void
+mt76_connac3_mac_write_txwi_80211(struct mt76_dev

*dev,

__le32

Quoted 31 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

*txwi,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+  struct sk_buff *skb,
+  struct ieee80211_key_conf *key) {
+struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb-

data;

Quoted 24 lines
Quoted 24 lines
Quoted 24 lines

+struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb-

Quoted 1 line

data;

+struct ieee80211_tx_info *info =
IEEE80211_SKB_CB(skb);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +9 -0
+bool multicast = is_multicast_ether_addr(hdr->addr1);
+u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+__le16 fc = hdr->frame_control;
+u8 fc_type, fc_stype;
+u32 val;
+
+if (ieee80211_is_action(fc) &&
+    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+    mgmt->u.action.u.addba_req.action_code ==

WLAN_ACTION_ADDBA_REQ)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +5 -0
+tid = MT_TX_ADDBA;
+else if (ieee80211_is_mgmt(hdr->frame_control))
+tid = MT_TX_NORMAL;
+
+val = FIELD_PREP(MT_TXD1_HDR_FORMAT,

MT_HDR_FORMAT_802_11)

Quoted 1 line
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +9 -0
+      FIELD_PREP(MT_TXD1_HDR_INFO,
+ ieee80211_get_hdrlen_from_skb(skb) / 2) |
+      FIELD_PREP(MT_TXD1_TID, tid);
+
+if (!ieee80211_is_data(fc) || multicast ||
+    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+val |= MT_TXD1_FIXED_RATE;
+
+if (key && multicast &&

ieee80211_is_robust_mgmt_frame(skb)

&&

Quoted 35 lines
Quoted 35 lines
Quoted 35 lines
Quoted 35 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +8 -0
+    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+val |= MT_TXD1_BIP;
+txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+}
+
+txwi[1] |= cpu_to_le32(val);
+
+fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >>

2;
+fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +7 -0
+
+val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+txwi[2] |= cpu_to_le32(val);
+
+txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM,

multicast));

drivers/net/wireless/mediatek/mt76/mt76_connac.h +16 -0
+if (ieee80211_is_beacon(fc)) {
+txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+}
+
+if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+if (ieee80211_is_back_req(hdr->frame_control)) {
+struct ieee80211_bar *bar;
+
+bar = (struct ieee80211_bar *)skb->data;
+seqno = le16_to_cpu(bar->start_seq_num);
+}
+
+val = MT_TXD3_SN_VALID |
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 8 lines

+ FIELD_PREP(MT_TXD3_SEQ,
IEEE80211_SEQ_TO_SN(seqno));

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+txwi[3] |= cpu_to_le32(val);
+txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+}
+}
+
+void mt76_connac3_mac_write_txwi(struct mt76_dev *dev,

__le32

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

*txwi,
+ struct sk_buff *skb, struct mt76_wcid
*wcid,
+ struct ieee80211_key_conf *key, int
pid,
+ enum mt76_txq_id qid, u32 changed)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+{
+u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 8 lines

MT_SDIO_TXD_SIZE;
+struct ieee80211_tx_info *info =
IEEE80211_SKB_CB(skb);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+struct ieee80211_vif *vif = info->control.vif;
+u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >>

2;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+bool is_8023 = info->flags &

IEEE80211_TX_CTL_HW_80211_ENCAP;

Quoted 269 lines
Quoted 269 lines
Quoted 269 lines
Quoted 269 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +5 -0
+struct mt76_vif *mvif;
+u16 tx_count = 15;
+bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+    BSS_CHANGED_BEACON_ENABLED));
+bool inband_disc = !!(changed &

(BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+ BSS_CHANGED_FILS_DISCOVERY));

drivers/net/wireless/mediatek/mt76/mt76_connac.h +16 -0
+
+mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+if (mvif) {
+omac_idx = mvif->omac_idx;
+wmm_idx = mvif->wmm_idx;
+band_idx = mvif->band_idx;
+}
+
+if (inband_disc) {
+p_fmt = MT_TX_TYPE_FW;
+q_idx = MT_LMAC_ALTX0;
+} else if (beacon) {
+p_fmt = MT_TX_TYPE_FW;
+q_idx = MT_LMAC_BCN0;
+} else if (qid >= MT_TXQ_PSD) {
+p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+q_idx = MT_LMAC_ALTX0;
+} else {
+p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :

MT_TX_TYPE_SF;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
+mt76_connac_lmac_mapping(skb_get_queue_mapping(

skb));

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+}
+
+val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd)

|

drivers/net/wireless/mediatek/mt76/mt76_connac.h +39 -0
+      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
+      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+txwi[0] = cpu_to_le32(val);
+
+val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+
+if (band_idx)
+val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
+
+txwi[1] = cpu_to_le32(val);
+txwi[2] = 0;
+
+val = MT_TXD3_SW_POWER_MGMT |
+      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+if (key)
+val |= MT_TXD3_PROTECT_FRAME;
+if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+val |= MT_TXD3_NO_ACK;
+if (wcid->amsdu)
+val |= MT_TXD3_HW_AMSDU;
+
+txwi[3] = cpu_to_le32(val);
+txwi[4] = 0;
+
+val = FIELD_PREP(MT_TXD5_PID, pid);
+if (pid >= MT_PACKET_ID_FIRST)
+val |= MT_TXD5_TX_STATUS_HOST;
+txwi[5] = cpu_to_le32(val);
+
+val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
+      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+txwi[6] = cpu_to_le32(val);
+txwi[7] = 0;
+
+if (is_8023)
+mt76_connac3_mac_write_txwi_8023(txwi, skb, wcid);
+else
+mt76_connac3_mac_write_txwi_80211(dev, txwi, skb,

key);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+
+if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
+struct ieee80211_hdr *hdr = (struct ieee80211_hdr

*)skb->data;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +14 -0
+bool mcast = ieee80211_is_data(hdr->frame_control) &&
+     is_multicast_ether_addr(hdr->addr1);
+u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
+
+if (mvif) {
+if (mcast && mvif->mcast_rates_idx)
+idx = mvif->mcast_rates_idx;
+else if (beacon && mvif->beacon_rates_idx)
+idx = mvif->beacon_rates_idx;
+else
+idx = mvif->basic_rates_idx;
+}
+
+txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,

idx));

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+}
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
+
+void mt76_connac3_txwi_free(struct mt76_dev *dev,

struct
mt76_txwi_cache *t,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +13 -0
+    struct ieee80211_sta *sta,
+    struct list_head *free_list)
+{
+__le32 *txwi;
+u16 wcid_idx;
+
+mt76_connac_txp_skb_unmap(dev, t);
+if (!t->skb)
+goto out;
+
+txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+if (sta) {
+struct mt76_wcid *wcid = (struct mt76_wcid *)sta-
Quoted 1 line

drv_priv;

drivers/net/wireless/mediatek/mt76/mt76_connac.h +3 -0
+
+wcid_idx = wcid->idx;
+if (likely(t->skb->protocol !=

cpu_to_be16(ETH_P_PAE)))

drivers/net/wireless/mediatek/mt76/mt76_connac.h +6 -0
+mt76_connac3_tx_check_aggr(sta, txwi);
+} else {
+wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+}
+
+__mt76_tx_complete_skb(dev, wcid_idx, t->skb,

free_list);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +8 -0
+out:
+t->skb = NULL;
+mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
+
+static bool
+mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev,

struct
mt76_wcid
*wcid,

drivers/net/wireless/mediatek/mt76/mt76_connac.h +53 -0
+     int pid, __le32 *txs_data)
+{
+struct mt76_sta_stats *stats = &wcid->stats;
+struct ieee80211_supported_band *sband;
+struct ieee80211_tx_info *info;
+u32 txrate, txs, mode, stbc;
+struct rate_info rate = {};
+struct sk_buff_head list;
+struct mt76_phy *mphy;
+struct sk_buff *skb;
+bool cck = false;
+
+mt76_tx_status_lock(dev, &list);
+skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
+if (!skb)
+goto out_no_skb;
+
+txs = le32_to_cpu(txs_data[0]);
+
+info = IEEE80211_SKB_CB(skb);
+if (!(txs & MT_TXS0_ACK_ERROR_MASK))
+info->flags |= IEEE80211_TX_STAT_ACK;
+
+info->status.ampdu_len = 1;
+info->status.ampdu_ack_len = !!(info->flags &
+IEEE80211_TX_STAT_ACK);
+info->status.rates[0].idx = -1;
+
+txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
+
+if (stbc && rate.nss > 1)
+rate.nss >>= 1;
+
+if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+stats->tx_nss[rate.nss - 1]++;
+if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+stats->tx_mcs[rate.mcs]++;
+
+mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+switch (mode) {
+case MT_PHY_TYPE_CCK:
+cck = true;
+fallthrough;
+case MT_PHY_TYPE_OFDM:
+mphy = mt76_dev_phy(dev, wcid->phy_idx);
+
+if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+sband = &mphy->sband_5g.sband;
+else if (mphy->chandef.chan->band ==

NL80211_BAND_6GHZ)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +5 -0
+sband = &mphy->sband_6g.sband;
+else
+sband = &mphy->sband_2g.sband;
+
+rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs,

cck);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +70 -0
+rate.legacy = sband->bitrates[rate.mcs].bitrate;
+break;
+case MT_PHY_TYPE_HT:
+case MT_PHY_TYPE_HT_GF:
+if (rate.mcs > 31)
+goto out;
+
+rate.flags = RATE_INFO_FLAGS_MCS;
+if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+break;
+case MT_PHY_TYPE_VHT:
+if (rate.mcs > 9)
+goto out;
+
+rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+break;
+case MT_PHY_TYPE_HE_SU:
+case MT_PHY_TYPE_HE_EXT_SU:
+case MT_PHY_TYPE_HE_TB:
+case MT_PHY_TYPE_HE_MU:
+if (rate.mcs > 11)
+goto out;
+
+rate.he_gi = wcid->rate.he_gi;
+rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
+rate.flags = RATE_INFO_FLAGS_HE_MCS;
+break;
+case MT_PHY_TYPE_EHT_SU:
+case MT_PHY_TYPE_EHT_TRIG:
+case MT_PHY_TYPE_EHT_MU:
+if (rate.mcs > 13)
+goto out;
+
+rate.eht_gi = wcid->rate.eht_gi;
+rate.flags = RATE_INFO_FLAGS_EHT_MCS;
+break;
+default:
+goto out;
+}
+
+stats->tx_mode[mode]++;
+
+switch (FIELD_GET(MT_TXS0_BW, txs)) {
+case IEEE80211_STA_RX_BW_320:
+rate.bw = RATE_INFO_BW_320;
+stats->tx_bw[4]++;
+break;
+case IEEE80211_STA_RX_BW_160:
+rate.bw = RATE_INFO_BW_160;
+stats->tx_bw[3]++;
+break;
+case IEEE80211_STA_RX_BW_80:
+rate.bw = RATE_INFO_BW_80;
+stats->tx_bw[2]++;
+break;
+case IEEE80211_STA_RX_BW_40:
+rate.bw = RATE_INFO_BW_40;
+stats->tx_bw[1]++;
+break;
+default:
+rate.bw = RATE_INFO_BW_20;
+stats->tx_bw[0]++;
+break;
+}
+wcid->rate = rate;
+
+out:
+mt76_tx_status_skb_done(dev, skb, &list);
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +7 -0
+out_no_skb:
+mt76_tx_status_unlock(dev, &list);
+
+return !!skb;
+}
+
+void mt76_connac3_mac_add_txs(struct mt76_dev *dev,

void

*data,

Quoted 77 lines
Quoted 77 lines
Quoted 76 lines
Quoted 72 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +8 -0
+      u32 max_wtbl_size)
+{
+struct mt76_wcid *wcid;
+__le32 *txs_data = data;
+u16 wcidx;
+u8 pid;
+
+if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) >

1)

drivers/net/wireless/mediatek/mt76/mt76_connac.h +18 -0
+return;
+
+wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
+pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+if (pid < MT_PACKET_ID_FIRST)
+return;
+
+if (wcidx >= max_wtbl_size)
+return;
+
+rcu_read_lock();
+
+wcid = rcu_dereference(dev->wcid[wcidx]);
+if (!wcid)
+goto out;
+
+mt76_connac3_mac_add_txs_skb(dev, wcid, pid,

txs_data);

drivers/net/wireless/mediatek/mt76/mt76_connac.h +27 -0
+if (!wcid->sta)
+goto out;
+
+spin_lock_bh(&dev->sta_poll_lock);
+if (list_empty(&wcid->poll_list))
+list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
+spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
+
+void mt76_connac3_tx_token_put(struct mt76_dev *dev)
+{
+struct mt76_txwi_cache *txwi;
+int id;
+
+spin_lock_bh(&dev->token_lock);
+idr_for_each_entry(&dev->token, txwi, id) {
+mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
+dev->token_count--;
+}
+spin_unlock_bh(&dev->token_lock);
+idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 6663a0b46541..bcc1d976b2b0 100644
---
a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
+++
b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h

drivers/net/wireless/mediatek/mt76/mt76_connac.h +1 -0
@@ -4,6 +4,24 @@
 #ifndef __MT76_CONNAC3_MAC_H
 #define __MT76_CONNAC3_MAC_H
 
+/* NOTE: used to map mt76_rates. idx may change if

firmware
expands
table */

drivers/net/wireless/mediatek/mt76/mt76_connac.h

Quoted 2 lines
drivers/net/wireless/mediatek/mt76/mt76_connac.h +2 -0
+#define MT76_CONNAC3_BASIC_RATES_TBL11
+#define MT76_CONNAC3_BEACON_RATES_TBL25

Different devices may have different defined value.

Quoted 2 lines
Quoted 2 lines

The other WiFi7 device I am working on relies on the values I

moved

Quoted 3 lines
Quoted 3 lines

in
mt76_connac3_mac.h (in common with mt7996). Moreover you can

still

Quoted 7 lines
Quoted 3 lines

have per-device values in mt7996/mac.h (I have not removed it).

Please double check with the mtk folk you work with. The 11 and
25

is

Quoted 3 lines

the value I discussed with firmware folks to avoid overlapping
the

tbl

Quoted 2 lines

mt7996 use (MU/other algo in fw), or it causes something hardly

solving

Quoted 1 line

issue

sure, thx for pointing this out.
@Deren: can you please double check?

Regards,
Lorenzo

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

I'm thinking if it's too early to create this patch for just

moving

Quoted 4 lines
Quoted 4 lines
Quoted 1 line

mt7996 to connac3_lib?

The code I moved is used by the other device as well. This series

is

Quoted 9 lines
Quoted 9 lines

a
preliminary series to support it.

Regards,
Lorenzo

Quoted 3 lines

Ryder

maintainer
#25 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

Quoted 21 lines · Shayne Chen (陳軒丞)
Quoted 20 lines · On Sat, 2023-06-10 at 12:06 +0200, [email protected] wrote:
Quoted 20 lines · Shayne Chen
Quoted 19 lines
Quoted 19 lines
Quoted 2 lines

On Fri, 2023-06-09 at 18:34 +0200,
[email protected]

Quoted 5 lines · wrote:
Quoted 5 lines · Ryder Lee
Quoted 4 lines
Quoted 2 lines · Lorenzo Bianconi

External email : Please do not click links or open

attachments

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

until you have verified the sender or the content.
Introduce connac3_mac in mt76_connac library to
reuse
mac

code

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

shared between WiFi7 chipsets.

Quoted 68 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Hi Lorenzo,

Hi Shayne,

Hi Lorenzo,

Quoted 59 lines
Quoted 12 lines
Quoted 12 lines

I don't think it's a good idea to start sharing mac or mcu functions
for all WiFi7 chipsets at such early stage.

The driver is still under many processes of bug fixing, performance
tuning, and new features development.
Chipsets that mainly used for AP or STA segment have different designs
and should face different problems.

Quoted 7 lines
Quoted 7 lines

Start sharing the code at early stage will break the independence,
make
it more hard to develop and do verifications, since many changes
will
affect chipsets of both segments.

my goal is to share the code that hardly will be changed (or that will have
very few changes in the future, i.e. I have not changed mcu codebase).
If you consider for example the routines below:

- mt76_connac*_mac_write_txwi_8023()
- mt76_connac*_mac_write_txwi_80211()
- mt76_connac*_mac_add_txs_skb()
- mt76_connac*_txwi_free()
- ...

they are the same for mt7615/mt7663, mt7921/mt7915, mt7996/.. , what
is
changing is just register map between versions (e.g. mt7615/mt7663 and
mt7915/mt7921). I think it is not a good idea to copy-paste the code
because it will just make the code much harder to maintain, and this
will be
more difficult to address in the future.
If you consider the commit below:

commit ead449023d3acb1424886d7b8cc672ed69bdd27e

Author: Lorenzo Bianconi <[email protected]>
Date:   Sun May 28 12:28:49 2023 +0200

wifi: mt76: mt7996: fix possible NULL pointer dereference in
mt7996_mac_write_txwi()

Fix possible NULL pointer dereference on mvif pointer in mt7996_mac_write_txwi routine.

Deren will needs to monitor the ML and apply the same fix for the other WiFi7
chipset too.

This depends on viewpoint. For instance, I planed to add many changes for mt7986 but 7921 doesn't use (or even don't care), but I need to check other don't care devices without any help (because they don't care), so we maintain more an more patches in local branch rather than upstreming.

Other that that, I think it's ok in wifi6 but wifi7 is REALLY different. it's better to wait the major MLO development finished to have a whole picture to know what the best way to unify.

Quoted 5 lines
Quoted 4 lines

Moreover I kept mt7996/mac.{c,h} to put the per-chipset codebase. If you think MT76_CONNAC3_BASIC_RATES_TBL11 and MT76_CONNAC3_BEACON_RATES_TBL25
are sensible, we can put them in mt7996/mac.h

and this is just one anther example I can tell right now.

Quoted 28 lines

I understand your concern, but if the code starts to be shared at early
stage, we may need to add several is_mt7996() to split different parts
temporarily or permanently, since we have different development procedure and focusing, on devices of different segements.

Below are some examples I concern:
- We're doing some tests about switching all TXS to PPDU TXS, and the code in mac_add_txs_skb() needs to be changed. If devices of STA segement don't want to change or won't switch in short time, we may need to add is_mt7996() to split.

- When adding MLO support, there will be many changes in mac_write_txwi() and txwi_free(), compared to previous chipsets. To prevent from adding side effects to other devices, we may also need to
add is_mt7996() to split code at least for temporary.

I would like to know is it fine with you to add some is_mt7996() to the
shared code for the above examples?
I think this could help to balance the trade off between sharing code and assuring the driver stability on different segements.

Thanks,
Shayne

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
#28 lore raw

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

In reply to [email protected]
Quoted 7 lines · "[email protected]" <[email protected]> writes:
Quoted 6 lines · Deren Wu
Quoted 5 lines · On Fri, 2023-06-09 at 18:45 +0200, [email protected] wrote:
Quoted 5 lines
Quoted 3 lines · On Fri, 2023-06-09 at 18:34 +0200, [email protected] wrote:
Quoted 2 lines · Ryder Lee
Quoted 1 line · Lorenzo Bianconi

Guys, please edit your quotes. You are now sending mails with 1000 lines and that makes it unreadable in patchwork:

https://patchwork.kernel.org/project/linux-wireless/patch/b7a029d6dfee8e58c58f483ea9e9e7b3bc8012b9.1686298162.git.lorenzo@kernel.org/

Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches