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
 -----BEGIN PGP SIGNATURE-----
 
 iQFFBAABCgAvFiEEiBjanGPFTz4PRfLobhckVSbrbZsFAmOW9EsRHGt2YWxvQGtl
 cm5lbC5vcmcACgkQbhckVSbrbZup1wf9EO1wK3M+wICOthV9hphaMK/cU5XQe455
 V27N+IGg3KkeLgERYj/35C1Xwa4vXeUxWN31KvNJ/51IQaM14NfUE3OOu+gqUO36
 a/HhECtcmzsjC+22hH1gvnN73/+S8VQEEfOJ//Jcg6exRmXVKRMWZU1o3rFupAR+
 qePWzvYuadobmE8G/Zq2VFB5Eouf5z7MSXLd7Y/8HJMdL812GmA0nhNJXhHDt27A
 /K5QBOSnRQ24ZLOG4P0eFZrJGqFTcI27+w4bv+rzUL2ME/Rgp1hB7wBwQbCwD8sU
 Aus05avcIcVNfsTk3z7kOnYiBqf08WX6Ng6ezb9HunXXfWhLW7JtAw==
 =AzL1
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Jakub Kicinski 2022-12-12 12:15:23 -08:00
commit fba119cee1
80 changed files with 2612 additions and 296 deletions

View file

@ -20,6 +20,7 @@ brcmfmac-objs += \
common.o \ common.o \
core.o \ core.o \
firmware.o \ firmware.o \
fwvid.o \
feature.o \ feature.o \
btcoex.o \ btcoex.o \
vendor.o \ vendor.o \
@ -47,3 +48,13 @@ brcmfmac-$(CONFIG_OF) += \
of.o of.o
brcmfmac-$(CONFIG_DMI) += \ brcmfmac-$(CONFIG_DMI) += \
dmi.o 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

View file

@ -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

View file

@ -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,
};

View file

@ -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);

View file

@ -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 */

View file

@ -959,33 +959,36 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
return ret; return ret;
} }
#define BRCMF_SDIO_DEVICE(dev_id) \ #define BRCMF_SDIO_DEVICE(dev_id, fw_vend) \
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id)} { \
SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id), \
.driver_data = BRCMF_FWVENDOR_ ## fw_vend \
}
/* devices we support, null terminated */ /* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = { static const struct sdio_device_id brcmf_sdmmc_ids[] = {
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373, CYW),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012, CYW),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, CYW),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW),
{ /* end: all zeroes */ } { /* end: all zeroes */ }
}; };
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); 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; sdiodev->bus_if = bus_if;
bus_if->bus_priv.sdio = sdiodev; bus_if->bus_priv.sdio = sdiodev;
bus_if->proto_type = BRCMF_PROTO_BCDC; bus_if->proto_type = BRCMF_PROTO_BCDC;
bus_if->fwvid = id->driver_data;
dev_set_drvdata(&func->dev, bus_if); dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func1->dev, bus_if); dev_set_drvdata(&sdiodev->func1->dev, bus_if);
sdiodev->dev = &sdiodev->func1->dev; sdiodev->dev = &sdiodev->func1->dev;

View file

@ -8,6 +8,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/device.h>
#include "debug.h" #include "debug.h"
/* IDs of the 6 default common rings of msgbuf protocol */ /* IDs of the 6 default common rings of msgbuf protocol */
@ -30,6 +31,15 @@
/* The maximum console interval value (5 mins) */ /* The maximum console interval value (5 mins) */
#define MAX_CONSOLE_INTERVAL (5 * 60) #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 */ /* The level of bus communication with the dongle */
enum brcmf_bus_state { enum brcmf_bus_state {
BRCMF_BUS_DOWN, /* Not ready for frame transfers */ BRCMF_BUS_DOWN, /* Not ready for frame transfers */
@ -74,6 +84,7 @@ struct brcmf_bus_dcmd {
* @get_ramsize: obtain size of device memory. * @get_ramsize: obtain size of device memory.
* @get_memdump: obtain device memory dump in provided buffer. * @get_memdump: obtain device memory dump in provided buffer.
* @get_blob: obtain a firmware blob. * @get_blob: obtain a firmware blob.
* @remove: initiate unbind of the device.
* *
* This structure provides an abstract interface towards the * This structure provides an abstract interface towards the
* bus specific driver. For control messages to common driver * bus specific driver. For control messages to common driver
@ -94,6 +105,7 @@ struct brcmf_bus_ops {
enum brcmf_blob_type type); enum brcmf_blob_type type);
void (*debugfs_create)(struct device *dev); void (*debugfs_create)(struct device *dev);
int (*reset)(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. * @stats: statistics shared between common and bus layer.
* @maxctl: maximum size for rxctl request message. * @maxctl: maximum size for rxctl request message.
* @chip: device identifier of the dongle chip. * @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. * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
* @wowl_supported: is wowl supported by bus driver. * @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. * @msgbuf: msgbuf protocol parameters provided by bus layer.
* @list: member used to add this bus instance to linked list.
*/ */
struct brcmf_bus { struct brcmf_bus {
union { union {
@ -160,11 +175,14 @@ struct brcmf_bus {
uint maxctl; uint maxctl;
u32 chip; u32 chip;
u32 chiprev; u32 chiprev;
enum brcmf_fwvendor fwvid;
bool always_use_fws_queue; bool always_use_fws_queue;
bool wowl_supported; bool wowl_supported;
const struct brcmf_bus_ops *ops; const struct brcmf_bus_ops *ops;
struct brcmf_bus_msgbuf *msgbuf; 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); 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 * interface functions from common layer
*/ */

View file

@ -18,6 +18,7 @@
#include "core.h" #include "core.h"
#include "bus.h" #include "bus.h"
#include "fwvid.h"
#include "debug.h" #include "debug.h"
#include "fwil_types.h" #include "fwil_types.h"
#include "p2p.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, "vendorid: 0x%04x\n", ri->vendorid);
seq_printf(s, "deviceid: 0x%04x\n", ri->deviceid); seq_printf(s, "deviceid: 0x%04x\n", ri->deviceid);
seq_printf(s, "radiorev: %s\n", brcmu_dotrev_str(ri->radiorev, drev)); 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, "chippkg: %u\n", ri->chippkg);
seq_printf(s, "corerev: %u\n", ri->corerev); seq_printf(s, "corerev: %u\n", ri->corerev);
seq_printf(s, "boardid: 0x%04x\n", ri->boardid); seq_printf(s, "boardid: 0x%04x\n", ri->boardid);
@ -1332,6 +1334,12 @@ int brcmf_attach(struct device *dev)
/* Link to bus module */ /* Link to bus module */
drvr->hdrlen = 0; 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 */ /* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr); ret = brcmf_proto_attach(drvr);
if (ret != 0) { if (ret != 0) {
@ -1443,6 +1451,8 @@ void brcmf_detach(struct device *dev)
brcmf_cfg80211_detach(drvr->config); brcmf_cfg80211_detach(drvr->config);
drvr->config = NULL; drvr->config = NULL;
} }
brcmf_fwvid_detach(drvr);
} }
void brcmf_free(struct device *dev) void brcmf_free(struct device *dev)

View file

@ -13,6 +13,12 @@
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "fweh.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_TX_CSUM_OL 0x00000001
#define TOE_RX_CSUM_OL 0x00000002 #define TOE_RX_CSUM_OL 0x00000002
@ -137,6 +143,8 @@ struct brcmf_pub {
u8 clmver[BRCMF_DCMD_SMLEN]; u8 clmver[BRCMF_DCMD_SMLEN];
u8 sta_mac_idx; u8 sta_mac_idx;
const struct brcmf_fwvid_ops *vops;
void *vdata;
}; };
/* forward declarations */ /* forward declarations */

View file

@ -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

View file

@ -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,
};

View file

@ -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);

View file

@ -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 */

View file

@ -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;
}

View file

@ -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_ */

View file

@ -736,7 +736,7 @@ static int brcmf_pcie_exit_download_state(struct brcmf_pciedev_info *devinfo,
} }
if (!brcmf_chip_set_active(devinfo->ci, resetintr)) if (!brcmf_chip_set_active(devinfo->ci, resetintr))
return -EINVAL; return -EIO;
return 0; 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->bus_priv.pcie = pcie_bus_dev;
bus->ops = &brcmf_pcie_bus_ops; bus->ops = &brcmf_pcie_bus_ops;
bus->proto_type = BRCMF_PROTO_MSGBUF; bus->proto_type = BRCMF_PROTO_MSGBUF;
bus->fwvid = id->driver_data;
bus->chip = devinfo->coreid; bus->chip = devinfo->coreid;
bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot); bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot);
dev_set_drvdata(&pdev->dev, bus); dev_set_drvdata(&pdev->dev, bus);
@ -2570,38 +2571,47 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = {
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
#define BRCMF_PCIE_DEVICE(dev_id) { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ #define BRCMF_PCIE_DEVICE(dev_id, fw_vend) \
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), \
BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ PCI_ANY_ID, PCI_ANY_ID, \
subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } 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[] = { static const struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355), BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_RAW_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_RAW_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_RAW_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_RAW_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4359_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4359_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4364_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4364_DEVICE_ID, BCA),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID, BCA),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID, BCA),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID, BCA),
BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365), BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365, BCA),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID, BCA),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID, BCA),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID, BCA),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(CY_PCIE_89459_DEVICE_ID), BRCMF_PCIE_DEVICE(CY_PCIE_89459_DEVICE_ID, CYW),
BRCMF_PCIE_DEVICE(CY_PCIE_89459_RAW_DEVICE_ID), BRCMF_PCIE_DEVICE(CY_PCIE_89459_RAW_DEVICE_ID, CYW),
{ /* end: all zeroes */ } { /* end: all zeroes */ }
}; };

