netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/10] RTW88: Add support for USB variants
@ 2022-05-30 13:54 Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 01/10] rtw88: Call rtw_fw_beacon_filter_config() with rtwdev->mutex held Sascha Hauer
                   ` (9 more replies)
  0 siblings, 10 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

This is the second round of patches for RTW88 USB support. I hopefully
addressed all comments to v1.

Overall changes since v1:
- Dropped rtl8723du chipset support (reported to be not working)
- make mostly checkpatch clean

see changelog in the patches for patch specific changes

Sascha

Sascha Hauer (10):
  rtw88: Call rtw_fw_beacon_filter_config() with rtwdev->mutex held
  rtw88: Drop rf_lock
  rtw88: Drop h2c.lock
  rtw88: Drop coex mutex
  rtw88: iterate over vif/sta list non-atomically
  rtw88: Add common USB chip support
  rtw88: Add rtw8821cu chipset support
  rtw88: Add rtw8822bu chipset support
  rtw88: Add rtw8822cu chipset support
  rtw88: disable powersave modes for USB devices

 drivers/net/wireless/realtek/rtw88/Kconfig    |   36 +
 drivers/net/wireless/realtek/rtw88/Makefile   |   11 +
 drivers/net/wireless/realtek/rtw88/coex.c     |    3 +-
 drivers/net/wireless/realtek/rtw88/debug.c    |   15 +
 drivers/net/wireless/realtek/rtw88/fw.c       |   13 +-
 drivers/net/wireless/realtek/rtw88/hci.h      |    9 +-
 drivers/net/wireless/realtek/rtw88/mac.c      |    3 +
 drivers/net/wireless/realtek/rtw88/mac80211.c |    5 +-
 drivers/net/wireless/realtek/rtw88/main.c     |    8 +-
 drivers/net/wireless/realtek/rtw88/main.h     |   11 +-
 drivers/net/wireless/realtek/rtw88/phy.c      |    6 +-
 drivers/net/wireless/realtek/rtw88/ps.c       |    2 +-
 drivers/net/wireless/realtek/rtw88/reg.h      |    1 +
 drivers/net/wireless/realtek/rtw88/rtw8821c.c |   23 +
 drivers/net/wireless/realtek/rtw88/rtw8821c.h |   21 +
 .../net/wireless/realtek/rtw88/rtw8821cu.c    |   50 +
 .../net/wireless/realtek/rtw88/rtw8821cu.h    |   10 +
 drivers/net/wireless/realtek/rtw88/rtw8822b.c |   19 +
 .../net/wireless/realtek/rtw88/rtw8822bu.c    |   90 ++
 .../net/wireless/realtek/rtw88/rtw8822bu.h    |   10 +
 drivers/net/wireless/realtek/rtw88/rtw8822c.c |   24 +
 .../net/wireless/realtek/rtw88/rtw8822cu.c    |   44 +
 .../net/wireless/realtek/rtw88/rtw8822cu.h    |   10 +
 drivers/net/wireless/realtek/rtw88/tx.h       |   31 +
 drivers/net/wireless/realtek/rtw88/usb.c      | 1037 +++++++++++++++++
 drivers/net/wireless/realtek/rtw88/usb.h      |  114 ++
 drivers/net/wireless/realtek/rtw88/util.c     |  103 ++
 drivers/net/wireless/realtek/rtw88/util.h     |   12 +-
 28 files changed, 1684 insertions(+), 37 deletions(-)
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8821cu.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8821cu.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822bu.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822bu.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822cu.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822cu.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/usb.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/usb.h

-- 
2.30.2


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

* [PATCH v2 01/10] rtw88: Call rtw_fw_beacon_filter_config() with rtwdev->mutex held
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 02/10] rtw88: Drop rf_lock Sascha Hauer
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

rtw_fw_beacon_filter_config() is called once with rtwdev->mutex held
and once without the mutex held. Call it consistently with rtwdev->mutex
held.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/net/wireless/realtek/rtw88/mac80211.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index 5cdc54c9a9aae..3c07485d6ba47 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -466,8 +466,8 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw,
 {
 	struct rtw_dev *rtwdev = hw->priv;
 
-	rtw_fw_beacon_filter_config(rtwdev, false, vif);
 	mutex_lock(&rtwdev->mutex);
+	rtw_fw_beacon_filter_config(rtwdev, false, vif);
 	rtw_sta_remove(rtwdev, sta, true);
 	mutex_unlock(&rtwdev->mutex);
 
-- 
2.30.2


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

* [PATCH v2 02/10] rtw88: Drop rf_lock
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 01/10] rtw88: Call rtw_fw_beacon_filter_config() with rtwdev->mutex held Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 03/10] rtw88: Drop h2c.lock Sascha Hauer
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

The rtwdev->rf_lock spinlock protects the rf register accesses in
rtw_read_rf() and rtw_write_rf(). Most callers of these functions hold
rtwdev->mutex already with the exception of the callsites in the debugfs
code. The debugfs code doesn't justify an extra lock, so acquire the mutex
there as well before calling rf register accessors and drop the now
unnecessary spinlock.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/net/wireless/realtek/rtw88/debug.c | 11 +++++++++++
 drivers/net/wireless/realtek/rtw88/hci.h   |  9 +++------
 drivers/net/wireless/realtek/rtw88/main.c  |  1 -
 drivers/net/wireless/realtek/rtw88/main.h  |  3 ---
 4 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c
index 1a52ff585fbc7..ba5ba852efb8c 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.c
+++ b/drivers/net/wireless/realtek/rtw88/debug.c
@@ -144,7 +144,9 @@ static int rtw_debugfs_get_rf_read(struct seq_file *m, void *v)
 	addr = debugfs_priv->rf_addr;
 	mask = debugfs_priv->rf_mask;
 
+	mutex_lock(&rtwdev->mutex);
 	val = rtw_read_rf(rtwdev, path, addr, mask);
+	mutex_unlock(&rtwdev->mutex);
 
 	seq_printf(m, "rf_read path:%d addr:0x%08x mask:0x%08x val=0x%08x\n",
 		   path, addr, mask, val);
@@ -418,7 +420,9 @@ static ssize_t rtw_debugfs_set_rf_write(struct file *filp,
 		return count;
 	}
 
+	mutex_lock(&rtwdev->mutex);
 	rtw_write_rf(rtwdev, path, addr, mask, val);
+	mutex_unlock(&rtwdev->mutex);
 	rtw_dbg(rtwdev, RTW_DBG_DEBUGFS,
 		"write_rf path:%d addr:0x%08x mask:0x%08x, val:0x%08x\n",
 		path, addr, mask, val);
@@ -523,6 +527,8 @@ static int rtw_debug_get_rf_dump(struct seq_file *m, void *v)
 	u32 addr, offset, data;
 	u8 path;
 
+	mutex_lock(&rtwdev->mutex);
+
 	for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
 		seq_printf(m, "RF path:%d\n", path);
 		for (addr = 0; addr < 0x100; addr += 4) {
@@ -537,6 +543,8 @@ static int rtw_debug_get_rf_dump(struct seq_file *m, void *v)
 		seq_puts(m, "\n");
 	}
 
+	mutex_unlock(&rtwdev->mutex);
+
 	return 0;
 }
 
@@ -1027,6 +1035,8 @@ static void dump_gapk_status(struct rtw_dev *rtwdev, struct seq_file *m)
 		   dm_info->dm_flags & BIT(RTW_DM_CAP_TXGAPK) ? '-' : '+',
 		   rtw_dm_cap_strs[RTW_DM_CAP_TXGAPK]);
 
+	mutex_lock(&rtwdev->mutex);
+
 	for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
 		val = rtw_read_rf(rtwdev, path, RF_GAINTX, RFREG_MASK);
 		seq_printf(m, "path %d:\n0x%x = 0x%x\n", path, RF_GAINTX, val);
@@ -1036,6 +1046,7 @@ static void dump_gapk_status(struct rtw_dev *rtwdev, struct seq_file *m)
 				   txgapk->rf3f_fs[path][i], i);
 		seq_puts(m, "\n");
 	}
+	mutex_unlock(&rtwdev->mutex);
 }
 
 static int rtw_debugfs_get_dm_cap(struct seq_file *m, void *v)
diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h
index 4c6fc6fb3f83b..830d7532f2a35 100644
--- a/drivers/net/wireless/realtek/rtw88/hci.h
+++ b/drivers/net/wireless/realtek/rtw88/hci.h
@@ -166,12 +166,11 @@ static inline u32
 rtw_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
 	    u32 addr, u32 mask)
 {
-	unsigned long flags;
 	u32 val;
 
-	spin_lock_irqsave(&rtwdev->rf_lock, flags);
+	lockdep_assert_held(&rtwdev->mutex);
+
 	val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
-	spin_unlock_irqrestore(&rtwdev->rf_lock, flags);
 
 	return val;
 }
@@ -180,11 +179,9 @@ static inline void
 rtw_write_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
 	     u32 addr, u32 mask, u32 data)
 {
-	unsigned long flags;
+	lockdep_assert_held(&rtwdev->mutex);
 
-	spin_lock_irqsave(&rtwdev->rf_lock, flags);
 	rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data);
-	spin_unlock_irqrestore(&rtwdev->rf_lock, flags);
 }
 
 static inline u32
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 8b9899e41b0bb..f9864840ffd9c 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1994,7 +1994,6 @@ int rtw_core_init(struct rtw_dev *rtwdev)
 	skb_queue_head_init(&rtwdev->coex.queue);
 	skb_queue_head_init(&rtwdev->tx_report.queue);
 
-	spin_lock_init(&rtwdev->rf_lock);
 	spin_lock_init(&rtwdev->h2c.lock);
 	spin_lock_init(&rtwdev->txq_lock);
 	spin_lock_init(&rtwdev->tx_report.q_lock);
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 17815af9dd4ea..df6c6032bbd3b 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -1994,9 +1994,6 @@ struct rtw_dev {
 	/* ensures exclusive access from mac80211 callbacks */
 	struct mutex mutex;
 
-	/* read/write rf register */
-	spinlock_t rf_lock;
-
 	/* watch dog every 2 sec */
 	struct delayed_work watch_dog_work;
 	u32 watch_dog_cnt;
-- 
2.30.2


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

* [PATCH v2 03/10] rtw88: Drop h2c.lock
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 01/10] rtw88: Call rtw_fw_beacon_filter_config() with rtwdev->mutex held Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 02/10] rtw88: Drop rf_lock Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 04/10] rtw88: Drop coex mutex Sascha Hauer
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

The h2c.lock spinlock is used in rtw_fw_send_h2c_command() and
rtw_fw_send_h2c_packet().  Most callers call this with rtwdev->mutex
held, except from one callsite in the debugfs code. The debugfs code
alone doesn't justify the extra lock, so acquire rtwdev->mutex in
debugfs and drop the now unnecessary spinlock.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/net/wireless/realtek/rtw88/debug.c |  2 ++
 drivers/net/wireless/realtek/rtw88/fw.c    | 13 ++++---------
 drivers/net/wireless/realtek/rtw88/main.c  |  1 -
 drivers/net/wireless/realtek/rtw88/main.h  |  2 --
 4 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c
index ba5ba852efb8c..79939aa6b752c 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.c
+++ b/drivers/net/wireless/realtek/rtw88/debug.c
@@ -396,7 +396,9 @@ static ssize_t rtw_debugfs_set_h2c(struct file *filp,
 		return -EINVAL;
 	}
 
+	mutex_lock(&rtwdev->mutex);
 	rtw_fw_h2c_cmd_dbg(rtwdev, param);
+	mutex_unlock(&rtwdev->mutex);
 
 	return count;
 }
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index aa2aeb5fb2ccd..c3ad2a1b47212 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -320,7 +320,7 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
 		h2c[3], h2c[2], h2c[1], h2c[0],
 		h2c[7], h2c[6], h2c[5], h2c[4]);
 
-	spin_lock(&rtwdev->h2c.lock);
+	lockdep_assert_held(&rtwdev->mutex);
 
 	box = rtwdev->h2c.last_box_num;
 	switch (box) {
@@ -342,7 +342,7 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
 		break;
 	default:
 		WARN(1, "invalid h2c mail box number\n");
-		goto out;
+		return;
 	}
 
 	ret = read_poll_timeout_atomic(rtw_read8, box_state,
@@ -351,7 +351,7 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
 
 	if (ret) {
 		rtw_err(rtwdev, "failed to send h2c command\n");
-		goto out;
+		return;
 	}
 
 	for (idx = 0; idx < 4; idx++)
@@ -361,9 +361,6 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
 
 	if (++rtwdev->h2c.last_box_num >= 4)
 		rtwdev->h2c.last_box_num = 0;
-
-out:
-	spin_unlock(&rtwdev->h2c.lock);
 }
 
 void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c)
@@ -375,15 +372,13 @@ static void rtw_fw_send_h2c_packet(struct rtw_dev *rtwdev, u8 *h2c_pkt)
 {
 	int ret;
 
-	spin_lock(&rtwdev->h2c.lock);
+	lockdep_assert_held(&rtwdev->mutex);
 
 	FW_OFFLOAD_H2C_SET_SEQ_NUM(h2c_pkt, rtwdev->h2c.seq);
 	ret = rtw_hci_write_data_h2c(rtwdev, h2c_pkt, H2C_PKT_SIZE);
 	if (ret)
 		rtw_err(rtwdev, "failed to send h2c packet\n");
 	rtwdev->h2c.seq++;
-
-	spin_unlock(&rtwdev->h2c.lock);
 }
 
 void
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index f9864840ffd9c..baf4d29fde678 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1994,7 +1994,6 @@ int rtw_core_init(struct rtw_dev *rtwdev)
 	skb_queue_head_init(&rtwdev->coex.queue);
 	skb_queue_head_init(&rtwdev->tx_report.queue);
 
-	spin_lock_init(&rtwdev->h2c.lock);
 	spin_lock_init(&rtwdev->txq_lock);
 	spin_lock_init(&rtwdev->tx_report.q_lock);
 
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index df6c6032bbd3b..619ee6e8d2807 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -2018,8 +2018,6 @@ struct rtw_dev {
 	struct {
 		/* incicate the mail box to use with fw */
 		u8 last_box_num;
-		/* protect to send h2c to fw */
-		spinlock_t lock;
 		u32 seq;
 	} h2c;
 
-- 
2.30.2


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

* [PATCH v2 04/10] rtw88: Drop coex mutex
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
                   ` (2 preceding siblings ...)
  2022-05-30 13:54 ` [PATCH v2 03/10] rtw88: Drop h2c.lock Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically Sascha Hauer
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

coex->mutex is used in rtw_coex_info_request() only. Most callers of this
function hold rtwdev->mutex already, except for one callsite in the
debugfs code. The debugfs code alone doesn't justify the extra lock, so
acquire rtwdev->mutex there as well and drop the now unnecessary
spinlock.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/net/wireless/realtek/rtw88/coex.c  | 3 +--
 drivers/net/wireless/realtek/rtw88/debug.c | 2 ++
 drivers/net/wireless/realtek/rtw88/main.c  | 2 --
 drivers/net/wireless/realtek/rtw88/main.h  | 2 --
 4 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c
index cac053f485c3b..b156f8c48ffbb 100644
--- a/drivers/net/wireless/realtek/rtw88/coex.c
+++ b/drivers/net/wireless/realtek/rtw88/coex.c
@@ -633,7 +633,7 @@ static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,
 	struct rtw_coex *coex = &rtwdev->coex;
 	struct sk_buff *skb_resp = NULL;
 
-	mutex_lock(&coex->mutex);
+	lockdep_assert_held(&rtwdev->mutex);
 
 	rtw_fw_query_bt_mp_info(rtwdev, req);
 
@@ -650,7 +650,6 @@ static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,
 	}
 
 out:
-	mutex_unlock(&coex->mutex);
 	return skb_resp;
 }
 
diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c
index 79939aa6b752c..1453a32ea3ef0 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.c
+++ b/drivers/net/wireless/realtek/rtw88/debug.c
@@ -842,7 +842,9 @@ static int rtw_debugfs_get_coex_info(struct seq_file *m, void *v)
 	struct rtw_debugfs_priv *debugfs_priv = m->private;
 	struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
 
+	mutex_lock(&rtwdev->mutex);
 	rtw_coex_display_coex_info(rtwdev, m);
+	mutex_unlock(&rtwdev->mutex);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index baf4d29fde678..5afb8bef9696a 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1998,7 +1998,6 @@ int rtw_core_init(struct rtw_dev *rtwdev)
 	spin_lock_init(&rtwdev->tx_report.q_lock);
 
 	mutex_init(&rtwdev->mutex);
-	mutex_init(&rtwdev->coex.mutex);
 	mutex_init(&rtwdev->hal.tx_power_mutex);
 
 	init_waitqueue_head(&rtwdev->coex.wait);
@@ -2066,7 +2065,6 @@ void rtw_core_deinit(struct rtw_dev *rtwdev)
 	}
 
 	mutex_destroy(&rtwdev->mutex);
-	mutex_destroy(&rtwdev->coex.mutex);
 	mutex_destroy(&rtwdev->hal.tx_power_mutex);
 }
 EXPORT_SYMBOL(rtw_core_deinit);
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 619ee6e8d2807..fc27066a67a72 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -1507,8 +1507,6 @@ struct rtw_coex_stat {
 };
 
 struct rtw_coex {
-	/* protects coex info request section */
-	struct mutex mutex;
 	struct sk_buff_head queue;
 	wait_queue_head_t wait;
 
-- 
2.30.2


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

* [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
                   ` (3 preceding siblings ...)
  2022-05-30 13:54 ` [PATCH v2 04/10] rtw88: Drop coex mutex Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-06-07 22:06   ` Martin Blumenstingl
  2022-06-09  2:55   ` Ping-Ke Shih
  2022-05-30 13:54 ` [PATCH v2 06/10] rtw88: Add common USB chip support Sascha Hauer
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

