summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2022-12-12 12:15:23 -0800
committerJakub Kicinski <kuba@kernel.org>2022-12-12 12:15:23 -0800
commitfba119cee1412f49c472f3913241d00f830761fd (patch)
treedf78b1d99bdfbcf504bf2951462e74e2479f00f2 /drivers
parent26f708a28454df2062a63fd869e983c379f50ff0 (diff)
parent832c3f66f53f1eb20f424b916a311ad82074ef0d (diff)
Merge tag 'wireless-next-2022-12-12' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Kalle Valo says: ==================== wireless-next patches for v6.2 Fourth set of patches for v6.2. Few final patches, a big change is that rtw88 now has USB support. Major changes: rtw88 * support USB devices rtw8821cu, rtw8822bu, rtw8822cu and rtw8723du * tag 'wireless-next-2022-12-12' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (43 commits) wifi: rtl8xxxu: fixing IQK failures for rtl8192eu wifi: rtlwifi: btcoexist: fix conditions branches that are never executed wifi: rtlwifi: rtl8192se: remove redundant rtl_get_bbreg() call wifi: rtw88: Add rtw8723du chipset support wifi: rtw88: Add rtw8822cu chipset support wifi: rtw88: Add rtw8822bu chipset support wifi: rtw88: Add rtw8821cu chipset support wifi: rtw88: Add common USB chip support wifi: rtw88: iterate over vif/sta list non-atomically wifi: rtw88: Drop coex mutex wifi: rtw88: Drop h2c.lock wifi: rtw88: Drop rf_lock wifi: rtw88: Call rtw_fw_beacon_filter_config() with rtwdev->mutex held wifi: rtw88: print firmware type in info message wifi: rtw89: add join info upon create interface wifi: rtw89: fix unsuccessful interface_add flow wifi: rtw89: stop mac port function when stop_ap() wifi: rtw89: add mac TSF sync function wifi: rtw89: request full firmware only once if it's early requested wifi: rtw89: don't request partial firmware if SECURITY_LOADPIN_ENFORCE ... ==================== Link: https://lore.kernel.org/r/20221212093026.5C5AEC433D2@smtp.kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile11
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/Makefile12
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c27
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c27
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/vops.h11
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c52
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h30
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c12
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/Makefile12
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c27
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c27
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/vops.h11
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c199
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h47
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c72
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c27
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/Makefile12
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c27
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c27
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/vops.h11
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2100.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dump.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mei/main.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mei/sap.h10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mei/trace-data.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mei/trace.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c38
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c33
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h2
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c73
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c101
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c5
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c3
-rw-r--r--drivers/net/wireless/realtek/rtw88/Kconfig47
-rw-r--r--drivers/net/wireless/realtek/rtw88/Makefile15
-rw-r--r--drivers/net/wireless/realtek/rtw88/coex.c3
-rw-r--r--drivers/net/wireless/realtek/rtw88/debug.c15
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.c13
-rw-r--r--drivers/net/wireless/realtek/rtw88/hci.h9
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac.c3
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac80211.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c12
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h12
-rw-r--r--drivers/net/wireless/realtek/rtw88/phy.c6
-rw-r--r--drivers/net/wireless/realtek/rtw88/ps.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/reg.h1
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8723d.c28
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8723d.h13
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8723du.c36
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821c.c18
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821c.h21
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821cu.c50
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822b.c19
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822bu.c90
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.c24
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822cu.c44
-rw-r--r--drivers/net/wireless/realtek/rtw88/tx.h31
-rw-r--r--drivers/net/wireless/realtek/rtw88/usb.c911
-rw-r--r--drivers/net/wireless/realtek/rtw88/usb.h107
-rw-r--r--drivers/net/wireless/realtek/rtw88/util.c103
-rw-r--r--drivers/net/wireless/realtek/rtw88/util.h12
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.c6
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c60
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.h22
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.c64
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.h3
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c3
-rw-r--r--drivers/net/wireless/realtek/rtw89/reg.h17
80 files changed, 2613 insertions, 297 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
index 13c13504a6e8..0e996cf24f88 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
@@ -20,6 +20,7 @@ brcmfmac-objs += \
common.o \
core.o \
firmware.o \
+ fwvid.o \
feature.o \
btcoex.o \
vendor.o \
@@ -47,3 +48,13 @@ brcmfmac-$(CONFIG_OF) += \
of.o
brcmfmac-$(CONFIG_DMI) += \
dmi.o
+
+ifeq ($(CONFIG_BRCMFMAC),m)
+obj-m += wcc/
+obj-m += cyw/
+obj-m += bca/
+else
+brcmfmac-$(CONFIG_BRCMFMAC) += wcc/core.o
+brcmfmac-$(CONFIG_BRCMFMAC) += cyw/core.o
+brcmfmac-$(CONFIG_BRCMFMAC) += bca/core.o
+endif
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/Makefile
new file mode 100644
index 000000000000..46098705e236
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: ISC
+#
+# Copyright (c) 2022 Broadcom Corporation
+
+ccflags-y += \
+ -I $(srctree)/$(src) \
+ -I $(srctree)/$(src)/.. \
+ -I $(srctree)/$(src)/../../include
+
+obj-m += brcmfmac-bca.o
+brcmfmac-bca-objs += \
+ core.o module.o
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c
new file mode 100644
index 000000000000..ac3a36fa3640
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <core.h>
+#include <bus.h>
+#include <fwvid.h>
+
+#include "vops.h"
+
+static int brcmf_bca_attach(struct brcmf_pub *drvr)
+{
+ pr_err("%s: executing\n", __func__);
+ return 0;
+}
+
+static void brcmf_bca_detach(struct brcmf_pub *drvr)
+{
+ pr_err("%s: executing\n", __func__);
+}
+
+const struct brcmf_fwvid_ops brcmf_bca_ops = {
+ .attach = brcmf_bca_attach,
+ .detach = brcmf_bca_detach,
+};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c
new file mode 100644
index 000000000000..d55f3271d619
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#include <linux/module.h>
+#include <bus.h>
+#include <core.h>
+#include <fwvid.h>
+
+#include "vops.h"
+
+static int __init brcmf_bca_init(void)
+{
+ return brcmf_fwvid_register_vendor(BRCMF_FWVENDOR_BCA, THIS_MODULE,
+ &brcmf_bca_ops);
+}
+
+static void __exit brcmf_bca_exit(void)
+{
+ brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_BCA, THIS_MODULE);
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(BRCMFMAC);
+
+module_init(brcmf_bca_init);
+module_exit(brcmf_bca_exit);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/vops.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/vops.h
new file mode 100644
index 000000000000..7897e6b6eefb
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/vops.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: ISC */
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#ifndef _BRCMFMAC_BCA_VOPS_H
+#define _BRCMFMAC_BCA_VOPS_H
+
+extern const struct brcmf_fwvid_ops brcmf_bca_ops;
+#define BCA_VOPS (&brcmf_bca_ops)
+
+#endif /* _BRCMFMAC_BCA_VOPS_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index d0daef674e72..b7c918f241c9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -959,33 +959,36 @@ out:
return ret;
}
-#define BRCMF_SDIO_DEVICE(dev_id) \
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id)}
+#define BRCMF_SDIO_DEVICE(dev_id, fw_vend) \
+ { \
+ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id), \
+ .driver_data = BRCMF_FWVENDOR_ ## fw_vend \
+ }
/* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = {
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752),
- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373, CYW),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012, CYW),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, CYW),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW),
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
@@ -1051,6 +1054,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
sdiodev->bus_if = bus_if;
bus_if->bus_priv.sdio = sdiodev;
bus_if->proto_type = BRCMF_PROTO_BCDC;
+ bus_if->fwvid = id->driver_data;
dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func1->dev, bus_if);
sdiodev->dev = &sdiodev->func1->dev;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 60f5645aead3..501136e011b5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/firmware.h>
+#include <linux/device.h>
#include "debug.h"
/* IDs of the 6 default common rings of msgbuf protocol */
@@ -30,6 +31,15 @@
/* The maximum console interval value (5 mins) */
#define MAX_CONSOLE_INTERVAL (5 * 60)
+enum brcmf_fwvendor {
+ BRCMF_FWVENDOR_WCC,
+ BRCMF_FWVENDOR_CYW,
+ BRCMF_FWVENDOR_BCA,
+ /* keep last */
+ BRCMF_FWVENDOR_NUM,
+ BRCMF_FWVENDOR_INVALID
+};
+
/* The level of bus communication with the dongle */
enum brcmf_bus_state {
BRCMF_BUS_DOWN, /* Not ready for frame transfers */
@@ -74,6 +84,7 @@ struct brcmf_bus_dcmd {
* @get_ramsize: obtain size of device memory.
* @get_memdump: obtain device memory dump in provided buffer.
* @get_blob: obtain a firmware blob.
+ * @remove: initiate unbind of the device.
*
* This structure provides an abstract interface towards the
* bus specific driver. For control messages to common driver
@@ -94,6 +105,7 @@ struct brcmf_bus_ops {
enum brcmf_blob_type type);
void (*debugfs_create)(struct device *dev);
int (*reset)(struct device *dev);
+ void (*remove)(struct device *dev);
};
@@ -141,10 +153,13 @@ struct brcmf_bus_stats {
* @stats: statistics shared between common and bus layer.
* @maxctl: maximum size for rxctl request message.
* @chip: device identifier of the dongle chip.
+ * @chiprev: revision of the dongle chip.
+ * @fwvid: firmware vendor-support identifier of the device.
* @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
* @wowl_supported: is wowl supported by bus driver.
- * @chiprev: revision of the dongle chip.
+ * @ops: callbacks for this bus instance.
* @msgbuf: msgbuf protocol parameters provided by bus layer.
+ * @list: member used to add this bus instance to linked list.
*/
struct brcmf_bus {
union {
@@ -160,11 +175,14 @@ struct brcmf_bus {
uint maxctl;
u32 chip;
u32 chiprev;
+ enum brcmf_fwvendor fwvid;
bool always_use_fws_queue;
bool wowl_supported;
const struct brcmf_bus_ops *ops;
struct brcmf_bus_msgbuf *msgbuf;
+
+ struct list_head list;
};
/*
@@ -257,6 +275,16 @@ int brcmf_bus_reset(struct brcmf_bus *bus)
return bus->ops->reset(bus->dev);
}
+static inline void brcmf_bus_remove(struct brcmf_bus *bus)
+{
+ if (!bus->ops->remove) {
+ device_release_driver(bus->dev);
+ return;
+ }
+
+ bus->ops->remove(bus->dev);
+}
+
/*
* interface functions from common layer
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index d354f79fd0ac..83ea251cfcec 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -18,6 +18,7 @@
#include "core.h"
#include "bus.h"
+#include "fwvid.h"
#include "debug.h"
#include "fwil_types.h"
#include "p2p.h"
@@ -1135,7 +1136,8 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
seq_printf(s, "vendorid: 0x%04x\n", ri->vendorid);
seq_printf(s, "deviceid: 0x%04x\n", ri->deviceid);
seq_printf(s, "radiorev: %s\n", brcmu_dotrev_str(ri->radiorev, drev));
- seq_printf(s, "chip: %s\n", ri->chipname);
+ seq_printf(s, "chip: %s (%s)\n", ri->chipname,
+ brcmf_fwvid_vendor_name(bus_if->drvr));
seq_printf(s, "chippkg: %u\n", ri->chippkg);
seq_printf(s, "corerev: %u\n", ri->corerev);
seq_printf(s, "boardid: 0x%04x\n", ri->boardid);
@@ -1332,6 +1334,12 @@ int brcmf_attach(struct device *dev)
/* Link to bus module */
drvr->hdrlen = 0;
+ ret = brcmf_fwvid_attach(drvr);
+ if (ret != 0) {
+ bphy_err(drvr, "brcmf_fwvid_attach failed\n");
+ goto fail;
+ }
+
/* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr);
if (ret != 0) {
@@ -1443,6 +1451,8 @@ void brcmf_detach(struct device *dev)
brcmf_cfg80211_detach(drvr->config);
drvr->config = NULL;
}
+
+ brcmf_fwvid_detach(drvr);
}
void brcmf_free(struct device *dev)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index 2e71b5c2a975..e4f911dd414b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -13,6 +13,12 @@
#include <net/cfg80211.h>
#include "fweh.h"
+#if IS_MODULE(CONFIG_BRCMFMAC)
+#define BRCMF_EXPORT_SYMBOL_GPL(__sym) EXPORT_SYMBOL_NS_GPL(__sym, BRCMFMAC)
+#else
+#define BRCMF_EXPORT_SYMBOL_GPL(__sym)
+#endif
+
#define TOE_TX_CSUM_OL 0x00000001
#define TOE_RX_CSUM_OL 0x00000002
@@ -137,6 +143,8 @@ struct brcmf_pub {
u8 clmver[BRCMF_DCMD_SMLEN];
u8 sta_mac_idx;
+ const struct brcmf_fwvid_ops *vops;
+ void *vdata;
};
/* forward declarations */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/Makefile
new file mode 100644
index 000000000000..5e1fddaff79e
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: ISC
+#
+# Copyright (c) 2022 Broadcom Corporation
+
+ccflags-y += \
+ -I $(srctree)/$(src) \
+ -I $(srctree)/$(src)/.. \
+ -I $(srctree)/$(src)/../../include
+
+obj-m += brcmfmac-cyw.o
+brcmfmac-cyw-objs += \
+ core.o module.o
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
new file mode 100644
index 000000000000..b75652ba9359
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <core.h>
+#include <bus.h>
+#include <fwvid.h>
+
+#include "vops.h"
+
+static int brcmf_cyw_attach(struct brcmf_pub *drvr)
+{
+ pr_err("%s: executing\n", __func__);
+ return 0;
+}
+
+static void brcmf_cyw_detach(struct brcmf_pub *drvr)
+{
+ pr_err("%s: executing\n", __func__);
+}
+
+const struct brcmf_fwvid_ops brcmf_cyw_ops = {
+ .attach = brcmf_cyw_attach,
+ .detach = brcmf_cyw_detach,
+};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c
new file mode 100644
index 000000000000..f82fbbe3ecef
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#include <linux/module.h>
+#include <bus.h>
+#include <core.h>
+#include <fwvid.h>
+
+#include "vops.h"
+
+static int __init brcmf_cyw_init(void)
+{
+ return brcmf_fwvid_register_vendor(BRCMF_FWVENDOR_CYW, THIS_MODULE,
+ &brcmf_cyw_ops);
+}
+
+static void __exit brcmf_cyw_exit(void)
+{
+ brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_CYW, THIS_MODULE);
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(BRCMFMAC);
+
+module_init(brcmf_cyw_init);
+module_exit(brcmf_cyw_exit);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/vops.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/vops.h
new file mode 100644
index 000000000000..870b5bead436
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/vops.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: ISC */
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#ifndef _BRCMFMAC_CYW_VOPS_H
+#define _BRCMFMAC_CYW_VOPS_H
+
+extern const struct brcmf_fwvid_ops brcmf_cyw_ops;
+#define CYW_VOPS (&brcmf_cyw_ops)
+
+#endif /* _BRCMFMAC_CYW_VOPS_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c
new file mode 100644
index 000000000000..86eafdb40541
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/printk.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
+#include "fwvid.h"
+
+#include "wcc/vops.h"
+#include "cyw/vops.h"
+#include "bca/vops.h"
+
+struct brcmf_fwvid_entry {
+ const char *name;
+ const struct brcmf_fwvid_ops *vops;
+ struct list_head drvr_list;
+#if IS_MODULE(CONFIG_BRCMFMAC)
+ struct module *vmod;
+ struct completion reg_done;
+#endif
+};
+
+static DEFINE_MUTEX(fwvid_list_lock);
+
+#if IS_MODULE(CONFIG_BRCMFMAC)
+#define FWVID_ENTRY_INIT(_vid, _name) \
+ [BRCMF_FWVENDOR_ ## _vid] = { \
+ .name = #_name, \
+ .reg_done = COMPLETION_INITIALIZER(fwvid_list[BRCMF_FWVENDOR_ ## _vid].reg_done), \
+ .drvr_list = LIST_HEAD_INIT(fwvid_list[BRCMF_FWVENDOR_ ## _vid].drvr_list), \
+ }
+#else
+#define FWVID_ENTRY_INIT(_vid, _name) \
+ [BRCMF_FWVENDOR_ ## _vid] = { \
+ .name = #_name, \
+ .drvr_list = LIST_HEAD_INIT(fwvid_list[BRCMF_FWVENDOR_ ## _vid].drvr_list), \
+ .vops = _vid ## _VOPS \
+ }
+#endif /* IS_MODULE(CONFIG_BRCMFMAC) */
+
+static struct brcmf_fwvid_entry fwvid_list[BRCMF_FWVENDOR_NUM] = {
+ FWVID_ENTRY_INIT(WCC, wcc),
+ FWVID_ENTRY_INIT(CYW, cyw),
+ FWVID_ENTRY_INIT(BCA, bca),
+};
+
+#if IS_MODULE(CONFIG_BRCMFMAC)
+static int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid)
+{
+ int ret;
+
+ if (!fwvid_list[fwvid].vmod) {
+ struct completion *reg_done = &fwvid_list[fwvid].reg_done;
+
+ mutex_unlock(&fwvid_list_lock);
+
+ ret = request_module("brcmfmac-%s", fwvid_list[fwvid].name);
+ if (ret)
+ goto fail;
+
+ ret = wait_for_completion_interruptible(reg_done);
+ if (ret)
+ goto fail;
+
+ mutex_lock(&fwvid_list_lock);
+ }
+ return 0;
+
+fail:
+ brcmf_err("mod=%s: failed %d\n", fwvid_list[fwvid].name, ret);
+ return ret;
+}
+
+int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod,
+ const struct brcmf_fwvid_ops *vops)
+{
+ if (fwvid >= BRCMF_FWVENDOR_NUM)
+ return -ERANGE;
+
+ if (WARN_ON(!vmod) || WARN_ON(!vops) ||
+ WARN_ON(!vops->attach) || WARN_ON(!vops->detach))
+ return -EINVAL;
+
+ if (WARN_ON(fwvid_list[fwvid].vmod))
+ return -EEXIST;
+
+ brcmf_dbg(TRACE, "mod=%s: enter\n", fwvid_list[fwvid].name);
+
+ mutex_lock(&fwvid_list_lock);
+
+ fwvid_list[fwvid].vmod = vmod;
+ fwvid_list[fwvid].vops = vops;
+
+ mutex_unlock(&fwvid_list_lock);
+
+ complete_all(&fwvid_list[fwvid].reg_done);
+
+ return 0;
+}
+BRCMF_EXPORT_SYMBOL_GPL(brcmf_fwvid_register_vendor);
+
+int brcmf_fwvid_unregister_vendor(enum brcmf_fwvendor fwvid, struct module *mod)
+{
+ struct brcmf_bus *bus, *tmp;
+
+ if (fwvid >= BRCMF_FWVENDOR_NUM)
+ return -ERANGE;
+
+ if (WARN_ON(fwvid_list[fwvid].vmod != mod))
+ return -ENOENT;
+
+ mutex_lock(&fwvid_list_lock);
+
+ list_for_each_entry_safe(bus, tmp, &fwvid_list[fwvid].drvr_list, list) {
+ mutex_unlock(&fwvid_list_lock);
+
+ brcmf_dbg(INFO, "mod=%s: removing %s\n", fwvid_list[fwvid].name,
+ dev_name(bus->dev));
+ brcmf_bus_remove(bus);
+
+ mutex_lock(&fwvid_list_lock);
+ }
+
+ fwvid_list[fwvid].vmod = NULL;
+ fwvid_list[fwvid].vops = NULL;
+ reinit_completion(&fwvid_list[fwvid].reg_done);
+
+ brcmf_dbg(TRACE, "mod=%s: exit\n", fwvid_list[fwvid].name);
+ mutex_unlock(&fwvid_list_lock);
+
+ return 0;
+}
+BRCMF_EXPORT_SYMBOL_GPL(brcmf_fwvid_unregister_vendor);
+#else
+static inline int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid)
+{
+ return 0;
+}
+#endif
+
+int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr)
+{
+ enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid;
+ int ret;
+
+ if (fwvid >= ARRAY_SIZE(fwvid_list))
+ return -ERANGE;
+
+ brcmf_dbg(TRACE, "mod=%s: enter: dev %s\n", fwvid_list[fwvid].name,
+ dev_name(drvr->bus_if->dev));
+
+ mutex_lock(&fwvid_list_lock);
+
+ ret = brcmf_fwvid_request_module(fwvid);
+ if (ret)
+ return ret;
+
+ drvr->vops = fwvid_list[fwvid].vops;
+ list_add(&drvr->bus_if->list, &fwvid_list[fwvid].drvr_list);
+
+ mutex_unlock(&fwvid_list_lock);
+
+ return ret;
+}
+
+void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr)
+{
+ enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid;
+
+ if (fwvid >= ARRAY_SIZE(fwvid_list))
+ return;
+
+ brcmf_dbg(TRACE, "mod=%s: enter: dev %s\n", fwvid_list[fwvid].name,
+ dev_name(drvr->bus_if->dev));
+
+ mutex_lock(&fwvid_list_lock);
+
+ drvr->vops = NULL;
+ list_del(&drvr->bus_if->list);
+
+ mutex_unlock(&fwvid_list_lock);
+}
+
+const char *brcmf_fwvid_vendor_name(struct brcmf_pub *drvr)
+{
+ return fwvid_list[drvr->bus_if->fwvid].name;
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h
new file mode 100644
index 000000000000..43df58bb70ad
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: ISC */
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#ifndef FWVID_H_
+#define FWVID_H_
+
+#include "firmware.h"
+
+struct brcmf_pub;
+
+struct brcmf_fwvid_ops {
+ int (*attach)(struct brcmf_pub *drvr);
+ void (*detach)(struct brcmf_pub *drvr);
+};
+
+/* exported functions */
+int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *mod,
+ const struct brcmf_fwvid_ops *ops);
+int brcmf_fwvid_unregister_vendor(enum brcmf_fwvendor fwvid, struct module *mod);
+
+/* core driver functions */
+int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr);
+void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr);
+const char *brcmf_fwvid_vendor_name(struct brcmf_pub *drvr);
+
+static inline int brcmf_fwvid_attach(struct brcmf_pub *drvr)
+{
+ int ret;
+
+ ret = brcmf_fwvid_attach_ops(drvr);
+ if (ret)
+ return ret;
+
+ return drvr->vops->attach(drvr);
+}
+
+static inline void brcmf_fwvid_detach(struct brcmf_pub *drvr)
+{
+ if (!drvr->vops)
+ return;
+
+ drvr->vops->detach(drvr);
+ brcmf_fwvid_detach_ops(drvr);
+}
+
+#endif /* FWVID_H_ */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index cf564adc612a..ae57a9a3ab05 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -736,7 +736,7 @@ static int brcmf_pcie_exit_download_state(struct brcmf_pciedev_info *devinfo,
}
if (!brcmf_chip_set_active(devinfo->ci, resetintr))
- return -EINVAL;
+ return -EIO;
return 0;
}
@@ -2389,6 +2389,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
bus->bus_priv.pcie = pcie_bus_dev;
bus->ops = &brcmf_pcie_bus_ops;
bus->proto_type = BRCMF_PROTO_MSGBUF;
+ bus->fwvid = id->driver_data;
bus->chip = devinfo->coreid;
bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot);
dev_set_drvdata(&pdev->dev, bus);
@@ -2570,38 +2571,47 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = {
#endif /* CONFIG_PM */
-#define BRCMF_PCIE_DEVICE(dev_id) { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
-#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev) { \
- BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
- subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
+#define BRCMF_PCIE_DEVICE(dev_id, fw_vend) \
+ { \
+ BRCM_PCIE_VENDOR_ID_BROADCOM, (dev_id), \
+ PCI_ANY_ID, PCI_ANY_ID, \
+ PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \
+ BRCMF_FWVENDOR_ ## fw_vend \
+ }
+#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev, fw_vend) \
+ { \
+ BRCM_PCIE_VENDOR_ID_BROADCOM, (dev_id), \
+ (subvend), (subdev), \
+ PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \
+ BRCMF_FWVENDOR_ ## fw_vend \
+ }
static const struct pci_device_id brcmf_pcie_devid_table[] = {
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
- BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_RAW_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_RAW_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4359_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4364_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID),
- BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID),
- BRCMF_PCIE_DEVICE(CY_PCIE_89459_DEVICE_ID),
- BRCMF_PCIE_DEVICE(CY_PCIE_89459_RAW_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_RAW_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_RAW_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4359_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4364_DEVICE_ID, BCA),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID, BCA),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID, BCA),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID, BCA),
+ BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365, BCA),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID, BCA),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID, BCA),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID, BCA),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(CY_PCIE_89459_DEVICE_ID, CYW),
+ BRCMF_PCIE_DEVICE(CY_PCIE_89459_RAW_DEVICE_ID, CYW),
{ /* end: all zeroes */ }
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 244ba48cc304..6b38d9de71af 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -3412,6 +3412,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
/* Take arm out of reset */
if (!brcmf_chip_set_active(bus->ci, rstvec)) {
brcmf_err("error getting out of ARM core reset\n");
+ bcmerror = -EIO;
goto err;
}
@@ -4171,6 +4172,15 @@ static int brcmf_sdio_bus_reset(struct device *dev)
return 0;
}
+static void brcmf_sdio_bus_remove(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio;
+
+ device_release_driver(&sdiod->func2->dev);
+ device_release_driver(&sdiod->func1->dev);
+}
+
static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.stop = brcmf_sdio_bus_stop,
.preinit = brcmf_sdio_bus_preinit,
@@ -4183,7 +4193,8 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.get_memdump = brcmf_sdio_bus_get_memdump,
.get_blob = brcmf_sdio_get_blob,
.debugfs_create = brcmf_sdio_debugfs_create,
- .reset = brcmf_sdio_bus_reset
+ .reset = brcmf_sdio_bus_reset,
+ .remove = brcmf_sdio_bus_remove,
};
#define BRCMF_SDIO_FW_CODE 0
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 85e18fb9c497..246843aeb696 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1240,7 +1240,8 @@ brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo)
return fwreq;
}
-static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
+static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
+ enum brcmf_fwvendor fwvid)
{
struct brcmf_bus *bus = NULL;
struct brcmf_usbdev *bus_pub = NULL;
@@ -1265,6 +1266,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
dev_set_drvdata(dev, bus);
bus->ops = &brcmf_usb_bus_ops;
bus->proto_type = BRCMF_PROTO_BCDC;
+ bus->fwvid = fwvid;
bus->always_use_fws_queue = true;
#ifdef CONFIG_PM
bus->wowl_supported = true;
@@ -1423,7 +1425,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
else
brcmf_dbg(USB, "Broadcom full speed USB WLAN interface detected\n");
- ret = brcmf_usb_probe_cb(devinfo);
+ ret = brcmf_usb_probe_cb(devinfo, id->driver_info);
if (ret)
goto fail;
@@ -1511,14 +1513,23 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf)
return ret;
}
-#define BRCMF_USB_DEVICE(dev_id) \
- { USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id) }
+#define BRCMF_USB_DEVICE(dev_id) \
+ { \
+ USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id), \
+ .driver_info = BRCMF_FWVENDOR_WCC \
+ }
-#define LINKSYS_USB_DEVICE(dev_id) \
- { USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id) }
+#define LINKSYS_USB_DEVICE(dev_id) \
+ { \
+ USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id), \
+ .driver_info = BRCMF_FWVENDOR_WCC \
+ }
-#define CYPRESS_USB_DEVICE(dev_id) \
- { USB_DEVICE(CY_USB_VENDOR_ID_CYPRESS, dev_id) }
+#define CYPRESS_USB_DEVICE(dev_id) \
+ { \
+ USB_DEVICE(CY_USB_VENDOR_ID_CYPRESS, dev_id), \
+ .driver_info = BRCMF_FWVENDOR_WCC \
+ }
static const struct usb_device_id brcmf_usb_devid_table[] = {
BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID),
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/Makefile
new file mode 100644
index 000000000000..7f455a19a2b1
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: ISC
+#
+# Copyright (c) 2022 Broadcom Corporation
+
+ccflags-y += \
+ -I $(srctree)/$(src) \
+ -I $(srctree)/$(src)/.. \
+ -I $(srctree)/$(src)/../../include
+
+obj-m += brcmfmac-wcc.o
+brcmfmac-wcc-objs += \
+ core.o module.o
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c
new file mode 100644
index 000000000000..02de99818efa
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <core.h>
+#include <bus.h>
+#include <fwvid.h>
+
+#include "vops.h"
+
+static int brcmf_wcc_attach(struct brcmf_pub *drvr)
+{
+ pr_err("%s: executing\n", __func__);
+ return 0;
+}
+
+static void brcmf_wcc_detach(struct brcmf_pub *drvr)
+{
+ pr_err("%s: executing\n", __func__);
+}
+
+const struct brcmf_fwvid_ops brcmf_wcc_ops = {
+ .attach = brcmf_wcc_attach,
+ .detach = brcmf_wcc_detach,
+};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c
new file mode 100644
index 000000000000..02918d434556
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#include <linux/module.h>
+#include <bus.h>
+#include <core.h>
+#include <fwvid.h>
+
+#include "vops.h"
+
+static int __init brcmf_wcc_init(void)
+{
+ return brcmf_fwvid_register_vendor(BRCMF_FWVENDOR_WCC, THIS_MODULE,
+ &brcmf_wcc_ops);
+}
+
+static void __exit brcmf_wcc_exit(void)
+{
+ brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_WCC, THIS_MODULE);
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(BRCMFMAC);
+
+module_init(brcmf_wcc_init);
+module_exit(brcmf_wcc_exit);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/vops.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/vops.h
new file mode 100644
index 000000000000..3aec44f80600
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/vops.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: ISC */
+/*
+ * Copyright (c) 2022 Broadcom Corporation
+ */
+#ifndef _BRCMFMAC_WCC_VOPS_H
+#define _BRCMFMAC_WCC_VOPS_H
+
+extern const struct brcmf_fwvid_ops brcmf_wcc_ops;
+#define WCC_VOPS (&brcmf_wcc_ops)
+
+#endif /* _BRCMFMAC_WCC_VOPS_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
index b0f23cf1a621..0812db8936f1 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -418,17 +418,6 @@ static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
}
-static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr)
-{
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
-}
-
-static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
-{
- write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
-}
-
static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
const u8 * buf)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
index d07982d8c897..9263413ee06f 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
@@ -382,9 +382,11 @@ enum iwl_scd_queue_cfg_operation {
* @u.add.cb_size: size code
* @u.add.bc_dram_addr: byte-count table IOVA
* @u.add.tfdq_dram_addr: TFD queue IOVA
- * @u.remove.queue: queue ID for removal
- * @u.modify.sta_mask: new station mask for modify
- * @u.modify.queue: queue ID to modify
+ * @u.remove.sta_mask: station mask of queue to remove
+ * @u.remove.tid: TID of queue to remove
+ * @u.modify.old_sta_mask: old station mask for modify
+ * @u.modify.tid: TID of queue to modify
+ * @u.modify.new_sta_mask: new station mask for modify
*/
struct iwl_scd_queue_cfg_cmd {
__le32 operation;
@@ -399,11 +401,13 @@ struct iwl_scd_queue_cfg_cmd {
__le64 tfdq_dram_addr;
} __packed add; /* TX_QUEUE_CFG_CMD_ADD_API_S_VER_1 */
struct {
- __le32 queue;
+ __le32 sta_mask;
+ __le32 tid;
} __packed remove; /* TX_QUEUE_CFG_CMD_REMOVE_API_S_VER_1 */
struct {
- __le32 sta_mask;
- __le32 queue;
+ __le32 old_sta_mask;
+ __le32 tid;
+ __le32 new_sta_mask;
} __packed modify; /* TX_QUEUE_CFG_CMD_MODIFY_API_S_VER_1 */
} __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1 */
} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3 */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
index b90f1e9ce691..792f7fee1840 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -157,7 +157,8 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu
base = fwrt->fw->inst_errlog_ptr;
}
- if (base < 0x400000) {
+ if ((fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ && !base) ||
+ (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ && base < 0x400000)) {
IWL_ERR(fwrt,
"Not valid error log pointer 0x%08X for %s uCode\n",
base,
@@ -376,7 +377,7 @@ static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt)
return;
}
- error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS);
+ error = iwl_read_umac_prph(trans, error);
IWL_ERR(trans, "IML/ROM dump:\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 476b90f32626..aa8e08487b52 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -1964,6 +1964,8 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
!!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED);
nvm->sku_cap_mimo_disabled =
!!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED);
+ if (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM)
+ nvm->sku_cap_11be_enable = true;
/* Initialize PHY sku data */
nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 32bd7f19f1d5..479a518c89a1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -976,6 +976,8 @@ struct iwl_trans_txqs {
* @max_skb_frags: maximum number of fragments an SKB can have when transmitted.
* 0 indicates that frag SKBs (NETIF_F_SG) aren't supported.
* @hw_rf_id a u32 with the device RF ID
+ * @hw_crf_id a u32 with the device CRF ID
+ * @hw_cdb_id a u32 with the device CDB ID
* @hw_id: a u32 with the ID of the device / sub-device.
* Set during transport allocation.
* @hw_id_str: a string with info about HW ID. Set during transport allocation.
@@ -1015,6 +1017,8 @@ struct iwl_trans {
u32 hw_rev;
u32 hw_rev_step;
u32 hw_rf_id;
+ u32 hw_crf_id;
+ u32 hw_cdb_id;
u32 hw_id;
char hw_id_str[52];
u32 sku_id[3];
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
index 2b639eef595d..ae66192feefe 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
+++ b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2021 Intel Corporation
*/
@@ -13,7 +13,7 @@
/**
* DOC: Introduction
*
- * iwlmei is the kernel module that is in charge of the commnunication between
+ * iwlmei is the kernel module that is in charge of the communication between
* the iwlwifi driver and the CSME firmware's WLAN driver. This communication
* uses the SAP protocol defined in another file.
* iwlwifi can request or release ownership on the WiFi device through iwlmei.
@@ -348,7 +348,7 @@ void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill);
/**
* iwl_mei_set_nic_info() - set mac address
* @mac_address: mac address to set
- * @nvm_address: NVM mac adsress to set
+ * @nvm_address: NVM mac address to set
*
* This function must be called upon mac address change.
*/
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c
index b89989b6399a..f9d11935ed97 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c
@@ -1963,7 +1963,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
iwl_mei_dbgfs_register(mei);
/*
- * We now have a Rx function in place, start the SAP procotol
+ * We now have a Rx function in place, start the SAP protocol
* we expect to get the SAP_ME_MSG_START_OK response later on.
*/
mutex_lock(&iwl_mei_mutex);
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/sap.h b/drivers/net/wireless/intel/iwlwifi/mei/sap.h
index 6c0ad4adbf32..3b56637b9697 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/sap.h
+++ b/drivers/net/wireless/intel/iwlwifi/mei/sap.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2021 - 2022 Intel Corporation
*/
@@ -25,7 +25,7 @@
*
* Since this messaging system cannot support high amounts of
* traffic, iwlwifi and the CSME firmware's WLAN driver have an
- * addtional communication pipe to exchange information. The body
+ * additional communication pipe to exchange information. The body
* of the message is copied to a shared area and the message that
* goes over the ME interface just signals the other side
* that a new message is waiting in the shared area. The ME
@@ -55,7 +55,7 @@
/**
* DOC: Host and driver state messages
*
- * In order to let CSME konw about the host state and the host driver state,
+ * In order to let CSME know about the host state and the host driver state,
* the host sends messages that let CSME know about the host's state.
* When the host driver is loaded, the host sends %SAP_MSG_NOTIF_WIFIDR_UP.
* When the host driver is unloaded, the host sends %SAP_MSG_NOTIF_WIFIDR_DOWN.
@@ -76,7 +76,7 @@
* DOC: Ownership
*
* The device can be controlled either by the CSME firmware or
- * by the host driver: iwlwifi. There is a negotiaion between
+ * by the host driver: iwlwifi. There is a negotiation between
* those two entities to determine who controls (or owns) the
* device. Since the CSME can control the device even when the
* OS is not working or even missing, the CSME can request the
@@ -136,7 +136,7 @@ enum iwl_sap_me_msg_id {
* struct iwl_sap_me_msg_hdr - the header of the ME message
* @type: the type of the message, see &enum iwl_sap_me_msg_id.
* @seq_num: a sequence number used for debug only.
- * @len: the length of the mssage.
+ * @len: the length of the message.
*/
struct iwl_sap_me_msg_hdr {
__le32 type;
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h b/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h
index 83639c6225ca..15cb0bb4e9dc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h
+++ b/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2021 Intel Corporation
*/
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/trace.h b/drivers/net/wireless/intel/iwlwifi/mei/trace.h
index 45ecb22ec84a..20ff836733bb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/trace.h
+++ b/drivers/net/wireless/intel/iwlwifi/mei/trace.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2021 Intel Corporation
*/
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 919b1f478b4c..c5ad34b063df 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -599,6 +599,11 @@ static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw,
switch (key->cipher) {
default:
return;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (!sta)
+ data->kek_kck_cmd->gtk_cipher =
+ cpu_to_le32(STA_KEY_FLG_TKIP);
+ return;
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_GCMP);
@@ -610,13 +615,13 @@ static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw,
if (!sta)
data->kek_kck_cmd->gtk_cipher =
cpu_to_le32(STA_KEY_FLG_CCM);
- break;
+ return;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
if (!sta)
data->kek_kck_cmd->gtk_cipher =
cpu_to_le32(STA_KEY_FLG_GCMP);
- break;
+ return;
}
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
index 8c5b97fb1941..6eee3d0b2157 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
@@ -1010,11 +1010,10 @@ static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id,
static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,
struct cfg80211_pmsr_result *res)
{
- struct iwl_mvm_smooth_entry *resp;
+ struct iwl_mvm_smooth_entry *resp = NULL, *iter;
s64 rtt_avg, rtt = res->ftm.rtt_avg;
u32 undershoot, overshoot;
u8 alpha;
- bool found;
if (!IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH)
return;
@@ -1028,15 +1027,14 @@ static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,
return;
}
- found = false;
- list_for_each_entry(resp, &mvm->ftm_initiator.smooth.resp, list) {
- if (!memcmp(res->addr, resp->addr, ETH_ALEN)) {
- found = true;
+ list_for_each_entry(iter, &mvm->ftm_initiator.smooth.resp, list) {
+ if (!memcmp(res->addr, iter->addr, ETH_ALEN)) {
+ resp = iter;
break;
}
}
- if (!found) {
+ if (!resp) {
resp = kzalloc(sizeof(*resp), GFP_KERNEL);
if (!resp)
return;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 0a41cd0ab243..0c6b49fcb00d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -122,6 +122,9 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
u32 version = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
UCODE_ALIVE_NTFY, 0);
u32 i;
+ struct iwl_trans *trans = mvm->trans;
+ enum iwl_device_family device_family = trans->trans_cfg->device_family;
+
if (version == 6) {
struct iwl_alive_ntf_v6 *palive;
@@ -230,7 +233,8 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
if (umac_error_table) {
if (umac_error_table >=
- mvm->trans->cfg->min_umac_error_event_table) {
+ mvm->trans->cfg->min_umac_error_event_table ||
+ device_family >= IWL_DEVICE_FAMILY_BZ) {
iwl_fw_umac_set_alive_err_table(mvm->trans,
umac_error_table);
} else {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index e78f5beaa2d0..ebe6d9c4ccaf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -92,6 +92,12 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
radio_cfg_dash = (phy_config & FW_PHY_CFG_RADIO_DASH) >>
FW_PHY_CFG_RADIO_DASH_POS;
+ IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type,
+ radio_cfg_step, radio_cfg_dash);
+
+ if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
+ return;
+
/* SKU control */
reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->hw_rev);
@@ -127,9 +133,6 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
CSR_HW_IF_CONFIG_REG_D3_DEBUG,
reg_val);
- IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type,
- radio_cfg_step, radio_cfg_dash);
-
/*
* W/A : NIC is stuck in a reset state after Early PCIe power off
* (PCIe power is lost before PERST# is asserted), causing ME FW
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 5f782ca1e254..97b67270f384 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -2066,22 +2066,30 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
struct ieee80211_rx_status *rx_status;
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_rx_no_data *desc = (void *)pkt->data;
- u32 rssi = le32_to_cpu(desc->rssi);
- u32 info_type = le32_to_cpu(desc->info) & RX_NO_DATA_INFO_TYPE_MSK;
+ u32 rssi;
+ u32 info_type;
struct ieee80211_sta *sta = NULL;
struct sk_buff *skb;
- struct iwl_mvm_rx_phy_data phy_data = {
- .d0 = desc->phy_info[0],
- .d1 = desc->phy_info[1],
- .phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD,
- .gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time),
- .rate_n_flags = le32_to_cpu(desc->rate),
- .energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK),
- .energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK),
- .channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK),
- };
+ struct iwl_mvm_rx_phy_data phy_data;
u32 format;
+ if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))
+ return;
+
+ if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(struct iwl_rx_no_data)))
+ return;
+
+ rssi = le32_to_cpu(desc->rssi);
+ info_type = le32_to_cpu(desc->info) & RX_NO_DATA_INFO_TYPE_MSK;
+ phy_data.d0 = desc->phy_info[0];
+ phy_data.d1 = desc->phy_info[1];
+ phy_data.phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD;
+ phy_data.gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time);
+ phy_data.rate_n_flags = le32_to_cpu(desc->rate);
+ phy_data.energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK);
+ phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK);
+ phy_data.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK);
+
if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
RX_NO_DATA_NOTIF, 0) < 2) {
IWL_DEBUG_DROP(mvm, "Got an old rate format. Old rate: 0x%x\n",
@@ -2093,12 +2101,6 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
- if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*desc)))
- return;
-
- if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))
- return;
-
/* Dont use dev_alloc_skb(), we'll have enough headroom once
* ieee80211_hdr pulled.
*/
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 515dd3e0730d..6c9c5d6e7783 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -316,7 +316,7 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue,
}
static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- u16 *queueptr, u8 tid)
+ int sta_id, u16 *queueptr, u8 tid)
{
int queue = *queueptr;
struct iwl_scd_txq_cfg_cmd cmd = {
@@ -333,7 +333,8 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
SCD_QUEUE_CONFIG_CMD);
struct iwl_scd_queue_cfg_cmd remove_cmd = {
.operation = cpu_to_le32(IWL_SCD_QUEUE_REMOVE),
- .u.remove.queue = cpu_to_le32(queue),
+ .u.remove.tid = cpu_to_le32(tid),
+ .u.remove.sta_mask = cpu_to_le32(BIT(sta_id)),
};
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0,
@@ -531,7 +532,7 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue,
iwl_mvm_invalidate_sta_queue(mvm, queue,
disable_agg_tids, false);
- ret = iwl_mvm_disable_txq(mvm, old_sta, &queue_tmp, tid);
+ ret = iwl_mvm_disable_txq(mvm, old_sta, sta_id, &queue_tmp, tid);
if (ret) {
IWL_ERR(mvm,
"Failed to free inactive queue %d (ret=%d)\n",
@@ -1408,7 +1409,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
out_err:
queue_tmp = queue;
- iwl_mvm_disable_txq(mvm, sta, &queue_tmp, tid);
+ iwl_mvm_disable_txq(mvm, sta, mvmsta->sta_id, &queue_tmp, tid);
return ret;
}
@@ -1854,7 +1855,8 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm,
if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE)
continue;
- iwl_mvm_disable_txq(mvm, sta, &mvm_sta->tid_data[i].txq_id, i);
+ iwl_mvm_disable_txq(mvm, sta, mvm_sta->sta_id,
+ &mvm_sta->tid_data[i].txq_id, i);
mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE;
}
@@ -2065,7 +2067,7 @@ static int iwl_mvm_add_int_sta_with_queue(struct iwl_mvm *mvm, int macidx,
ret = iwl_mvm_add_int_sta_common(mvm, sta, addr, macidx, maccolor);
if (ret) {
if (!iwl_mvm_has_new_tx_api(mvm))
- iwl_mvm_disable_txq(mvm, NULL, queue,
+ iwl_mvm_disable_txq(mvm, NULL, sta->sta_id, queue,
IWL_MAX_TID_COUNT);
return ret;
}
@@ -2138,7 +2140,8 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA))
return -EINVAL;
- iwl_mvm_disable_txq(mvm, NULL, &mvm->snif_queue, IWL_MAX_TID_COUNT);
+ iwl_mvm_disable_txq(mvm, NULL, mvm->snif_sta.sta_id,
+ &mvm->snif_queue, IWL_MAX_TID_COUNT);
ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id);
if (ret)
IWL_WARN(mvm, "Failed sending remove station\n");
@@ -2155,7 +2158,8 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm)
if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA))
return -EINVAL;
- iwl_mvm_disable_txq(mvm, NULL, &mvm->aux_queue, IWL_MAX_TID_COUNT);
+ iwl_mvm_disable_txq(mvm, NULL, mvm->aux_sta.sta_id,
+ &mvm->aux_queue, IWL_MAX_TID_COUNT);
ret = iwl_mvm_rm_sta_common(mvm, mvm->aux_sta.sta_id);
if (ret)
IWL_WARN(mvm, "Failed sending remove station\n");
@@ -2272,7 +2276,8 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm,
}
queue = *queueptr;
- iwl_mvm_disable_txq(mvm, NULL, queueptr, IWL_MAX_TID_COUNT);
+ iwl_mvm_disable_txq(mvm, NULL, mvmvif->bcast_sta.sta_id,
+ queueptr, IWL_MAX_TID_COUNT);
if (iwl_mvm_has_new_tx_api(mvm))
return;
@@ -2507,7 +2512,8 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true);
- iwl_mvm_disable_txq(mvm, NULL, &mvmvif->cab_queue, 0);
+ iwl_mvm_disable_txq(mvm, NULL, mvmvif->mcast_sta.sta_id,
+ &mvmvif->cab_queue, 0);
ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id);
if (ret)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index ed8ba81a6043..e403a240a82f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -376,12 +376,11 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
struct iwl_time_event_notif *notif)
{
- struct iwl_mvm_time_event_data *te_data, *tmp;
- bool aux_roc_te = false;
+ struct iwl_mvm_time_event_data *aux_roc_te = NULL, *te_data;
- list_for_each_entry_safe(te_data, tmp, &mvm->aux_roc_te_list, list) {
+ list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
if (le32_to_cpu(notif->unique_id) == te_data->uid) {
- aux_roc_te = true;
+ aux_roc_te = te_data;
break;
}
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 4f699862e7f7..99768d6a6032 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -1350,15 +1350,13 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
};
/*
- * In case that there is no OTP on the NIC, get the rf id and cdb info
- * from the prph registers.
+ * Read rf id and cdb info from prph register and store it
*/
static int get_crf_id(struct iwl_trans *iwl_trans)
{
int ret = 0;
u32 sd_reg_ver_addr;
- u32 cdb = 0;
- u32 val;
+ u32 val = 0;
if (iwl_trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
sd_reg_ver_addr = SD_REG_VER_GEN2;
@@ -1377,10 +1375,26 @@ static int get_crf_id(struct iwl_trans *iwl_trans)
iwl_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val);
/* Read crf info */
- val = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr);
+ iwl_trans->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr);
/* Read cdb info (also contains the jacket info if needed in the future */
- cdb = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR);
+ iwl_trans->hw_cdb_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR);
+
+ iwl_trans_release_nic_access(iwl_trans);
+
+out:
+ return ret;
+}
+
+/*
+ * In case that there is no OTP on the NIC, map the rf id and cdb info
+ * from the prph registers.
+ */
+static int map_crf_id(struct iwl_trans *iwl_trans)
+{
+ int ret = 0;
+ u32 val = iwl_trans->hw_crf_id;
+ u32 cdb = iwl_trans->hw_cdb_id;
/* Map between crf id to rf id */
switch (REG_CRF_ID_TYPE(val)) {
@@ -1410,7 +1424,7 @@ static int get_crf_id(struct iwl_trans *iwl_trans)
IWL_ERR(iwl_trans,
"Can find a correct rfid for crf id 0x%x\n",
REG_CRF_ID_TYPE(val));
- goto out_release;
+ goto out;
}
@@ -1423,8 +1437,6 @@ static int get_crf_id(struct iwl_trans *iwl_trans)
IWL_INFO(iwl_trans, "Detected RF 0x%x from crf id 0x%x\n",
iwl_trans->hw_rf_id, REG_CRF_ID_TYPE(val));
-out_release:
- iwl_trans_release_nic_access(iwl_trans);
out:
return ret;
@@ -1544,6 +1556,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
iwl_trans->hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID);
+ get_crf_id(iwl_trans);
/*
* The RF_ID is set to zero in blank OTP so read version to
@@ -1552,7 +1565,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
if (iwl_trans->trans_cfg->rf_id &&
iwl_trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_9000 &&
- !CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) && get_crf_id(iwl_trans)) {
+ !CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) && map_crf_id(iwl_trans)) {
ret = -EINVAL;
goto out_free_trans;
}
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
index 136992f0200c..d26df4095da0 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
@@ -1240,7 +1240,7 @@ struct rtl8723bu_c2h {
u8 bw;
} __packed ra_report;
};
-};
+} __packed;
struct rtl8xxxu_fileops;
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
index 6dc1e5858e77..a7d76693c02d 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
@@ -780,6 +780,12 @@ static int rtl8192eu_iqk_path_a(struct rtl8xxxu_priv *priv)
*/
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00180);
+
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x20000);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0x07f77);
+
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
/* Path A IQK setting */
@@ -825,11 +831,16 @@ static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv)
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
- rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf117b);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf1173);
+
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_WE_LUT, 0x800a0);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x30000);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G1, 0x0000f);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf1173);
/* PA/PAD control by 0x56, and set = 0x0 */
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00980);
- rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x51000);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x511e0);
/* Enter IQK mode */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
@@ -844,14 +855,14 @@ static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv)
rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c);
rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
- rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c1f);
- rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x68160c1f);
+ rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x8216031f);
+ rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x6816031f);
/* LO calibration setting */
rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911);
/* One shot, path A LOK & IQK */
- rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000);
+ rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
mdelay(10);
@@ -882,11 +893,16 @@ static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv)
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
- rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7ffa);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7ff2);
+
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_WE_LUT, 0x800a0);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x30000);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G1, 0x0000f);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf7ff2);
/* PA/PAD control by 0x56, and set = 0x0 */
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00980);
- rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x51000);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x510e0);
/* Enter IQK mode */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
@@ -900,14 +916,14 @@ static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv)
rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c);
rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
- rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c1f);
- rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c1f);
+ rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x821608ff);
+ rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x281608ff);
/* LO calibration setting */
rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a891);
/* One shot, path A LOK & IQK */
- rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000);
+ rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
mdelay(10);
@@ -937,9 +953,12 @@ static int rtl8192eu_iqk_path_b(struct rtl8xxxu_priv *priv)
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00180);
- rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
- rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_WE_LUT, 0x800a0);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x20000);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G1, 0x0000f);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0x07f77);
+
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
/* Path B IQK setting */
@@ -948,11 +967,11 @@ static int rtl8192eu_iqk_path_b(struct rtl8xxxu_priv *priv)
rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x18008c1c);
rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
- rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x821403e2);
+ rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82140303);
rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x68160000);
/* LO calibration setting */
- rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00492911);
+ rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00462911);
/* One shot, path A LOK & IQK */
rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000);
@@ -988,11 +1007,16 @@ static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv)
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_WE_LUT, 0x800a0);
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x30000);
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G1, 0x0000f);
- rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf117b);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf1173);
+
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf1173);
/* PA/PAD control by 0x56, and set = 0x0 */
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00980);
- rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x51000);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x511e0);
/* Enter IQK mode */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
@@ -1007,8 +1031,8 @@ static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv)
rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x18008c1c);
rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
- rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82160c1f);
- rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x68160c1f);
+ rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x8216031f);
+ rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x6816031f);
/* LO calibration setting */
rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911);
@@ -1048,11 +1072,16 @@ static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv)
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_WE_LUT, 0x800a0);
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x30000);
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G1, 0x0000f);
- rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf7ffa);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf7ff2);
+
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
+ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7ff2);
/* PA/PAD control by 0x56, and set = 0x0 */
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00980);
- rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x51000);
+ rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x510e0);
/* Enter IQK mode */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
@@ -1066,8 +1095,8 @@ static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv)
rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c);
rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x18008c1c);
- rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c1f);
- rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c1f);
+ rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x821608ff);
+ rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x281608ff);
/* LO calibration setting */
rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a891);
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 28f136064297..3ed435401e57 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -4598,6 +4598,32 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time)
}
}
+static void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt,
+ u8 rate, u8 sgi, u8 bw)
+{
+ u8 mcs, nss;
+
+ rarpt->txrate.flags = 0;
+
+ if (rate <= DESC_RATE_54M) {
+ rarpt->txrate.legacy = rtl8xxxu_legacy_ratetable[rate].bitrate;
+ } else {
+ rtl8xxxu_desc_to_mcsrate(rate, &mcs, &nss);
+ rarpt->txrate.flags |= RATE_INFO_FLAGS_MCS;
+
+ rarpt->txrate.mcs = mcs;
+ rarpt->txrate.nss = nss;
+
+ if (sgi)
+ rarpt->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+ rarpt->txrate.bw = bw;
+ }
+
+ rarpt->bit_rate = cfg80211_calculate_bitrate(&rarpt->txrate);
+ rarpt->desc_rate = rate;
+}
+
static void
rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, u64 changed)
@@ -4620,9 +4646,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 ramask;
int sgi = 0;
u8 highest_rate;
- u8 mcs = 0, nss = 0;
- u32 bit_rate;
-
+ u8 bw;
rcu_read_lock();
sta = ieee80211_find_sta(vif, bss_conf->bssid);
@@ -4647,37 +4671,19 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
sgi = 1;
highest_rate = fls(ramask) - 1;
- if (highest_rate < DESC_RATE_MCS0) {
- rarpt->txrate.legacy =
- rtl8xxxu_legacy_ratetable[highest_rate].bitrate;
- } else {
- rtl8xxxu_desc_to_mcsrate(highest_rate,
- &mcs, &nss);
- rarpt->txrate.flags |= RATE_INFO_FLAGS_MCS;
-
- rarpt->txrate.mcs = mcs;
- rarpt->txrate.nss = nss;
-
- if (sgi) {
- rarpt->txrate.flags |=
- RATE_INFO_FLAGS_SHORT_GI;
- }
-
- if (rtl8xxxu_ht40_2g &&
- (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
- rarpt->txrate.bw = RATE_INFO_BW_40;
- else
- rarpt->txrate.bw = RATE_INFO_BW_20;
- }
+ if (rtl8xxxu_ht40_2g &&
+ (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+ bw = RATE_INFO_BW_40;
+ else
+ bw = RATE_INFO_BW_20;
rcu_read_unlock();
- bit_rate = cfg80211_calculate_bitrate(&rarpt->txrate);
- rarpt->bit_rate = bit_rate;
- rarpt->desc_rate = highest_rate;
+
+ rtl8xxxu_update_ra_report(rarpt, highest_rate, sgi, bw);
priv->vif = vif;
priv->rssi_level = RTL8XXXU_RATR_STA_INIT;
- priv->fops->update_rate_mask(priv, ramask, 0, sgi, rarpt->txrate.bw == RATE_INFO_BW_40);
+ priv->fops->update_rate_mask(priv, ramask, 0, sgi, bw == RATE_INFO_BW_40);
rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
@@ -5538,9 +5544,7 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work)
u8 bt_info = 0;
struct rtl8xxxu_btcoex *btcoex;
struct rtl8xxxu_ra_report *rarpt;
- u8 rate, sgi, bw;
- u32 bit_rate;
- u8 mcs = 0, nss = 0;
+ u8 bw;
priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work);
btcoex = &priv->bt_coex;
@@ -5566,32 +5570,17 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work)
rtl8723bu_handle_bt_info(priv);
break;
case C2H_8723B_RA_REPORT:
- rarpt->txrate.flags = 0;
- rate = c2h->ra_report.rate;
- sgi = c2h->ra_report.sgi;
- bw = c2h->ra_report.bw;
-
- if (rate < DESC_RATE_MCS0) {
- rarpt->txrate.legacy =
- rtl8xxxu_legacy_ratetable[rate].bitrate;
- } else {
- rtl8xxxu_desc_to_mcsrate(rate, &mcs, &nss);
- rarpt->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ bw = rarpt->txrate.bw;
- rarpt->txrate.mcs = mcs;
- rarpt->txrate.nss = nss;
-
- if (sgi) {
- rarpt->txrate.flags |=
- RATE_INFO_FLAGS_SHORT_GI;
- }
-
- if (bw == RATE_INFO_BW_20)
- rarpt->txrate.bw |= RATE_INFO_BW_20;
+ if (skb->len >= offsetofend(typeof(*c2h), ra_report.bw)) {
+ if (c2h->ra_report.bw == RTL8XXXU_CHANNEL_WIDTH_40)
+ bw = RATE_INFO_BW_40;
+ else
+ bw = RATE_INFO_BW_20;
}
- bit_rate = cfg80211_calculate_bitrate(&rarpt->txrate);
- rarpt->bit_rate = bit_rate;
- rarpt->desc_rate = rate;
+
+ rtl8xxxu_update_ra_report(rarpt, c2h->ra_report.rate,
+ c2h->ra_report.sgi, bw);
break;
default:
break;
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
index 70492929d7e4..039bbedb41c2 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
@@ -1903,7 +1903,7 @@ btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoexist)
true, 32);
halbtc8723b1ant_coex_table_with_type(btcoexist,
NORMAL_EXEC, 4);
- } else if (bt_link_info->a2dp_exist) {
+ } else if (bt_link_info->pan_exist) {
halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 22);
halbtc8723b1ant_coex_table_with_type(btcoexist,
@@ -1964,8 +1964,7 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist)
true, 32);
halbtc8723b1ant_coex_table_with_type(btcoexist,
NORMAL_EXEC, 4);
- } else if (bt_link_info->a2dp_exist &&
- bt_link_info->pan_exist) {
+ } else if (bt_link_info->pan_exist) {
halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 22);
halbtc8723b1ant_coex_table_with_type(btcoexist,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
index aaa004d4d6d0..09591a0b5a81 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
@@ -115,9 +115,6 @@ static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw,
retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
BLSSI_READBACK_DATA);
- retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
- BLSSI_READBACK_DATA);
-
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n",
rfpath, pphyreg->rf_rb, retvalue);
diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig
index e3d7cb6c1290..651ab56d9c6b 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
@@ -39,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
@@ -50,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
@@ -61,6 +86,17 @@ config RTW88_8723DE
802.11n PCIe wireless network adapter
+config RTW88_8723DU
+ tristate "Realtek 8723DU USB wireless network adapter"
+ depends on USB
+ select RTW88_CORE
+ select RTW88_USB
+ select RTW88_8723D
+ help
+ Select this option will enable support for 8723DU chipset
+
+ 802.11n USB wireless network adapter
+
config RTW88_8821CE
tristate "Realtek 8821CE PCI wireless network adapter"
depends on PCI
@@ -72,6 +108,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 834c66ec0af9..fe7293ee87b4 100644
--- a/drivers/net/wireless/realtek/rtw88/Makefile
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -26,23 +26,38 @@ 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
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
obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o
rtw88_8723de-objs := rtw8723de.o
+obj-$(CONFIG_RTW88_8723DU) += rtw88_8723du.o
+rtw88_8723du-objs := rtw8723du.o
+
obj-$(CONFIG_RTW88_8821C) += rtw88_8821c.o
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
rtw88_pci-objs := pci.o
+
+obj-$(CONFIG_RTW88_USB) += rtw88_usb.o
+rtw88_usb-objs := usb.o
diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c
index 6276ad624299..38697237ee5f 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 9ebe544e51d0..fa3d73b333ba 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);
@@ -390,7 +392,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;
}
@@ -414,7 +418,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);
@@ -519,6 +525,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) {
@@ -533,6 +541,8 @@ static int rtw_debug_get_rf_dump(struct seq_file *m, void *v)
seq_puts(m, "\n");
}
+ mutex_unlock(&rtwdev->mutex);
+
return 0;
}
@@ -831,7 +841,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;
}
@@ -1026,6 +1038,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);
@@ -1035,6 +1049,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/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index 5e760c884f89..82295ac6402e 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -322,7 +322,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) {
@@ -344,7 +344,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,
@@ -353,7 +353,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;
}
rtw_write32(rtwdev, box_ex_reg, le32_to_cpu(h2c_cmd->msg_ext));
@@ -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/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h
index 4c6fc6fb3f83..830d7532f2a3 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/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c
index c7e64f7036ac..98777f294945 100644
--- a/drivers/net/wireless/realtek/rtw88/mac.c
+++ b/drivers/net/wireless/realtek/rtw88/mac.c
@@ -1048,6 +1048,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/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index 07578ccc4bab..776a9a9884b5 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -487,8 +487,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);
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 67151dbf8384..888427cf3bdf 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1731,7 +1731,8 @@ static void rtw_load_firmware_cb(const struct firmware *firmware, void *context)
update_firmware_info(rtwdev, fw);
complete_all(&fw->completion);
- rtw_info(rtwdev, "Firmware version %u.%u.%u, H2C version %u\n",
+ rtw_info(rtwdev, "%sFirmware version %u.%u.%u, H2C version %u\n",
+ fw->type == RTW_WOWLAN_FW ? "WOW " : "",
fw->version, fw->sub_version, fw->sub_index, fw->h2c_version);
}
@@ -1757,6 +1758,7 @@ static int rtw_load_firmware(struct rtw_dev *rtwdev, enum rtw_fw_type type)
return -ENOENT;
}
+ fw->type = type;
fw->rtwdev = rtwdev;
init_completion(&fw->completion);
@@ -1781,6 +1783,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;
@@ -2065,13 +2071,10 @@ 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);
mutex_init(&rtwdev->mutex);
- mutex_init(&rtwdev->coex.mutex);
mutex_init(&rtwdev->hal.tx_power_mutex);
init_waitqueue_head(&rtwdev->coex.wait);
@@ -2143,7 +2146,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 bccd7b28f60c..165f299e8e1f 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -871,6 +871,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);
@@ -1501,8 +1505,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;
@@ -1851,6 +1853,7 @@ struct rtw_fw_state {
u16 h2c_version;
u32 feature;
u32 feature_ext;
+ enum rtw_fw_type type;
};
enum rtw_sar_sources {
@@ -1994,9 +1997,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;
@@ -2022,8 +2022,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;
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index bd7d05e08084..128e75a81bf3 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 c93da743681f..11594940d6b0 100644
--- a/drivers/net/wireless/realtek/rtw88/ps.c
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
@@ -61,7 +61,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/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
index 03bd8dc53f72..8852b24d6c2a 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/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c
index 0a4f770fcbb7..2d2f768bae2e 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c
@@ -210,6 +210,12 @@ static void rtw8723de_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr);
}
+static void rtw8723du_efuse_parsing(struct rtw_efuse *efuse,
+ struct rtw8723d_efuse *map)
+{
+ ether_addr_copy(efuse->addr, map->u.mac_addr);
+}
+
static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
@@ -239,6 +245,9 @@ static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_PCIE:
rtw8723de_efuse_parsing(efuse, map);
break;
+ case RTW_HCI_TYPE_USB:
+ rtw8723du_efuse_parsing(efuse, map);
+ break;
default:
/* unsupported now */
return -ENOTSUPP;
@@ -1945,6 +1954,24 @@ static void rtw8723d_pwr_track(struct rtw_dev *rtwdev)
dm_info->pwr_trk_triggered = false;
}
+static void rtw8723d_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) */
+ __le16 chksum = 0;
+ __le16 *data = (__le16 *)(txdesc);
+
+ SET_TX_DESC_TXDESC_CHECKSUM(txdesc, 0x0000);
+
+ while (words--)
+ chksum ^= *data++;
+
+ chksum = ~chksum;
+
+ SET_TX_DESC_TXDESC_CHECKSUM(txdesc, __le16_to_cpu(chksum));
+}
+
static struct rtw_chip_ops rtw8723d_ops = {
.phy_set_param = rtw8723d_phy_set_param,
.read_efuse = rtw8723d_read_efuse,
@@ -1965,6 +1992,7 @@ static struct rtw_chip_ops rtw8723d_ops = {
.config_bfee = NULL,
.set_gid_table = NULL,
.cfg_csi_rate = NULL,
+ .fill_txdesc_checksum = rtw8723d_fill_txdesc_checksum,
.coex_set_init = rtw8723d_coex_cfg_init,
.coex_set_ant_switch = NULL,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.h b/drivers/net/wireless/realtek/rtw88/rtw8723d.h
index 4641f6e047b4..a356318a5c15 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8723d.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.h
@@ -41,6 +41,14 @@ struct rtw8723de_efuse {
u8 sub_device_id[2];
};
+struct rtw8723du_efuse {
+ u8 res4[48]; /* 0xd0 */
+ u8 vender_id[2]; /* 0x100 */
+ u8 product_id[2]; /* 0x102 */
+ u8 usb_option; /* 0x104 */
+ u8 mac_addr[ETH_ALEN]; /* 0x107 */
+};
+
struct rtw8723d_efuse {
__le16 rtl_id;
u8 rsvd[2];
@@ -69,7 +77,10 @@ struct rtw8723d_efuse {
u8 rfe_option;
u8 country_code[2];
u8 res[3];
- struct rtw8723de_efuse e;
+ union {
+ struct rtw8723de_efuse e;
+ struct rtw8723du_efuse u;
+ };
};
extern const struct rtw_chip_info rtw8723d_hw_spec;
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723du.c b/drivers/net/wireless/realtek/rtw88/rtw8723du.c
new file mode 100644
index 000000000000..322a805da76b
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8723du.c
@@ -0,0 +1,36 @@
+// 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 "rtw8723d.h"
+#include "usb.h"
+
+static const struct usb_device_id rtw_8723du_id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd723, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&(rtw8723d_hw_spec) }, /* 8723DU 1*1 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd611, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&(rtw8723d_hw_spec) }, /* Edimax EW-7611ULB V2 */
+ { },
+};
+MODULE_DEVICE_TABLE(usb, rtw_8723du_id_table);
+
+static int rtw8723du_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return rtw_usb_probe(intf, id);
+}
+
+static struct usb_driver rtw_8723du_driver = {
+ .name = "rtw_8723du",
+ .id_table = rtw_8723du_id_table,
+ .probe = rtw8723du_probe,
+ .disconnect = rtw_usb_disconnect,
+};
+module_usb_driver(rtw_8723du_driver);
+
+MODULE_AUTHOR("Hans Ulli Kroll <linux@ulli-kroll.de>");
+MODULE_DESCRIPTION("Realtek 802.11n wireless 8723du driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
index 9afdc5ce86b4..17f800f6efbd 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;
@@ -1148,6 +1157,13 @@ 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)
+{
+ fill_txdesc_checksum_common(txdesc, 16);
+}
+
static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = {
{0x0086,
RTW_PWR_CUT_ALL_MSK,
@@ -1521,6 +1537,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[] = {
@@ -1595,6 +1612,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 2698801fc35d..1c81260f3a54 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 000000000000..7a5cbdc31ef7
--- /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 "rtw8821c.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/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
index 690e35c98f6e..74dfb89b2c94 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 000000000000..ab620a0b1dfc
--- /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 "rtw8822b.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/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index fccb15dfb959..964e27887fe2 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)
+{
+ const 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 000000000000..af28ca09d41f
--- /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 "rtw8822c.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/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h
index 8419603adce4..a2f3ac326041 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.h
+++ b/drivers/net/wireless/realtek/rtw88/tx.h
@@ -71,6 +71,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,
@@ -123,4 +131,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)
+{
+ const 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 000000000000..4ef38279b64c
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -0,0 +1,911 @@
+// 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 512
+
+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 u32 rtw_usb_read(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 idx, ret;
+ static int count;
+
+ spin_lock_irqsave(&rtwusb->usb_lock, flags);
+
+ idx = rtwusb->usb_data_index;
+ rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1);
+
+ spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
+
+ data = &rtwusb->usb_data[idx];
+
+ 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, "read register 0x%x failed with %d\n",
+ addr, ret);
+
+ return le32_to_cpu(*data);
+}
+
+static u8 rtw_usb_read8(struct rtw_dev *rtwdev, u32 addr)
+{
+ return (u8)rtw_usb_read(rtwdev, addr, 1);
+}
+
+static u16 rtw_usb_read16(struct rtw_dev *rtwdev, u32 addr)
+{
+ return (u16)rtw_usb_read(rtwdev, addr, 2);
+}
+
+static u32 rtw_usb_read32(struct rtw_dev *rtwdev, u32 addr)
+{
+ return (u32)rtw_usb_read(rtwdev, addr, 4);
+}
+
+static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len)
+{
+ struct rtw_usb *rtwusb = (struct rtw_usb *)rtwdev->priv;
+ struct usb_device *udev = rtwusb->udev;
+ unsigned long flags;
+ __le32 *data;
+ int idx, ret;
+ static int count;
+
+ spin_lock_irqsave(&rtwusb->usb_lock, flags);
+
+ idx = rtwusb->usb_data_index;
+ rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1);
+
+ spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
+
+ data = &rtwusb->usb_data[idx];
+
+ *data = cpu_to_le32(val);
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
+ addr, 0, data, len, 30000);
+ if (ret < 0 && ret != -ENODEV && count++ < 4)
+ rtw_err(rtwdev, "write register 0x%x failed with %d\n",
+ addr, ret);
+}
+
+static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val)
+{
+ rtw_usb_write(rtwdev, addr, val, 1);
+}
+
+static void rtw_usb_write16(struct rtw_dev *rtwdev, u32 addr, u16 val)
+{
+ rtw_usb_write(rtwdev, addr, val, 2);
+}
+
+static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
+{
+ rtw_usb_write(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] = 0;
+ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID7] = 0;
+ 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_write_port_tx_complete(struct urb *urb)
+{
+ struct rtw_usb_txcb *txcb = urb->context;
+ struct rtw_dev *rtwdev = txcb->rtwdev;
+ struct ieee80211_hw *hw = rtwdev->hw;
+
+ while (true) {
+ struct sk_buff *skb = skb_dequeue(&txcb->tx_ack_queue);
+ struct ieee80211_tx_info *info;
+ struct rtw_usb_tx_data *tx_data;
+
+ if (!skb)
+ break;
+
+ info = IEEE80211_SKB_CB(skb);
+ 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);
+ continue;
+ }
+
+ /* 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);
+ }
+
+ kfree(txcb);
+}
+
+static int qsel_to_ep(struct rtw_usb *rtwusb, unsigned int qsel)
+{
+ if (qsel >= ARRAY_SIZE(rtwusb->qsel_to_ep))
+ return 0;
+
+ return rtwusb->qsel_to_ep[qsel];
+}
+
+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 = qsel_to_ep(rtwusb, 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 bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list)
+{
+ struct rtw_dev *rtwdev = rtwusb->rtwdev;
+ struct rtw_usb_txcb *txcb;
+ struct sk_buff *skb_head;
+ struct sk_buff *skb_iter;
+ int agg_num = 0;
+ unsigned int align_next = 0;
+
+ if (skb_queue_empty(list))
+ return false;
+
+ txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC);
+ if (!txcb)
+ return false;
+
+ txcb->rtwdev = rtwdev;
+ skb_queue_head_init(&txcb->tx_ack_queue);
+
+ skb_iter = skb_dequeue(list);
+
+ if (skb_queue_empty(list)) {
+ skb_head = skb_iter;
+ goto queue;
+ }
+
+ skb_head = dev_alloc_skb(RTW_USB_MAX_XMITBUF_SZ);
+ if (!skb_head) {
+ skb_head = skb_iter;
+ goto queue;
+ }
+
+ while (skb_iter) {
+ unsigned long flags;
+
+ skb_put(skb_head, align_next);
+ skb_put_data(skb_head, skb_iter->data, skb_iter->len);
+
+ align_next = ALIGN(skb_iter->len, 8) - skb_iter->len;
+
+ agg_num++;
+
+ skb_queue_tail(&txcb->tx_ack_queue, skb_iter);
+
+ spin_lock_irqsave(&list->lock, flags);
+
+ skb_iter = skb_peek(list);
+
+ if (skb_iter && skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ)
+ __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);
+
+queue:
+ skb_queue_tail(&txcb->tx_ack_queue, skb_head);
+
+ rtw_usb_write_port(rtwdev, GET_TX_DESC_QSEL(skb_head->data), skb_head,
+ rtw_usb_write_port_tx_complete, txcb);
+
+ return true;
+}
+
+static void rtw_usb_tx_handler(struct work_struct *work)
+{
+ struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, tx_work);
+ int i, limit;
+
+ for (i = ARRAY_SIZE(rtwusb->tx_queue) - 1; i >= 0; i--) {
+ for (limit = 0; limit < 200; limit++) {
+ struct sk_buff_head *list = &rtwusb->tx_queue[i];
+
+ if (!rtw_usb_tx_agg_skb(rtwusb, list))
+ 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)
+{
+ const 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)
+{
+ const 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);
+
+ 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);
+ const 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 = qsel_to_ep(rtwusb, 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;
+ const 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_read_port_complete(struct urb *urb);
+
+static void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, struct rx_usb_ctrl_block *rxcb)
+{
+ struct rtw_dev *rtwdev = rtwusb->rtwdev;
+ int error;
+
+ rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_ATOMIC);
+ 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);
+
+ error = usb_submit_urb(rxcb->rx_urb, GFP_ATOMIC);
+ if (error) {
+ kfree_skb(rxcb->rx_skb);
+ if (error != -ENODEV)
+ rtw_err(rtwdev, "Err sending rx data urb %d\n",
+ error);
+ }
+}
+
+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_resubmit(rtwusb, rxcb);
+ } 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 %d\n", urb->status);
+ break;
+ }
+ if (skb)
+ dev_kfree_skb_any(skb);
+ }
+}
+
+static void rtw_usb_cancel_rx_bufs(struct rtw_usb *rtwusb)
+{
+ struct rx_usb_ctrl_block *rxcb;
+ int i;
+
+ for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
+ rxcb = &rtwusb->rx_cb[i];
+ if (rxcb->rx_urb)
+ usb_kill_urb(rxcb->rx_urb);
+ }
+}
+
+static void rtw_usb_free_rx_bufs(struct rtw_usb *rtwusb)
+{
+ struct rx_usb_ctrl_block *rxcb;
+ int i;
+
+ for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
+ rxcb = &rtwusb->rx_cb[i];
+ if (rxcb->rx_urb) {
+ usb_kill_urb(rxcb->rx_urb);
+ 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->n = i;
+ rxcb->rtwdev = rtwusb->rtwdev;
+ rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!rxcb->rx_urb)
+ goto err;
+ }
+
+ 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)
+{
+ return 0;
+}
+
+static void rtw_usb_stop(struct rtw_dev *rtwdev)
+{
+}
+
+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,
+ .write16 = rtw_usb_write16,
+ .write32 = rtw_usb_write32,
+ .read8 = rtw_usb_read8,
+ .read16 = rtw_usb_read16,
+ .read32 = rtw_usb_read32,
+
+ .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);
+ int i;
+
+ 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);
+
+ for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
+ struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
+
+ rtw_usb_rx_resubmit(rtwusb, rxcb);
+ }
+
+ 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_RXTX_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;
+
+ 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 000000000000..30647f0dd61c
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/usb.h
@@ -0,0 +1,107 @@
+/* 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_RXTX_COUNT 128
+#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 (1024 * 20)
+#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;
+ int n;
+};
+
+struct rtw_usb_tx_data {
+ u8 sn;
+};
+
+struct rtw_usb {
+ struct rtw_dev *rtwdev;
+ struct usb_device *udev;
+
+ /* protects usb_data_index */
+ spinlock_t usb_lock;
+ __le32 *usb_data;
+ unsigned 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 cdfd66a85075..ff3c269fb1a7 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;
+};
+
+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_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 0c23b5069be0..dc8965525400 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;
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 5ab95250755d..931aff8b5dc9 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -3420,6 +3420,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
u32 bus_data_size,
const struct rtw89_chip_info *chip)
{
+ const struct firmware *firmware;
struct ieee80211_hw *hw;
struct rtw89_dev *rtwdev;
struct ieee80211_ops *ops;
@@ -3427,7 +3428,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
u32 early_feat_map = 0;
bool no_chanctx;
- rtw89_early_fw_feature_recognize(device, chip, &early_feat_map);
+ firmware = rtw89_early_fw_feature_recognize(device, chip, &early_feat_map);
ops = kmemdup(&rtw89_ops, sizeof(rtw89_ops), GFP_KERNEL);
if (!ops)
@@ -3454,6 +3455,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
rtwdev->dev = device;
rtwdev->ops = ops;
rtwdev->chip = chip;
+ rtwdev->fw.firmware = firmware;
rtw89_debug(rtwdev, RTW89_DBG_FW, "probe driver %s chanctx\n",
no_chanctx ? "without" : "with");
@@ -3462,6 +3464,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
err:
kfree(ops);
+ release_firmware(firmware);
return NULL;
}
EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw);
@@ -3469,6 +3472,7 @@ EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw);
void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev)
{
kfree(rtwdev->ops);
+ release_firmware(rtwdev->fw.firmware);
ieee80211_free_hw(rtwdev->hw);
}
EXPORT_SYMBOL(rtw89_free_ieee80211_hw);
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 7e682709232d..de1f23779fc6 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -273,29 +273,42 @@ static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
}
}
-void rtw89_early_fw_feature_recognize(struct device *device,
- const struct rtw89_chip_info *chip,
- u32 *early_feat_map)
-{
- union {
- struct rtw89_mfw_hdr mfw_hdr;
- u8 fw_hdr[RTW89_FW_HDR_SIZE];
- } buf = {};
+const struct firmware *
+rtw89_early_fw_feature_recognize(struct device *device,
+ const struct rtw89_chip_info *chip,
+ u32 *early_feat_map)
+{
+ union rtw89_compat_fw_hdr buf = {};
const struct firmware *firmware;
+ bool full_req = false;
u32 ver_code;
int ret;
int i;
- ret = request_partial_firmware_into_buf(&firmware, chip->fw_name,
- device, &buf, sizeof(buf), 0);
+ /* If SECURITY_LOADPIN_ENFORCE is enabled, reading partial files will
+ * be denied (-EPERM). Then, we don't get right firmware things as
+ * expected. So, in this case, we have to request full firmware here.
+ */
+ if (IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE))
+ full_req = true;
+
+ if (full_req)
+ ret = request_firmware(&firmware, chip->fw_name, device);
+ else
+ ret = request_partial_firmware_into_buf(&firmware, chip->fw_name,
+ device, &buf, sizeof(buf),
+ 0);
+
if (ret) {
dev_err(device, "failed to early request firmware: %d\n", ret);
- return;
+ return NULL;
}
- ver_code = buf.mfw_hdr.sig != RTW89_MFW_SIG ?
- RTW89_FW_HDR_VER_CODE(&buf.fw_hdr) :
- RTW89_MFW_HDR_VER_CODE(&buf.mfw_hdr);
+ if (full_req)
+ ver_code = rtw89_compat_fw_hdr_ver_code(firmware->data);
+ else
+ ver_code = rtw89_compat_fw_hdr_ver_code(&buf);
+
if (!ver_code)
goto out;
@@ -310,7 +323,11 @@ void rtw89_early_fw_feature_recognize(struct device *device,
}
out:
+ if (full_req)
+ return firmware;
+
release_firmware(firmware);
+ return NULL;
}
int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
@@ -617,6 +634,13 @@ int rtw89_load_firmware(struct rtw89_dev *rtwdev)
fw->rtwdev = rtwdev;
init_completion(&fw->completion);
+ if (fw->firmware) {
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "full firmware has been early requested\n");
+ complete_all(&fw->completion);
+ return 0;
+ }
+
ret = request_firmware_nowait(THIS_MODULE, true, fw_name, rtwdev->dev,
GFP_KERNEL, fw, rtw89_load_firmware_cb);
if (ret) {
@@ -633,8 +657,14 @@ void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
rtw89_wait_firmware_completion(rtwdev);
- if (fw->firmware)
+ if (fw->firmware) {
release_firmware(fw->firmware);
+
+ /* assign NULL back in case rtw89_free_ieee80211_hw()
+ * try to release the same one again.
+ */
+ fw->firmware = NULL;
+ }
}
#define H2C_CAM_LEN 60
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 46d57414f24e..4d2f9ea9e002 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -3291,6 +3291,21 @@ struct fwcmd_hdr {
__le32 hdr1;
};
+union rtw89_compat_fw_hdr {
+ struct rtw89_mfw_hdr mfw_hdr;
+ u8 fw_hdr[RTW89_FW_HDR_SIZE];
+};
+
+static inline u32 rtw89_compat_fw_hdr_ver_code(const void *fw_buf)
+{
+ const union rtw89_compat_fw_hdr *compat = (typeof(compat))fw_buf;
+
+ if (compat->mfw_hdr.sig == RTW89_MFW_SIG)
+ return RTW89_MFW_HDR_VER_CODE(&compat->mfw_hdr);
+ else
+ return RTW89_FW_HDR_VER_CODE(&compat->fw_hdr);
+}
+
#define RTW89_H2C_RF_PAGE_SIZE 500
#define RTW89_H2C_RF_PAGE_NUM 3
struct rtw89_fw_h2c_rf_reg_info {
@@ -3429,9 +3444,10 @@ struct rtw89_fw_h2c_rf_get_mccch {
int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev);
int rtw89_fw_recognize(struct rtw89_dev *rtwdev);
-void rtw89_early_fw_feature_recognize(struct device *device,
- const struct rtw89_chip_info *chip,
- u32 *early_feat_map);
+const struct firmware *
+rtw89_early_fw_feature_recognize(struct device *device,
+ const struct rtw89_chip_info *chip,
+ u32 *early_feat_map);
int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type);
int rtw89_load_firmware(struct rtw89_dev *rtwdev);
void rtw89_unload_firmware(struct rtw89_dev *rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index d80050c2e9b3..cf9a0a3120a7 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -3877,11 +3877,16 @@ static void rtw89_mac_port_cfg_hiq_drop(struct rtw89_dev *rtwdev,
}
static void rtw89_mac_port_cfg_func_en(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif *rtwvif, bool enable)
{
const struct rtw89_port_reg *p = &rtw_port_base;
- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN);
+ if (enable)
+ rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg,
+ B_AX_PORT_FUNC_EN);
+ else
+ rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg,
+ B_AX_PORT_FUNC_EN);
}
static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev,
@@ -3913,6 +3918,49 @@ static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev,
B_AX_TBTT_SHIFT_OFST_MASK, val);
}
+static void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_vif *rtwvif_src, u8 offset,
+ int *n_offset)
+{
+ u32 val, reg;
+
+ if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif == rtwvif_src)
+ return;
+
+ /* adjust offset randomly to avoid beacon conflict */
+ offset = offset - offset / 4 + get_random_u32() % (offset / 2);
+ val = RTW89_PORT_OFFSET_MS_TO_32US((*n_offset)++, offset);
+ reg = rtw89_mac_reg_by_idx(R_AX_PORT0_TSF_SYNC + rtwvif->port * 4,
+ rtwvif->mac_idx);
+
+ rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_SRC, rtwvif_src->port);
+ rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_OFFSET_VAL, val);
+ rtw89_write32_set(rtwdev, reg, B_AX_SYNC_NOW);
+}
+
+static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_vif *src = NULL, *tmp;
+ u8 offset = 100, vif_aps = 0;
+ int n_offset = 1;
+
+ rtw89_for_each_rtwvif(rtwdev, tmp) {
+ if (!src || tmp->net_type == RTW89_NET_TYPE_INFRA)
+ src = tmp;
+ if (tmp->net_type == RTW89_NET_TYPE_AP_MODE)
+ vif_aps++;
+ }
+
+ if (vif_aps == 0)
+ return;
+
+ offset /= (vif_aps + 1);
+
+ rtw89_for_each_rtwvif(rtwdev, tmp)
+ rtw89_mac_port_tsf_sync(rtwdev, tmp, src, offset, &n_offset);
+}
+
int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
int ret;
@@ -3932,6 +3980,10 @@ int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
if (ret)
return ret;
+ ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
+ if (ret)
+ return ret;
+
ret = rtw89_cam_init(rtwdev, rtwvif);
if (ret)
return ret;
@@ -3990,7 +4042,8 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif);
rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif);
rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif);
- rtw89_mac_port_cfg_func_en(rtwdev, rtwvif);
+ rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, true);
+ rtw89_mac_port_tsf_resync_all(rtwdev);
fsleep(BCN_ERLY_SET_DLY);
rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif);
@@ -4041,6 +4094,11 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
rtw89_write32_set(rtwdev, reg, B_AX_RXTRIG_RU26_DIS);
}
+void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+{
+ rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, false);
+}
+
int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
int ret;
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index adb0c86a98d3..f0b684b205f1 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -168,6 +168,8 @@ enum rtw89_mac_ax_l0_to_l1_event {
MAC_AX_L0_TO_L1_EVENT_MAX = 15,
};
+#define RTW89_PORT_OFFSET_MS_TO_32US(n, shift_ms) ((n) * (shift_ms) * 1000 / 32)
+
enum rtw89_mac_dbg_port_sel {
/* CMAC 0 related */
RTW89_DBG_PORT_SEL_PTCL_C0 = 0,
@@ -906,6 +908,7 @@ int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif);
+void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev);
int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw);
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 1a99267d710d..f9b95c52916b 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -125,6 +125,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
RTW89_PORT_NUM);
if (rtwvif->port == RTW89_PORT_NUM) {
ret = -ENOSPC;
+ list_del_init(&rtwvif->list);
goto out;
}
@@ -138,6 +139,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
ret = rtw89_mac_add_vif(rtwdev, rtwvif);
if (ret) {
rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port);
+ list_del_init(&rtwvif->list);
goto out;
}
@@ -454,6 +456,7 @@ void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
mutex_lock(&rtwdev->mutex);
+ rtw89_mac_stop_ap(rtwdev, rtwvif);
rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL);
rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
mutex_unlock(&rtwdev->mutex);
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index f2634062f377..5324e645728b 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -2048,6 +2048,23 @@
#define B_AX_PTCL_TOP_ERR_IND BIT(1)
#define B_AX_SCHEDULE_TOP_ERR_IND BIT(0)
+#define R_AX_PORT0_TSF_SYNC 0xC2A0
+#define R_AX_PORT0_TSF_SYNC_C1 0xE2A0
+#define R_AX_PORT1_TSF_SYNC 0xC2A4
+#define R_AX_PORT1_TSF_SYNC_C1 0xE2A4
+#define R_AX_PORT2_TSF_SYNC 0xC2A8
+#define R_AX_PORT2_TSF_SYNC_C1 0xE2A8
+#define R_AX_PORT3_TSF_SYNC 0xC2AC
+#define R_AX_PORT3_TSF_SYNC_C1 0xE2AC
+#define R_AX_PORT4_TSF_SYNC 0xC2B0
+#define R_AX_PORT4_TSF_SYNC_C1 0xE2B0
+#define B_AX_SYNC_NOW BIT(30)
+#define B_AX_SYNC_ONCE BIT(29)
+#define B_AX_SYNC_AUTO BIT(28)
+#define B_AX_SYNC_PORT_SRC GENMASK(26, 24)
+#define B_AX_SYNC_PORT_OFFSET_SIGN BIT(18)
+#define B_AX_SYNC_PORT_OFFSET_VAL GENMASK(17, 0)
+
#define R_AX_MACID_SLEEP_0 0xC2C0
#define R_AX_MACID_SLEEP_0_C1 0xE2C0
#define B_AX_MACID31_0_SLEEP_SH 0