View file

@ -3412,6 +3412,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
/* Take arm out of reset */ /* Take arm out of reset */
if (!brcmf_chip_set_active(bus->ci, rstvec)) { if (!brcmf_chip_set_active(bus->ci, rstvec)) {
brcmf_err("error getting out of ARM core reset\n"); brcmf_err("error getting out of ARM core reset\n");
bcmerror = -EIO;
goto err; goto err;
} }
@ -4171,6 +4172,15 @@ static int brcmf_sdio_bus_reset(struct device *dev)
return 0; 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 = { static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.stop = brcmf_sdio_bus_stop, .stop = brcmf_sdio_bus_stop,
.preinit = brcmf_sdio_bus_preinit, .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_memdump = brcmf_sdio_bus_get_memdump,
.get_blob = brcmf_sdio_get_blob, .get_blob = brcmf_sdio_get_blob,
.debugfs_create = brcmf_sdio_debugfs_create, .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 #define BRCMF_SDIO_FW_CODE 0

View file

@ -1240,7 +1240,8 @@ brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo)
return fwreq; 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_bus *bus = NULL;
struct brcmf_usbdev *bus_pub = 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); dev_set_drvdata(dev, bus);
bus->ops = &brcmf_usb_bus_ops; bus->ops = &brcmf_usb_bus_ops;
bus->proto_type = BRCMF_PROTO_BCDC; bus->proto_type = BRCMF_PROTO_BCDC;
bus->fwvid = fwvid;
bus->always_use_fws_queue = true; bus->always_use_fws_queue = true;
#ifdef CONFIG_PM #ifdef CONFIG_PM
bus->wowl_supported = true; bus->wowl_supported = true;
@ -1423,7 +1425,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
else else
brcmf_dbg(USB, "Broadcom full speed USB WLAN interface detected\n"); 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) if (ret)
goto fail; goto fail;
@ -1511,14 +1513,23 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf)
return ret; return ret;
} }
#define BRCMF_USB_DEVICE(dev_id) \ #define BRCMF_USB_DEVICE(dev_id) \
{ USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id) } { \
USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id), \
.driver_info = BRCMF_FWVENDOR_WCC \
}
#define LINKSYS_USB_DEVICE(dev_id) \ #define LINKSYS_USB_DEVICE(dev_id) \
{ USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id) } { \
USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id), \
.driver_info = BRCMF_FWVENDOR_WCC \
}
#define CYPRESS_USB_DEVICE(dev_id) \ #define CYPRESS_USB_DEVICE(dev_id) \
{ USB_DEVICE(CY_USB_VENDOR_ID_CYPRESS, 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[] = { static const struct usb_device_id brcmf_usb_devid_table[] = {
BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID), BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID),

View file

@ -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

View file

@ -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,
};

View file

@ -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);

View file

@ -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 */

View file

@ -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); 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, static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
const u8 * buf) const u8 * buf)
{ {

View file

@ -382,9 +382,11 @@ enum iwl_scd_queue_cfg_operation {
* @u.add.cb_size: size code * @u.add.cb_size: size code
* @u.add.bc_dram_addr: byte-count table IOVA * @u.add.bc_dram_addr: byte-count table IOVA
* @u.add.tfdq_dram_addr: TFD queue IOVA * @u.add.tfdq_dram_addr: TFD queue IOVA
* @u.remove.queue: queue ID for removal * @u.remove.sta_mask: station mask of queue to remove
* @u.modify.sta_mask: new station mask for modify * @u.remove.tid: TID of queue to remove
* @u.modify.queue: queue ID to modify * @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 { struct iwl_scd_queue_cfg_cmd {
__le32 operation; __le32 operation;
@ -399,11 +401,13 @@ struct iwl_scd_queue_cfg_cmd {
__le64 tfdq_dram_addr; __le64 tfdq_dram_addr;
} __packed add; /* TX_QUEUE_CFG_CMD_ADD_API_S_VER_1 */ } __packed add; /* TX_QUEUE_CFG_CMD_ADD_API_S_VER_1 */
struct { struct {
__le32 queue; __le32 sta_mask;
__le32 tid;
} __packed remove; /* TX_QUEUE_CFG_CMD_REMOVE_API_S_VER_1 */ } __packed remove; /* TX_QUEUE_CFG_CMD_REMOVE_API_S_VER_1 */
struct { struct {
__le32 sta_mask; __le32 old_sta_mask;
__le32 queue; __le32 tid;
__le32 new_sta_mask;
} __packed modify; /* TX_QUEUE_CFG_CMD_MODIFY_API_S_VER_1 */ } __packed modify; /* TX_QUEUE_CFG_CMD_MODIFY_API_S_VER_1 */
} __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1 */ } __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1 */
} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3 */ } __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3 */

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause // 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) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland 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; 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, IWL_ERR(fwrt,
"Not valid error log pointer 0x%08X for %s uCode\n", "Not valid error log pointer 0x%08X for %s uCode\n",
base, base,
@ -376,7 +377,7 @@ static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt)
return; 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"); IWL_ERR(trans, "IML/ROM dump:\n");

View file

@ -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); !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED);
nvm->sku_cap_mimo_disabled = nvm->sku_cap_mimo_disabled =
!!(mac_flags & NVM_MAC_SKU_FLAGS_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 */ /* Initialize PHY sku data */
nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains);

View file