The driver uses ieee80211_iterate_active_interfaces_atomic()
and ieee80211_iterate_stations_atomic() in several places and does
register accesses in the iterators. This doesn't cope with upcoming
USB support as registers can only be accessed non-atomically.

Split these into a two stage process: First use the atomic iterator
functions to collect all active interfaces or stations on a list, then
iterate over the list non-atomically and call the iterator on each
entry.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Suggested-by: Pkshih <pkshih@realtek.com>
---

Notes:
    Changes since v1:
    - Change subject
    - Add some lockdep_assert_held(&rtwdev->mutex);
    - make locally used functions static
    - Add comment how &rtwdev->mutex protects us from stations/interfaces
      being deleted between collecting them and iterating over them.

 drivers/net/wireless/realtek/rtw88/phy.c  |   6 +-
 drivers/net/wireless/realtek/rtw88/ps.c   |   2 +-
 drivers/net/wireless/realtek/rtw88/util.c | 103 ++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw88/util.h |  12 ++-
 4 files changed, 116 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index e505d17f107e4..5521a7c2c1afe 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -300,7 +300,7 @@ static void rtw_phy_stat_rssi(struct rtw_dev *rtwdev)
 
 	data.rtwdev = rtwdev;
 	data.min_rssi = U8_MAX;
-	rtw_iterate_stas_atomic(rtwdev, rtw_phy_stat_rssi_iter, &data);
+	rtw_iterate_stas(rtwdev, rtw_phy_stat_rssi_iter, &data);
 
 	dm_info->pre_min_rssi = dm_info->min_rssi;
 	dm_info->min_rssi = data.min_rssi;
@@ -544,7 +544,7 @@ static void rtw_phy_ra_info_update(struct rtw_dev *rtwdev)
 	if (rtwdev->watch_dog_cnt & 0x3)
 		return;
 
-	rtw_iterate_stas_atomic(rtwdev, rtw_phy_ra_info_update_iter, rtwdev);
+	rtw_iterate_stas(rtwdev, rtw_phy_ra_info_update_iter, rtwdev);
 }
 
 static u32 rtw_phy_get_rrsr_mask(struct rtw_dev *rtwdev, u8 rate_idx)
@@ -597,7 +597,7 @@ static void rtw_phy_rrsr_update(struct rtw_dev *rtwdev)
 	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
 
 	dm_info->rrsr_mask_min = RRSR_RATE_ORDER_MAX;
-	rtw_iterate_stas_atomic(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev);
+	rtw_iterate_stas(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev);
 	rtw_write32(rtwdev, REG_RRSR, dm_info->rrsr_val_init & dm_info->rrsr_mask_min);
 }
 
diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c
index bfa64c038f5f0..a7213ff2c2244 100644
--- a/drivers/net/wireless/realtek/rtw88/ps.c
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
@@ -58,7 +58,7 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
 		return ret;
 	}
 
-	rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
+	rtw_iterate_vifs(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
 
 	rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
 
diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c
index 2c515af214e76..ed61c962fa27f 100644
--- a/drivers/net/wireless/realtek/rtw88/util.c
+++ b/drivers/net/wireless/realtek/rtw88/util.c
@@ -105,3 +105,106 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
 		*mcs = rate - DESC_RATEMCS0;
 	}
 }
+
+struct rtw_stas_entry {
+	struct list_head list;
+	struct ieee80211_sta *sta;
+};
+
+struct rtw_iter_stas_data {
+	struct rtw_dev *rtwdev;
+	struct list_head list;
+};
+
+static void rtw_collect_sta_iter(void *data, struct ieee80211_sta *sta)
+{
+	struct rtw_iter_stas_data *iter_stas = data;
+	struct rtw_stas_entry *stas_entry;
+
+	stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC);
+	if (!stas_entry)
+		return;
+
+	stas_entry->sta = sta;
+	list_add_tail(&stas_entry->list, &iter_stas->list);
+}
+
+void rtw_iterate_stas(struct rtw_dev *rtwdev,
+		      void (*iterator)(void *data,
+				       struct ieee80211_sta *sta),
+		      void *data)
+{
+	struct rtw_iter_stas_data iter_data;
+	struct rtw_stas_entry *sta_entry, *tmp;
+
+	/* &rtwdev->mutex makes sure no stations can be removed between
+	 * collecting the stations and iterating over them.
+	 */
+	lockdep_assert_held(&rtwdev->mutex);
+
+	iter_data.rtwdev = rtwdev;
+	INIT_LIST_HEAD(&iter_data.list);
+
+	ieee80211_iterate_stations_atomic(rtwdev->hw, rtw_collect_sta_iter,
+					  &iter_data);
+
+	list_for_each_entry_safe(sta_entry, tmp, &iter_data.list,
+				 list) {
+		list_del_init(&sta_entry->list);
+		iterator(data, sta_entry->sta);
+		kfree(sta_entry);
+	}
+}
+
+struct rtw_vifs_entry {
+	struct list_head list;
+	struct ieee80211_vif *vif;
+	u8 mac[ETH_ALEN];
+};
+
+struct rtw_iter_vifs_data {
+	struct rtw_dev *rtwdev;
+	struct list_head list;
+};
+
+void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+	struct rtw_iter_vifs_data *iter_stas = data;
+	struct rtw_vifs_entry *vifs_entry;
+
+	vifs_entry = kmalloc(sizeof(*vifs_entry), GFP_ATOMIC);
+	if (!vifs_entry)
+		return;
+
+	vifs_entry->vif = vif;
+	ether_addr_copy(vifs_entry->mac, mac);
+	list_add_tail(&vifs_entry->list, &iter_stas->list);
+}
+
+void rtw_iterate_vifs(struct rtw_dev *rtwdev,
+		      void (*iterator)(void *data, u8 *mac,
+				       struct ieee80211_vif *vif),
+		      void *data)
+{
+	struct rtw_iter_vifs_data iter_data;
+	struct rtw_vifs_entry *vif_entry, *tmp;
+
+	/* &rtwdev->mutex makes sure no interfaces can be removed between
+	 * collecting the interfaces and iterating over them.
+	 */
+	lockdep_assert_held(&rtwdev->mutex);
+
+	iter_data.rtwdev = rtwdev;
+	INIT_LIST_HEAD(&iter_data.list);
+
+	ieee80211_iterate_active_interfaces_atomic(rtwdev->hw,
+						   IEEE80211_IFACE_ITER_NORMAL,
+						   rtw_collect_vif_iter, &iter_data);
+
+	list_for_each_entry_safe(vif_entry, tmp, &iter_data.list,
+				 list) {
+		list_del_init(&vif_entry->list);
+		iterator(data, vif_entry->mac, vif_entry->vif);
+		kfree(vif_entry);
+	}
+}
diff --git a/drivers/net/wireless/realtek/rtw88/util.h b/drivers/net/wireless/realtek/rtw88/util.h
index 0c23b5069be0b..dc89655254002 100644
--- a/drivers/net/wireless/realtek/rtw88/util.h
+++ b/drivers/net/wireless/realtek/rtw88/util.h
@@ -7,9 +7,6 @@
 
 struct rtw_dev;
 
-#define rtw_iterate_vifs(rtwdev, iterator, data)                               \
-	ieee80211_iterate_active_interfaces(rtwdev->hw,                        \
-			IEEE80211_IFACE_ITER_NORMAL, iterator, data)
 #define rtw_iterate_vifs_atomic(rtwdev, iterator, data)                        \
 	ieee80211_iterate_active_interfaces_atomic(rtwdev->hw,                 \
 			IEEE80211_IFACE_ITER_NORMAL, iterator, data)
@@ -20,6 +17,15 @@ struct rtw_dev;
 #define rtw_iterate_keys_rcu(rtwdev, vif, iterator, data)		       \
 	ieee80211_iter_keys_rcu((rtwdev)->hw, vif, iterator, data)
 
+void rtw_iterate_vifs(struct rtw_dev *rtwdev,
+		      void (*iterator)(void *data, u8 *mac,
+				       struct ieee80211_vif *vif),
+		      void *data);
+void rtw_iterate_stas(struct rtw_dev *rtwdev,
+		      void (*iterator)(void *data,
+				       struct ieee80211_sta *sta),
+				       void *data);
+
 static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
 {
 	__le16 fc = hdr->frame_control;
-- 
2.30.2


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

* [PATCH v2 06/10] rtw88: Add common USB chip support
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
                   ` (4 preceding siblings ...)
  2022-05-30 13:54 ` [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 07/10] rtw88: Add rtw8821cu chipset support Sascha Hauer
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer, neo_jou

Add the common bits and pieces to add USB support to the RTW88 driver.
This is based on https://github.com/ulli-kroll/rtw88-usb.git which
itself is first written by Neo Jou.

Signed-off-by: neo_jou <neo_jou@realtek.com>
Signed-off-by: Hans Ulli Kroll <linux@ulli-kroll.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---

Notes:
    Changes since v1:
    - Make checkpatch.pl clean
    - Drop WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL flag
    - Use 'ret' as variable name for return values
    - Sort variable declarations in reverse Xmas tree order
    - Change potentially endless loop to a limited loop
    - Change locking to be more obviously correct
    - drop unnecessary check for !rtwdev
    - make sure the refill workqueue is not restarted again after we have
      cancelled it

 drivers/net/wireless/realtek/rtw88/Kconfig  |    3 +
 drivers/net/wireless/realtek/rtw88/Makefile |    2 +
 drivers/net/wireless/realtek/rtw88/mac.c    |    3 +
 drivers/net/wireless/realtek/rtw88/main.c   |    4 +
 drivers/net/wireless/realtek/rtw88/main.h   |    4 +
 drivers/net/wireless/realtek/rtw88/reg.h    |    1 +
 drivers/net/wireless/realtek/rtw88/tx.h     |   31 +
 drivers/net/wireless/realtek/rtw88/usb.c    | 1037 +++++++++++++++++++
 drivers/net/wireless/realtek/rtw88/usb.h    |  114 ++
 drivers/net/wireless/realtek/rtw88/util.c   |    2 +-
 10 files changed, 1200 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/wireless/realtek/rtw88/usb.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/usb.h

diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig
index e3d7cb6c12902..1624c5db69bac 100644
--- a/drivers/net/wireless/realtek/rtw88/Kconfig
+++ b/drivers/net/wireless/realtek/rtw88/Kconfig
@@ -16,6 +16,9 @@ config RTW88_CORE
 config RTW88_PCI
 	tristate
 
+config RTW88_USB
+	tristate
+
 config RTW88_8822B
 	tristate
 
diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile
index 834c66ec0af9e..9e095f8181483 100644
--- a/drivers/net/wireless/realtek/rtw88/Makefile
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -45,4 +45,6 @@ obj-$(CONFIG_RTW88_8821CE)	+= rtw88_8821ce.o
 rtw88_8821ce-objs		:= rtw8821ce.o
 
 obj-$(CONFIG_RTW88_PCI)		+= rtw88_pci.o
+obj-$(CONFIG_RTW88_USB)		+= rtw88_usb.o
 rtw88_pci-objs			:= pci.o
+rtw88_usb-objs			:= usb.o
diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c
index d1678aed9d9cb..19728c705eaa9 100644
--- a/drivers/net/wireless/realtek/rtw88/mac.c
+++ b/drivers/net/wireless/realtek/rtw88/mac.c
@@ -1032,6 +1032,9 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev)
 	if (rtw_chip_wcpu_11ac(rtwdev))
 		rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL);
 
+	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB)
+		rtw_write8_set(rtwdev, REG_TXDMA_PQ_MAP, BIT_RXDMA_ARBBW_EN);
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 5afb8bef9696a..c191260e67a79 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1715,6 +1715,10 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev)
 		rtwdev->hci.rpwm_addr = 0x03d9;
 		rtwdev->hci.cpwm_addr = 0x03da;
 		break;
+	case RTW_HCI_TYPE_USB:
+		rtwdev->hci.rpwm_addr = 0xfe58;
+		rtwdev->hci.cpwm_addr = 0xfe57;
+		break;
 	default:
 		rtw_err(rtwdev, "unsupported hci type\n");
 		return -EINVAL;
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index fc27066a67a72..007da6df088a3 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -876,6 +876,10 @@ struct rtw_chip_ops {
 			       bool is_tx2_path);
 	void (*config_txrx_mode)(struct rtw_dev *rtwdev, u8 tx_path,
 				 u8 rx_path, bool is_tx2_path);
+	/* for USB/SDIO only */
+	void (*fill_txdesc_checksum)(struct rtw_dev *rtwdev,
+				     struct rtw_tx_pkt_info *pkt_info,
+				     u8 *txdesc);
 
 	/* for coex */
 	void (*coex_set_init)(struct rtw_dev *rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
index 84ba9ec489c37..a928899030863 100644
--- a/drivers/net/wireless/realtek/rtw88/reg.h
+++ b/drivers/net/wireless/realtek/rtw88/reg.h
@@ -184,6 +184,7 @@
 #define BIT_TXDMA_VIQ_MAP(x)                                                   \
 	(((x) & BIT_MASK_TXDMA_VIQ_MAP) << BIT_SHIFT_TXDMA_VIQ_MAP)
 #define REG_TXDMA_PQ_MAP	0x010C
+#define BIT_RXDMA_ARBBW_EN	BIT(0)
 #define BIT_SHIFT_TXDMA_BEQ_MAP	8
 #define BIT_MASK_TXDMA_BEQ_MAP	0x3
 #define BIT_TXDMA_BEQ_MAP(x)                                                   \
diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h
index 56371eff9f7ff..f900d7c08c84c 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.h
+++ b/drivers/net/wireless/realtek/rtw88/tx.h
@@ -67,6 +67,14 @@
 	le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(15))
 #define SET_TX_DESC_BT_NULL(txdesc, value)				       \
 	le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(23))
+#define SET_TX_DESC_TXDESC_CHECKSUM(txdesc, value)				\
+	le32p_replace_bits((__le32 *)(txdesc) + 0x07, value, GENMASK(15, 0))
+#define SET_TX_DESC_DMA_TXAGG_NUM(txdesc, value)				\
+	le32p_replace_bits((__le32 *)(txdesc) + 0x07, value, GENMASK(31, 24))
+#define GET_TX_DESC_PKT_OFFSET(txdesc)						\
+	le32_get_bits(*((__le32 *)(txdesc) + 0x01), GENMASK(28, 24))
+#define GET_TX_DESC_QSEL(txdesc)						\
+	le32_get_bits(*((__le32 *)(txdesc) + 0x01), GENMASK(12, 8))
 
 enum rtw_tx_desc_queue_select {
 	TX_DESC_QSEL_TID0	= 0,
@@ -119,4 +127,27 @@ rtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev,
 			  struct rtw_tx_pkt_info *pkt_info,
 			  u8 *buf, u32 size);
 