@ -976,6 +976,8 @@ struct iwl_trans_txqs {
* @max_skb_frags: maximum number of fragments an SKB can have when transmitted. * @max_skb_frags: maximum number of fragments an SKB can have when transmitted.
* 0 indicates that frag SKBs (NETIF_F_SG) aren't supported. * 0 indicates that frag SKBs (NETIF_F_SG) aren't supported.
* @hw_rf_id a u32 with the device RF ID * @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. * @hw_id: a u32 with the ID of the device / sub-device.
* Set during transport allocation. * Set during transport allocation.
* @hw_id_str: a string with info about HW ID. 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;
u32 hw_rev_step; u32 hw_rev_step;
u32 hw_rf_id; u32 hw_rf_id;
u32 hw_crf_id;
u32 hw_cdb_id;
u32 hw_id; u32 hw_id;
char hw_id_str[52]; char hw_id_str[52];
u32 sku_id[3]; u32 sku_id[3];

View file

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-only /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (C) 2021 Intel Corporation * Copyright (C) 2021 Intel Corporation
*/ */
@ -13,7 +13,7 @@
/** /**
* DOC: Introduction * 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 * the iwlwifi driver and the CSME firmware's WLAN driver. This communication
* uses the SAP protocol defined in another file. * uses the SAP protocol defined in another file.
* iwlwifi can request or release ownership on the WiFi device through iwlmei. * 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 * iwl_mei_set_nic_info() - set mac address
* @mac_address: mac address to set * @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. * This function must be called upon mac address change.
*/ */

View file

@ -1963,7 +1963,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
iwl_mei_dbgfs_register(mei); 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. * we expect to get the SAP_ME_MSG_START_OK response later on.
*/ */
mutex_lock(&iwl_mei_mutex); mutex_lock(&iwl_mei_mutex);

View file

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-only /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (C) 2021 - 2022 Intel Corporation * Copyright (C) 2021 - 2022 Intel Corporation
*/ */
@ -25,7 +25,7 @@
* *
* Since this messaging system cannot support high amounts of * Since this messaging system cannot support high amounts of
* traffic, iwlwifi and the CSME firmware's WLAN driver have an * 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 * of the message is copied to a shared area and the message that
* goes over the ME interface just signals the other side * goes over the ME interface just signals the other side
* that a new message is waiting in the shared area. The ME * that a new message is waiting in the shared area. The ME
@ -55,7 +55,7 @@
/** /**
* DOC: Host and driver state messages * 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. * 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 loaded, the host sends %SAP_MSG_NOTIF_WIFIDR_UP.
* When the host driver is unloaded, the host sends %SAP_MSG_NOTIF_WIFIDR_DOWN. * When the host driver is unloaded, the host sends %SAP_MSG_NOTIF_WIFIDR_DOWN.
@ -76,7 +76,7 @@
* DOC: Ownership * DOC: Ownership
* *
* The device can be controlled either by the CSME firmware or * 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 * those two entities to determine who controls (or owns) the
* device. Since the CSME can control the device even when the * device. Since the CSME can control the device even when the
* OS is not working or even missing, the CSME can request 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 * 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. * @type: the type of the message, see &enum iwl_sap_me_msg_id.
* @seq_num: a sequence number used for debug only. * @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 { struct iwl_sap_me_msg_hdr {
__le32 type; __le32 type;

View file

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-only /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright(c) 2021 Intel Corporation * Copyright(c) 2021 Intel Corporation
*/ */

View file

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-only /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright(c) 2021 Intel Corporation * Copyright(c) 2021 Intel Corporation
*/ */

View file

@ -599,6 +599,11 @@ static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw,
switch (key->cipher) { switch (key->cipher) {
default: default:
return; 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_256:
case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_128:
data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_GCMP); 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) if (!sta)
data->kek_kck_cmd->gtk_cipher = data->kek_kck_cmd->gtk_cipher =
cpu_to_le32(STA_KEY_FLG_CCM); cpu_to_le32(STA_KEY_FLG_CCM);
break; return;
case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_GCMP_256:
if (!sta) if (!sta)
data->kek_kck_cmd->gtk_cipher = data->kek_kck_cmd->gtk_cipher =
cpu_to_le32(STA_KEY_FLG_GCMP); cpu_to_le32(STA_KEY_FLG_GCMP);
break; return;
} }
} }

View file

@ -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, static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,
struct cfg80211_pmsr_result *res) 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; s64 rtt_avg, rtt = res->ftm.rtt_avg;
u32 undershoot, overshoot; u32 undershoot, overshoot;
u8 alpha; u8 alpha;
bool found;
if (!IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH) if (!IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH)
return; return;
@ -1028,15 +1027,14 @@ static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,
return; return;
} }
found = false; list_for_each_entry(iter, &mvm->ftm_initiator.smooth.resp, list) {
list_for_each_entry(resp, &mvm->ftm_initiator.smooth.resp, list) { if (!memcmp(res->addr, iter->addr, ETH_ALEN)) {
if (!memcmp(res->addr, resp->addr, ETH_ALEN)) { resp = iter;
found = true;
break; break;
} }
} }
if (!found) { if (!resp) {
resp = kzalloc(sizeof(*resp), GFP_KERNEL); resp = kzalloc(sizeof(*resp), GFP_KERNEL);
if (!resp) if (!resp)
return; return;

View file

@ -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, u32 version = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
UCODE_ALIVE_NTFY, 0); UCODE_ALIVE_NTFY, 0);
u32 i; u32 i;
struct iwl_trans *trans = mvm->trans;
enum iwl_device_family device_family = trans->trans_cfg->device_family;
if (version == 6) { if (version == 6) {
struct iwl_alive_ntf_v6 *palive; 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) {
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, iwl_fw_umac_set_alive_err_table(mvm->trans,
umac_error_table); umac_error_table);
} else { } else {

View file

@ -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) >> radio_cfg_dash = (phy_config & FW_PHY_CFG_RADIO_DASH) >>
FW_PHY_CFG_RADIO_DASH_POS; 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 */ /* SKU control */
reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->hw_rev); 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, CSR_HW_IF_CONFIG_REG_D3_DEBUG,
reg_val); 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 * 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 * (PCIe power is lost before PERST# is asserted), causing ME FW

View file

@ -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 ieee80211_rx_status *rx_status;
struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_rx_no_data *desc = (void *)pkt->data; struct iwl_rx_no_data *desc = (void *)pkt->data;
u32 rssi = le32_to_cpu(desc->rssi); u32 rssi;
u32 info_type = le32_to_cpu(desc->info) & RX_NO_DATA_INFO_TYPE_MSK; u32 info_type;
struct ieee80211_sta *sta = NULL; struct ieee80211_sta *sta = NULL;
struct sk_buff *skb; struct sk_buff *skb;
struct iwl_mvm_rx_phy_data phy_data = { 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),
};
u32 format; 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, if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
RX_NO_DATA_NOTIF, 0) < 2) { RX_NO_DATA_NOTIF, 0) < 2) {
IWL_DEBUG_DROP(mvm, "Got an old rate format. Old rate: 0x%x\n", 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; 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 /* Dont use dev_alloc_skb(), we'll have enough headroom once
* ieee80211_hdr pulled. * ieee80211_hdr pulled.
*/ */

View file

@ -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, 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; int queue = *queueptr;
struct iwl_scd_txq_cfg_cmd cmd = { 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); SCD_QUEUE_CONFIG_CMD);
struct iwl_scd_queue_cfg_cmd remove_cmd = { struct iwl_scd_queue_cfg_cmd remove_cmd = {
.operation = cpu_to_le32(IWL_SCD_QUEUE_REMOVE), .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, 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, iwl_mvm_invalidate_sta_queue(mvm, queue,
disable_agg_tids, false); 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) { if (ret) {
IWL_ERR(mvm, IWL_ERR(mvm,
"Failed to free inactive queue %d (ret=%d)\n", "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: out_err:
queue_tmp = queue; 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; 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) if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE)
continue; 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; 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); ret = iwl_mvm_add_int_sta_common(mvm, sta, addr, macidx, maccolor);
if (ret) { if (ret) {
if (!iwl_mvm_has_new_tx_api(mvm)) 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); IWL_MAX_TID_COUNT);
return ret; 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)) if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA))
return -EINVAL; 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); ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id);
if (ret) if (ret)
IWL_WARN(mvm, "Failed sending remove station\n"); 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)) if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA))
return -EINVAL; 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); ret = iwl_mvm_rm_sta_common(mvm, mvm->aux_sta.sta_id);
if (ret) if (ret)
IWL_WARN(mvm, "Failed sending remove station\n"); 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; 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)) if (iwl_mvm_has_new_tx_api(mvm))
return; 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_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); ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id);
if (ret) if (ret)

View file

@ -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, static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
struct iwl_time_event_notif *notif) struct iwl_time_event_notif *notif)
{ {
struct iwl_mvm_time_event_data *te_data, *tmp; struct iwl_mvm_time_event_data *aux_roc_te = NULL, *te_data;
bool aux_roc_te = false;
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) { if (le32_to_cpu(notif->unique_id) == te_data->uid) {
aux_roc_te = true; aux_roc_te = te_data;
break; break;
} }
} }

View file