+static inline
+void fill_txdesc_checksum_common(u8 *txdesc, size_t words)
+{
+	__le16 chksum = 0;
+	__le16 *data = (__le16 *)(txdesc);
+
+	SET_TX_DESC_TXDESC_CHECKSUM(txdesc, 0x0000);
+
+	while (words--)
+		chksum ^= *data++;
+
+	SET_TX_DESC_TXDESC_CHECKSUM(txdesc, __le16_to_cpu(chksum));
+}
+
+static inline void rtw_tx_fill_txdesc_checksum(struct rtw_dev *rtwdev,
+					       struct rtw_tx_pkt_info *pkt_info,
+					       u8 *txdesc)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+
+	chip->ops->fill_txdesc_checksum(rtwdev, pkt_info, txdesc);
+}
+
 #endif
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
new file mode 100644
index 0000000000000..500d5208086dd
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -0,0 +1,1037 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2018-2019  Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include "main.h"
+#include "debug.h"
+#include "reg.h"
+#include "tx.h"
+#include "rx.h"
+#include "fw.h"
+#include "ps.h"
+#include "usb.h"
+
+#define RTW_USB_MAX_RXQ_LEN	128
+
+struct rtw_usb_txcb {
+	struct rtw_dev *rtwdev;
+	struct sk_buff_head tx_ack_queue;
+};
+
+static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb,
+				     struct sk_buff *skb, int agg_num)
+{
+	struct rtw_dev *rtwdev = rtwusb->rtwdev;
+	struct rtw_tx_pkt_info pkt_info;
+
+	SET_TX_DESC_DMA_TXAGG_NUM(skb->data, agg_num);
+	pkt_info.pkt_offset = GET_TX_DESC_PKT_OFFSET(skb->data);
+	rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data);
+}
+
+static void usbctrl_async_callback(struct urb *urb)
+{
+	/* free dr */
+	kfree(urb->setup_packet);
+	/* free databuf */
+	kfree(urb->transfer_buffer);
+}
+
+static int usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
+					 u16 value, u16 index, void *pdata,
+					 u16 len)
+{
+	const u16 databuf_maxlen = RTW_USB_VENQT_MAX_BUF_SIZE;
+	struct usb_ctrlrequest *dr;
+	unsigned int pipe;
+	struct urb *urb;
+	u8 *databuf;
+	u8 reqtype;
+	int ret;
+
+	if (WARN_ON_ONCE(len > databuf_maxlen))
+		len = databuf_maxlen;
+
+	pipe = usb_sndctrlpipe(udev, 0); /* write_out */
+	reqtype = RTW_USB_CMD_WRITE;
+
+	dr = kzalloc(sizeof(*dr), GFP_ATOMIC);
+	if (!dr)
+		return -ENOMEM;
+
+	databuf = kmemdup(pdata, len, GFP_ATOMIC);
+	if (!databuf) {
+		kfree(dr);
+		return -ENOMEM;
+	}
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		kfree(databuf);
+		kfree(dr);
+		return -ENOMEM;
+	}
+
+	dr->bRequestType = reqtype;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16(value);
+	dr->wIndex = cpu_to_le16(index);
+	dr->wLength = cpu_to_le16(len);
+
+	usb_fill_control_urb(urb, udev, pipe,
+			     (unsigned char *)dr, databuf, len,
+			     usbctrl_async_callback, NULL);
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret < 0) {
+		kfree(databuf);
+		kfree(dr);
+	}
+
+	usb_free_urb(urb);
+
+	return ret;
+}
+
+static u32 rtw_usb_read_sync(struct rtw_dev *rtwdev, u32 addr, u16 len)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	struct usb_device *udev = rtwusb->udev;
+	__le32 *data;
+	unsigned long flags;
+	int ret;
+	static int count;
+
+	spin_lock_irqsave(&rtwusb->usb_lock, flags);
+
+	if (++rtwusb->usb_data_index >= RTW_USB_MAX_RX_COUNT)
+		rtwusb->usb_data_index = 0;
+	data = &rtwusb->usb_data[rtwusb->usb_data_index];
+
+	spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr,
+			      RTW_USB_VENQT_CMD_IDX, data, len, 1000);
+	if (ret < 0 && ret != -ENODEV && count++ < 4)
+		rtw_err(rtwdev, "reg 0x%x, usbctrl_vendorreq failed with %d\n",
+			addr, ret);
+
+	return le32_to_cpu(*data);
+}
+
+static u8 rtw_usb_read8_sync(struct rtw_dev *rtwdev, u32 addr)
+{
+	return (u8)rtw_usb_read_sync(rtwdev, addr, 1);
+}
+
+static u16 rtw_usb_read16_sync(struct rtw_dev *rtwdev, u32 addr)
+{
+	return (u16)rtw_usb_read_sync(rtwdev, addr, 2);
+}
+
+static u32 rtw_usb_read32_sync(struct rtw_dev *rtwdev, u32 addr)
+{
+	return (u32)rtw_usb_read_sync(rtwdev, addr, 4);
+}
+
+static void rtw_usb_write_async(struct rtw_dev *rtwdev, u32 addr, u32 val,
+				u16 len)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	struct usb_device *udev = rtwusb->udev;
+	u8 request;
+	u16 wvalue;
+	u16 index;
+	__le32 data;
+
+	request = RTW_USB_CMD_REQ;
+	index = RTW_USB_VENQT_CMD_IDX; /* n/a */
+	wvalue = (u16)(addr & 0x0000ffff);
+	data = cpu_to_le32(val);
+	usbctrl_vendorreq_async_write(udev, request, wvalue, index, &data, len);
+}
+
+static void rtw_usb_write8_async(struct rtw_dev *rtwdev, u32 addr, u8 val)
+{
+	rtw_usb_write_async(rtwdev, addr, val, 1);
+}
+
+static void rtw_usb_write16_async(struct rtw_dev *rtwdev, u32 addr, u16 val)
+{
+	rtw_usb_write_async(rtwdev, addr, val, 2);
+}
+
+static void rtw_usb_write32_async(struct rtw_dev *rtwdev, u32 addr, u32 val)
+{
+	rtw_usb_write_async(rtwdev, addr, val, 4);
+}
+
+static int rtw_usb_parse(struct rtw_dev *rtwdev,
+			 struct usb_interface *interface)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	struct usb_host_interface *host_interface = &interface->altsetting[0];
+	struct usb_interface_descriptor *interface_desc = &host_interface->desc;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_device *usbd = interface_to_usbdev(interface);
+	int num_out_pipes = 0;
+	int i;
+	u8 num;
+
+	for (i = 0; i < interface_desc->bNumEndpoints; i++) {
+		endpoint = &host_interface->endpoint[i].desc;
+		num = usb_endpoint_num(endpoint);
+
+		if (usb_endpoint_dir_in(endpoint) &&
+		    usb_endpoint_xfer_bulk(endpoint)) {
+			if (rtwusb->pipe_in) {
+				rtw_err(rtwdev, "IN pipes overflow\n");
+				return -EINVAL;
+			}
+
+			rtwusb->pipe_in = num;
+		}
+
+		if (usb_endpoint_dir_in(endpoint) &&
+		    usb_endpoint_xfer_int(endpoint)) {
+			if (rtwusb->pipe_interrupt) {
+				rtw_err(rtwdev, "INT pipes overflow\n");
+				return -EINVAL;
+			}
+
+			rtwusb->pipe_interrupt = num;
+		}
+
+		if (usb_endpoint_dir_out(endpoint) &&
+		    usb_endpoint_xfer_bulk(endpoint)) {
+			if (num_out_pipes >= ARRAY_SIZE(rtwusb->out_ep)) {
+				rtw_err(rtwdev, "OUT pipes overflow\n");
+				return -EINVAL;
+			}
+
+			rtwusb->out_ep[num_out_pipes++] = num;
+		}
+	}
+
+	switch (usbd->speed) {
+	case USB_SPEED_LOW:
+	case USB_SPEED_FULL:
+		rtwusb->bulkout_size = RTW_USB_FULL_SPEED_BULK_SIZE;
+		break;
+	case USB_SPEED_HIGH:
+		rtwusb->bulkout_size = RTW_USB_HIGH_SPEED_BULK_SIZE;
+		break;
+	case USB_SPEED_SUPER:
+		rtwusb->bulkout_size = RTW_USB_SUPER_SPEED_BULK_SIZE;
+		break;
+	default:
+		rtw_err(rtwdev, "failed to detect usb speed\n");
+		return -EINVAL;
+	}
+
+	rtwdev->hci.bulkout_num = num_out_pipes;
+
+	switch (num_out_pipes) {
+	case 4:
+	case 3:
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = 2;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = 2;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = 2;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = 2;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID4] = 1;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID5] = 1;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID6] = 1;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID7] = 1;
+		break;
+	case 2:
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = 1;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = 1;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = 1;
+		rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = 1;
+		break;
+	case 1:
+		break;
+	default:
+		rtw_err(rtwdev, "failed to get out_pipes(%d)\n", num_out_pipes);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void rtw_usb_txcb_enqueue(struct rtw_usb_txcb *txcb, struct sk_buff *skb)
+{
+	skb_queue_tail(&txcb->tx_ack_queue, skb);
+}
+
+static void rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list,
+			       struct sk_buff *skb_head, struct sk_buff *skb,
+			       struct rtw_usb_txcb *txcb)
+{
+	struct sk_buff *skb_iter;
+	unsigned long flags;
+	u8 *data_ptr;
+	int agg_num = 0, len, max_len;
+
+	data_ptr = skb_head->data;
+	skb_iter = skb;
+
+	while (skb_iter) {
+		memcpy(data_ptr, skb_iter->data, skb_iter->len);
+		len = ALIGN(skb_iter->len, 8);
+		skb_put(skb_head, len);
+		data_ptr += len;
+		agg_num++;
+
+		rtw_usb_txcb_enqueue(txcb, skb_iter);
+
+		spin_lock_irqsave(&list->lock, flags);
+
+		skb_iter = skb_peek(list);
+		max_len = RTW_USB_MAX_XMITBUF_SZ - skb_head->len;
+
+		if (skb_iter && skb_iter->len < max_len)
+			__skb_unlink(skb_iter, list);
+		else
+			skb_iter = NULL;
+		spin_unlock_irqrestore(&list->lock, flags);
+	}
+
+	if (agg_num > 1)
+		rtw_usb_fill_tx_checksum(rtwusb, skb_head, agg_num);
+}
+
+static void rtw_usb_indicate_tx_status(struct rtw_dev *rtwdev,
+				       struct sk_buff *skb)
+{
+	struct ieee80211_hw *hw = rtwdev->hw;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct rtw_usb_tx_data *tx_data = rtw_usb_get_tx_data(skb);
+
+	/* enqueue to wait for tx report */
+	if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
+		rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn);
+		return;
+	}
+
+	/* always ACK for others, then they won't be marked as drop */
+	ieee80211_tx_info_clear_status(info);
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+	else
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	ieee80211_tx_status_irqsafe(hw, skb);
+}
+
+static void rtw_usb_write_port_tx_complete(struct urb *urb)
+{
+	struct rtw_usb_txcb *txcb = urb->context;
+	struct rtw_dev *rtwdev = txcb->rtwdev;
+
+	while (true) {
+		struct sk_buff *skb = skb_dequeue(&txcb->tx_ack_queue);
+
+		if (!skb)
+			break;
+
+		if (GET_TX_DESC_QSEL(skb->data) <= TX_DESC_QSEL_TID7)
+			rtw_usb_indicate_tx_status(rtwdev, skb);
+		else
+			dev_kfree_skb_any(skb);
+	}
+
+	kfree(txcb);
+}
+
+static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *skb,
+			      usb_complete_t cb, void *context)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	struct usb_device *usbd = rtwusb->udev;
+	struct urb *urb;
+	unsigned int pipe;
+	int ret;
+	int ep = rtwusb->qsel_to_ep[qsel];
+
+	pipe = usb_sndbulkpipe(usbd, rtwusb->out_ep[ep]);
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb)
+		return -ENOMEM;
+
+	usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len, cb, context);
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+
+	usb_free_urb(urb);
+
+	return ret;
+}
+
+static struct sk_buff *rtw_usb_tx_agg_check(struct rtw_usb *rtwusb,
+					    struct sk_buff *skb,
+					    int index,
+					    struct rtw_usb_txcb *txcb)
+{
+	struct sk_buff_head *list;
+	struct sk_buff *skb_head;
+
+	list = &rtwusb->tx_queue[index];
+	if (skb_queue_empty(list))
+		return NULL;
+
+	skb_head = dev_alloc_skb(RTW_USB_MAX_XMITBUF_SZ);
+	if (!skb_head)
+		return NULL;
+
+	rtw_usb_tx_agg_skb(rtwusb, list, skb_head, skb, txcb);
+
+	return skb_head;
+}
+
+static void rtw_usb_tx_agg(struct rtw_usb *rtwusb, struct sk_buff *skb, int index)
+{
+	struct rtw_dev *rtwdev = rtwusb->rtwdev;
+	struct sk_buff *skb_head;
+	struct rtw_usb_txcb *txcb;
+	u8 qsel;
+
+	txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC);
+	if (!txcb)
+		return;
+
+	txcb->rtwdev = rtwdev;
+	skb_queue_head_init(&txcb->tx_ack_queue);
+
+	skb_head = rtw_usb_tx_agg_check(rtwusb, skb, index, txcb);
+	if (!skb_head) {
+		skb_head = skb;
+		rtw_usb_txcb_enqueue(txcb, skb);
+	}
+
+	qsel = GET_TX_DESC_QSEL(skb->data);
+
+	rtw_usb_write_port(rtwdev, qsel, skb_head,
+			   rtw_usb_write_port_tx_complete, txcb);
+
+	if (skb_head != skb)
+		dev_kfree_skb(skb_head);
+}
+
+static void rtw_usb_tx_handler(struct work_struct *work)
+{
+	struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, tx_work);
+	struct sk_buff *skb;
+	int index, limit;
+
+	for (index = ARRAY_SIZE(rtwusb->tx_queue) - 1; index >= 0; index--) {
+		for (limit = 0; limit < 200; limit++) {
+			skb = skb_dequeue(&rtwusb->tx_queue[index]);
+			if (skb)
+				rtw_usb_tx_agg(rtwusb, skb, index);
+			else
+				break;
+		}
+	}
+}
+
+static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
+		skb_queue_purge(&rtwusb->tx_queue[i]);
+}
+
+static void rtw_usb_write_port_complete(struct urb *urb)
+{
+	struct sk_buff *skb = urb->context;
+
+	dev_kfree_skb_any(skb);
+}
+
+static int rtw_usb_write_data(struct rtw_dev *rtwdev,
+			      struct rtw_tx_pkt_info *pkt_info,
+			      u8 *buf)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	struct sk_buff *skb;
+	unsigned int desclen, headsize, size;
+	u8 qsel;
+	int ret = 0;
+
+	size = pkt_info->tx_pkt_size;
+	qsel = pkt_info->qsel;
+	desclen = chip->tx_pkt_desc_sz;
+	headsize = pkt_info->offset ? pkt_info->offset : desclen;
+
+	skb = dev_alloc_skb(headsize + size);
+	if (unlikely(!skb))
+		return -ENOMEM;
+
+	skb_reserve(skb, headsize);
+	skb_put_data(skb, buf, size);
+	skb_push(skb, headsize);
+	memset(skb->data, 0, headsize);
+	rtw_tx_fill_tx_desc(pkt_info, skb);
+	rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data);
+
+	ret = rtw_usb_write_port(rtwdev, qsel, skb,
+				 rtw_usb_write_port_complete, skb);
+	if (unlikely(ret))
+		rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret);
+
+	return ret;
+}
+
+static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
+					u32 size)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	struct rtw_usb *rtwusb;
+	struct rtw_tx_pkt_info pkt_info = {0};
+	u32 len, desclen;
+
+	rtwusb = rtw_get_usb_priv(rtwdev);
+	if (unlikely(!rtwusb))
+		return -EINVAL;
+
+	pkt_info.tx_pkt_size = size;
+	pkt_info.qsel = TX_DESC_QSEL_BEACON;
+
+	desclen = chip->tx_pkt_desc_sz;
+	len = desclen + size;
+	if (len % rtwusb->bulkout_size == 0) {
+		len += RTW_USB_PACKET_OFFSET_SZ;
+		pkt_info.offset = desclen + RTW_USB_PACKET_OFFSET_SZ;
+		pkt_info.pkt_offset = 1;
+	} else {
+		pkt_info.offset = desclen;
+	}
+
+	return rtw_usb_write_data(rtwdev, &pkt_info, buf);
+}
+
+static int rtw_usb_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size)
+{
+	struct rtw_tx_pkt_info pkt_info = {0};
+
+	pkt_info.tx_pkt_size = size;
+	pkt_info.qsel = TX_DESC_QSEL_H2C;
+
+	return rtw_usb_write_data(rtwdev, &pkt_info, buf);
+}
+
+static u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	__le16 fc = hdr->frame_control;
+	u8 qsel;
+
+	if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
+		qsel = TX_DESC_QSEL_MGMT;
+	else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK)
+		qsel = skb->priority;
+	else
+		qsel = TX_DESC_QSEL_BEACON;
+
+	return qsel;
+}
+
+static int rtw_usb_tx_write(struct rtw_dev *rtwdev,
+			    struct rtw_tx_pkt_info *pkt_info,
+			    struct sk_buff *skb)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	struct rtw_chip_info *chip = rtwdev->chip;
+	struct rtw_usb_tx_data *tx_data;
+	u8 *pkt_desc;
+	int ep;
+
+	pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
+	memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
+	pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb);
+	ep = rtwusb->qsel_to_ep[pkt_info->qsel];
+	rtw_tx_fill_tx_desc(pkt_info, skb);
+	rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data);
+	tx_data = rtw_usb_get_tx_data(skb);
+	tx_data->sn = pkt_info->sn;
+
+	skb_queue_tail(&rtwusb->tx_queue[ep], skb);
+
+	return 0;
+}
+
+static void rtw_usb_tx_kick_off(struct rtw_dev *rtwdev)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+
+	queue_work(rtwusb->txwq, &rtwusb->tx_work);
+}
+
+static void rtw_usb_rx_handler(struct work_struct *work)
+{
+	struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work);
+	struct rtw_dev *rtwdev = rtwusb->rtwdev;
+	struct rtw_chip_info *chip = rtwdev->chip;
+	struct rtw_rx_pkt_stat pkt_stat;
+	struct ieee80211_rx_status rx_status;
+	struct sk_buff *skb;
+	u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
+	u32 pkt_offset;
+	u8 *rx_desc;
+	int limit;
+
+	for (limit = 0; limit < 200; limit++) {
+		skb = skb_dequeue(&rtwusb->rx_queue);
+		if (!skb)
+			break;
+
+		rx_desc = skb->data;
+		chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat,
+					 &rx_status);
+		pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
+			     pkt_stat.shift;
+
+		if (pkt_stat.is_c2h) {
+			skb_put(skb, pkt_stat.pkt_len + pkt_offset);
+			rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset,
+						  skb);
+			continue;
+		}
+
+		if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) {
+			rtw_err(rtwdev, "failed to get rx_queue, overflow\n");
+			dev_kfree_skb_any(skb);
+			continue;
+		}
+
+		skb_put(skb, pkt_stat.pkt_len);
+		skb_reserve(skb, pkt_offset);
+		memcpy(skb->cb, &rx_status, sizeof(rx_status));
+		ieee80211_rx_irqsafe(rtwdev->hw, skb);
+	}
+}
+
+static void rtw_usb_rx_data_put(struct rtw_usb *rtwusb,
+				struct rx_usb_ctrl_block *rxcb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rtwusb->rx_data_list_lock, flags);
+	list_move(&rxcb->list, &rtwusb->rx_data_free);
+	spin_unlock_irqrestore(&rtwusb->rx_data_list_lock, flags);
+}
+
+static void rtw_usb_read_port_complete(struct urb *urb)
+{
+	struct rx_usb_ctrl_block *rxcb = urb->context;
+	struct rtw_dev *rtwdev = rxcb->rtwdev;
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	struct sk_buff *skb = rxcb->rx_skb;
+
+	if (urb->status == 0) {
+		if (urb->actual_length >= RTW_USB_MAX_RECVBUF_SZ ||
+		    urb->actual_length < 24) {
+			rtw_err(rtwdev, "failed to get urb length:%d\n",
+				urb->actual_length);
+			if (skb)
+				dev_kfree_skb_any(skb);
+		} else {
+			skb_queue_tail(&rtwusb->rx_queue, skb);
+			queue_work(rtwusb->rxwq, &rtwusb->rx_work);
+		}
+
+		rtw_usb_rx_data_put(rtwusb, rxcb);
+		if (rtwusb->running)
+			queue_work(rtwusb->rxwq, &rtwusb->rx_refill_work);
+	} else {
+		switch (urb->status) {
+		case -EINVAL:
+		case -EPIPE:
+		case -ENODEV:
+		case -ESHUTDOWN:
+		case -ENOENT:
+		case -EPROTO:
+		case -EILSEQ:
+		case -ETIME:
+		case -ECOMM:
+		case -EOVERFLOW:
+		case -EINPROGRESS:
+			break;
+		default:
+			rtw_err(rtwdev, "status unknown=%d\n", urb->status);
+			break;
+		}
+		if (skb)
+			dev_kfree_skb_any(skb);
+	}
+}
+
+static void rtw_usb_rx_refill_work(struct work_struct *work)
+{
+	struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_refill_work);
+	struct rtw_dev *rtwdev = rtwusb->rtwdev;
+	struct rx_usb_ctrl_block *rxcb;
+	unsigned long flags;
+	int error, limit;
+
+	for (limit = 0; limit < 200; limit++) {
+		spin_lock_irqsave(&rtwusb->rx_data_list_lock, flags);
+
+		rxcb = list_first_entry_or_null(&rtwusb->rx_data_free,
+						struct rx_usb_ctrl_block, list);
+
+		spin_unlock_irqrestore(&rtwusb->rx_data_list_lock, flags);
+		if (!rxcb)
+			return;
+
+		rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_KERNEL);
+		if (!rxcb->rx_skb)
+			return;
+
+		usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev,
+				  usb_rcvbulkpipe(rtwusb->udev, rtwusb->pipe_in),
+				  rxcb->rx_skb->data, RTW_USB_MAX_RECVBUF_SZ,
+				  rtw_usb_read_port_complete, rxcb);
+
+		spin_lock_irqsave(&rtwusb->rx_data_list_lock, flags);
+		list_move(&rxcb->list, &rtwusb->rx_data_used);
+		spin_unlock_irqrestore(&rtwusb->rx_data_list_lock, flags);
+
+		error = usb_submit_urb(rxcb->rx_urb, GFP_KERNEL);
+		if (error) {
+			kfree_skb(rxcb->rx_skb);
+			if (error != -ENODEV)
+				rtw_err(rtwdev, "Err sending rx data urb %d\n",
+					error);
+			rtw_usb_rx_data_put(rtwusb, rxcb);
+
+			return;
+		}
+	}
+}
+
+static void rtw_usb_cancel_rx_bufs(struct rtw_usb *rtwusb)
+{
+	struct rx_usb_ctrl_block *rxcb;
+
+	rtwusb->running = 0;
+	cancel_work_sync(&rtwusb->rx_refill_work);
+
+	while (true) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&rtwusb->rx_data_list_lock, flags);
+
+		rxcb = list_first_entry_or_null(&rtwusb->rx_data_used,
+						struct rx_usb_ctrl_block, list);
+		if (rxcb)
+			list_move(&rxcb->list, &rtwusb->rx_data_free);
+
+		spin_unlock_irqrestore(&rtwusb->rx_data_list_lock, flags);
+
+		if (!rxcb)
+			break;
+
+		usb_kill_urb(rxcb->rx_urb);
+	}
+}
+
+static void rtw_usb_free_rx_bufs(struct rtw_usb *rtwusb)
+{
+	struct rx_usb_ctrl_block *rxcb;
+
+	list_for_each_entry(rxcb, &rtwusb->rx_data_free, list)
+		usb_free_urb(rxcb->rx_urb);
+}
+
+static int rtw_usb_alloc_rx_bufs(struct rtw_usb *rtwusb)
+{
+	int i;
+
+	for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
+		struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
+
+		rxcb->rtwdev = rtwusb->rtwdev;
+		rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!rxcb->rx_urb)
+			goto err;
+		list_add_tail(&rxcb->list, &rtwusb->rx_data_free);
+	}
+
+	return 0;
+err:
+	rtw_usb_free_rx_bufs(rtwusb);
+	return -ENOMEM;
+}
+
+static int rtw_usb_setup(struct rtw_dev *rtwdev)
+{
+	/* empty function for rtw_hci_ops */
+	return 0;
+}
+
+static int rtw_usb_start(struct rtw_dev *rtwdev)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+
+	rtwusb->running = 1;
+	queue_work(rtwusb->rxwq, &rtwusb->rx_refill_work);
+
+	return 0;
+}
+
+static void rtw_usb_stop(struct rtw_dev *rtwdev)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+
+	rtw_usb_cancel_rx_bufs(rtwusb);
+}
+
+static void rtw_usb_deep_ps(struct rtw_dev *rtwdev, bool enter)
+{
+	/* empty function for rtw_hci_ops */
+}
+
+static void rtw_usb_link_ps(struct rtw_dev *rtwdev, bool enter)
+{
+	/* empty function for rtw_hci_ops */
+}
+
+static void rtw_usb_interface_cfg(struct rtw_dev *rtwdev)
+{
+	/* empty function for rtw_hci_ops */
+}
+
+static struct rtw_hci_ops rtw_usb_ops = {
+	.tx_write = rtw_usb_tx_write,
+	.tx_kick_off = rtw_usb_tx_kick_off,
+	.setup = rtw_usb_setup,
+	.start = rtw_usb_start,
+	.stop = rtw_usb_stop,
+	.deep_ps = rtw_usb_deep_ps,
+	.link_ps = rtw_usb_link_ps,
+	.interface_cfg = rtw_usb_interface_cfg,
+
+	.write8  = rtw_usb_write8_async,
+	.write16 = rtw_usb_write16_async,
+	.write32 = rtw_usb_write32_async,
+	.read8	= rtw_usb_read8_sync,
+	.read16 = rtw_usb_read16_sync,
+	.read32 = rtw_usb_read32_sync,
+
+	.write_data_rsvd_page = rtw_usb_write_data_rsvd_page,
+	.write_data_h2c = rtw_usb_write_data_h2c,
+};
+
+static int rtw_usb_init_rx(struct rtw_dev *rtwdev)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+
+	rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq");
+	if (!rtwusb->rxwq) {
+		rtw_err(rtwdev, "failed to create RX work queue\n");
+		return -ENOMEM;
+	}
+
+	skb_queue_head_init(&rtwusb->rx_queue);
+
+	INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler);
+
+	return 0;
+}
+
+static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+
+	skb_queue_purge(&rtwusb->rx_queue);
+
+	flush_workqueue(rtwusb->rxwq);
+	destroy_workqueue(rtwusb->rxwq);
+}
+
+static int rtw_usb_init_tx(struct rtw_dev *rtwdev)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	int i;
+
+	rtwusb->txwq = create_singlethread_workqueue("rtw88_usb: tx wq");
+	if (!rtwusb->txwq) {
+		rtw_err(rtwdev, "failed to create TX work queue\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
+		skb_queue_head_init(&rtwusb->tx_queue[i]);
+
+	INIT_WORK(&rtwusb->tx_work, rtw_usb_tx_handler);
+
+	return 0;
+}
+
+static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+
+	rtw_usb_tx_queue_purge(rtwusb);
+	flush_workqueue(rtwusb->txwq);
+	destroy_workqueue(rtwusb->txwq);
+}
+
+static int rtw_usb_intf_init(struct rtw_dev *rtwdev,
+			     struct usb_interface *intf)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+	struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf));
+	int ret;
+
+	rtwusb->udev = udev;
+	ret = rtw_usb_parse(rtwdev, intf);
+	if (ret)
+		return ret;
+
+	rtwusb->usb_data = kcalloc(RTW_USB_MAX_RX_COUNT, sizeof(u32),
+				   GFP_KERNEL);
+	if (!rtwusb->usb_data)
+		return -ENOMEM;
+
+	usb_set_intfdata(intf, rtwdev->hw);
+
+	SET_IEEE80211_DEV(rtwdev->hw, &intf->dev);
+	spin_lock_init(&rtwusb->usb_lock);
+
+	return 0;
+}
+
+static void rtw_usb_intf_deinit(struct rtw_dev *rtwdev,
+				struct usb_interface *intf)
+{
+	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+
+	usb_put_dev(rtwusb->udev);
+	usb_set_intfdata(intf, NULL);
+}
+
+int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct rtw_dev *rtwdev;
+	struct ieee80211_hw *hw;
+	struct rtw_usb *rtwusb;
+	int drv_data_size;
+	int ret;
+
+	drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_usb);
+	hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops);
+	if (!hw)
+		return -ENOMEM;
+
+	rtwdev = hw->priv;
+	rtwdev->hw = hw;
+	rtwdev->dev = &intf->dev;
+	rtwdev->chip = (struct rtw_chip_info *)id->driver_info;
+	rtwdev->hci.ops = &rtw_usb_ops;
+	rtwdev->hci.type = RTW_HCI_TYPE_USB;
+
+	rtwusb = rtw_get_usb_priv(rtwdev);
+	rtwusb->rtwdev = rtwdev;
+
+	INIT_WORK(&rtwusb->rx_refill_work, rtw_usb_rx_refill_work);
+	INIT_LIST_HEAD(&rtwusb->rx_data_free);
+	INIT_LIST_HEAD(&rtwusb->rx_data_used);
+	spin_lock_init(&rtwusb->rx_data_list_lock);
+
+	ret = rtw_usb_alloc_rx_bufs(rtwusb);
+	if (ret)
+		return ret;
+
+	ret = rtw_core_init(rtwdev);
+	if (ret)
+		goto err_release_hw;
+
+	ret = rtw_usb_intf_init(rtwdev, intf);
+	if (ret) {
+		rtw_err(rtwdev, "failed to init USB interface\n");
+		goto err_deinit_core;
+	}
+
+	ret = rtw_usb_init_tx(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to init USB TX\n");
+		goto err_destroy_usb;
+	}
+
+	ret = rtw_usb_init_rx(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to init USB RX\n");
+		goto err_destroy_txwq;
+	}
+
+	ret = rtw_chip_info_setup(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to setup chip information\n");
+		goto err_destroy_rxwq;
+	}
+
+	ret = rtw_register_hw(rtwdev, rtwdev->hw);
+	if (ret) {
+		rtw_err(rtwdev, "failed to register hw\n");
+		goto err_destroy_rxwq;
+	}
+
+	return 0;
+
+err_destroy_rxwq:
+	rtw_usb_deinit_rx(rtwdev);
+
+err_destroy_txwq:
+	rtw_usb_deinit_tx(rtwdev);
+
+err_destroy_usb:
+	rtw_usb_intf_deinit(rtwdev, intf);
+
+err_deinit_core:
+	rtw_core_deinit(rtwdev);
+
+err_release_hw:
+	ieee80211_free_hw(hw);
+
+	return ret;
+}
+EXPORT_SYMBOL(rtw_usb_probe);
+
+void rtw_usb_disconnect(struct usb_interface *intf)
+{
+	struct ieee80211_hw *hw = usb_get_intfdata(intf);
+	struct rtw_dev *rtwdev;
+	struct rtw_usb *rtwusb;
+
+	if (!hw)
+		return;
+
+	rtwdev = hw->priv;
+	rtwusb = rtw_get_usb_priv(rtwdev);
+
+	rtw_usb_cancel_rx_bufs(rtwusb);
+
+	rtw_unregister_hw(rtwdev, hw);
+	rtw_usb_deinit_tx(rtwdev);
+	rtw_usb_deinit_rx(rtwdev);
+
+	if (rtwusb->udev->state != USB_STATE_NOTATTACHED)
+		usb_reset_device(rtwusb->udev);
+
+	rtw_usb_free_rx_bufs(rtwusb);
+
+	rtw_usb_intf_deinit(rtwdev, intf);
+	rtw_core_deinit(rtwdev);
+	ieee80211_free_hw(hw);
+}
+EXPORT_SYMBOL(rtw_usb_disconnect);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless USB driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/usb.h b/drivers/net/wireless/realtek/rtw88/usb.h
new file mode 100644
index 0000000000000..0e219150ee87a
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/usb.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2018-2019  Realtek Corporation
+ */
+
+#ifndef __RTW_USB_H_
+#define __RTW_USB_H_
+
+#define FW_8192C_START_ADDRESS		0x1000
+#define FW_8192C_END_ADDRESS		0x5fff
+
+#define RTW_USB_MAX_RX_COUNT		100
+#define RTW_USB_VENQT_MAX_BUF_SIZE	254
+#define MAX_USBCTRL_VENDORREQ_TIMES	10
+
+#define RTW_USB_CMD_READ		0xc0
+#define RTW_USB_CMD_WRITE		0x40
+#define RTW_USB_CMD_REQ			0x05
+
+#define RTW_USB_VENQT_CMD_IDX		0x00
+
+#define RTW_USB_SUPER_SPEED_BULK_SIZE	1024
+#define RTW_USB_HIGH_SPEED_BULK_SIZE	512
+#define RTW_USB_FULL_SPEED_BULK_SIZE	64
+
+#define RTW_USB_TX_SEL_HQ		BIT(0)
+#define RTW_USB_TX_SEL_LQ		BIT(1)
+#define RTW_USB_TX_SEL_NQ		BIT(2)
+#define RTW_USB_TX_SEL_EQ		BIT(3)
+
+#define RTW_USB_BULK_IN_ADDR		0x80
+#define RTW_USB_INT_IN_ADDR		0x81
+
+#define RTW_USB_HW_QUEUE_ENTRY		8
+
+#define RTW_USB_PACKET_OFFSET_SZ	8
+#define RTW_USB_MAX_XMITBUF_SZ		(1592 * 3)
+#define RTW_USB_MAX_RECVBUF_SZ		32768
+
+#define RTW_USB_RECVBUFF_ALIGN_SZ	8
+
+#define RTW_USB_RXAGG_SIZE		6
+#define RTW_USB_RXAGG_TIMEOUT		10
+
+#define RTW_USB_RXCB_NUM		4
+
+#define RTW_USB_EP_MAX			4
+
+#define TX_DESC_QSEL_MAX		20
+
+#define RTW_USB_VENDOR_ID_REALTEK	0x0bda
+
+static inline struct rtw_usb *rtw_get_usb_priv(struct rtw_dev *rtwdev)
+{
+	return (struct rtw_usb *)rtwdev->priv;
+}
+
+struct rx_usb_ctrl_block {
+	struct rtw_dev *rtwdev;
+	struct urb *rx_urb;
+	struct sk_buff *rx_skb;
+	struct list_head list;
+};
+
+struct rtw_usb_tx_data {
+	u8 sn;
+};
+
+struct rtw_usb {
+	struct rtw_dev *rtwdev;
+	struct usb_device *udev;
+
+	/* protects rx_data_free and rx_data_used lists */
+	spinlock_t rx_data_list_lock;
+	bool running;
+	struct work_struct rx_refill_work;
+	struct list_head rx_data_free;
+	struct list_head rx_data_used;
+
+	/* protects usb_data_index */
+	spinlock_t usb_lock;
+	__le32 *usb_data;
+	int usb_data_index;
+
+	u32 bulkout_size;
+	u8 pipe_interrupt;
+	u8 pipe_in;
+	u8 out_ep[RTW_USB_EP_MAX];
+	u8 qsel_to_ep[TX_DESC_QSEL_MAX];
+	u8 usb_txagg_num;
+
+	struct workqueue_struct *txwq, *rxwq;
+
+	struct sk_buff_head tx_queue[RTW_USB_EP_MAX];
+	struct work_struct tx_work;
+
+	struct rx_usb_ctrl_block rx_cb[RTW_USB_RXCB_NUM];
+	struct sk_buff_head rx_queue;
+	struct work_struct rx_work;
+};
+
+static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+	BUILD_BUG_ON(sizeof(struct rtw_usb_tx_data) >
+		sizeof(info->status.status_driver_data));
+
+	return (struct rtw_usb_tx_data *)info->status.status_driver_data;
+}
+
+int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id);
+void rtw_usb_disconnect(struct usb_interface *intf);
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c
index ed61c962fa27f..ce983ab8f947b 100644
--- a/drivers/net/wireless/realtek/rtw88/util.c
+++ b/drivers/net/wireless/realtek/rtw88/util.c
@@ -167,7 +167,7 @@ struct rtw_iter_vifs_data {
 	struct list_head list;
 };
 