@ -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 * Read rf id and cdb info from prph register and store it
* from the prph registers.
*/ */
static int get_crf_id(struct iwl_trans *iwl_trans) static int get_crf_id(struct iwl_trans *iwl_trans)
{ {
int ret = 0; int ret = 0;
u32 sd_reg_ver_addr; u32 sd_reg_ver_addr;
u32 cdb = 0; u32 val = 0;
u32 val;
if (iwl_trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) if (iwl_trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
sd_reg_ver_addr = SD_REG_VER_GEN2; 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); iwl_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val);
/* Read crf info */ /* 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 */ /* 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 */ /* Map between crf id to rf id */
switch (REG_CRF_ID_TYPE(val)) { switch (REG_CRF_ID_TYPE(val)) {
@ -1410,7 +1424,7 @@ static int get_crf_id(struct iwl_trans *iwl_trans)
IWL_ERR(iwl_trans, IWL_ERR(iwl_trans,
"Can find a correct rfid for crf id 0x%x\n", "Can find a correct rfid for crf id 0x%x\n",
REG_CRF_ID_TYPE(val)); 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_INFO(iwl_trans, "Detected RF 0x%x from crf id 0x%x\n",
iwl_trans->hw_rf_id, REG_CRF_ID_TYPE(val)); iwl_trans->hw_rf_id, REG_CRF_ID_TYPE(val));
out_release:
iwl_trans_release_nic_access(iwl_trans);
out: out:
return ret; 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); 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 * 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 && if (iwl_trans->trans_cfg->rf_id &&
iwl_trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_9000 && 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; ret = -EINVAL;
goto out_free_trans; goto out_free_trans;
} }

View file

@ -1240,7 +1240,7 @@ struct rtl8723bu_c2h {
u8 bw; u8 bw;
} __packed ra_report; } __packed ra_report;
}; };
}; } __packed;
struct rtl8xxxu_fileops; struct rtl8xxxu_fileops;

View file

@ -780,6 +780,12 @@ static int rtl8192eu_iqk_path_a(struct rtl8xxxu_priv *priv)
*/ */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000); 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_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); rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
/* Path A IQK setting */ /* 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_WE_LUT, 0x800a0);
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); 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_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 */ /* 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_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 */ /* Enter IQK mode */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); 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_TX_IQK_TONE_B, 0x38008c1c);
rtl8xxxu_write32(priv, REG_RX_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_TX_IQK_PI_A, 0x8216031f);
rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x68160c1f); rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x6816031f);
/* LO calibration setting */ /* LO calibration setting */
rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911); rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911);
/* One shot, path A LOK & IQK */ /* 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); rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
mdelay(10); 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_WE_LUT, 0x800a0);
rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); 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_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 */ /* 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_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 */ /* Enter IQK mode */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); 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_TX_IQK_TONE_B, 0x38008c1c);
rtl8xxxu_write32(priv, REG_RX_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_TX_IQK_PI_A, 0x821608ff);
rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c1f); rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x281608ff);
/* LO calibration setting */ /* LO calibration setting */
rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a891); rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a891);
/* One shot, path A LOK & IQK */ /* 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); rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
mdelay(10); mdelay(10);
@ -937,9 +953,12 @@ static int rtl8192eu_iqk_path_b(struct rtl8xxxu_priv *priv)
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000); rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00180); 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); rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
/* Path B IQK setting */ /* 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_TX_IQK_TONE_B, 0x18008c1c);
rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); 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); rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x68160000);
/* LO calibration setting */ /* 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 */ /* One shot, path A LOK & IQK */
rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000); 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_WE_LUT, 0x800a0);
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x30000); 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_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 */ /* 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_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 */ /* Enter IQK mode */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); 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_TX_IQK_TONE_B, 0x18008c1c);
rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82160c1f); rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x8216031f);
rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x68160c1f); rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x6816031f);
/* LO calibration setting */ /* LO calibration setting */
rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911); 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_WE_LUT, 0x800a0);
rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x30000); 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_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 */ /* 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_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 */ /* Enter IQK mode */
rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); 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_TX_IQK_TONE_B, 0x38008c1c);
rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x18008c1c); rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x18008c1c);
rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c1f); rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x821608ff);
rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c1f); rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x281608ff);
/* LO calibration setting */ /* LO calibration setting */
rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a891); rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a891);

View file

@ -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 static void
rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, u64 changed) 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; u32 ramask;
int sgi = 0; int sgi = 0;
u8 highest_rate; u8 highest_rate;
u8 mcs = 0, nss = 0; u8 bw;
u32 bit_rate;
rcu_read_lock(); rcu_read_lock();
sta = ieee80211_find_sta(vif, bss_conf->bssid); 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; sgi = 1;
highest_rate = fls(ramask) - 1; highest_rate = fls(ramask) - 1;
if (highest_rate < DESC_RATE_MCS0) { if (rtl8xxxu_ht40_2g &&
rarpt->txrate.legacy = (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
rtl8xxxu_legacy_ratetable[highest_rate].bitrate; bw = RATE_INFO_BW_40;
} else { else
rtl8xxxu_desc_to_mcsrate(highest_rate, bw = RATE_INFO_BW_20;
&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;
}
rcu_read_unlock(); rcu_read_unlock();
bit_rate = cfg80211_calculate_bitrate(&rarpt->txrate);
rarpt->bit_rate = bit_rate; rtl8xxxu_update_ra_report(rarpt, highest_rate, sgi, bw);
rarpt->desc_rate = highest_rate;
priv->vif = vif; priv->vif = vif;
priv->rssi_level = RTL8XXXU_RATR_STA_INIT; 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); 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; u8 bt_info = 0;
struct rtl8xxxu_btcoex *btcoex; struct rtl8xxxu_btcoex *btcoex;
struct rtl8xxxu_ra_report *rarpt; struct rtl8xxxu_ra_report *rarpt;
u8 rate, sgi, bw; u8 bw;
u32 bit_rate;
u8 mcs = 0, nss = 0;
priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work); priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work);
btcoex = &priv->bt_coex; btcoex = &priv->bt_coex;
@ -5566,32 +5570,17 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work)
rtl8723bu_handle_bt_info(priv); rtl8723bu_handle_bt_info(priv);
break; break;
case C2H_8723B_RA_REPORT: case C2H_8723B_RA_REPORT:
rarpt->txrate.flags = 0; bw = rarpt->txrate.bw;
rate = c2h->ra_report.rate;
sgi = c2h->ra_report.sgi;
bw = c2h->ra_report.bw;
if (rate < DESC_RATE_MCS0) { if (skb->len >= offsetofend(typeof(*c2h), ra_report.bw)) {
rarpt->txrate.legacy = if (c2h->ra_report.bw == RTL8XXXU_CHANNEL_WIDTH_40)
rtl8xxxu_legacy_ratetable[rate].bitrate; bw = RATE_INFO_BW_40;
} else { else
rtl8xxxu_desc_to_mcsrate(rate, &mcs, &nss); bw = RATE_INFO_BW_20;
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 (bw == RATE_INFO_BW_20)
rarpt->txrate.bw |= RATE_INFO_BW_20;
} }
bit_rate = cfg80211_calculate_bitrate(&rarpt->txrate);
rarpt->bit_rate = bit_rate; rtl8xxxu_update_ra_report(rarpt, c2h->ra_report.rate,
rarpt->desc_rate = rate; c2h->ra_report.sgi, bw);
break; break;
default: default:
break; break;

View file

@ -1903,7 +1903,7 @@ btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoexist)
true, 32); true, 32);
halbtc8723b1ant_coex_table_with_type(btcoexist, halbtc8723b1ant_coex_table_with_type(btcoexist,
NORMAL_EXEC, 4); NORMAL_EXEC, 4);
} else if (bt_link_info->a2dp_exist) { } else if (bt_link_info->pan_exist) {
halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 22); true, 22);
halbtc8723b1ant_coex_table_with_type(btcoexist, halbtc8723b1ant_coex_table_with_type(btcoexist,
@ -1964,8 +1964,7 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist)
true, 32); true, 32);
halbtc8723b1ant_coex_table_with_type(btcoexist, halbtc8723b1ant_coex_table_with_type(btcoexist,
NORMAL_EXEC, 4); NORMAL_EXEC, 4);
} else if (bt_link_info->a2dp_exist && } else if (bt_link_info->pan_exist) {
bt_link_info->pan_exist) {
halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 22); true, 22);
halbtc8723b1ant_coex_table_with_type(btcoexist, halbtc8723b1ant_coex_table_with_type(btcoexist,

View file

@ -115,9 +115,6 @@ static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw,
retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb, retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
BLSSI_READBACK_DATA); 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", rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n",
rfpath, pphyreg->rf_rb, retvalue); rfpath, pphyreg->rf_rb, retvalue);

View file

@ -16,6 +16,9 @@ config RTW88_CORE
config RTW88_PCI config RTW88_PCI
tristate tristate
config RTW88_USB
tristate
config RTW88_8822B config RTW88_8822B
tristate tristate
@ -39,6 +42,17 @@ config RTW88_8822BE
802.11ac PCIe wireless network adapter 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 config RTW88_8822CE
tristate "Realtek 8822CE PCI wireless network adapter" tristate "Realtek 8822CE PCI wireless network adapter"
depends on PCI depends on PCI
@ -50,6 +64,17 @@ config RTW88_8822CE
802.11ac PCIe wireless network adapter 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 config RTW88_8723DE
tristate "Realtek 8723DE PCI wireless network adapter" tristate "Realtek 8723DE PCI wireless network adapter"
depends on PCI depends on PCI
@ -61,6 +86,17 @@ config RTW88_8723DE
802.11n PCIe wireless network adapter 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 config RTW88_8821CE
tristate "Realtek 8821CE PCI wireless network adapter" tristate "Realtek 8821CE PCI wireless network adapter"
depends on PCI depends on PCI
@ -72,6 +108,17 @@ config RTW88_8821CE
802.11ac PCIe wireless network adapter 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 config RTW88_DEBUG
bool "Realtek rtw88 debug support" bool "Realtek rtw88 debug support"
depends on RTW88_CORE depends on RTW88_CORE

View file

@ -26,23 +26,38 @@ rtw88_8822b-objs := rtw8822b.o rtw8822b_table.o
obj-$(CONFIG_RTW88_8822BE) += rtw88_8822be.o obj-$(CONFIG_RTW88_8822BE) += rtw88_8822be.o
rtw88_8822be-objs := rtw8822be.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 obj-$(CONFIG_RTW88_8822C) += rtw88_8822c.o
rtw88_8822c-objs := rtw8822c.o rtw8822c_table.o rtw88_8822c-objs := rtw8822c.o rtw8822c_table.o
obj-$(CONFIG_RTW88_8822CE) += rtw88_8822ce.o obj-$(CONFIG_RTW88_8822CE) += rtw88_8822ce.o
rtw88_8822ce-objs := rtw8822ce.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 obj-$(CONFIG_RTW88_8723D) += rtw88_8723d.o
rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o
obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o
rtw88_8723de-objs := rtw8723de.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 obj-$(CONFIG_RTW88_8821C) += rtw88_8821c.o
rtw88_8821c-objs := rtw8821c.o rtw8821c_table.o rtw88_8821c-objs := rtw8821c.o rtw8821c_table.o
obj-$(CONFIG_RTW88_8821CE) += rtw88_8821ce.o obj-$(CONFIG_RTW88_8821CE) += rtw88_8821ce.o
rtw88_8821ce-objs := rtw8821ce.o rtw88_8821ce-objs := rtw8821ce.o
obj-$(CONFIG_RTW88_8821CU) += rtw88_8821cu.o
rtw88_8821cu-objs := rtw8821cu.o
obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o
rtw88_pci-objs := pci.o rtw88_pci-objs := pci.o
obj-$(CONFIG_RTW88_USB) += rtw88_usb.o
rtw88_usb-objs := usb.o

View file

@ -633,7 +633,7 @@ static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct sk_buff *skb_resp = NULL; struct sk_buff *skb_resp = NULL;
mutex_lock(&coex->mutex); lockdep_assert_held(&rtwdev->mutex);
rtw_fw_query_bt_mp_info(rtwdev, req); 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: out:
mutex_unlock(&coex->mutex);
return skb_resp; return skb_resp;
} }

View file

@ -144,7 +144,9 @@ static int rtw_debugfs_get_rf_read(struct seq_file *m, void *v)
addr = debugfs_priv->rf_addr; addr = debugfs_priv->rf_addr;
mask = debugfs_priv->rf_mask; mask = debugfs_priv->rf_mask;
mutex_lock(&rtwdev->mutex);
val = rtw_read_rf(rtwdev, path, addr, mask); 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", seq_printf(m, "rf_read path:%d addr:0x%08x mask:0x%08x val=0x%08x\n",
path, addr, mask, val); path, addr, mask, val);
@ -390,7 +392,9 @@ static ssize_t rtw_debugfs_set_h2c(struct file *filp,
return -EINVAL; return -EINVAL;
} }
mutex_lock(&rtwdev->mutex);
rtw_fw_h2c_cmd_dbg(rtwdev, param); rtw_fw_h2c_cmd_dbg(rtwdev, param);
mutex_unlock(&rtwdev->mutex);
return count; return count;
} }
@ -414,7 +418,9 @@ static ssize_t rtw_debugfs_set_rf_write(struct file *filp,
return count; return count;
} }
mutex_lock(&rtwdev->mutex);
rtw_write_rf(rtwdev, path, addr, mask, val); rtw_write_rf(rtwdev, path, addr, mask, val);
mutex_unlock(&rtwdev->mutex);
rtw_dbg(rtwdev, RTW_DBG_DEBUGFS, rtw_dbg(rtwdev, RTW_DBG_DEBUGFS,
"write_rf path:%d addr:0x%08x mask:0x%08x, val:0x%08x\n", "write_rf path:%d addr:0x%08x mask:0x%08x, val:0x%08x\n",
path, addr, mask, val); 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; u32 addr, offset, data;
u8 path; u8 path;
mutex_lock(&rtwdev->mutex);
for (path = 0; path < rtwdev->hal.rf_path_num; path++) { for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
seq_printf(m, "RF path:%d\n", path); seq_printf(m, "RF path:%d\n", path);
for (addr = 0; addr < 0x100; addr += 4) { 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"); seq_puts(m, "\n");
} }
mutex_unlock(&rtwdev->mutex);
return 0; 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_debugfs_priv *debugfs_priv = m->private;
struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
mutex_lock(&rtwdev->mutex);
rtw_coex_display_coex_info(rtwdev, m); rtw_coex_display_coex_info(rtwdev, m);
mutex_unlock(&rtwdev->mutex);
return 0; 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) ? '-' : '+', dm_info->dm_flags & BIT(RTW_DM_CAP_TXGAPK) ? '-' : '+',
rtw_dm_cap_strs[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++) { for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
val = rtw_read_rf(rtwdev, path, RF_GAINTX, RFREG_MASK); val = rtw_read_rf(rtwdev, path, RF_GAINTX, RFREG_MASK);
seq_printf(m, "path %d:\n0x%x = 0x%x\n", path, RF_GAINTX, val); 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); txgapk->rf3f_fs[path][i], i);
seq_puts(m, "\n"); seq_puts(m, "\n");
} }
mutex_unlock(&rtwdev->mutex);
} }
static int rtw_debugfs_get_dm_cap(struct seq_file *m, void *v) static int rtw_debugfs_get_dm_cap(struct seq_file *m, void *v)

View file

@ -322,7 +322,7 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
h2c[3], h2c[2], h2c[1], h2c[0], h2c[3], h2c[2], h2c[1], h2c[0],
h2c[7], h2c[6], h2c[5], h2c[4]); h2c[7], h2c[6], h2c[5], h2c[4]);
spin_lock(&rtwdev->h2c.lock); lockdep_assert_held(&rtwdev->mutex);
box = rtwdev->h2c.last_box_num; box = rtwdev->h2c.last_box_num;
switch (box) { switch (box) {
@ -344,7 +344,7 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
break; break;
default: default:
WARN(1, "invalid h2c mail box number\n"); WARN(1, "invalid h2c mail box number\n");
goto out; return;
} }
ret = read_poll_timeout_atomic(rtw_read8, box_state, 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) { if (ret) {
rtw_err(rtwdev, "failed to send h2c command\n"); 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)); 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) if (++rtwdev->h2c.last_box_num >= 4)
rtwdev->h2c.last_box_num = 0; rtwdev->h2c.last_box_num = 0;
out:
spin_unlock(&rtwdev->h2c.lock);
} }
void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c) 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; int ret;
spin_lock(&rtwdev->h2c.lock); lockdep_assert_held(&rtwdev->mutex);
FW_OFFLOAD_H2C_SET_SEQ_NUM(h2c_pkt, rtwdev->h2c.seq); FW_OFFLOAD_H2C_SET_SEQ_NUM(h2c_pkt, rtwdev->h2c.seq);
ret = rtw_hci_write_data_h2c(rtwdev, h2c_pkt, H2C_PKT_SIZE); ret = rtw_hci_write_data_h2c(rtwdev, h2c_pkt, H2C_PKT_SIZE);
if (ret) if (ret)
rtw_err(rtwdev, "failed to send h2c packet\n"); rtw_err(rtwdev, "failed to send h2c packet\n");
rtwdev->h2c.seq++; rtwdev->h2c.seq++;
spin_unlock(&rtwdev->h2c.lock);
} }
void void