-void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+static void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 {
 	struct rtw_iter_vifs_data *iter_stas = data;
 	struct rtw_vifs_entry *vifs_entry;
-- 
2.30.2


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

* [PATCH v2 07/10] rtw88: Add rtw8821cu chipset support
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
                   ` (5 preceding siblings ...)
  2022-05-30 13:54 ` [PATCH v2 06/10] rtw88: Add common USB chip support Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-31  1:00   ` Ping-Ke Shih
  2022-05-30 13:54 ` [PATCH v2 08/10] rtw88: Add rtw8822bu " Sascha Hauer
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

Add support for the rtw8821cu chipset based on
https://github.com/ulli-kroll/rtw88-usb.git

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/net/wireless/realtek/rtw88/Kconfig    | 11 ++++
 drivers/net/wireless/realtek/rtw88/Makefile   |  3 ++
 drivers/net/wireless/realtek/rtw88/rtw8821c.c | 23 +++++++++
 drivers/net/wireless/realtek/rtw88/rtw8821c.h | 21 ++++++++
 .../net/wireless/realtek/rtw88/rtw8821cu.c    | 50 +++++++++++++++++++
 .../net/wireless/realtek/rtw88/rtw8821cu.h    | 10 ++++
 6 files changed, 118 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8821cu.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8821cu.h

diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig
index 1624c5db69bac..2b500dbefbc2d 100644
--- a/drivers/net/wireless/realtek/rtw88/Kconfig
+++ b/drivers/net/wireless/realtek/rtw88/Kconfig
@@ -75,6 +75,17 @@ config RTW88_8821CE
 
 	  802.11ac PCIe wireless network adapter
 
+config RTW88_8821CU
+	tristate "Realtek 8821CU USB wireless network adapter"
+	depends on USB
+	select RTW88_CORE
+	select RTW88_USB
+	select RTW88_8821C
+	help
+	  Select this option will enable support for 8821CU chipset
+
+	  802.11ac USB wireless network adapter
+
 config RTW88_DEBUG
 	bool "Realtek rtw88 debug support"
 	depends on RTW88_CORE
diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile
index 9e095f8181483..3c1f08f12e44e 100644
--- a/drivers/net/wireless/realtek/rtw88/Makefile
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -44,6 +44,9 @@ rtw88_8821c-objs		:= rtw8821c.o rtw8821c_table.o
 obj-$(CONFIG_RTW88_8821CE)	+= rtw88_8821ce.o
 rtw88_8821ce-objs		:= rtw8821ce.o
 
+obj-$(CONFIG_RTW88_8821CU)	+= rtw88_8821cu.o
+rtw88_8821cu-objs		:= rtw8821cu.o
+
 obj-$(CONFIG_RTW88_PCI)		+= rtw88_pci.o
 obj-$(CONFIG_RTW88_USB)		+= rtw88_usb.o
 rtw88_pci-objs			:= pci.o
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
index 99eee128ae945..82e78559d8264 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
@@ -26,6 +26,12 @@ static void rtw8821ce_efuse_parsing(struct rtw_efuse *efuse,
 	ether_addr_copy(efuse->addr, map->e.mac_addr);
 }
 
+static void rtw8821cu_efuse_parsing(struct rtw_efuse *efuse,
+				    struct rtw8821c_efuse *map)
+{
+	ether_addr_copy(efuse->addr, map->u.mac_addr);
+}
+
 enum rtw8821ce_rf_set {
 	SWITCH_TO_BTG,
 	SWITCH_TO_WLG,
@@ -68,6 +74,9 @@ static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
 	case RTW_HCI_TYPE_PCIE:
 		rtw8821ce_efuse_parsing(efuse, map);
 		break;
+	case RTW_HCI_TYPE_USB:
+		rtw8821cu_efuse_parsing(efuse, map);
+		break;
 	default:
 		/* unsupported now */
 		return -ENOTSUPP;
@@ -1142,6 +1151,18 @@ static void rtw8821c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
 			 dm_info->cck_pd_default + new_lvl * 2);
 }
 