View file

@ -166,12 +166,11 @@ static inline u32
rtw_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, rtw_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask) u32 addr, u32 mask)
{ {
unsigned long flags;
u32 val; 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); val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
spin_unlock_irqrestore(&rtwdev->rf_lock, flags);
return val; return val;
} }
@ -180,11 +179,9 @@ static inline void
rtw_write_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, rtw_write_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data) 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); rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data);
spin_unlock_irqrestore(&rtwdev->rf_lock, flags);
} }
static inline u32 static inline u32

View file

@ -1048,6 +1048,9 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev)
if (rtw_chip_wcpu_11ac(rtwdev)) if (rtw_chip_wcpu_11ac(rtwdev))
rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); 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; return 0;
} }

View file

@ -487,8 +487,8 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw,
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
rtw_fw_beacon_filter_config(rtwdev, false, vif);
mutex_lock(&rtwdev->mutex); mutex_lock(&rtwdev->mutex);
rtw_fw_beacon_filter_config(rtwdev, false, vif);
rtw_sta_remove(rtwdev, sta, true); rtw_sta_remove(rtwdev, sta, true);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);

View file

@ -1731,7 +1731,8 @@ static void rtw_load_firmware_cb(const struct firmware *firmware, void *context)
update_firmware_info(rtwdev, fw); update_firmware_info(rtwdev, fw);
complete_all(&fw->completion); 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); 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; return -ENOENT;
} }
fw->type = type;
fw->rtwdev = rtwdev; fw->rtwdev = rtwdev;
init_completion(&fw->completion); 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.rpwm_addr = 0x03d9;
rtwdev->hci.cpwm_addr = 0x03da; rtwdev->hci.cpwm_addr = 0x03da;
break; break;
case RTW_HCI_TYPE_USB:
rtwdev->hci.rpwm_addr = 0xfe58;
rtwdev->hci.cpwm_addr = 0xfe57;
break;
default: default:
rtw_err(rtwdev, "unsupported hci type\n"); rtw_err(rtwdev, "unsupported hci type\n");
return -EINVAL; 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->coex.queue);
skb_queue_head_init(&rtwdev->tx_report.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->txq_lock);
spin_lock_init(&rtwdev->tx_report.q_lock); spin_lock_init(&rtwdev->tx_report.q_lock);
mutex_init(&rtwdev->mutex); mutex_init(&rtwdev->mutex);
mutex_init(&rtwdev->coex.mutex);
mutex_init(&rtwdev->hal.tx_power_mutex); mutex_init(&rtwdev->hal.tx_power_mutex);
init_waitqueue_head(&rtwdev->coex.wait); 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->mutex);
mutex_destroy(&rtwdev->coex.mutex);
mutex_destroy(&rtwdev->hal.tx_power_mutex); mutex_destroy(&rtwdev->hal.tx_power_mutex);
} }
EXPORT_SYMBOL(rtw_core_deinit); EXPORT_SYMBOL(rtw_core_deinit);

View file

@ -871,6 +871,10 @@ struct rtw_chip_ops {
bool is_tx2_path); bool is_tx2_path);
void (*config_txrx_mode)(struct rtw_dev *rtwdev, u8 tx_path, void (*config_txrx_mode)(struct rtw_dev *rtwdev, u8 tx_path,
u8 rx_path, bool is_tx2_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 */ /* for coex */
void (*coex_set_init)(struct rtw_dev *rtwdev); void (*coex_set_init)(struct rtw_dev *rtwdev);
@ -1501,8 +1505,6 @@ struct rtw_coex_stat {
}; };
struct rtw_coex { struct rtw_coex {
/* protects coex info request section */
struct mutex mutex;
struct sk_buff_head queue; struct sk_buff_head queue;
wait_queue_head_t wait; wait_queue_head_t wait;
@ -1851,6 +1853,7 @@ struct rtw_fw_state {
u16 h2c_version; u16 h2c_version;
u32 feature; u32 feature;
u32 feature_ext; u32 feature_ext;
enum rtw_fw_type type;
}; };
enum rtw_sar_sources { enum rtw_sar_sources {
@ -1994,9 +1997,6 @@ struct rtw_dev {
/* ensures exclusive access from mac80211 callbacks */ /* ensures exclusive access from mac80211 callbacks */
struct mutex mutex; struct mutex mutex;
/* read/write rf register */
spinlock_t rf_lock;
/* watch dog every 2 sec */ /* watch dog every 2 sec */
struct delayed_work watch_dog_work; struct delayed_work watch_dog_work;
u32 watch_dog_cnt; u32 watch_dog_cnt;
@ -2022,8 +2022,6 @@ struct rtw_dev {
struct { struct {
/* incicate the mail box to use with fw */ /* incicate the mail box to use with fw */
u8 last_box_num; u8 last_box_num;
/* protect to send h2c to fw */
spinlock_t lock;
u32 seq; u32 seq;
} h2c; } h2c;

View file

@ -300,7 +300,7 @@ static void rtw_phy_stat_rssi(struct rtw_dev *rtwdev)
data.rtwdev = rtwdev; data.rtwdev = rtwdev;
data.min_rssi = U8_MAX; 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->pre_min_rssi = dm_info->min_rssi;
dm_info->min_rssi = data.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) if (rtwdev->watch_dog_cnt & 0x3)
return; 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) 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; struct rtw_dm_info *dm_info = &rtwdev->dm_info;
dm_info->rrsr_mask_min = RRSR_RATE_ORDER_MAX; 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); rtw_write32(rtwdev, REG_RRSR, dm_info->rrsr_val_init & dm_info->rrsr_mask_min);
} }

View file

@ -61,7 +61,7 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
return ret; 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); rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);

View file

@ -184,6 +184,7 @@
#define BIT_TXDMA_VIQ_MAP(x) \ #define BIT_TXDMA_VIQ_MAP(x) \
(((x) & BIT_MASK_TXDMA_VIQ_MAP) << BIT_SHIFT_TXDMA_VIQ_MAP) (((x) & BIT_MASK_TXDMA_VIQ_MAP) << BIT_SHIFT_TXDMA_VIQ_MAP)
#define REG_TXDMA_PQ_MAP 0x010C #define REG_TXDMA_PQ_MAP 0x010C
#define BIT_RXDMA_ARBBW_EN BIT(0)
#define BIT_SHIFT_TXDMA_BEQ_MAP 8 #define BIT_SHIFT_TXDMA_BEQ_MAP 8
#define BIT_MASK_TXDMA_BEQ_MAP 0x3 #define BIT_MASK_TXDMA_BEQ_MAP 0x3
#define BIT_TXDMA_BEQ_MAP(x) \ #define BIT_TXDMA_BEQ_MAP(x) \

View file

@ -210,6 +210,12 @@ static void rtw8723de_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr); 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) static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{ {
struct rtw_efuse *efuse = &rtwdev->efuse; 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: case RTW_HCI_TYPE_PCIE:
rtw8723de_efuse_parsing(efuse, map); rtw8723de_efuse_parsing(efuse, map);
break; break;
case RTW_HCI_TYPE_USB:
rtw8723du_efuse_parsing(efuse, map);
break;
default: default:
/* unsupported now */ /* unsupported now */
return -ENOTSUPP; return -ENOTSUPP;
@ -1945,6 +1954,24 @@ static void rtw8723d_pwr_track(struct rtw_dev *rtwdev)
dm_info->pwr_trk_triggered = false; 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 = { static struct rtw_chip_ops rtw8723d_ops = {
.phy_set_param = rtw8723d_phy_set_param, .phy_set_param = rtw8723d_phy_set_param,
.read_efuse = rtw8723d_read_efuse, .read_efuse = rtw8723d_read_efuse,
@ -1965,6 +1992,7 @@ static struct rtw_chip_ops rtw8723d_ops = {
.config_bfee = NULL, .config_bfee = NULL,
.set_gid_table = NULL, .set_gid_table = NULL,
.cfg_csi_rate = NULL, .cfg_csi_rate = NULL,
.fill_txdesc_checksum = rtw8723d_fill_txdesc_checksum,
.coex_set_init = rtw8723d_coex_cfg_init, .coex_set_init = rtw8723d_coex_cfg_init,
.coex_set_ant_switch = NULL, .coex_set_ant_switch = NULL,

View file

@ -41,6 +41,14 @@ struct rtw8723de_efuse {
u8 sub_device_id[2]; 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 { struct rtw8723d_efuse {
__le16 rtl_id; __le16 rtl_id;
u8 rsvd[2]; u8 rsvd[2];
@ -69,7 +77,10 @@ struct rtw8723d_efuse {
u8 rfe_option; u8 rfe_option;
u8 country_code[2]; u8 country_code[2];
u8 res[3]; 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; extern const struct rtw_chip_info rtw8723d_hw_spec;

View file

@ -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");

View file

@ -26,6 +26,12 @@ static void rtw8821ce_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr); 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 { enum rtw8821ce_rf_set {
SWITCH_TO_BTG, SWITCH_TO_BTG,
SWITCH_TO_WLG, SWITCH_TO_WLG,
@ -68,6 +74,9 @@ static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_PCIE: case RTW_HCI_TYPE_PCIE:
rtw8821ce_efuse_parsing(efuse, map); rtw8821ce_efuse_parsing(efuse, map);
break; break;
case RTW_HCI_TYPE_USB:
rtw8821cu_efuse_parsing(efuse, map);
break;
default: default:
/* unsupported now */ /* unsupported now */
return -ENOTSUPP; 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); 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[] = { static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = {
{0x0086, {0x0086,
RTW_PWR_CUT_ALL_MSK, 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), [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
[4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
[6] = RTW_DEF_RFE(8821c, 0, 0), [6] = RTW_DEF_RFE(8821c, 0, 0),
[34] = RTW_DEF_RFE(8821c, 0, 0),
}; };
static struct rtw_hw_reg rtw8821c_dig[] = { static struct rtw_hw_reg rtw8821c_dig[] = {
@ -1595,6 +1612,7 @@ static struct rtw_chip_ops rtw8821c_ops = {
.config_bfee = rtw8821c_bf_config_bfee, .config_bfee = rtw8821c_bf_config_bfee,
.set_gid_table = rtw_bf_set_gid_table, .set_gid_table = rtw_bf_set_gid_table,
.cfg_csi_rate = rtw_bf_cfg_csi_rate, .cfg_csi_rate = rtw_bf_cfg_csi_rate,
.fill_txdesc_checksum = rtw8821c_fill_txdesc_checksum,
.coex_set_init = rtw8821c_coex_cfg_init, .coex_set_init = rtw8821c_coex_cfg_init,
.coex_set_ant_switch = rtw8821c_coex_cfg_ant_switch, .coex_set_ant_switch = rtw8821c_coex_cfg_ant_switch,

View file

@ -9,6 +9,26 @@
#define RCR_VHT_ACK BIT(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 { struct rtw8821ce_efuse {
u8 mac_addr[ETH_ALEN]; /* 0xd0 */ u8 mac_addr[ETH_ALEN]; /* 0xd0 */
u8 vender_id[2]; u8 vender_id[2];
@ -73,6 +93,7 @@ struct rtw8821c_efuse {
u8 res[3]; u8 res[3];
union { union {
struct rtw8821ce_efuse e; struct rtw8821ce_efuse e;
struct rtw8821cu_efuse u;
}; };
}; };

View file

@ -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");

View file

@ -26,6 +26,12 @@ static void rtw8822be_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr); 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) static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{ {
struct rtw_efuse *efuse = &rtwdev->efuse; 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: case RTW_HCI_TYPE_PCIE:
rtw8822be_efuse_parsing(efuse, map); rtw8822be_efuse_parsing(efuse, map);
break; break;
case RTW_HCI_TYPE_USB:
rtw8822bu_efuse_parsing(efuse, map);
break;
default: default:
/* unsupported now */ /* unsupported now */
return -ENOTSUPP; return -ENOTSUPP;
@ -1588,6 +1597,15 @@ static void rtw8822b_adaptivity(struct rtw_dev *rtwdev)
rtw_phy_set_edcca_th(rtwdev, l2h, h2l); 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[] = { static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = {
{0x0086, {0x0086,
RTW_PWR_CUT_ALL_MSK, RTW_PWR_CUT_ALL_MSK,
@ -2163,6 +2181,7 @@ static struct rtw_chip_ops rtw8822b_ops = {
.cfg_csi_rate = rtw_bf_cfg_csi_rate, .cfg_csi_rate = rtw_bf_cfg_csi_rate,
.adaptivity_init = rtw8822b_adaptivity_init, .adaptivity_init = rtw8822b_adaptivity_init,
.adaptivity = rtw8822b_adaptivity, .adaptivity = rtw8822b_adaptivity,
.fill_txdesc_checksum = rtw8822b_fill_txdesc_checksum,
.coex_set_init = rtw8822b_coex_cfg_init, .coex_set_init = rtw8822b_coex_cfg_init,
.coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch, .coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch,

View file

@ -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");

View file

@ -29,6 +29,12 @@ static void rtw8822ce_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr); 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) static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{ {
struct rtw_efuse *efuse = &rtwdev->efuse; 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: case RTW_HCI_TYPE_PCIE:
rtw8822ce_efuse_parsing(efuse, map); rtw8822ce_efuse_parsing(efuse, map);
break; break;
case RTW_HCI_TYPE_USB:
rtw8822cu_efuse_parsing(efuse, map);
break;
default: default:
/* unsupported now */ /* unsupported now */
return -ENOTSUPP; return -ENOTSUPP;
@ -4557,6 +4566,18 @@ static void rtw8822c_adaptivity(struct rtw_dev *rtwdev)
rtw_phy_set_edcca_th(rtwdev, l2h, h2l); 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[] = { static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = {
{0x0086, {0x0086,
RTW_PWR_CUT_ALL_MSK, 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), [0] = RTW_DEF_RFE(8822c, 0, 0),
[1] = RTW_DEF_RFE(8822c, 0, 0), [1] = RTW_DEF_RFE(8822c, 0, 0),
[2] = 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), [5] = RTW_DEF_RFE(8822c, 0, 5),
[6] = RTW_DEF_RFE(8822c, 0, 0), [6] = RTW_DEF_RFE(8822c, 0, 0),
}; };
@ -4978,6 +5001,7 @@ static struct rtw_chip_ops rtw8822c_ops = {
.cfo_track = rtw8822c_cfo_track, .cfo_track = rtw8822c_cfo_track,
.config_tx_path = rtw8822c_config_tx_path, .config_tx_path = rtw8822c_config_tx_path,
.config_txrx_mode = rtw8822c_config_trx_mode, .config_txrx_mode = rtw8822c_config_trx_mode,
.fill_txdesc_checksum = rtw8822c_fill_txdesc_checksum,
.coex_set_init = rtw8822c_coex_cfg_init, .coex_set_init = rtw8822c_coex_cfg_init,
.coex_set_ant_switch = NULL, .coex_set_ant_switch = NULL,

View file

@ -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");

View file

@ -71,6 +71,14 @@
le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(15)) le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(15))
#define SET_TX_DESC_BT_NULL(txdesc, value) \ #define SET_TX_DESC_BT_NULL(txdesc, value) \
le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(23)) 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 { enum rtw_tx_desc_queue_select {
TX_DESC_QSEL_TID0 = 0, 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, struct rtw_tx_pkt_info *pkt_info,
u8 *buf, u32 size); 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 #endif

View file

@ -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");

View file

@ -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

View file

@ -105,3 +105,106 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
*mcs = rate - DESC_RATEMCS0; *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);
}
}

View file

@ -7,9 +7,6 @@
struct rtw_dev; 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) \ #define rtw_iterate_vifs_atomic(rtwdev, iterator, data) \
ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, \ ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, \
IEEE80211_IFACE_ITER_NORMAL, iterator, data) IEEE80211_IFACE_ITER_NORMAL, iterator, data)
@ -20,6 +17,15 @@ struct rtw_dev;
#define rtw_iterate_keys_rcu(rtwdev, vif, iterator, data) \ #define rtw_iterate_keys_rcu(rtwdev, vif, iterator, data) \
ieee80211_iter_keys_rcu((rtwdev)->hw, 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) static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
{ {
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;

View file

@ -3420,6 +3420,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
u32 bus_data_size, u32 bus_data_size,
const struct rtw89_chip_info *chip) const struct rtw89_chip_info *chip)
{ {
const struct firmware *firmware;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct rtw89_dev *rtwdev; struct rtw89_dev *rtwdev;
struct ieee80211_ops *ops; struct ieee80211_ops *ops;
@ -3427,7 +3428,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
u32 early_feat_map = 0; u32 early_feat_map = 0;
bool no_chanctx; 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); ops = kmemdup(&rtw89_ops, sizeof(rtw89_ops), GFP_KERNEL);
if (!ops) if (!ops)
@ -3454,6 +3455,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
rtwdev->dev = device; rtwdev->dev = device;
rtwdev->ops = ops; rtwdev->ops = ops;
rtwdev->chip = chip; rtwdev->chip = chip;
rtwdev->fw.firmware = firmware;
rtw89_debug(rtwdev, RTW89_DBG_FW, "probe driver %s chanctx\n", rtw89_debug(rtwdev, RTW89_DBG_FW, "probe driver %s chanctx\n",
no_chanctx ? "without" : "with"); no_chanctx ? "without" : "with");
@ -3462,6 +3464,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
err: err:
kfree(ops); kfree(ops);
release_firmware(firmware);
return NULL; return NULL;
} }
EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw); 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) void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev)
{ {
kfree(rtwdev->ops); kfree(rtwdev->ops);
release_firmware(rtwdev->fw.firmware);
ieee80211_free_hw(rtwdev->hw); ieee80211_free_hw(rtwdev->hw);
} }
EXPORT_SYMBOL(rtw89_free_ieee80211_hw); EXPORT_SYMBOL(rtw89_free_ieee80211_hw);

View file

@ -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 firmware *
const struct rtw89_chip_info *chip, rtw89_early_fw_feature_recognize(struct device *device,
u32 *early_feat_map) const struct rtw89_chip_info *chip,
u32 *early_feat_map)
{ {
union { union rtw89_compat_fw_hdr buf = {};
struct rtw89_mfw_hdr mfw_hdr;
u8 fw_hdr[RTW89_FW_HDR_SIZE];
} buf = {};
const struct firmware *firmware; const struct firmware *firmware;
bool full_req = false;
u32 ver_code; u32 ver_code;
int ret; int ret;
int i; int i;
ret = request_partial_firmware_into_buf(&firmware, chip->fw_name, /* If SECURITY_LOADPIN_ENFORCE is enabled, reading partial files will
device, &buf, sizeof(buf), 0); * 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) { if (ret) {
dev_err(device, "failed to early request firmware: %d\n", ret); dev_err(device, "failed to early request firmware: %d\n", ret);
return; return NULL;
} }
ver_code = buf.mfw_hdr.sig != RTW89_MFW_SIG ? if (full_req)
RTW89_FW_HDR_VER_CODE(&buf.fw_hdr) : ver_code = rtw89_compat_fw_hdr_ver_code(firmware->data);
RTW89_MFW_HDR_VER_CODE(&buf.mfw_hdr); else
ver_code = rtw89_compat_fw_hdr_ver_code(&buf);
if (!ver_code) if (!ver_code)
goto out; goto out;
@ -310,7 +323,11 @@ void rtw89_early_fw_feature_recognize(struct device *device,
} }
out: out:
if (full_req)
return firmware;
release_firmware(firmware); release_firmware(firmware);
return NULL;
} }
int rtw89_fw_recognize(struct rtw89_dev *rtwdev) int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
@ -617,6 +634,13 @@ int rtw89_load_firmware(struct rtw89_dev *rtwdev)
fw->rtwdev = rtwdev; fw->rtwdev = rtwdev;
init_completion(&fw->completion); 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, ret = request_firmware_nowait(THIS_MODULE, true, fw_name, rtwdev->dev,
GFP_KERNEL, fw, rtw89_load_firmware_cb); GFP_KERNEL, fw, rtw89_load_firmware_cb);
if (ret) { if (ret) {
@ -633,8 +657,14 @@ void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
rtw89_wait_firmware_completion(rtwdev); rtw89_wait_firmware_completion(rtwdev);
if (fw->firmware) if (fw->firmware) {
release_firmware(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 #define H2C_CAM_LEN 60

View file

@ -3291,6 +3291,21 @@ struct fwcmd_hdr {
__le32 hdr1; __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_SIZE 500
#define RTW89_H2C_RF_PAGE_NUM 3 #define RTW89_H2C_RF_PAGE_NUM 3
struct rtw89_fw_h2c_rf_reg_info { 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_check_rdy(struct rtw89_dev *rtwdev);
int rtw89_fw_recognize(struct rtw89_dev *rtwdev); int rtw89_fw_recognize(struct rtw89_dev *rtwdev);
void rtw89_early_fw_feature_recognize(struct device *device, const struct firmware *
const struct rtw89_chip_info *chip, rtw89_early_fw_feature_recognize(struct device *device,
u32 *early_feat_map); 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_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type);
int rtw89_load_firmware(struct rtw89_dev *rtwdev); int rtw89_load_firmware(struct rtw89_dev *rtwdev);
void rtw89_unload_firmware(struct rtw89_dev *rtwdev); void rtw89_unload_firmware(struct rtw89_dev *rtwdev);

View file

@ -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, 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; 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, 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); 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 rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{ {
int ret; int ret;
@ -3932,6 +3980,10 @@ int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
if (ret) if (ret)
return ret; return ret;
ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
if (ret)
return ret;
ret = rtw89_cam_init(rtwdev, rtwvif); ret = rtw89_cam_init(rtwdev, rtwvif);
if (ret) if (ret)
return 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_tbtt_shift(rtwdev, rtwvif);
rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif); rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif);
rtw89_mac_port_cfg_mbssid(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); fsleep(BCN_ERLY_SET_DLY);
rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif); 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); 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 rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{ {
int ret; int ret;

View file

@ -168,6 +168,8 @@ enum rtw89_mac_ax_l0_to_l1_event {
MAC_AX_L0_TO_L1_EVENT_MAX = 15, 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 { enum rtw89_mac_dbg_port_sel {
/* CMAC 0 related */ /* CMAC 0 related */
RTW89_DBG_PORT_SEL_PTCL_C0 = 0, 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); 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, void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif); 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); int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev); void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev);
int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw); int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw);

View file

@ -125,6 +125,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
RTW89_PORT_NUM); RTW89_PORT_NUM);
if (rtwvif->port == RTW89_PORT_NUM) { if (rtwvif->port == RTW89_PORT_NUM) {
ret = -ENOSPC; ret = -ENOSPC;
list_del_init(&rtwvif->list);
goto out; goto out;
} }
@ -138,6 +139,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
ret = rtw89_mac_add_vif(rtwdev, rtwvif); ret = rtw89_mac_add_vif(rtwdev, rtwvif);
if (ret) { if (ret) {
rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port);
list_del_init(&rtwvif->list);
goto out; 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; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
mutex_lock(&rtwdev->mutex); mutex_lock(&rtwdev->mutex);
rtw89_mac_stop_ap(rtwdev, rtwvif);
rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL);
rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);

View file

@ -2048,6 +2048,23 @@
#define B_AX_PTCL_TOP_ERR_IND BIT(1) #define B_AX_PTCL_TOP_ERR_IND BIT(1)
#define B_AX_SCHEDULE_TOP_ERR_IND BIT(0) #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 0xC2C0
#define R_AX_MACID_SLEEP_0_C1 0xE2C0 #define R_AX_MACID_SLEEP_0_C1 0xE2C0
#define B_AX_MACID31_0_SLEEP_SH 0 #define B_AX_MACID31_0_SLEEP_SH 0