+static void rtw8821c_fill_txdesc_checksum(struct rtw_dev *rtwdev,
+					  struct rtw_tx_pkt_info *pkt_info,
+					  u8 *txdesc)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	size_t words;
+
+	words = (pkt_info->pkt_offset * 8 + chip->tx_pkt_desc_sz) / 2;
+
+	fill_txdesc_checksum_common(txdesc, words);
+}
+
 static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = {
 	{0x0086,
 	 RTW_PWR_CUT_ALL_MSK,
@@ -1515,6 +1536,7 @@ static const struct rtw_rfe_def rtw8821c_rfe_defs[] = {
 	[2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
 	[4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
 	[6] = RTW_DEF_RFE(8821c, 0, 0),
+	[34] = RTW_DEF_RFE(8821c, 0, 0),
 };
 
 static struct rtw_hw_reg rtw8821c_dig[] = {
@@ -1589,6 +1611,7 @@ static struct rtw_chip_ops rtw8821c_ops = {
 	.config_bfee		= rtw8821c_bf_config_bfee,
 	.set_gid_table		= rtw_bf_set_gid_table,
 	.cfg_csi_rate		= rtw_bf_cfg_csi_rate,
+	.fill_txdesc_checksum	= rtw8821c_fill_txdesc_checksum,
 
 	.coex_set_init		= rtw8821c_coex_cfg_init,
 	.coex_set_ant_switch	= rtw8821c_coex_cfg_ant_switch,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h
index d9fbddd7b0f35..e2e17a822e48d 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h
@@ -9,6 +9,26 @@
 
 #define RCR_VHT_ACK		BIT(26)
 
+struct rtw8821cu_efuse {
+	u8 res4[4];			/* 0xd0 */
+	u8 usb_optional_function;
+	u8 res5[0x1e];
+	u8 res6[2];
+	u8 serial[0x0b];		/* 0xf5 */
+	u8 vid;				/* 0x100 */
+	u8 res7;
+	u8 pid;
+	u8 res8[4];
+	u8 mac_addr[ETH_ALEN];		/* 0x107 */
+	u8 res9[2];
+	u8 vendor_name[0x07];
+	u8 res10[2];
+	u8 device_name[0x14];
+	u8 res11[0xcf];
+	u8 package_type;		/* 0x1fb */
+	u8 res12[0x4];
+};
+
 struct rtw8821ce_efuse {
 	u8 mac_addr[ETH_ALEN];		/* 0xd0 */
 	u8 vender_id[2];
@@ -73,6 +93,7 @@ struct rtw8821c_efuse {
 	u8 res[3];
 	union {
 		struct rtw8821ce_efuse e;
+		struct rtw8821cu_efuse u;
 	};
 };
 
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c
new file mode 100644
index 0000000000000..f43e200515f5b
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2018-2019  Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "main.h"
+#include "rtw8821cu.h"
+#include "usb.h"
+
+static const struct usb_device_id rtw_8821cu_id_table[] = {
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82b, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb820, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc821, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc820, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82a, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82b, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc811, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8811CU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8811, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8811CU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2006, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* TOTOLINK A650UA v3 */
+	{},
+};
+MODULE_DEVICE_TABLE(usb, rtw_8821cu_id_table);
+
+static int rtw_8821cu_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	return rtw_usb_probe(intf, id);
+}
+
+static struct usb_driver rtw_8821cu_driver = {
+	.name = "rtw_8821cu",
+	.id_table = rtw_8821cu_id_table,
+	.probe = rtw_8821cu_probe,
+	.disconnect = rtw_usb_disconnect,
+};
+module_usb_driver(rtw_8821cu_driver);
+
+MODULE_AUTHOR("Hans Ulli Kroll <linux@ulli-kroll.de>");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821cu driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821cu.h b/drivers/net/wireless/realtek/rtw88/rtw8821cu.h
new file mode 100644
index 0000000000000..c896792240011
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821cu.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2018-2019  Realtek Corporation
+ */
+
+#ifndef __RTW_8821CU_H_
+#define __RTW_8821CU_H_
+
+extern struct rtw_chip_info rtw8821c_hw_spec;
+
+#endif
-- 
2.30.2


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

* [PATCH v2 08/10] rtw88: Add rtw8822bu chipset support
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
                   ` (6 preceding siblings ...)
  2022-05-30 13:54 ` [PATCH v2 07/10] rtw88: Add rtw8821cu chipset support Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 09/10] rtw88: Add rtw8822cu " Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 10/10] rtw88: disable powersave modes for USB devices Sascha Hauer
  9 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

Add support for the rtw8822bu chipset based on
https://github.com/ulli-kroll/rtw88-usb.git

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---

Notes:
    Changes since v1:
    - Add more Device IDs from https://github.com/morrownr/88x2bu-20210702.git

 drivers/net/wireless/realtek/rtw88/Kconfig    | 11 +++
 drivers/net/wireless/realtek/rtw88/Makefile   |  3 +
 drivers/net/wireless/realtek/rtw88/rtw8822b.c | 19 ++++
 .../net/wireless/realtek/rtw88/rtw8822bu.c    | 90 +++++++++++++++++++
 .../net/wireless/realtek/rtw88/rtw8822bu.h    | 10 +++
 5 files changed, 133 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822bu.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822bu.h

diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig
index 2b500dbefbc2d..10f4e7f88b858 100644
--- a/drivers/net/wireless/realtek/rtw88/Kconfig
+++ b/drivers/net/wireless/realtek/rtw88/Kconfig
@@ -42,6 +42,17 @@ config RTW88_8822BE
 
 	  802.11ac PCIe wireless network adapter
 
+config RTW88_8822BU
+	tristate "Realtek 8822BU USB wireless network adapter"
+	depends on USB
+	select RTW88_CORE
+	select RTW88_USB
+	select RTW88_8822B
+	help
+	  Select this option will enable support for 8822BU chipset
+
+	  802.11ac USB wireless network adapter
+
 config RTW88_8822CE
 	tristate "Realtek 8822CE PCI wireless network adapter"
 	depends on PCI
diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile
index 3c1f08f12e44e..1d28cc4fff7b2 100644
--- a/drivers/net/wireless/realtek/rtw88/Makefile
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -26,6 +26,9 @@ rtw88_8822b-objs		:= rtw8822b.o rtw8822b_table.o
 obj-$(CONFIG_RTW88_8822BE)	+= rtw88_8822be.o
 rtw88_8822be-objs		:= rtw8822be.o
 
+obj-$(CONFIG_RTW88_8822BU)	+= rtw88_8822bu.o
+rtw88_8822bu-objs		:= rtw8822bu.o
+
 obj-$(CONFIG_RTW88_8822C)	+= rtw88_8822c.o
 rtw88_8822c-objs		:= rtw8822c.o rtw8822c_table.o
 
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
index eee7bf0354030..10497d351f229 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
@@ -26,6 +26,12 @@ static void rtw8822be_efuse_parsing(struct rtw_efuse *efuse,
 	ether_addr_copy(efuse->addr, map->e.mac_addr);
 }
 
+static void rtw8822bu_efuse_parsing(struct rtw_efuse *efuse,
+				    struct rtw8822b_efuse *map)
+{
+	ether_addr_copy(efuse->addr, map->u.mac_addr);
+}
+
 static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
 {
 	struct rtw_efuse *efuse = &rtwdev->efuse;
@@ -56,6 +62,9 @@ static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
 	case RTW_HCI_TYPE_PCIE:
 		rtw8822be_efuse_parsing(efuse, map);
 		break;
+	case RTW_HCI_TYPE_USB:
+		rtw8822bu_efuse_parsing(efuse, map);
+		break;
 	default:
 		/* unsupported now */
 		return -ENOTSUPP;
@@ -1588,6 +1597,15 @@ static void rtw8822b_adaptivity(struct rtw_dev *rtwdev)
 	rtw_phy_set_edcca_th(rtwdev, l2h, h2l);
 }
 
+static void rtw8822b_fill_txdesc_checksum(struct rtw_dev *rtwdev,
+					  struct rtw_tx_pkt_info *pkt_info,
+					  u8 *txdesc)
+{
+	size_t words = 32 / 2; /* calculate the first 32 bytes (16 words) */
+
+	fill_txdesc_checksum_common(txdesc, words);
+}
+
 static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = {
 	{0x0086,
 	 RTW_PWR_CUT_ALL_MSK,
@@ -2163,6 +2181,7 @@ static struct rtw_chip_ops rtw8822b_ops = {
 	.cfg_csi_rate		= rtw_bf_cfg_csi_rate,
 	.adaptivity_init	= rtw8822b_adaptivity_init,
 	.adaptivity		= rtw8822b_adaptivity,
+	.fill_txdesc_checksum	= rtw8822b_fill_txdesc_checksum,
 
 	.coex_set_init		= rtw8822b_coex_cfg_init,
 	.coex_set_ant_switch	= rtw8822b_coex_cfg_ant_switch,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822bu.c b/drivers/net/wireless/realtek/rtw88/rtw8822bu.c
new file mode 100644
index 0000000000000..d1ddb3a32694f
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822bu.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2018-2019  Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "main.h"
+#include "rtw8822bu.h"
+#include "usb.h"
+
+static const struct usb_device_id rtw_8822bu_id_table[] = {
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb812, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82c, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2102, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* CCNC */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xb822, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822ULC */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xc822, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822UTC */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd822, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xe822, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xf822, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822UAD */
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb81a, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Default ID */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1841, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS AC1300 USB-AC55 B1 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x184c, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS U2 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x19aa, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS - USB-AC58 rev A1 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x1870, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x1874, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331e, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Dlink - DWA-181 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331c, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Dlink - DWA-182 - D1 */
+	{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331f, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec)}, /* Dlink - DWA-183 D Ver */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Linksys WUSB6400M */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0045, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Linksys WUSB3600 v2 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x012d, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T3U v1 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0138, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T3U Plus v1 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0115, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T4U V3 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x012e, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0116, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0117, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9055, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Netgear A6150 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0025, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Hawking HW12ACU */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x04ca, 0x8602, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* LiteOn */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x808a, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TRENDnet TEW-808UBM */
+	{},
+};
+MODULE_DEVICE_TABLE(usb, rtw_8822bu_id_table);
+
+static int rtw8822bu_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	return rtw_usb_probe(intf, id);
+}
+
+static struct usb_driver rtw_8822bu_driver = {
+	.name = "rtw_8822bu",
+	.id_table = rtw_8822bu_id_table,
+	.probe = rtw8822bu_probe,
+	.disconnect = rtw_usb_disconnect,
+};
+module_usb_driver(rtw_8822bu_driver);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822bu driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822bu.h b/drivers/net/wireless/realtek/rtw88/rtw8822bu.h
new file mode 100644
index 0000000000000..8a6deb28d13aa
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822bu.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2018-2019  Realtek Corporation
+ */
+
+#ifndef __RTW_8822BU_H_
+#define __RTW_8822BU_H_
+
+extern struct rtw_chip_info rtw8822b_hw_spec;
+
+#endif
-- 
2.30.2


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

* [PATCH v2 09/10] rtw88: Add rtw8822cu chipset support
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
                   ` (7 preceding siblings ...)
  2022-05-30 13:54 ` [PATCH v2 08/10] rtw88: Add rtw8822bu " Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-30 13:54 ` [PATCH v2 10/10] rtw88: disable powersave modes for USB devices Sascha Hauer
  9 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

Add support for the rtw8822cu chipset based on
https://github.com/ulli-kroll/rtw88-usb.git

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---

Notes:
    Changes since v1:
    - Add more Device IDs from https://github.com/morrownr/8821cu-20210118.git

 drivers/net/wireless/realtek/rtw88/Kconfig    | 11 +++++
 drivers/net/wireless/realtek/rtw88/Makefile   |  3 ++
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 24 ++++++++++
 .../net/wireless/realtek/rtw88/rtw8822cu.c    | 44 +++++++++++++++++++
 .../net/wireless/realtek/rtw88/rtw8822cu.h    | 10 +++++
 5 files changed, 92 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822cu.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822cu.h

diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig
index 10f4e7f88b858..138289bc5ad0c 100644
--- a/drivers/net/wireless/realtek/rtw88/Kconfig
+++ b/drivers/net/wireless/realtek/rtw88/Kconfig
@@ -64,6 +64,17 @@ config RTW88_8822CE
 
 	  802.11ac PCIe wireless network adapter
 
+config RTW88_8822CU
+	tristate "Realtek 8822CU USB wireless network adapter"
+	depends on USB
+	select RTW88_CORE
+	select RTW88_USB
+	select RTW88_8822C
+	help
+	  Select this option will enable support for 8822CU chipset
+
+	  802.11ac USB wireless network adapter
+
 config RTW88_8723DE
 	tristate "Realtek 8723DE PCI wireless network adapter"
 	depends on PCI
diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile
index 1d28cc4fff7b2..06883d7323b05 100644
--- a/drivers/net/wireless/realtek/rtw88/Makefile
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -35,6 +35,9 @@ rtw88_8822c-objs		:= rtw8822c.o rtw8822c_table.o
 obj-$(CONFIG_RTW88_8822CE)	+= rtw88_8822ce.o
 rtw88_8822ce-objs		:= rtw8822ce.o
 
+obj-$(CONFIG_RTW88_8822CU)	+= rtw88_8822cu.o
+rtw88_8822cu-objs		:= rtw8822cu.o
+
 obj-$(CONFIG_RTW88_8723D)	+= rtw88_8723d.o
 rtw88_8723d-objs		:= rtw8723d.o rtw8723d_table.o
 
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index cd74607a61a28..51c90ef20c456 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -29,6 +29,12 @@ static void rtw8822ce_efuse_parsing(struct rtw_efuse *efuse,
 	ether_addr_copy(efuse->addr, map->e.mac_addr);
 }
 
+static void rtw8822cu_efuse_parsing(struct rtw_efuse *efuse,
+				    struct rtw8822c_efuse *map)
+{
+	ether_addr_copy(efuse->addr, map->u.mac_addr);
+}
+
 static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
 {
 	struct rtw_efuse *efuse = &rtwdev->efuse;
@@ -58,6 +64,9 @@ static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
 	case RTW_HCI_TYPE_PCIE:
 		rtw8822ce_efuse_parsing(efuse, map);
 		break;
+	case RTW_HCI_TYPE_USB:
+		rtw8822cu_efuse_parsing(efuse, map);
+		break;
 	default:
 		/* unsupported now */
 		return -ENOTSUPP;
@@ -4557,6 +4566,18 @@ static void rtw8822c_adaptivity(struct rtw_dev *rtwdev)
 	rtw_phy_set_edcca_th(rtwdev, l2h, h2l);
 }
 
+static void rtw8822c_fill_txdesc_checksum(struct rtw_dev *rtwdev,
+					  struct rtw_tx_pkt_info *pkt_info,
+					  u8 *txdesc)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	size_t words;
+
+	words = (pkt_info->pkt_offset * 8 + chip->tx_pkt_desc_sz) / 2;
+
+	fill_txdesc_checksum_common(txdesc, words);
+}
+
 static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = {
 	{0x0086,
 	 RTW_PWR_CUT_ALL_MSK,
@@ -4895,6 +4916,8 @@ static const struct rtw_rfe_def rtw8822c_rfe_defs[] = {
 	[0] = RTW_DEF_RFE(8822c, 0, 0),
 	[1] = RTW_DEF_RFE(8822c, 0, 0),
 	[2] = RTW_DEF_RFE(8822c, 0, 0),
+	[3] = RTW_DEF_RFE(8822c, 0, 0),
+	[4] = RTW_DEF_RFE(8822c, 0, 0),
 	[5] = RTW_DEF_RFE(8822c, 0, 5),
 	[6] = RTW_DEF_RFE(8822c, 0, 0),
 };
@@ -4978,6 +5001,7 @@ static struct rtw_chip_ops rtw8822c_ops = {
 	.cfo_track		= rtw8822c_cfo_track,
 	.config_tx_path		= rtw8822c_config_tx_path,
 	.config_txrx_mode	= rtw8822c_config_trx_mode,
+	.fill_txdesc_checksum	= rtw8822c_fill_txdesc_checksum,
 
 	.coex_set_init		= rtw8822c_coex_cfg_init,
 	.coex_set_ant_switch	= NULL,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822cu.c b/drivers/net/wireless/realtek/rtw88/rtw8822cu.c
new file mode 100644
index 0000000000000..f839790e9fd08
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822cu.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2018-2019  Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "main.h"
+#include "rtw8822cu.h"
+#include "usb.h"
+
+static const struct usb_device_id rtw_8822cu_id_table[] = {
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82c, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc812, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82e, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd820, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd82b, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, /* Alpha - Alpha */
+	{},
+};
+MODULE_DEVICE_TABLE(usb, rtw_8822cu_id_table);
+
+static int rtw8822bu_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	return rtw_usb_probe(intf, id);
+}
+
+static struct usb_driver rtw_8822cu_driver = {
+	.name = "rtw_8822cu",
+	.id_table = rtw_8822cu_id_table,
+	.probe = rtw8822bu_probe,
+	.disconnect = rtw_usb_disconnect,
+};
+module_usb_driver(rtw_8822cu_driver);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822cu driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822cu.h b/drivers/net/wireless/realtek/rtw88/rtw8822cu.h
new file mode 100644
index 0000000000000..4b35343aacb1c
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822cu.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2018-2019  Realtek Corporation
+ */
+
+#ifndef __RTW_8822CU_H_
+#define __RTW_8822CU_H_
+
+extern struct rtw_chip_info rtw8822c_hw_spec;
+
+#endif
-- 
2.30.2


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

* [PATCH v2 10/10] rtw88: disable powersave modes for USB devices
  2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
                   ` (8 preceding siblings ...)
  2022-05-30 13:54 ` [PATCH v2 09/10] rtw88: Add rtw8822cu " Sascha Hauer
@ 2022-05-30 13:54 ` Sascha Hauer
  2022-05-31  1:07   ` Ping-Ke Shih
  9 siblings, 1 reply; 22+ messages in thread
From: Sascha Hauer @ 2022-05-30 13:54 UTC (permalink / raw)
  To: linux-wireless
  Cc: Neo Jou, Hans Ulli Kroll, Ping-Ke Shih, Yan-Hsuan Chuang,
	Kalle Valo, netdev, linux-kernel, Martin Blumenstingl, kernel,
	Johannes Berg, Sascha Hauer

The powersave modes do not work with USB devices (tested with a
RTW8822CU) properly. With powersave modes enabled the driver issues
messages like:

rtw_8822cu 1-1:1.2: firmware failed to leave lps state
rtw_8822cu 1-1:1.2: timed out to flush queue 3

Also ping round trip times increase significantly from 1..2ms to
10..200ms.

Until this has been resolved disable the powersave modes for USB
devices.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/net/wireless/realtek/rtw88/mac80211.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index 3c07485d6ba47..fb5faf3bf1eed 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -89,7 +89,8 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
-		if (hw->conf.flags & IEEE80211_CONF_PS) {
+		if (hw->conf.flags & IEEE80211_CONF_PS &&
+		    rtw_hci_type(rtwdev) != RTW_HCI_TYPE_USB) {
 			rtwdev->ps_enabled = true;
 		} else {
 			rtwdev->ps_enabled = false;
-- 
2.30.2


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

* Re: [PATCH v2 07/10] rtw88: Add rtw8821cu chipset support
  2022-05-30 13:54 ` [PATCH v2 07/10] rtw88: Add rtw8821cu chipset support Sascha Hauer
@ 2022-05-31  1:00   ` Ping-Ke Shih
  0 siblings, 0 replies; 22+ messages in thread
From: Ping-Ke Shih @ 2022-05-31  1:00 UTC (permalink / raw)
  To: s.hauer, linux-wireless
  Cc: johannes, kernel, neojou, kvalo, tony0620emma, linux-kernel,
	martin.blumenstingl, linux, netdev

On Mon, 2022-05-30 at 15:54 +0200, Sascha Hauer wrote:
> Add support for the rtw8821cu chipset based on
> https://github.com/ulli-kroll/rtw88-usb.git
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> 

[...]

> diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821cu.h
> b/drivers/net/wireless/realtek/rtw88/rtw8821cu.h
> new file mode 100644
> index 0000000000000..c896792240011
> --- /dev/null
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8821cu.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
> +/* Copyright(c) 2018-2019  Realtek Corporation
> + */
> +
> +#ifndef __RTW_8821CU_H_
> +#define __RTW_8821CU_H_
> +
> +extern struct rtw_chip_info rtw8821c_hw_spec;

This extern has moved to rtw8821c.h [1], so we don't need rtw8821cu.h.
As well as 8822bu.h and 8822cu.h.


[1] 
https://lore.kernel.org/linux-wireless/20220524153621.19027-2-Larry.Finger@lwfinger.net/T/#m2edcc347daa08d133071eeb3437701100054af7f

--
Ping-Ke



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

* Re: [PATCH v2 10/10] rtw88: disable powersave modes for USB devices
  2022-05-30 13:54 ` [PATCH v2 10/10] rtw88: disable powersave modes for USB devices Sascha Hauer
@ 2022-05-31  1:07   ` Ping-Ke Shih
  2022-05-31  7:42     ` s.hauer
  0 siblings, 1 reply; 22+ messages in thread
From: Ping-Ke Shih @ 2022-05-31  1:07 UTC (permalink / raw)
  To: s.hauer, linux-wireless
  Cc: johannes, kernel, neojou, kvalo, tony0620emma, linux-kernel,
	martin.blumenstingl, linux, netdev

On Mon, 2022-05-30 at 15:54 +0200, Sascha Hauer wrote:
> The powersave modes do not work with USB devices (tested with a
> RTW8822CU) properly. With powersave modes enabled the driver issues
> messages like:
> 
> rtw_8822cu 1-1:1.2: firmware failed to leave lps state
> rtw_8822cu 1-1:1.2: timed out to flush queue 3

Could you try module parameter rtw_disable_lps_deep_mode=1 to see
if it can work?

If it works, I suggest to apply below code: 

diff --git a/main.c b/main.c
index 3f7a5d54..3bb07898 100644
--- a/main.c
+++ b/main.c
@@ -1345,6 +1345,9 @@ static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev,
 {
        struct rtw_chip_info *chip = rtwdev->chip;
 
+       if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB)
+               return LPS_DEEP_MODE_NONE;
+
        if (rtw_disable_lps_deep_mode || !chip->lps_deep_mode_supported ||
            !fw->feature)
                return LPS_DEEP_MODE_NONE;

--
Ping-Ke



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

* Re: [PATCH v2 10/10] rtw88: disable powersave modes for USB devices
  2022-05-31  1:07   ` Ping-Ke Shih
@ 2022-05-31  7:42     ` s.hauer
  2022-06-09 12:51       ` Ping-Ke Shih
  0 siblings, 1 reply; 22+ messages in thread
From: s.hauer @ 2022-05-31  7:42 UTC (permalink / raw)
  To: Ping-Ke Shih
  Cc: linux-wireless, johannes, kernel, neojou, kvalo, tony0620emma,
	linux-kernel, martin.blumenstingl, linux, netdev

On Tue, May 31, 2022 at 01:07:36AM +0000, Ping-Ke Shih wrote:
> On Mon, 2022-05-30 at 15:54 +0200, Sascha Hauer wrote:
> > The powersave modes do not work with USB devices (tested with a
> > RTW8822CU) properly. With powersave modes enabled the driver issues
> > messages like:
> > 
> > rtw_8822cu 1-1:1.2: firmware failed to leave lps state
> > rtw_8822cu 1-1:1.2: timed out to flush queue 3
> 
> Could you try module parameter rtw_disable_lps_deep_mode=1 to see
> if it can work?

No, this module parameter doesn't seem to make any difference.

# cat /sys/module/rtw88_core/parameters/disable_lps_deep
Y

Still "firmware failed to leave lps state" and poor performance.

Any other ideas what may go wrong here?

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically
  2022-05-30 13:54 ` [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically Sascha Hauer
@ 2022-06-07 22:06   ` Martin Blumenstingl
  2022-06-08 13:25     ` Ping-Ke Shih
  2022-06-09  2:55   ` Ping-Ke Shih
  1 sibling, 1 reply; 22+ messages in thread
From: Martin Blumenstingl @ 2022-06-07 22:06 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-wireless, Neo Jou, Hans Ulli Kroll, Ping-Ke Shih,
	Yan-Hsuan Chuang, Kalle Valo, netdev, linux-kernel, kernel,
	Johannes Berg

Hi Sascha,

thanks for this patch!

On Mon, May 30, 2022 at 3:55 PM Sascha Hauer <s.hauer@pengutronix.de> wrote:
[...]
>  drivers/net/wireless/realtek/rtw88/phy.c  |   6 +-
>  drivers/net/wireless/realtek/rtw88/ps.c   |   2 +-
>  drivers/net/wireless/realtek/rtw88/util.c | 103 ++++++++++++++++++++++
>  drivers/net/wireless/realtek/rtw88/util.h |  12 ++-
>  4 files changed, 116 insertions(+), 7 deletions(-)
I compared the changes from this patch with my earlier work. I would
like to highlight a few functions to understand if they were left out
on purpose or by accident.

__fw_recovery_work() in main.c (unfortunately I am not sure how to
trigger/test this "firmware recovery" logic):
- this is already called with &rtwdev->mutex held
- it uses rtw_iterate_keys_rcu() (which internally uses rtw_write32
from rtw_sec_clear_cam). feel free to either add [0] to your series or
even squash it into an existing patch
- it uses rtw_iterate_stas_atomic() (which internally uses
rtw_fw_send_h2c_command from rtw_fw_media_status_report)
- it uses rtw_iterate_vifs_atomic() (which internally can read/write
registers from rtw_chip_config_bfee)
- in my previous series I simply replaced the
rtw_iterate_stas_atomic() and rtw_iterate_vifs_atomic() calls with the
non-atomic variants (for the rtw_iterate_keys_rcu() call I did some
extra cleanup, see [0])

rtw_wow_fw_media_status() in wow.c (unfortunately I am also not sure
how to test WoWLAN):
- I am not sure if &rtwdev->mutex is held when this function is called
- it uses rtw_iterate_stas_atomic() (which internally uses
rtw_fw_send_h2c_command from rtw_fw_media_status_report)
- in my previous series I simply replaced rtw_iterate_stas_atomic()
with it's non-atomic variant

Additionally I rebased my SDIO work on top of your USB series.
This makes SDIO support a lot easier - so thank you for your work!
I found that three of my previous patches (in addition to [0] which I
already mentioned earlier) are still needed to get rid of some
warnings when using the SDIO interface (the same warnings may or may
not be there with the USB interface - it just depends on whether your
AP makes rtw88 hit that specific code-path):
- [1]: rtw88: Configure the registers from rtw_bf_assoc() outside the RCU lock
- [2]: rtw88: Move rtw_chip_cfg_csi_rate() out of rtw_vif_watch_dog_iter()
- [3]: rtw88: Move rtw_update_sta_info() out of rtw_ra_mask_info_update_iter()

These three patches are freshly rebased to apply on top of your series.
If you (or Ping-Ke) think those are needed for USB support then please
feel free to include them in your series, squash them into one of your
patches or just ask me to send them as an individual series)

I am running out of time for today. I'll be able to continue on this
later this week/during the weekend.


Best regards,
Martin


[0] https://lore.kernel.org/all/20220108005533.947787-6-martin.blumenstingl@googlemail.com/
[1] https://github.com/xdarklight/linux/commit/420bb40511151fbc9f5447aced4fde3a7bb0566b.patch
[2] https://github.com/xdarklight/linux/commit/cc08cc8fb697157b99304ad3ec89b1cca0900697.patch
[3] https://github.com/xdarklight/linux/commit/5db636e3035a425e104fba7983301b0085366268.patch

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

* Re: [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically
  2022-06-07 22:06   ` Martin Blumenstingl
@ 2022-06-08 13:25     ` Ping-Ke Shih
  2022-06-08 13:37       ` s.hauer
  0 siblings, 1 reply; 22+ messages in thread
From: Ping-Ke Shih @ 2022-06-08 13:25 UTC (permalink / raw)
  To: martin.blumenstingl, s.hauer
  Cc: johannes, kernel, neojou, kvalo, tony0620emma, linux-wireless,
	netdev, linux-kernel, linux

Hi Martin and Sascha,

Thank you both.

On Wed, 2022-06-08 at 00:06 +0200, Martin Blumenstingl wrote:
> Hi Sascha,
> 
> thanks for this patch!
> 
> On Mon, May 30, 2022 at 3:55 PM Sascha Hauer <s.hauer@pengutronix.de> wrote:
> [...]
> >  drivers/net/wireless/realtek/rtw88/phy.c  |   6 +-
> >  drivers/net/wireless/realtek/rtw88/ps.c   |   2 +-
> >  drivers/net/wireless/realtek/rtw88/util.c | 103 ++++++++++++++++++++++
> >  drivers/net/wireless/realtek/rtw88/util.h |  12 ++-
> >  4 files changed, 116 insertions(+), 7 deletions(-)
> I compared the changes from this patch with my earlier work. I would
> like to highlight a few functions to understand if they were left out
> on purpose or by accident.
> 
> __fw_recovery_work() in main.c (unfortunately I am not sure how to
> trigger/test this "firmware recovery" logic):

This can be triggered by 'echo 1 > /sys/kernel/debug/ieee80211/rtw88/fw_crash',
but only the latest firmware of 8822c can support this.

> - this is already called with &rtwdev->mutex held
> - it uses rtw_iterate_keys_rcu() (which internally uses rtw_write32
> from rtw_sec_clear_cam). feel free to either add [0] to your series or
> even squash it into an existing patch

ieee80211_iter_keys() check lockdep_assert_wiphy(hw->wiphy), but we don't
hold the lock in this work; it also do mutex_lock(&local->key_mtx) that 
I'm afraid it could cause deadlock.
 
So, I think we can use _rcu version to collect key list like sta and vif.

> - it uses rtw_iterate_stas_atomic() (which internally uses
> rtw_fw_send_h2c_command from rtw_fw_media_status_report)
> - it uses rtw_iterate_vifs_atomic() (which internally can read/write
> registers from rtw_chip_config_bfee)
> - in my previous series I simply replaced the
> rtw_iterate_stas_atomic() and rtw_iterate_vifs_atomic() calls with the
> non-atomic variants (for the rtw_iterate_keys_rcu() call I did some
> extra cleanup, see [0])
> 
> rtw_wow_fw_media_status() in wow.c (unfortunately I am also not sure
> how to test WoWLAN):
> - I am not sure if &rtwdev->mutex is held when this function is called
> - it uses rtw_iterate_stas_atomic() (which internally uses
> rtw_fw_send_h2c_command from rtw_fw_media_status_report)
> - in my previous series I simply replaced rtw_iterate_stas_atomic()
> with it's non-atomic variant
> 
> Additionally I rebased my SDIO work on top of your USB series.
> This makes SDIO support a lot easier - so thank you for your work!
> I found that three of my previous patches (in addition to [0] which I
> already mentioned earlier) are still needed to get rid of some
> warnings when using the SDIO interface (the same warnings may or may
> not be there with the USB interface - it just depends on whether your
> AP makes rtw88 hit that specific code-path):
> - [1]: rtw88: Configure the registers from rtw_bf_assoc() outside the RCU lock

I think we need this.

> - [2]: rtw88: Move rtw_chip_cfg_csi_rate() out of rtw_vif_watch_dog_iter()

I think we don't need this, but just use rtw_iterate_vifs() to
iterate rtw_vif_watch_dog_iter.

> - [3]: rtw88: Move rtw_update_sta_info() out of rtw_ra_mask_info_update_iter()

Need partial -- hold rtwdev->mutex before entering rtw_ra_mask_info_update().

Then, use rtw_iterate_stas() to iterate rtw_ra_mask_info_update_iter. 
No need others.


Sascha, could you squash Martin's patches into your patchset?
And, then I can do more tests on PCI cards.

I do long run on 8822CE with the patchset v2. It works fine.
After adding more, I will verify it again.

By the way, I still don't have resource to check PS of 8822CU.
Sorry for that.

Ping-Ke


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

* Re: [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically
  2022-06-08 13:25     ` Ping-Ke Shih
@ 2022-06-08 13:37       ` s.hauer
  0 siblings, 0 replies; 22+ messages in thread
From: s.hauer @ 2022-06-08 13:37 UTC (permalink / raw)
  To: Ping-Ke Shih
  Cc: martin.blumenstingl, johannes, kernel, neojou, kvalo,
	tony0620emma, linux-wireless, netdev, linux-kernel, linux

On Wed, Jun 08, 2022 at 01:25:34PM +0000, Ping-Ke Shih wrote:
> Hi Martin and Sascha,
> 
> Thank you both.
> 
> On Wed, 2022-06-08 at 00:06 +0200, Martin Blumenstingl wrote:
> > Hi Sascha,
> > 
> > thanks for this patch!
> > 
> > On Mon, May 30, 2022 at 3:55 PM Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > [...]
> > >  drivers/net/wireless/realtek/rtw88/phy.c  |   6 +-
> > >  drivers/net/wireless/realtek/rtw88/ps.c   |   2 +-
> > >  drivers/net/wireless/realtek/rtw88/util.c | 103 ++++++++++++++++++++++
> > >  drivers/net/wireless/realtek/rtw88/util.h |  12 ++-
> > >  4 files changed, 116 insertions(+), 7 deletions(-)
> > I compared the changes from this patch with my earlier work. I would
> > like to highlight a few functions to understand if they were left out
> > on purpose or by accident.
> > 
> > __fw_recovery_work() in main.c (unfortunately I am not sure how to
> > trigger/test this "firmware recovery" logic):
> 
> This can be triggered by 'echo 1 > /sys/kernel/debug/ieee80211/rtw88/fw_crash',
> but only the latest firmware of 8822c can support this.
> 
> > - this is already called with &rtwdev->mutex held
> > - it uses rtw_iterate_keys_rcu() (which internally uses rtw_write32
> > from rtw_sec_clear_cam). feel free to either add [0] to your series or
> > even squash it into an existing patch
> 
> ieee80211_iter_keys() check lockdep_assert_wiphy(hw->wiphy), but we don't
> hold the lock in this work; it also do mutex_lock(&local->key_mtx) that 
> I'm afraid it could cause deadlock.
>  
> So, I think we can use _rcu version to collect key list like sta and vif.
> 
> > - it uses rtw_iterate_stas_atomic() (which internally uses
> > rtw_fw_send_h2c_command from rtw_fw_media_status_report)
> > - it uses rtw_iterate_vifs_atomic() (which internally can read/write
> > registers from rtw_chip_config_bfee)
> > - in my previous series I simply replaced the
> > rtw_iterate_stas_atomic() and rtw_iterate_vifs_atomic() calls with the
> > non-atomic variants (for the rtw_iterate_keys_rcu() call I did some
> > extra cleanup, see [0])
> > 
> > rtw_wow_fw_media_status() in wow.c (unfortunately I am also not sure
> > how to test WoWLAN):
> > - I am not sure if &rtwdev->mutex is held when this function is called
> > - it uses rtw_iterate_stas_atomic() (which internally uses
> > rtw_fw_send_h2c_command from rtw_fw_media_status_report)
> > - in my previous series I simply replaced rtw_iterate_stas_atomic()
> > with it's non-atomic variant
> > 
> > Additionally I rebased my SDIO work on top of your USB series.
> > This makes SDIO support a lot easier - so thank you for your work!
> > I found that three of my previous patches (in addition to [0] which I
> > already mentioned earlier) are still needed to get rid of some
> > warnings when using the SDIO interface (the same warnings may or may
> > not be there with the USB interface - it just depends on whether your
> > AP makes rtw88 hit that specific code-path):
> > - [1]: rtw88: Configure the registers from rtw_bf_assoc() outside the RCU lock
> 
> I think we need this.
> 
> > - [2]: rtw88: Move rtw_chip_cfg_csi_rate() out of rtw_vif_watch_dog_iter()
> 
> I think we don't need this, but just use rtw_iterate_vifs() to
> iterate rtw_vif_watch_dog_iter.
> 
> > - [3]: rtw88: Move rtw_update_sta_info() out of rtw_ra_mask_info_update_iter()
> 
> Need partial -- hold rtwdev->mutex before entering rtw_ra_mask_info_update().
> 
> Then, use rtw_iterate_stas() to iterate rtw_ra_mask_info_update_iter. 
> No need others.
> 
> 
> Sascha, could you squash Martin's patches into your patchset?
> And, then I can do more tests on PCI cards.

Yes, will do and send a v3 with it.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically
  2022-05-30 13:54 ` [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically Sascha Hauer
  2022-06-07 22:06   ` Martin Blumenstingl
@ 2022-06-09  2:55   ` Ping-Ke Shih
  1 sibling, 0 replies; 22+ messages in thread
From: Ping-Ke Shih @ 2022-06-09  2:55 UTC (permalink / raw)
  To: s.hauer, linux-wireless
  Cc: johannes, kernel, neojou, kvalo, tony0620emma, linux-kernel,
	martin.blumenstingl, linux, netdev

On Mon, 2022-05-30 at 15:54 +0200, Sascha Hauer wrote:
> The driver uses ieee80211_iterate_active_interfaces_atomic()
> and ieee80211_iterate_stations_atomic() in several places and does
> register accesses in the iterators. This doesn't cope with upcoming
> USB support as registers can only be accessed non-atomically.
> 
> Split these into a two stage process: First use the atomic iterator
> functions to collect all active interfaces or stations on a list, then
> iterate over the list non-atomically and call the iterator on each
> entry.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Suggested-by: Pkshih <pkshih@realtek.com>
> ---
> 
> Notes:
>     Changes since v1:
>     - Change subject
>     - Add some lockdep_assert_held(&rtwdev->mutex);
>     - make locally used functions static
>     - Add comment how &rtwdev->mutex protects us from stations/interfaces
>       being deleted between collecting them and iterating over them.
> 
>  drivers/net/wireless/realtek/rtw88/phy.c  |   6 +-
>  drivers/net/wireless/realtek/rtw88/ps.c   |   2 +-
>  drivers/net/wireless/realtek/rtw88/util.c | 103 ++++++++++++++++++++++
>  drivers/net/wireless/realtek/rtw88/util.h |  12 ++-
>  4 files changed, 116 insertions(+), 7 deletions(-)
> 
> 

[...]

> +
> +struct rtw_vifs_entry {
> +	struct list_head list;
> +	struct ieee80211_vif *vif;
> +	u8 mac[ETH_ALEN];
> +};
> +
> +struct rtw_iter_vifs_data {
> +	struct rtw_dev *rtwdev;
> +	struct list_head list;
> +};
> +
> +void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)

You do this change in patch "rtw88: Add common USB chip support".
Please move to here.

-void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+static void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)

> +{
> +	struct rtw_iter_vifs_data *iter_stas = data;
> +	struct rtw_vifs_entry *vifs_entry;
> +
> +	vifs_entry = kmalloc(sizeof(*vifs_entry), GFP_ATOMIC);
> +	if (!vifs_entry)
> +		return;
> +
> +	vifs_entry->vif = vif;
> +	ether_addr_copy(vifs_entry->mac, mac);
> +	list_add_tail(&vifs_entry->list, &iter_stas->list);
> +}
> +
> +void rtw_iterate_vifs(struct rtw_dev *rtwdev,
> +		      void (*iterator)(void *data, u8 *mac,
> +				       struct ieee80211_vif *vif),
> +		      void *data)
> +{
> +	struct rtw_iter_vifs_data iter_data;
> +	struct rtw_vifs_ent

[...]

> diff --git a/drivers/net/wireless/realtek/rtw88/util.h b/drivers/net/wireless/realtek/rtw88/util.h
> index 0c23b5069be0b..dc89655254002 100644
> --- a/drivers/net/wireless/realtek/rtw88/util.h
> +++ b/drivers/net/wireless/realtek/rtw88/util.h
> @@ -7,9 +7,6 @@
>  
>  struct rtw_dev;
>  
> -#define rtw_iterate_vifs(rtwdev, iterator, data)                               \
> -	ieee80211_iterate_active_interfaces(rtwdev->hw,                        \
> -			IEEE80211_IFACE_ITER_NORMAL, iterator, data)
>  #define rtw_iterate_vifs_atomic(rtwdev, iterator, data)                        \
>  	ieee80211_iterate_active_interfaces_atomic(rtwdev->hw,                 \
>  			IEEE80211_IFACE_ITER_NORMAL, iterator, data)

After read Martin's patches, I think we can review all places where use
_aotmic version of vif and sta, even we don't really meet problem for now.
Then, use non-atomic version if possible.

Ping-Ke



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

* Re: [PATCH v2 10/10] rtw88: disable powersave modes for USB devices
  2022-05-31  7:42     ` s.hauer
@ 2022-06-09 12:51       ` Ping-Ke Shih
  2022-06-10 13:26         ` s.hauer
  0 siblings, 1 reply; 22+ messages in thread
From: Ping-Ke Shih @ 2022-06-09 12:51 UTC (permalink / raw)
  To: s.hauer
  Cc: johannes, kernel, neojou, kvalo, tony0620emma, linux-wireless,
	martin.blumenstingl, linux-kernel, netdev, linux

On Tue, 2022-05-31 at 09:42 +0200, s.hauer@pengutronix.de wrote:
> On Tue, May 31, 2022 at 01:07:36AM +0000, Ping-Ke Shih wrote:
> > On Mon, 2022-05-30 at 15:54 +0200, Sascha Hauer wrote:
> > > The powersave modes do not work with USB devices (tested with a
> > > RTW8822CU) properly. With powersave modes enabled the driver issues
> > > messages like:
> > > 
> > > rtw_8822cu 1-1:1.2: firmware failed to leave lps state
> > > rtw_8822cu 1-1:1.2: timed out to flush queue 3
> > 
> > Could you try module parameter rtw_disable_lps_deep_mode=1 to see
> > if it can work?
> 
> No, this module parameter doesn't seem to make any difference.
> 
> # cat /sys/module/rtw88_core/parameters/disable_lps_deep
> Y
> 
> Still "firmware failed to leave lps state" and poor performance.
> 
> Any other ideas what may go wrong here?
> 

Today, I borrow a 8822cu, and use your patchset but revert
patch 10/10 to reproduce this issue. With firmware 7.3.0,
it looks bad. After checking something about firmware, I
found the firmware is old, so upgrade to 9.9.11, and then
it works well for 10 minutes, no abnormal messages.

Please try if it also works to you.

Ping-Ke



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

* Re: [PATCH v2 10/10] rtw88: disable powersave modes for USB devices
  2022-06-09 12:51       ` Ping-Ke Shih
@ 2022-06-10 13:26         ` s.hauer
  2022-06-13  0:02           ` Ping-Ke Shih
  0 siblings, 1 reply; 22+ messages in thread
From: s.hauer @ 2022-06-10 13:26 UTC (permalink / raw)
  To: Ping-Ke Shih
  Cc: johannes, kernel, neojou, kvalo, tony0620emma, linux-wireless,
	martin.blumenstingl, linux-kernel, netdev, linux

On Thu, Jun 09, 2022 at 12:51:49PM +0000, Ping-Ke Shih wrote:
> On Tue, 2022-05-31 at 09:42 +0200, s.hauer@pengutronix.de wrote:
> > On Tue, May 31, 2022 at 01:07:36AM +0000, Ping-Ke Shih wrote:
> > > On Mon, 2022-05-30 at 15:54 +0200, Sascha Hauer wrote:
> > > > The powersave modes do not work with USB devices (tested with a
> > > > RTW8822CU) properly. With powersave modes enabled the driver issues
> > > > messages like:
> > > > 
> > > > rtw_8822cu 1-1:1.2: firmware failed to leave lps state
> > > > rtw_8822cu 1-1:1.2: timed out to flush queue 3
> > > 
> > > Could you try module parameter rtw_disable_lps_deep_mode=1 to see
> > > if it can work?
> > 
> > No, this module parameter doesn't seem to make any difference.
> > 
> > # cat /sys/module/rtw88_core/parameters/disable_lps_deep
> > Y
> > 
> > Still "firmware failed to leave lps state" and poor performance.
> > 
> > Any other ideas what may go wrong here?
> > 
> 
> Today, I borrow a 8822cu, and use your patchset but revert
> patch 10/10 to reproduce this issue. With firmware 7.3.0,
> it looks bad. After checking something about firmware, I
> found the firmware is old, so upgrade to 9.9.11, and then
> it works well for 10 minutes, no abnormal messages.

I originally used firmware 5.0.0. Then I have tried 9.9.6 I have lying
around here from my distro. That version behaves like the old 5.0.0
version. Finally I switched to 9.9.11 from current linux-firmware
repository. That doesn't work at all for me unfortunately:

[  221.076279] rtw_8822cu 2-1:1.2: Firmware version 9.9.11, H2C version 15
[  221.078405] rtw_8822cu 2-1:1.2: Firmware version 9.9.4, H2C version 15
[  239.783261] wlan0: authenticate with 76:83:c2:ce:83:0b
[  242.398435] wlan0: send auth to 76:83:c2:ce:83:0b (try 1/3)
[  242.402992] wlan0: authenticated
[  242.420735] wlan0: associate with 76:83:c2:ce:83:0b (try 1/3)
[  242.437094] wlan0: RX AssocResp from 76:83:c2:ce:83:0b (capab=0x1411 status=0 aid=4)
[  242.485521] wlan0: associated
[  242.564847] wlan0: Connection to AP 76:83:c2:ce:83:0b lost
[  244.577617] wlan0: authenticate with 76:83:c2:cd:83:0b
[  244.578257] wlan0: bad VHT capabilities, disabling VHT
[  246.866182] wlan0: send auth to 76:83:c2:cd:83:0b (try 1/3)
[  246.871830] wlan0: authenticated
[  246.892754] wlan0: associate with 76:83:c2:cd:83:0b (try 1/3)
[  246.911045] wlan0: RX AssocResp from 76:83:c2:cd:83:0b (capab=0x1431 status=0 aid=3)
[  246.940608] wlan0: associated
[  247.152308] wlan0: Connection to AP 76:83:c2:cd:83:0b lost
[  248.912821] wlan0: Connection to AP 00:00:00:00:00:00 lost
[  249.105517] wlan0: authenticate with 76:83:c2:ce:83:0b
[  251.482183] wlan0: send auth to 76:83:c2:ce:83:0b (try 1/3)
[  251.486765] wlan0: authenticated
[  251.508731] wlan0: associate with 76:83:c2:ce:83:0b (try 1/3)
[  251.521904] wlan0: RX AssocResp from 76:83:c2:ce:83:0b (capab=0x1411 status=0 aid=4)
[  251.565233] wlan0: associated
[  251.720602] wlan0: Connection to AP 76:83:c2:ce:83:0b lost
[  253.527904] wlan0: Connection to AP 00:00:00:00:00:00 lost
[  253.728243] wlan0: authenticate with 76:83:c2:cd:83:0b
[  253.728921] wlan0: bad VHT capabilities, disabling VHT
[  256.014184] wlan0: send auth to 76:83:c2:cd:83:0b (try 1/3)
[  256.019608] wlan0: authenticated
[  256.044702] wlan0: associate with 76:83:c2:cd:83:0b (try 1/3)
[  256.062049] wlan0: RX AssocResp from 76:83:c2:cd:83:0b (capab=0x1431 status=0 aid=3)
[  256.093117] wlan0: associated
[  256.169071] wlan0: Connection to AP 76:83:c2:cd:83:0b lost
[  258.145286] wlan0: authenticate with 76:83:c2:ce:83:0b
[  260.626182] wlan0: send auth to 76:83:c2:ce:83:0b (try 1/3)
[  260.630495] wlan0: authenticated
[  260.652783] wlan0: associate with 76:83:c2:ce:83:0b (try 1/3)
[  260.666201] wlan0: RX AssocResp from 76:83:c2:ce:83:0b (capab=0x1411 status=0 aid=4)
[  260.708596] wlan0: associated
[  260.769613] wlan0: Connection to AP 76:83:c2:ce:83:0b lost
[  262.770668] wlan0: authenticate with 76:83:c2:cd:83:0b
[  262.771272] wlan0: bad VHT capabilities, disabling VHT
[  265.158184] wlan0: send auth to 76:83:c2:cd:83:0b (try 1/3)

This goes on forever. I finally tried 9.9.10 and 9.9.9, they also behave
like 9.9.11.

No luck today :(

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH v2 10/10] rtw88: disable powersave modes for USB devices
  2022-06-10 13:26         ` s.hauer
@ 2022-06-13  0:02           ` Ping-Ke Shih
  2022-06-14  7:06             ` s.hauer
  0 siblings, 1 reply; 22+ messages in thread
From: Ping-Ke Shih @ 2022-06-13  0:02 UTC (permalink / raw)
  To: s.hauer
  Cc: johannes, kernel, neojou, kvalo, tony0620emma, linux-kernel,
	linux-wireless, netdev, martin.blumenstingl, linux

On Fri, 2022-06-10 at 15:26 +0200, s.hauer@pengutronix.de wrote:
> On Thu, Jun 09, 2022 at 12:51:49PM +0000, Ping-Ke Shih wrote:
> > 
> > Today, I borrow a 8822cu, and use your patchset but revert
> > patch 10/10 to reproduce this issue. With firmware 7.3.0,
> > it looks bad. After checking something about firmware, I
> > found the firmware is old, so upgrade to 9.9.11, and then
> > it works well for 10 minutes, no abnormal messages.
> 
> I originally used firmware 5.0.0. Then I have tried 9.9.6 I have lying
> around here from my distro. That version behaves like the old 5.0.0
> version. Finally I switched to 9.9.11 from current linux-firmware
> repository. That doesn't work at all for me unfortunately:
> 
> [  221.076279] rtw_8822cu 2-1:1.2: Firmware version 9.9.11, H2C version 15
> [  221.078405] rtw_8822cu 2-1:1.2: Firmware version 9.9.4, H2C version 15
> [  239.783261] wlan0: authenticate with 76:83:c2:ce:83:0b
> [  242.398435] wlan0: send auth to 76:83:c2:ce:83:0b (try 1/3)
> [  242.402992] wlan0: authenticated
> [  242.420735] wlan0: associate with 76:83:c2:ce:83:0b (try 1/3)
> [  242.437094] wlan0: RX AssocResp from 76:83:c2:ce:83:0b (capab=0x1411 status=0 aid=4)
> [  242.485521] wlan0: associated
> [  242.564847] wlan0: Connection to AP 76:83:c2:ce:83:0b lost
> [  244.577617] wlan0: authenticate with 76:83:c2:cd:83:0b
> [  244.578257] wlan0: bad VHT capabilities, disabling VHT
> 
> This goes on forever. I finally tried 9.9.10 and 9.9.9, they also behave
> like 9.9.11.
> 

Please help do more experiements on your 8822cu with the
latest firmware 9.9.11.

1. which module RFE type you are using?
   My 8822cu is RFE type 4.
   Get this information from 

   cat /sys/kernel/debug/ieee80211/phyXXX/rtw88/coex_info

   The 4th line:
   Mech/ RFE                                = Non-Shared/ 4   

4. Disable power save to see if it still disconnect from AP

   iw wlan0 set power_save off

   If this can work well, still power save mode works abnormal.

3. Disable keep-alive. (with power_save on)

--- a/main.c
+++ b/main.c
@@ -2199,6 +2199,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
        ieee80211_hw_set(hw, HAS_RATE_CONTROL);
        ieee80211_hw_set(hw, TX_AMSDU);
        ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
+       ieee80211_hw_set(hw, CONNECTION_MONITOR);

   This can make it still connected even it doesn't receive anything.
   Check if it can leave power save without abnormal messages.

4. USB interference

   Very low possibility, but simply try USB 2.0 and 3.0 ports.

5. Try another AP working on different band (2.4GHz or 5Ghz)


I wise these can narrow down the problem you met.

Ping-Ke



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

* Re: [PATCH v2 10/10] rtw88: disable powersave modes for USB devices
  2022-06-13  0:02           ` Ping-Ke Shih
@ 2022-06-14  7:06             ` s.hauer
  0 siblings, 0 replies; 22+ messages in thread
From: s.hauer @ 2022-06-14  7:06 UTC (permalink / raw)
  To: Ping-Ke Shih
  Cc: linux, martin.blumenstingl, netdev, kvalo, linux-wireless,
	linux-kernel, tony0620emma, neojou, kernel, johannes

On Mon, Jun 13, 2022 at 12:02:23AM +0000, Ping-Ke Shih wrote:
> On Fri, 2022-06-10 at 15:26 +0200, s.hauer@pengutronix.de wrote:
> > On Thu, Jun 09, 2022 at 12:51:49PM +0000, Ping-Ke Shih wrote:
> > > 
> > > Today, I borrow a 8822cu, and use your patchset but revert
> > > patch 10/10 to reproduce this issue. With firmware 7.3.0,
> > > it looks bad. After checking something about firmware, I
> > > found the firmware is old, so upgrade to 9.9.11, and then
> > > it works well for 10 minutes, no abnormal messages.
> > 
> > I originally used firmware 5.0.0. Then I have tried 9.9.6 I have lying
> > around here from my distro. That version behaves like the old 5.0.0
> > version. Finally I switched to 9.9.11 from current linux-firmware
> > repository. That doesn't work at all for me unfortunately:
> > 
> > [  221.076279] rtw_8822cu 2-1:1.2: Firmware version 9.9.11, H2C version 15
> > [  221.078405] rtw_8822cu 2-1:1.2: Firmware version 9.9.4, H2C version 15
> > [  239.783261] wlan0: authenticate with 76:83:c2:ce:83:0b
> > [  242.398435] wlan0: send auth to 76:83:c2:ce:83:0b (try 1/3)
> > [  242.402992] wlan0: authenticated
> > [  242.420735] wlan0: associate with 76:83:c2:ce:83:0b (try 1/3)
> > [  242.437094] wlan0: RX AssocResp from 76:83:c2:ce:83:0b (capab=0x1411 status=0 aid=4)
> > [  242.485521] wlan0: associated
> > [  242.564847] wlan0: Connection to AP 76:83:c2:ce:83:0b lost
> > [  244.577617] wlan0: authenticate with 76:83:c2:cd:83:0b
> > [  244.578257] wlan0: bad VHT capabilities, disabling VHT
> > 
> > This goes on forever. I finally tried 9.9.10 and 9.9.9, they also behave
> > like 9.9.11.
> > 
> 
> Please help do more experiements on your 8822cu with the
> latest firmware 9.9.11.
> 
> 1. which module RFE type you are using?
>    My 8822cu is RFE type 4.
>    Get this information from 
> 
>    cat /sys/kernel/debug/ieee80211/phyXXX/rtw88/coex_info
> 
>    The 4th line:
>    Mech/ RFE                                = Non-Shared/ 4  

I have:

Mech/ RFE                                = Shared/ 3

As you mention this I remember that I added this hunk to rtw8822c.c:

@@ -4895,6 +4916,8 @@ static const struct rtw_rfe_def rtw8822c_rfe_defs[] = {
        [0] = RTW_DEF_RFE(8822c, 0, 0),
        [1] = RTW_DEF_RFE(8822c, 0, 0),
        [2] = RTW_DEF_RFE(8822c, 0, 0),
+       [3] = RTW_DEF_RFE(8822c, 0, 0),
+       [4] = RTW_DEF_RFE(8822c, 0, 0),
        [5] = RTW_DEF_RFE(8822c, 0, 5),
        [6] = RTW_DEF_RFE(8822c, 0, 0),
 };

I copied [4] from Hans Ulli Krolls repository, but the [3] entry needed
for my hardware I made up myself. I don't know if that's correct and
what difference it makes, but I stopped thinking about it when I
realized that it works.

> 
> 4. Disable power save to see if it still disconnect from AP
> 
>    iw wlan0 set power_save off
> 
>    If this can work well, still power save mode works abnormal.

With powersave disabled it still doesn't work.

> 
> 3. Disable keep-alive. (with power_save on)
> 
> --- a/main.c
> +++ b/main.c
> @@ -2199,6 +2199,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
>         ieee80211_hw_set(hw, HAS_RATE_CONTROL);
>         ieee80211_hw_set(hw, TX_AMSDU);
>         ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
> +       ieee80211_hw_set(hw, CONNECTION_MONITOR);
> 
>    This can make it still connected even it doesn't receive anything.
>    Check if it can leave power save without abnormal messages.
> 
> 4. USB interference
> 
>    Very low possibility, but simply try USB 2.0 and 3.0 ports.

Surprisingly this really makes a difference. I have a EHCI port which I
used up to now. One other port is behind a XHCI controller and on that
port the device behaves much better, but still far from perfect.

> 
> 5. Try another AP working on different band (2.4GHz or 5Ghz)

I have tried two access points in both 2.4GHt and 5GHz bands. That
doesn't make any significant difference.

Some other things I saw yesterday during testing:

I've seen this more than once:

[  249.914750] rtw_8822cu 4-1:1.2: error beacon valid
[  249.914890] rtw_8822cu 4-1:1.2: Download probe request to firmware failed
[  249.914903] rtw_8822cu 4-1:1.2: Update probe request failed
[  249.925005] rtw_8822cu 4-1:1.2: HW scan failed with status: -16
[  251.246244] rtw_8822cu 4-1:1.2: error beacon valid
[  251.246387] rtw_8822cu 4-1:1.2: Download probe request to firmware failed
[  251.246400] rtw_8822cu 4-1:1.2: Update probe request failed
[  251.255539] rtw_8822cu 4-1:1.2: HW scan failed with status: -16
[  262.611263] rtw_8822cu 4-1:1.2: error beacon valid

With powersave enabled I saw this while pinging the device from a remote
host:

64 bytes from 192.168.0.196: icmp_seq=304 ttl=64 time=169 ms
64 bytes from 192.168.0.196: icmp_seq=305 ttl=64 time=15405 ms
64 bytes from 192.168.0.196: icmp_seq=306 ttl=64 time=14395 ms
64 bytes from 192.168.0.196: icmp_seq=307 ttl=64 time=13371 ms
64 bytes from 192.168.0.196: icmp_seq=310 ttl=64 time=10300 ms
64 bytes from 192.168.0.196: icmp_seq=311 ttl=64 time=9276 ms
64 bytes from 192.168.0.196: icmp_seq=312 ttl=64 time=8252 ms
64 bytes from 192.168.0.196: icmp_seq=313 ttl=64 time=7229 ms
64 bytes from 192.168.0.196: icmp_seq=314 ttl=64 time=6205 ms
64 bytes from 192.168.0.196: icmp_seq=315 ttl=64 time=5181 ms
64 bytes from 192.168.0.196: icmp_seq=316 ttl=64 time=4154 ms
64 bytes from 192.168.0.196: icmp_seq=317 ttl=64 time=3130 ms
64 bytes from 192.168.0.196: icmp_seq=318 ttl=64 time=2110 ms
64 bytes from 192.168.0.196: icmp_seq=319 ttl=64 time=1087 ms
64 bytes from 192.168.0.196: icmp_seq=320 ttl=64 time=63.8 ms

You see that we have a 16s lag and then all of a sudden the answer to 16
ping packets come in at once.

This all looks very erratic now. I would be grateful for hints where I
could look at. In the meantime I see if I get get another rtl8822cu wifi
dongle to see if my hardware is bad.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

end of thread, other threads:[~2022-06-14  7:07 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-30 13:54 [PATCH v2 00/10] RTW88: Add support for USB variants Sascha Hauer
2022-05-30 13:54 ` [PATCH v2 01/10] rtw88: Call rtw_fw_beacon_filter_config() with rtwdev->mutex held Sascha Hauer
2022-05-30 13:54 ` [PATCH v2 02/10] rtw88: Drop rf_lock Sascha Hauer
2022-05-30 13:54 ` [PATCH v2 03/10] rtw88: Drop h2c.lock Sascha Hauer
2022-05-30 13:54 ` [PATCH v2 04/10] rtw88: Drop coex mutex Sascha Hauer
2022-05-30 13:54 ` [PATCH v2 05/10] rtw88: iterate over vif/sta list non-atomically Sascha Hauer
2022-06-07 22:06   ` Martin Blumenstingl
2022-06-08 13:25     ` Ping-Ke Shih
2022-06-08 13:37       ` s.hauer
2022-06-09  2:55   ` Ping-Ke Shih
2022-05-30 13:54 ` [PATCH v2 06/10] rtw88: Add common USB chip support Sascha Hauer
2022-05-30 13:54 ` [PATCH v2 07/10] rtw88: Add rtw8821cu chipset support Sascha Hauer
2022-05-31  1:00   ` Ping-Ke Shih
2022-05-30 13:54 ` [PATCH v2 08/10] rtw88: Add rtw8822bu " Sascha Hauer
2022-05-30 13:54 ` [PATCH v2 09/10] rtw88: Add rtw8822cu " Sascha Hauer
2022-05-30 13:54 ` [PATCH v2 10/10] rtw88: disable powersave modes for USB devices Sascha Hauer
2022-05-31  1:07   ` Ping-Ke Shih
2022-05-31  7:42     ` s.hauer
2022-06-09 12:51       ` Ping-Ke Shih
2022-06-10 13:26         ` s.hauer
2022-06-13  0:02           ` Ping-Ke Shih
2022-06-14  7:06             ` s.hauer

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