wireless-next patches for 6.4

Major changes:
 
 cfg80211
  * 6 GHz improvements
  * HW timestamping support
  * support for randomized auth/deauth TA for PASN privacy
    (also for mac80211)
 
 mac80211
  * radiotap TLV and EHT support for the iwlwifi sniffer
  * HW timestamping support
  * per-link debugfs for multi-link
 
 brcmfmac
  * support for Apple (M1 Pro/Max) devices
 
 iwlwifi
  * support for a few new devices
  * EHT sniffer support
 
 rtw88
  * better support for some SDIO devices
    (e.g. MAC address from efuse)
 
 rtw89
  * HW scan support for 8852b
  * better support for 6 GHz scanning
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmQLG7oACgkQ10qiO8sP
 aAAqsBAAmiGDd9CDToWmXiyf3Qwv7eazNtqqz5LUKbSnmAXyyDDpHR28A8DlsEU0
 OTlrQK0yQr3R4sUhLVY+tL49gZvgqp0B9pj7NqnK3HIOniFdfpZdTXdFNdx3KuEs
 k1c/D+wGAIhVHP8csIKhh49KpGFa4U2YMXCUx4mNrUQKGhO+b/XbiMKS8jmoQAF9
 1GQk/KcGblBmuKFWE1euSScyBh2CvvcJq+F9f25eiX/+OgVXNYWWfAHfr3jjX7RG
 lSdlMvKvF4LImCW0vnhmFUeSSl+GpszNXwaqIh6OGLrw2CBZDcujGTT88cOw3A1t
 JFTB3EgeuFL3fDHQogWFxQ/RhfZB/tHeBYEQSx+1WizHKtJEMY2pvjuj9rZ7TEWy
 HHFfP1OaU1tbqMIkkhchAhOyciVJpk77Cl6yO0TcpRLt9VR1LvACMAd3/3eqfQGf
 gJxS8x7qWHp3pSWTNa3X8Q2NPatstKz/LUO0JMQP690/sRwdta9RwR11CYm0/Mdb
 22TwOSa6lfAlOF/l/YkEy39U8J1XNxPschkdAz4h001N88h8dAf6UZieDqqPYZFK
 4sYsGLqtACEU5W/Y5PG7v3/ZZ+QtEtfWU057tEtvHkVws2BKvRRQ3c0DBG5QTVG0
 4k9QU6mxKxL/R2Nkf6+rB8lvQkHEyXp6voF3LmqRlB/gnh1FKY0=
 =sPir
 -----END PGP SIGNATURE-----

Merge tag 'wireless-next-2023-03-10' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next

Johannes Berg says:

====================
wireless-next patches for 6.4

Major changes:

cfg80211
 * 6 GHz improvements
 * HW timestamping support
 * support for randomized auth/deauth TA for PASN privacy
   (also for mac80211)

mac80211
 * radiotap TLV and EHT support for the iwlwifi sniffer
 * HW timestamping support
 * per-link debugfs for multi-link

brcmfmac
 * support for Apple (M1 Pro/Max) devices

iwlwifi
 * support for a few new devices
 * EHT sniffer support

rtw88
 * better support for some SDIO devices
   (e.g. MAC address from efuse)

rtw89
 * HW scan support for 8852b
 * better support for 6 GHz scanning

* tag 'wireless-next-2023-03-10' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (84 commits)
  wifi: iwlwifi: mvm: fix EOF bit reporting
  wifi: iwlwifi: Do not include radiotap EHT user info if not needed
  wifi: iwlwifi: mvm: add EHT RU allocation to radiotap
  wifi: iwlwifi: Update logs for yoyo reset sw changes
  wifi: iwlwifi: mvm: clean up duplicated defines
  wifi: iwlwifi: rs-fw: break out for unsupported bandwidth
  wifi: iwlwifi: Add support for B step of BnJ-Fm4
  wifi: iwlwifi: mvm: make flush code a bit clearer
  wifi: iwlwifi: mvm: avoid UB shift of snif_queue
  wifi: iwlwifi: mvm: add primary 80 known for EHT radiotap
  wifi: iwlwifi: mvm: parse FW frame metadata for EHT sniffer mode
  wifi: iwlwifi: mvm: decode USIG_B1_B7 RU to nl80211 RU width
  wifi: iwlwifi: mvm: rename define to generic name
  wifi: iwlwifi: mvm: allow Microsoft to use TAS
  wifi: iwlwifi: mvm: add all EHT based on data0 info from HW
  wifi: iwlwifi: mvm: add EHT radiotap info based on rate_n_flags
  wifi: iwlwifi: mvm: add an helper function radiotap TLVs
  wifi: radiotap: separate vendor TLV into header/content
  wifi: iwlwifi: reduce verbosity of some logging events
  wifi: iwlwifi: Adding the code to get RF name for MsP device
  ...
====================

Link: https://lore.kernel.org/r/20230310120159.36518-1-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2023-03-10 18:22:28 -08:00
commit 2af560e5a5
77 changed files with 2645 additions and 643 deletions

View File

@ -48,6 +48,8 @@ brcmfmac-$(CONFIG_OF) += \
of.o
brcmfmac-$(CONFIG_DMI) += \
dmi.o
brcmfmac-$(CONFIG_ACPI) += \
acpi.o
ifeq ($(CONFIG_BRCMFMAC),m)
obj-m += wcc/

View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: ISC
/*
* Copyright The Asahi Linux Contributors
*/
#include <linux/acpi.h>
#include "debug.h"
#include "core.h"
#include "common.h"
void brcmf_acpi_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings)
{
acpi_status status;
const union acpi_object *o;
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_device *adev = ACPI_COMPANION(dev);
if (!adev)
return;
if (!ACPI_FAILURE(acpi_dev_get_property(adev, "module-instance",
ACPI_TYPE_STRING, &o))) {
brcmf_dbg(INFO, "ACPI module-instance=%s\n", o->string.pointer);
settings->board_type = devm_kasprintf(dev, GFP_KERNEL,
"apple,%s",
o->string.pointer);
} else {
brcmf_dbg(INFO, "No ACPI module-instance\n");
return;
}
status = acpi_evaluate_object(adev->handle, "RWCV", NULL, &buf);
o = buf.pointer;
if (!ACPI_FAILURE(status) && o && o->type == ACPI_TYPE_BUFFER &&
o->buffer.length >= 2) {
char *antenna_sku = devm_kzalloc(dev, 3, GFP_KERNEL);
if (antenna_sku) {
memcpy(antenna_sku, o->buffer.pointer, 2);
brcmf_dbg(INFO, "ACPI RWCV data=%*phN antenna-sku=%s\n",
(int)o->buffer.length, o->buffer.pointer,
antenna_sku);
settings->antenna_sku = antenna_sku;
}
kfree(buf.pointer);
} else {
brcmf_dbg(INFO, "No ACPI antenna-sku\n");
}
}

View File

@ -55,6 +55,7 @@ enum brcmf_bus_protocol_type {
/* Firmware blobs that may be available */
enum brcmf_blob_type {
BRCMF_BLOB_CLM,
BRCMF_BLOB_TXCAP,
};
struct brcmf_mp_device;

View File

@ -1039,12 +1039,134 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
}
}
static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le,
struct brcmf_scan_params_le *params_le)
{
size_t params_size;
u32 ch;
int n_channels, n_ssids;
memcpy(&params_le->ssid_le, &params_v2_le->ssid_le,
sizeof(params_le->ssid_le));
memcpy(&params_le->bssid, &params_v2_le->bssid,
sizeof(params_le->bssid));
params_le->bss_type = params_v2_le->bss_type;
params_le->scan_type = le32_to_cpu(params_v2_le->scan_type);
params_le->nprobes = params_v2_le->nprobes;
params_le->active_time = params_v2_le->active_time;
params_le->passive_time = params_v2_le->passive_time;
params_le->home_time = params_v2_le->home_time;
params_le->channel_num = params_v2_le->channel_num;
ch = le32_to_cpu(params_v2_le->channel_num);
n_channels = ch & BRCMF_SCAN_PARAMS_COUNT_MASK;
n_ssids = ch >> BRCMF_SCAN_PARAMS_NSSID_SHIFT;
params_size = sizeof(u16) * n_channels;
if (n_ssids > 0) {
params_size = roundup(params_size, sizeof(u32));
params_size += sizeof(struct brcmf_ssid_le) * n_ssids;
}
memcpy(&params_le->channel_list[0],
&params_v2_le->channel_list[0], params_size);
}
static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
struct brcmf_scan_params_v2_le *params_le,
struct cfg80211_scan_request *request)
{
u32 n_ssids;
u32 n_channels;
s32 i;
s32 offset;
u16 chanspec;
char *ptr;
int length;
struct brcmf_ssid_le ssid_le;
eth_broadcast_addr(params_le->bssid);
length = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
params_le->version = cpu_to_le16(BRCMF_SCAN_PARAMS_VERSION_V2);
params_le->bss_type = DOT11_BSSTYPE_ANY;
params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_ACTIVE);
params_le->channel_num = 0;
params_le->nprobes = cpu_to_le32(-1);
params_le->active_time = cpu_to_le32(-1);
params_le->passive_time = cpu_to_le32(-1);
params_le->home_time = cpu_to_le32(-1);
memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
/* Scan abort */
if (!request) {
length += sizeof(u16);
params_le->channel_num = cpu_to_le32(1);
params_le->channel_list[0] = cpu_to_le16(-1);
params_le->length = cpu_to_le16(length);
return;
}
n_ssids = request->n_ssids;
n_channels = request->n_channels;
/* Copy channel array if applicable */
brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
n_channels);
if (n_channels > 0) {
length += roundup(sizeof(u16) * n_channels, sizeof(u32));
for (i = 0; i < n_channels; i++) {
chanspec = channel_to_chanspec(&cfg->d11inf,
request->channels[i]);
brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
request->channels[i]->hw_value, chanspec);
params_le->channel_list[i] = cpu_to_le16(chanspec);
}
} else {
brcmf_dbg(SCAN, "Scanning all channels\n");
}
/* Copy ssid array if applicable */
brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
if (n_ssids > 0) {
offset = offsetof(struct brcmf_scan_params_v2_le, channel_list) +
n_channels * sizeof(u16);
offset = roundup(offset, sizeof(u32));
length += sizeof(ssid_le) * n_ssids,
ptr = (char *)params_le + offset;
for (i = 0; i < n_ssids; i++) {
memset(&ssid_le, 0, sizeof(ssid_le));
ssid_le.SSID_len =
cpu_to_le32(request->ssids[i].ssid_len);
memcpy(ssid_le.SSID, request->ssids[i].ssid,
request->ssids[i].ssid_len);
if (!ssid_le.SSID_len)
brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
else
brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
i, ssid_le.SSID, ssid_le.SSID_len);
memcpy(ptr, &ssid_le, sizeof(ssid_le));
ptr += sizeof(ssid_le);
}
} else {
brcmf_dbg(SCAN, "Performing passive scan\n");
params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_PASSIVE);
}
params_le->length = cpu_to_le16(length);
/* Adding mask to channel numbers */
params_le->channel_num =
cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
}
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp, bool aborted,
bool fw_abort)
{
struct brcmf_pub *drvr = cfg->pub;
struct brcmf_scan_params_le params_le;
struct brcmf_scan_params_v2_le params_v2_le;
struct cfg80211_scan_request *scan_request;
u64 reqid;
u32 bucket;
@ -1063,20 +1185,23 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
if (fw_abort) {
/* Do a scan abort to stop the driver's scan engine */
brcmf_dbg(SCAN, "ABORT scan in firmware\n");
memset(&params_le, 0, sizeof(params_le));
eth_broadcast_addr(params_le.bssid);
params_le.bss_type = DOT11_BSSTYPE_ANY;
params_le.scan_type = 0;
params_le.channel_num = cpu_to_le32(1);
params_le.nprobes = cpu_to_le32(1);
params_le.active_time = cpu_to_le32(-1);
params_le.passive_time = cpu_to_le32(-1);
params_le.home_time = cpu_to_le32(-1);
/* Scan is aborted by setting channel_list[0] to -1 */
params_le.channel_list[0] = cpu_to_le16(-1);
brcmf_escan_prep(cfg, &params_v2_le, NULL);
/* E-Scan (or anyother type) can be aborted by SCAN */
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&params_le, sizeof(params_le));
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&params_v2_le,
sizeof(params_v2_le));
} else {
struct brcmf_scan_params_le params_le;
brcmf_scan_params_v2_to_v1(&params_v2_le, &params_le);
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&params_le,
sizeof(params_le));
}
if (err)
bphy_err(drvr, "Scan abort failed\n");
}
@ -1295,83 +1420,13 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
return err;
}
static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
struct brcmf_scan_params_le *params_le,
struct cfg80211_scan_request *request)
{
u32 n_ssids;
u32 n_channels;
s32 i;
s32 offset;
u16 chanspec;
char *ptr;
struct brcmf_ssid_le ssid_le;
eth_broadcast_addr(params_le->bssid);
params_le->bss_type = DOT11_BSSTYPE_ANY;
params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
params_le->channel_num = 0;
params_le->nprobes = cpu_to_le32(-1);
params_le->active_time = cpu_to_le32(-1);
params_le->passive_time = cpu_to_le32(-1);
params_le->home_time = cpu_to_le32(-1);
memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
n_ssids = request->n_ssids;
n_channels = request->n_channels;
/* Copy channel array if applicable */
brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
n_channels);
if (n_channels > 0) {
for (i = 0; i < n_channels; i++) {
chanspec = channel_to_chanspec(&cfg->d11inf,
request->channels[i]);
brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
request->channels[i]->hw_value, chanspec);
params_le->channel_list[i] = cpu_to_le16(chanspec);
}
} else {
brcmf_dbg(SCAN, "Scanning all channels\n");
}
/* Copy ssid array if applicable */
brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
if (n_ssids > 0) {
offset = offsetof(struct brcmf_scan_params_le, channel_list) +
n_channels * sizeof(u16);
offset = roundup(offset, sizeof(u32));
ptr = (char *)params_le + offset;
for (i = 0; i < n_ssids; i++) {
memset(&ssid_le, 0, sizeof(ssid_le));
ssid_le.SSID_len =
cpu_to_le32(request->ssids[i].ssid_len);
memcpy(ssid_le.SSID, request->ssids[i].ssid,
request->ssids[i].ssid_len);
if (!ssid_le.SSID_len)
brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
else
brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
i, ssid_le.SSID, ssid_le.SSID_len);
memcpy(ptr, &ssid_le, sizeof(ssid_le));
ptr += sizeof(ssid_le);
}
} else {
brcmf_dbg(SCAN, "Performing passive scan\n");
params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
}
/* Adding mask to channel numbers */
params_le->channel_num =
cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
}
static s32
brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
struct cfg80211_scan_request *request)
{
struct brcmf_pub *drvr = cfg->pub;
s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
offsetof(struct brcmf_escan_params_le, params_le);
s32 params_size = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE +
offsetof(struct brcmf_escan_params_le, params_v2_le);
struct brcmf_escan_params_le *params;
s32 err = 0;
@ -1391,8 +1446,22 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
goto exit;
}
BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
brcmf_escan_prep(cfg, &params->params_le, request);
params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
brcmf_escan_prep(cfg, &params->params_v2_le, request);
params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION_V2);
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
struct brcmf_escan_params_le *params_v1;
params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE;
params_v1 = kzalloc(params_size, GFP_KERNEL);
params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
brcmf_scan_params_v2_to_v1(&params->params_v2_le, &params_v1->params_le);
kfree(params);
params = params_v1;
}
params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
params->sync_id = cpu_to_le16(0x1234);
@ -1617,13 +1686,14 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
{
struct brcmf_pub *drvr = ifp->drvr;
struct brcmf_wsec_pmk_le pmk;
int i, err;
int err;
/* convert to firmware key format */
pmk.key_len = cpu_to_le16(pmk_len << 1);
pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
for (i = 0; i < pmk_len; i++)
snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);
memset(&pmk, 0, sizeof(pmk));
/* pass pmk directly */
pmk.key_len = cpu_to_le16(pmk_len);
pmk.flags = cpu_to_le16(0);
memcpy(pmk.key, pmk_data, pmk_len);
/* store psk in firmware */
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
@ -4237,6 +4307,37 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
return 0;
}
static s32
brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa,
bool alive)
{
struct brcmf_pmk_op_v3_le *pmk_op;
int length = offsetof(struct brcmf_pmk_op_v3_le, pmk);
int ret;
pmk_op = kzalloc(sizeof(*pmk_op), GFP_KERNEL);
pmk_op->version = cpu_to_le16(BRCMF_PMKSA_VER_3);
if (!pmksa) {
/* Flush operation, operate on entire list */
pmk_op->count = cpu_to_le16(0);
} else {
/* Single PMK operation */
pmk_op->count = cpu_to_le16(1);
length += sizeof(struct brcmf_pmksa_v3);
memcpy(pmk_op->pmk[0].bssid, pmksa->bssid, ETH_ALEN);
memcpy(pmk_op->pmk[0].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
pmk_op->pmk[0].pmkid_len = WLAN_PMKID_LEN;
pmk_op->pmk[0].time_left = cpu_to_le32(alive ? BRCMF_PMKSA_NO_EXPIRY : 0);
}
pmk_op->length = cpu_to_le16(length);
ret = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_op, sizeof(*pmk_op));
kfree(pmk_op);
return ret;
}
static __used s32
brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
{
@ -4270,6 +4371,14 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
if (!check_vif_up(ifp->vif))
return -EIO;
brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmksa->bssid);
brcmf_dbg(CONN, "%*ph\n", WLAN_PMKID_LEN, pmksa->pmkid);
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
return brcmf_pmksa_v3_op(ifp, pmksa, true);
/* TODO: implement PMKID_V2 */
npmk = le32_to_cpu(cfg->pmk_list.npmk);
for (i = 0; i < npmk; i++)
if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
@ -4286,9 +4395,6 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
return -EINVAL;
}
brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
brcmf_dbg(CONN, "%*ph\n", WLAN_PMKID_LEN, pmk[npmk].pmkid);
err = brcmf_update_pmklist(cfg, ifp);
brcmf_dbg(TRACE, "Exit\n");
@ -4312,6 +4418,11 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
return brcmf_pmksa_v3_op(ifp, pmksa, false);
/* TODO: implement PMKID_V2 */
npmk = le32_to_cpu(cfg->pmk_list.npmk);
for (i = 0; i < npmk; i++)
if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
@ -4348,6 +4459,11 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
if (!check_vif_up(ifp->vif))
return -EIO;
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
return brcmf_pmksa_v3_op(ifp, NULL, false);
/* TODO: implement PMKID_V2 */
memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
err = brcmf_update_pmklist(cfg, ifp);
@ -6489,18 +6605,20 @@ static s32 brcmf_notify_rssi(struct brcmf_if *ifp,
{
struct brcmf_cfg80211_vif *vif = ifp->vif;
struct brcmf_rssi_be *info = data;
s32 rssi, snr, noise;
s32 rssi, snr = 0, noise = 0;
s32 low, high, last;
if (e->datalen < sizeof(*info)) {
if (e->datalen >= sizeof(*info)) {
rssi = be32_to_cpu(info->rssi);
snr = be32_to_cpu(info->snr);
noise = be32_to_cpu(info->noise);
} else if (e->datalen >= sizeof(rssi)) {
rssi = be32_to_cpu(*(__be32 *)data);
} else {
brcmf_err("insufficient RSSI event data\n");
return 0;
}
rssi = be32_to_cpu(info->rssi);
snr = be32_to_cpu(info->snr);
noise = be32_to_cpu(info->noise);
low = vif->cqm_rssi_low;
high = vif->cqm_rssi_high;
last = vif->cqm_rssi_last;

View File

@ -212,8 +212,9 @@ struct sbsocramregs {
#define ARMCR4_TCBANB_MASK 0xf
#define ARMCR4_TCBANB_SHIFT 0
#define ARMCR4_BSZ_MASK 0x3f
#define ARMCR4_BSZ_MASK 0x7f
#define ARMCR4_BSZ_MULT 8192
#define ARMCR4_BLK_1K_MASK 0x200
struct brcmf_core_priv {
struct brcmf_core pub;
@ -684,6 +685,7 @@ static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4)
u32 nbb;
u32 totb;
u32 bxinfo;
u32 blksize;
u32 idx;
corecap = brcmf_chip_core_read32(cr4, ARMCR4_CAP);
@ -695,7 +697,11 @@ static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4)
for (idx = 0; idx < totb; idx++) {
brcmf_chip_core_write32(cr4, ARMCR4_BANKIDX, idx);
bxinfo = brcmf_chip_core_read32(cr4, ARMCR4_BANKINFO);
memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT;
blksize = ARMCR4_BSZ_MULT;
if (bxinfo & ARMCR4_BLK_1K_MASK)
blksize >>= 3;
memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * blksize;
}
return memsize;
@ -737,6 +743,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
return 0x170000;
case BRCM_CC_4378_CHIP_ID:
return 0x352000;
case BRCM_CC_4387_CHIP_ID:
return 0x740000;
default:
brcmf_err("unknown chip: %s\n", ci->pub.name);
break;
@ -1292,15 +1300,18 @@ static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip)
static inline void
brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip)
{
int i;
struct brcmf_core *core;
brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4);
core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET |
D11_BCMA_IOCTL_PHYCLOCKEN,
D11_BCMA_IOCTL_PHYCLOCKEN,
D11_BCMA_IOCTL_PHYCLOCKEN);
/* Disable the cores only and let the firmware enable them.
* Releasing reset ourselves breaks BCM4387 in weird ways.
*/
for (i = 0; (core = brcmf_chip_get_d11core(&chip->pub, i)); i++)
brcmf_chip_coredisable(core, D11_BCMA_IOCTL_PHYRESET |
D11_BCMA_IOCTL_PHYCLOCKEN,
D11_BCMA_IOCTL_PHYCLOCKEN);
}
static bool brcmf_chip_cr4_set_active(struct brcmf_chip_priv *chip, u32 rstvec)

View File

@ -101,7 +101,7 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
struct brcmf_dload_data_le *dload_buf,
u32 len)
u32 len, const char *var)
{
s32 err;
@ -111,18 +111,18 @@ static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
dload_buf->len = cpu_to_le32(len);
dload_buf->crc = cpu_to_le32(0);
err = brcmf_fil_iovar_data_set(ifp, "clmload", dload_buf,
err = brcmf_fil_iovar_data_set(ifp, var, dload_buf,
struct_size(dload_buf, data, len));
return err;
}
static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
static int brcmf_c_download_blob(struct brcmf_if *ifp,
const void *data, size_t size,
const char *loadvar, const char *statvar)
{
struct brcmf_pub *drvr = ifp->drvr;
struct brcmf_bus *bus = drvr->bus_if;
struct brcmf_dload_data_le *chunk_buf;
const struct firmware *clm = NULL;
u32 chunk_len;
u32 datalen;
u32 cumulative_len;
@ -132,21 +132,14 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
brcmf_dbg(TRACE, "Enter\n");
err = brcmf_bus_get_blob(bus, &clm, BRCMF_BLOB_CLM);
if (err || !clm) {
brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
err);
return 0;
}
chunk_buf = kzalloc(struct_size(chunk_buf, data, MAX_CHUNK_LEN),
GFP_KERNEL);
if (!chunk_buf) {
err = -ENOMEM;
goto done;
return -ENOMEM;
}
datalen = clm->size;
datalen = size;
cumulative_len = 0;
do {
if (datalen > MAX_CHUNK_LEN) {
@ -155,9 +148,10 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
chunk_len = datalen;
dl_flag |= DL_END;
}
memcpy(chunk_buf->data, clm->data + cumulative_len, chunk_len);
memcpy(chunk_buf->data, data + cumulative_len, chunk_len);
err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len);
err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len,
loadvar);
dl_flag &= ~DL_BEGIN;
@ -166,20 +160,64 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
} while ((datalen > 0) && (err == 0));
if (err) {
bphy_err(drvr, "clmload (%zu byte file) failed (%d)\n",
clm->size, err);
/* Retrieve clmload_status and print */
err = brcmf_fil_iovar_int_get(ifp, "clmload_status", &status);
bphy_err(drvr, "%s (%zu byte file) failed (%d)\n",
loadvar, size, err);
/* Retrieve status and print */
err = brcmf_fil_iovar_int_get(ifp, statvar, &status);
if (err)
bphy_err(drvr, "get clmload_status failed (%d)\n", err);
bphy_err(drvr, "get %s failed (%d)\n", statvar, err);
else
brcmf_dbg(INFO, "clmload_status=%d\n", status);
brcmf_dbg(INFO, "%s=%d\n", statvar, status);
err = -EIO;
}
kfree(chunk_buf);
done:
release_firmware(clm);
return err;
}
static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = ifp->drvr;
struct brcmf_bus *bus = drvr->bus_if;
const struct firmware *fw = NULL;
s32 err;
brcmf_dbg(TRACE, "Enter\n");
err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_CLM);
if (err || !fw) {
brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
err);
return 0;
}
err = brcmf_c_download_blob(ifp, fw->data, fw->size,
"clmload", "clmload_status");
release_firmware(fw);
return err;
}
static int brcmf_c_process_txcap_blob(struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = ifp->drvr;
struct brcmf_bus *bus = drvr->bus_if;
const struct firmware *fw = NULL;
s32 err;
brcmf_dbg(TRACE, "Enter\n");
err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_TXCAP);
if (err || !fw) {
brcmf_info("no txcap_blob available (err=%d)\n", err);
return 0;
}
brcmf_info("TxCap blob found, loading\n");
err = brcmf_c_download_blob(ifp, fw->data, fw->size,
"txcapload", "txcapload_status");
release_firmware(fw);
return err;
}
@ -208,6 +246,23 @@ static const u8 brcmf_default_mac_address[ETH_ALEN] = {
0x00, 0x90, 0x4c, 0xc5, 0x12, 0x38
};
static int brcmf_c_process_cal_blob(struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = ifp->drvr;
struct brcmf_mp_device *settings = drvr->settings;
s32 err;
brcmf_dbg(TRACE, "Enter\n");
if (!settings->cal_blob || !settings->cal_size)
return 0;
brcmf_info("Calibration blob provided by platform, loading\n");
err = brcmf_c_download_blob(ifp, settings->cal_blob, settings->cal_size,
"calload", "calload_status");
return err;
}
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = ifp->drvr;
@ -291,6 +346,20 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
goto done;
}
/* Do TxCap downloading, if needed */
err = brcmf_c_process_txcap_blob(ifp);
if (err < 0) {
bphy_err(drvr, "download TxCap blob file failed, %d\n", err);
goto done;
}
/* Download external calibration blob, if available */
err = brcmf_c_process_cal_blob(ifp);
if (err < 0) {
bphy_err(drvr, "download calibration blob file failed, %d\n", err);
goto done;
}
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
@ -487,6 +556,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
/* No platform data for this device, try OF and DMI data */
brcmf_dmi_probe(settings, chip, chiprev);
brcmf_of_probe(dev, bus_type, settings);
brcmf_acpi_probe(dev, bus_type, settings);
}
return settings;
}

View File

@ -54,6 +54,8 @@ struct brcmf_mp_device {
const char *board_type;
unsigned char mac[ETH_ALEN];
const char *antenna_sku;
const void *cal_blob;
int cal_size;
union {
struct brcmfmac_sdio_pd sdio;
} bus;
@ -77,6 +79,15 @@ static inline void
brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {}
#endif
#ifdef CONFIG_ACPI
void brcmf_acpi_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings);
#else
static inline void brcmf_acpi_probe(struct device *dev,
enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings) {}
#endif
u8 brcmf_map_prio_to_prec(void *cfg, u8 prio);
u8 brcmf_map_prio_to_aci(void *cfg, u8 prio);

View File

@ -126,6 +126,53 @@ static void brcmf_feat_firmware_overrides(struct brcmf_pub *drv)
drv->feat_flags |= feat_flags;
}
struct brcmf_feat_wlcfeat {
u16 min_ver_major;
u16 min_ver_minor;
u32 feat_flags;
};
static const struct brcmf_feat_wlcfeat brcmf_feat_wlcfeat_map[] = {
{ 12, 0, BIT(BRCMF_FEAT_PMKID_V2) },
{ 13, 0, BIT(BRCMF_FEAT_PMKID_V3) },
};
static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv)
{
struct brcmf_if *ifp = brcmf_get_ifp(drv, 0);
const struct brcmf_feat_wlcfeat *e;
struct brcmf_wlc_version_le ver;
u32 feat_flags = 0;
int i, err, major, minor;
err = brcmf_fil_iovar_data_get(ifp, "wlc_ver", &ver, sizeof(ver));
if (err)
return;
major = le16_to_cpu(ver.wlc_ver_major);
minor = le16_to_cpu(ver.wlc_ver_minor);
brcmf_dbg(INFO, "WLC version: %d.%d\n", major, minor);
for (i = 0; i < ARRAY_SIZE(brcmf_feat_wlcfeat_map); i++) {
e = &brcmf_feat_wlcfeat_map[i];
if (major > e->min_ver_major ||
(major == e->min_ver_major &&
minor >= e->min_ver_minor)) {
feat_flags |= e->feat_flags;
}
}
if (!feat_flags)
return;
for (i = 0; i < BRCMF_FEAT_LAST; i++)
if (feat_flags & BIT(i))
brcmf_dbg(INFO, "enabling firmware feature: %s\n",
brcmf_feat_names[i]);
drv->feat_flags |= feat_flags;
}
/**
* brcmf_feat_iovar_int_get() - determine feature through iovar query.
*
@ -290,6 +337,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver");
if (drvr->settings->feature_disable) {
brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
@ -298,6 +346,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
}
brcmf_feat_wlc_version_overrides(drvr);
brcmf_feat_firmware_overrides(drvr);
/* set chip related quirks */

View File

@ -30,6 +30,7 @@
* SAE: simultaneous authentication of equals
* FWAUTH: Firmware authenticator
* DUMP_OBSS: Firmware has capable to dump obss info to support ACS
* SCAN_V2: Version 2 scan params
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
@ -53,7 +54,10 @@
BRCMF_FEAT_DEF(DOT11H) \
BRCMF_FEAT_DEF(SAE) \
BRCMF_FEAT_DEF(FWAUTH) \
BRCMF_FEAT_DEF(DUMP_OBSS)
BRCMF_FEAT_DEF(DUMP_OBSS) \
BRCMF_FEAT_DEF(SCAN_V2) \
BRCMF_FEAT_DEF(PMKID_V2) \
BRCMF_FEAT_DEF(PMKID_V3)
/*
* Quirks:

View File

@ -48,6 +48,10 @@
/* size of brcmf_scan_params not including variable length array */
#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
#define BRCMF_SCAN_PARAMS_V2_FIXED_SIZE 72
/* version of brcmf_scan_params structure */
#define BRCMF_SCAN_PARAMS_VERSION_V2 2
/* masks for channel and ssid count */
#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
@ -67,6 +71,7 @@
#define BRCMF_PRIMARY_KEY (1 << 1)
#define DOT11_BSSTYPE_ANY 2
#define BRCMF_ESCAN_REQ_VERSION 1
#define BRCMF_ESCAN_REQ_VERSION_V2 2
#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
@ -169,6 +174,10 @@
#define BRCMF_HE_CAP_MCS_MAP_NSS_MAX 8
#define BRCMF_PMKSA_VER_2 2
#define BRCMF_PMKSA_VER_3 3
#define BRCMF_PMKSA_NO_EXPIRY 0xffffffff
/* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each
* ioctl. It is relatively small because firmware has small maximum size input
* playload restriction for ioctls.
@ -350,6 +359,12 @@ struct brcmf_ssid_le {
unsigned char SSID[IEEE80211_MAX_SSID_LEN];
};
/* Alternate SSID structure used in some places... */
struct brcmf_ssid8_le {
u8 SSID_len;
unsigned char SSID[IEEE80211_MAX_SSID_LEN];
};
struct brcmf_scan_params_le {
struct brcmf_ssid_le ssid_le; /* default: {0, ""} */
u8 bssid[ETH_ALEN]; /* default: bcast */
@ -386,6 +401,45 @@ struct brcmf_scan_params_le {
__le16 channel_list[1]; /* list of chanspecs */
};
struct brcmf_scan_params_v2_le {
__le16 version; /* structure version */
__le16 length; /* structure length */
struct brcmf_ssid_le ssid_le; /* default: {0, ""} */
u8 bssid[ETH_ALEN]; /* default: bcast */
s8 bss_type; /* default: any,
* DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
*/
u8 pad;
__le32 scan_type; /* flags, 0 use default */
__le32 nprobes; /* -1 use default, number of probes per channel */
__le32 active_time; /* -1 use default, dwell time per channel for
* active scanning
*/
__le32 passive_time; /* -1 use default, dwell time per channel
* for passive scanning
*/
__le32 home_time; /* -1 use default, dwell time for the
* home channel between channel scans
*/
__le32 channel_num; /* count of channels and ssids that follow
*
* low half is count of channels in
* channel_list, 0 means default (use all
* available channels)
*
* high half is entries in struct brcmf_ssid
* array that follows channel_list, aligned for
* s32 (4 bytes) meaning an odd channel count
* implies a 2-byte pad between end of
* channel_list and first ssid
*
* if ssid count is zero, single ssid in the
* fixed parameter portion is assumed, otherwise
* ssid in the fixed portion is ignored
*/
__le16 channel_list[1]; /* list of chanspecs */
};
struct brcmf_scan_results {
u32 buflen;
u32 version;
@ -397,7 +451,10 @@ struct brcmf_escan_params_le {
__le32 version;
__le16 action;
__le16 sync_id;
struct brcmf_scan_params_le params_le;
union {
struct brcmf_scan_params_le params_le;
struct brcmf_scan_params_v2_le params_v2_le;
};
};
struct brcmf_escan_result_le {
@ -741,6 +798,31 @@ struct brcmf_rev_info_le {
__le32 nvramrev;
};
/**
* struct brcmf_wlc_version_le - firmware revision info.
*
* @version: structure version.
* @length: structure length.
* @epi_ver_major: EPI major version
* @epi_ver_minor: EPI minor version
* @epi_ver_rc: EPI rc version
* @epi_ver_incr: EPI increment version
* @wlc_ver_major: WLC major version
* @wlc_ver_minor: WLC minor version
*/
struct brcmf_wlc_version_le {
__le16 version;
__le16 length;
__le16 epi_ver_major;
__le16 epi_ver_minor;
__le16 epi_ver_rc;
__le16 epi_ver_incr;
__le16 wlc_ver_major;
__le16 wlc_ver_minor;
};
/**
* struct brcmf_assoclist_le - request assoc list.
*
@ -803,6 +885,51 @@ struct brcmf_pmksa {
u8 pmkid[WLAN_PMKID_LEN];
};
/**
* struct brcmf_pmksa_v2 - PMK Security Association
*
* @length: Length of the structure.
* @bssid: The AP's BSSID.
* @pmkid: The PMK ID.
* @pmk: PMK material for FILS key derivation.
* @pmk_len: Length of PMK data.
* @ssid: The AP's SSID.
* @fils_cache_id: FILS cache identifier
*/
struct brcmf_pmksa_v2 {
__le16 length;
u8 bssid[ETH_ALEN];
u8 pmkid[WLAN_PMKID_LEN];
u8 pmk[WLAN_PMK_LEN_SUITE_B_192];
__le16 pmk_len;
struct brcmf_ssid8_le ssid;
u16 fils_cache_id;
};
/**
* struct brcmf_pmksa_v3 - PMK Security Association
*
* @bssid: The AP's BSSID.
* @pmkid: The PMK ID.
* @pmkid_len: The length of the PMK ID.
* @pmk: PMK material for FILS key derivation.
* @pmk_len: Length of PMK data.
* @fils_cache_id: FILS cache identifier
* @ssid: The AP's SSID.
* @time_left: Remaining time until expiry. 0 = expired, ~0 = no expiry.
*/
struct brcmf_pmksa_v3 {
u8 bssid[ETH_ALEN];
u8 pmkid[WLAN_PMKID_LEN];
u8 pmkid_len;
u8 pmk[WLAN_PMK_LEN_SUITE_B_192];
u8 pmk_len;
__le16 fils_cache_id;
u8 pad;
struct brcmf_ssid8_le ssid;
__le32 time_left;
};
/**
* struct brcmf_pmk_list_le - List of pmksa's.
*
@ -814,6 +941,34 @@ struct brcmf_pmk_list_le {
struct brcmf_pmksa pmk[BRCMF_MAXPMKID];
};
/**
* struct brcmf_pmk_list_v2_le - List of pmksa's.
*
* @version: Request version.
* @length: Length of this structure.
* @pmk: PMK SA information.
*/
struct brcmf_pmk_list_v2_le {
__le16 version;
__le16 length;
struct brcmf_pmksa_v2 pmk[BRCMF_MAXPMKID];
};
/**
* struct brcmf_pmk_op_v3_le - Operation on PMKSA list.
*
* @version: Request version.
* @length: Length of this structure.
* @pmk: PMK SA information.
*/
struct brcmf_pmk_op_v3_le {
__le16 version;
__le16 length;
__le16 count;
__le16 pad;
struct brcmf_pmksa_v3 pmk[BRCMF_MAXPMKID];
};
/**
* struct brcmf_pno_param_le - PNO scan configuration parameters
*

View File

@ -86,6 +86,13 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
if (!of_property_read_string(np, "apple,antenna-sku", &prop))
settings->antenna_sku = prop;
/* The WLAN calibration blob is normally stored in SROM, but Apple
* ARM64 platforms pass it via the DT instead.
*/
prop = of_get_property(np, "brcm,cal-blob", &settings->cal_size);
if (prop && settings->cal_size)
settings->cal_blob = prop;
/* Set board-type to the first string of the machine compatible prop */
root = of_find_node_by_path("/");
if (root && err) {

View File

@ -15,6 +15,7 @@
#include <linux/sched/signal.h>
#include <linux/kthread.h>
#include <linux/io.h>
#include <linux/random.h>
#include <asm/unaligned.h>
#include <soc.h>
@ -57,6 +58,7 @@ BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-pcie");
BRCMF_FW_CLM_DEF(43570, "brcmfmac43570-pcie");
BRCMF_FW_DEF(4358, "brcmfmac4358-pcie");
BRCMF_FW_DEF(4359, "brcmfmac4359-pcie");
BRCMF_FW_DEF(4359C, "brcmfmac4359c-pcie");
BRCMF_FW_CLM_DEF(4364B2, "brcmfmac4364b2-pcie");
BRCMF_FW_CLM_DEF(4364B3, "brcmfmac4364b3-pcie");
BRCMF_FW_DEF(4365B, "brcmfmac4365b-pcie");
@ -66,6 +68,8 @@ BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie");
BRCMF_FW_DEF(4371, "brcmfmac4371-pcie");
BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie");
BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie");
BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie");
BRCMF_FW_CLM_DEF(4387C2, "brcmfmac4387c2-pcie");
/* firmware config files */
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt");
@ -74,6 +78,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt");
/* per-board firmware binaries */
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin");
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.clm_blob");
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txcap_blob");
static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602),
@ -88,7 +93,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570),
BRCMF_FW_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570),
BRCMF_FW_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358),
BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0x000001FF, 4359),
BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFE00, 4359C),
BRCMF_FW_ENTRY(BRCM_CC_4364_CHIP_ID, 0x0000000F, 4364B2), /* 3 */
BRCMF_FW_ENTRY(BRCM_CC_4364_CHIP_ID, 0xFFFFFFF0, 4364B3), /* 4 */
BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B),
@ -99,7 +105,9 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C),
BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
BRCMF_FW_ENTRY(BRCM_CC_4377_CHIP_ID, 0xFFFFFFFF, 4377B3), /* revision ID 4 */
BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFFF, 4378B1), /* revision ID 3 */
BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0x0000000F, 4378B1), /* revision ID 3 */
BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFE0, 4378B3), /* revision ID 5 */
BRCMF_FW_ENTRY(BRCM_CC_4387_CHIP_ID, 0xFFFFFFFF, 4387C2), /* revision ID 7 */
};
#define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */
@ -326,7 +334,9 @@ struct brcmf_pciedev_info {
char fw_name[BRCMF_FW_NAME_LEN];
char nvram_name[BRCMF_FW_NAME_LEN];
char clm_name[BRCMF_FW_NAME_LEN];
char txcap_name[BRCMF_FW_NAME_LEN];
const struct firmware *clm_fw;
const struct firmware *txcap_fw;
const struct brcmf_pcie_reginfo *reginfo;
void __iomem *regs;
void __iomem *tcm;
@ -1517,6 +1527,10 @@ static int brcmf_pcie_get_blob(struct device *dev, const struct firmware **fw,
*fw = devinfo->clm_fw;
devinfo->clm_fw = NULL;
break;
case BRCMF_BLOB_TXCAP:
*fw = devinfo->txcap_fw;
devinfo->txcap_fw = NULL;
break;
default:
return -ENOENT;
}
@ -1653,6 +1667,13 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
return 0;
}
struct brcmf_random_seed_footer {
__le32 length;
__le32 magic;
};
#define BRCMF_RANDOM_SEED_MAGIC 0xfeedc0de
#define BRCMF_RANDOM_SEED_LENGTH 0x100
static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
const struct firmware *fw, void *nvram,
@ -1689,6 +1710,30 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
nvram_len;
memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
brcmf_fw_nvram_free(nvram);
if (devinfo->otp.valid) {
size_t rand_len = BRCMF_RANDOM_SEED_LENGTH;
struct brcmf_random_seed_footer footer = {
.length = cpu_to_le32(rand_len),
.magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC),
};
void *randbuf;
/* Some Apple chips/firmwares expect a buffer of random
* data to be present before NVRAM
*/
brcmf_dbg(PCIE, "Download random seed\n");
address -= sizeof(footer);
memcpy_toio(devinfo->tcm + address, &footer,
sizeof(footer));
address -= rand_len;
randbuf = kzalloc(rand_len, GFP_KERNEL);
get_random_bytes(randbuf, rand_len);
memcpy_toio(devinfo->tcm + address, randbuf, rand_len);
kfree(randbuf);
}
} else {
brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",
devinfo->nvram_name);
@ -2016,6 +2061,11 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
base = 0x1120;
words = 0x170;
break;
case BRCM_CC_4387_CHIP_ID:
coreid = BCMA_CORE_GCI;
base = 0x113c;
words = 0x170;
break;
default:
/* OTP not supported on this chip */
return 0;
@ -2073,6 +2123,7 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
#define BRCMF_PCIE_FW_CODE 0
#define BRCMF_PCIE_FW_NVRAM 1
#define BRCMF_PCIE_FW_CLM 2
#define BRCMF_PCIE_FW_TXCAP 3
static void brcmf_pcie_setup(struct device *dev, int ret,
struct brcmf_fw_request *fwreq)
@ -2099,6 +2150,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
devinfo->txcap_fw = fwreq->items[BRCMF_PCIE_FW_TXCAP].binary;
kfree(fwreq);
ret = brcmf_chip_get_raminfo(devinfo->ci);
@ -2180,6 +2232,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
{ ".bin", devinfo->fw_name },
{ ".txt", devinfo->nvram_name },
{ ".clm_blob", devinfo->clm_name },
{ ".txcap_blob", devinfo->txcap_name },
};
fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
@ -2194,6 +2247,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_PCIE_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL;
fwreq->items[BRCMF_PCIE_FW_TXCAP].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_PCIE_FW_TXCAP].flags = BRCMF_FW_REQF_OPTIONAL;
/* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */
fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
fwreq->bus_nr = devinfo->pdev->bus->number;
@ -2491,6 +2546,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)
brcmf_pcie_reset_device(devinfo);
brcmf_pcie_release_resource(devinfo);
release_firmware(devinfo->clm_fw);
release_firmware(devinfo->txcap_fw);
if (devinfo->ci)
brcmf_chip_detach(devinfo->ci);
@ -2630,6 +2686,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_43596_DEVICE_ID, CYW),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC),
{ /* end: all zeroes */ }
};

View File

@ -54,6 +54,7 @@
#define BRCM_CC_4371_CHIP_ID 0x4371
#define BRCM_CC_4377_CHIP_ID 0x4377
#define BRCM_CC_4378_CHIP_ID 0x4378
#define BRCM_CC_4387_CHIP_ID 0x4387
#define CY_CC_4373_CHIP_ID 0x4373
#define CY_CC_43012_CHIP_ID 43012
#define CY_CC_43439_CHIP_ID 43439
@ -95,6 +96,7 @@
#define BRCM_PCIE_43596_DEVICE_ID 0x4415
#define BRCM_PCIE_4377_DEVICE_ID 0x4488
#define BRCM_PCIE_4378_DEVICE_ID 0x4425
#define BRCM_PCIE_4387_DEVICE_ID 0x4433
/* brcmsmac IDs */
#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */

View File

@ -62,6 +62,7 @@
#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-"
#define IWL_BNJ_A_FM_A_FW_PRE "iwlwifi-BzBnj-a0-fm-a0-"
#define IWL_BNJ_A_FM4_A_FW_PRE "iwlwifi-BzBnj-a0-fm4-a0-"
#define IWL_BNJ_B_FM4_B_FW_PRE "iwlwifi-BzBnj-b0-fm4-b0-"
#define IWL_BNJ_A_GF_A_FW_PRE "iwlwifi-BzBnj-a0-gf-a0-"
#define IWL_BNJ_A_GF4_A_FW_PRE "iwlwifi-BzBnj-a0-gf4-a0-"
#define IWL_BNJ_A_HR_B_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-"
@ -132,6 +133,8 @@
IWL_BNJ_A_FM_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(api) \
IWL_BNJ_A_FM4_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(api) \
IWL_BNJ_B_FM4_B_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_A_GF_A_MODULE_FIRMWARE(api) \
IWL_BNJ_A_GF_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(api) \
@ -998,6 +1001,14 @@ const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0 = {
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bnj_b0_fm4_b0 = {
.fw_name_pre = IWL_BNJ_B_FM4_B_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0 = {
.fw_name_pre = IWL_BNJ_A_GF_A_FW_PRE,
.uhb_supported = true,
@ -1059,6 +1070,7 @@ MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));

View File

@ -373,9 +373,6 @@ enum {
/* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */
#define RATE_VHT_MCS_RATE_CODE_MSK 0xf
#define RATE_VHT_MCS_NSS_POS 4
#define RATE_VHT_MCS_NSS_MSK (3 << RATE_VHT_MCS_NSS_POS)
#define RATE_VHT_MCS_MIMO2_MSK BIT(RATE_VHT_MCS_NSS_POS)
/*
* Legacy OFDM rate format for bits 7:0
@ -449,11 +446,16 @@ enum {
* 1 2xLTF+0.8us
* 2 2xLTF+1.6us
* 3 4xLTF+3.2us
* HE TRIG:
* HE-EHT TRIG:
* 0 1xLTF+1.6us
* 1 2xLTF+1.6us
* 2 4xLTF+3.2us
* 3 (does not occur)
* EHT MU:
* 0 2xLTF+0.8us
* 1 2xLTF+1.6us
* 2 4xLTF+0.8us
* 3 4xLTF+3.2us
*/
#define RATE_MCS_HE_GI_LTF_POS 20
#define RATE_MCS_HE_GI_LTF_MSK_V1 (3 << RATE_MCS_HE_GI_LTF_POS)
@ -546,12 +548,17 @@ enum {
/*
* Bits 13-11: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz, (4) 320MHz
*/
#define RATE_MCS_CHAN_WIDTH_MSK (0x7 << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_20 (0 << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_40 (1 << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_80 (2 << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_160 (3 << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_320 (4 << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_MSK (0x7 << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_20_VAL 0
#define RATE_MCS_CHAN_WIDTH_20 (RATE_MCS_CHAN_WIDTH_20_VAL << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_40_VAL 1
#define RATE_MCS_CHAN_WIDTH_40 (RATE_MCS_CHAN_WIDTH_40_VAL << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_80_VAL 2
#define RATE_MCS_CHAN_WIDTH_80 (RATE_MCS_CHAN_WIDTH_80_VAL << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_160_VAL 3
#define RATE_MCS_CHAN_WIDTH_160 (RATE_MCS_CHAN_WIDTH_160_VAL << RATE_MCS_CHAN_WIDTH_POS)
#define RATE_MCS_CHAN_WIDTH_320_VAL 4
#define RATE_MCS_CHAN_WIDTH_320 (RATE_MCS_CHAN_WIDTH_320_VAL << RATE_MCS_CHAN_WIDTH_POS)
/* Bit 15-14: Antenna selection:
* Bit 14: Ant A active

View File

@ -367,7 +367,8 @@ enum iwl_rx_phy_eht_data1 {
/* number of EHT-LTF symbols 0 - 1 EHT-LTF, 1 - 2 EHT-LTFs, 2 - 4 EHT-LTFs,
* 3 - 6 EHT-LTFs, 4 - 8 EHT-LTFs */
IWL_RX_PHY_DATA1_EHT_SIG_LTF_NUM = 0x000000e0,
IWL_RX_PHY_DATA1_EHT_RU_ALLOC = 0x0000ff00,
IWL_RX_PHY_DATA1_EHT_B0 = 0x00000100,
IWL_RX_PHY_DATA1_EHT_RU_B1_B7_ALLOC = 0x0000fe00,
};
/* goes into Metadata DW 7 */
@ -413,7 +414,7 @@ enum iwl_rx_phy_eht_data2 {
/* OFDM_RX_VECTOR_COMMON_RU_ALLOC_0_OUT */
IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_A1 = 0x000001ff,
IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_A2 = 0x0003fe00,
IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_A3 = 0x01fc0000,
IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_B1 = 0x07fc0000,
/* info type: EHT-TB-EXT */
IWL_RX_PHY_DATA2_EHT_TB_EXT_TRIG_SIGA1 = 0xffffffff,
@ -423,19 +424,18 @@ enum iwl_rx_phy_eht_data2 {
enum iwl_rx_phy_eht_data3 {
/* info type: EHT-MU-EXT */
/* OFDM_RX_VECTOR_COMMON_RU_ALLOC_1_OUT */
IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_B1 = 0x000001ff,
IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_B2 = 0x0003fe00,
IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_B3 = 0x01fc0000,
IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_B2 = 0x000001ff,
IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_C1 = 0x0003fe00,
IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_C2 = 0x07fc0000,
};
/* goes into Metadata DW 4 */
enum iwl_rx_phy_eht_data4 {
/* info type: EHT-MU-EXT */
/* OFDM_RX_VECTOR_COMMON_RU_ALLOC_2_OUT */
IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_C1 = 0x000001ff,
IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_C2 = 0x0003fe00,
IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_C3 = 0x01fc0000,
IWL_RX_PHY_DATA4_EHT_MU_EXT_SIGB_MCS = 0x18000000,
IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_D1 = 0x000001ff,
IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_D2 = 0x0003fe00,
IWL_RX_PHY_DATA4_EHT_MU_EXT_SIGB_MCS = 0x000c0000,
};
/* goes into Metadata DW 16 */
@ -673,22 +673,31 @@ struct iwl_rx_mpdu_desc {
* @mac_phy_idx: MAC/PHY index
*/
u8 mac_phy_idx;
/* DW4 - carries csum data only when rpa_en == 1 */
/**
* @raw_csum: raw checksum (alledgedly unreliable)
*/
__le16 raw_csum;
/* DW4 */
union {
/**
* @l3l4_flags: &enum iwl_rx_l3l4_flags
*/
__le16 l3l4_flags;
struct {
/* carries csum data only when rpa_en == 1 */
/**
* @raw_csum: raw checksum (alledgedly unreliable)
*/
__le16 raw_csum;
union {
/**
* @l3l4_flags: &enum iwl_rx_l3l4_flags
*/
__le16 l3l4_flags;
/**
* @phy_data4: depends on info type, see phy_data1
*/
__le16 phy_data4;
};
};
/**
* @phy_data4: depends on info type, see phy_data1
* @phy_eht_data4: depends on info type, see phy_data1
*/
__le16 phy_data4;
__le32 phy_eht_data4;
};
/* DW5 */
/**
@ -725,7 +734,7 @@ struct iwl_rx_mpdu_desc {
#define RX_NO_DATA_INFO_TYPE_RX_ERR 1
#define RX_NO_DATA_INFO_TYPE_NDP 2
#define RX_NO_DATA_INFO_TYPE_MU_UNMATCHED 3
#define RX_NO_DATA_INFO_TYPE_HE_TB_UNMATCHED 4
#define RX_NO_DATA_INFO_TYPE_TB_UNMATCHED 4
#define RX_NO_DATA_INFO_ERR_POS 8
#define RX_NO_DATA_INFO_ERR_MSK (0xff << RX_NO_DATA_INFO_ERR_POS)
@ -743,6 +752,35 @@ struct iwl_rx_mpdu_desc {
#define RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK 0x38000000
#define RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK 0x00f00000
/* content of OFDM_RX_VECTOR_USIG_A1_OUT */
enum iwl_rx_usig_a1 {
IWL_RX_USIG_A1_ENHANCED_WIFI_VER_ID = 0x00000007,
IWL_RX_USIG_A1_BANDWIDTH = 0x00000038,
IWL_RX_USIG_A1_UL_FLAG = 0x00000040,
IWL_RX_USIG_A1_BSS_COLOR = 0x00001f80,
IWL_RX_USIG_A1_TXOP_DURATION = 0x000fe000,
IWL_RX_USIG_A1_DISREGARD = 0x01f00000,
IWL_RX_USIG_A1_VALIDATE = 0x02000000,
IWL_RX_USIG_A1_EHT_BW320_SLOT = 0x04000000,
IWL_RX_USIG_A1_EHT_TYPE = 0x18000000,
IWL_RX_USIG_A1_RDY = 0x80000000,
};
/* content of OFDM_RX_VECTOR_USIG_A2_EHT_OUT */
enum iwl_rx_usig_a2_eht {
IWL_RX_USIG_A2_EHT_PPDU_TYPE = 0x00000003,
IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2 = 0x00000004,
IWL_RX_USIG_A2_EHT_PUNC_CHANNEL = 0x000000f8,
IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B8 = 0x00000100,
IWL_RX_USIG_A2_EHT_SIG_MCS = 0x00000600,
IWL_RX_USIG_A2_EHT_SIG_SYM_NUM = 0x0000f800,
IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_1 = 0x000f0000,
IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_2 = 0x00f00000,
IWL_RX_USIG_A2_EHT_TRIG_USIG2_DISREGARD = 0x1f000000,
IWL_RX_USIG_A2_EHT_CRC_OK = 0x40000000,
IWL_RX_USIG_A2_EHT_RDY = 0x80000000,
};
/**
* struct iwl_rx_no_data - RX no data descriptor
* @info: 7:0 frame type, 15:8 RX error type
@ -780,7 +818,7 @@ struct iwl_rx_no_data {
* @rx_vec: DW-12:9 raw RX vectors from DSP according to modulation type.
* for VHT: OFDM_RX_VECTOR_SIGA1_OUT, OFDM_RX_VECTOR_SIGA2_OUT
* for HE: OFDM_RX_VECTOR_HE_SIGA1_OUT, OFDM_RX_VECTOR_HE_SIGA2_OUT
* for EHT: OFDM_RX_VECTOR_USIG_A1_OUT, OFDM_RX_VECTOR_USIG_A2_OUT,
* for EHT: OFDM_RX_VECTOR_USIG_A1_OUT, OFDM_RX_VECTOR_USIG_A2_EHT_OUT,
* OFDM_RX_VECTOR_EHT_OUT, OFDM_RX_VECTOR_EHT_USER_FIELD_OUT
*/
struct iwl_rx_no_data_ver_3 {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2021 Intel Corporation
* Copyright (C) 2021-2022 Intel Corporation
*/
#include <net/mac80211.h>
@ -126,7 +126,7 @@ u32 iwl_new_rate_from_v1(u32 rate_v1)
rate_v1 & RATE_MCS_HE_MSK_V1) {
rate_v2 |= rate_v1 & RATE_VHT_MCS_RATE_CODE_MSK;
rate_v2 |= rate_v1 & RATE_VHT_MCS_MIMO2_MSK;
rate_v2 |= rate_v1 & RATE_MCS_NSS_MSK;
if (rate_v1 & RATE_MCS_HE_MSK_V1) {
u32 he_type_bits = rate_v1 & RATE_MCS_HE_TYPE_MSK_V1;

View File

@ -659,6 +659,7 @@ extern const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0;
extern const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0;
extern const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0;
extern const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0;
extern const struct iwl_cfg iwl_cfg_bnj_b0_fm4_b0;
#endif /* CONFIG_IWLMVM */
#endif /* __IWL_CONFIG_H__ */

View File

@ -348,6 +348,7 @@ enum {
#define CSR_HW_RF_ID_TYPE_HRCDB (0x00109F00)
#define CSR_HW_RF_ID_TYPE_GF (0x0010D000)
#define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000)
#define CSR_HW_RF_ID_TYPE_MS (0x00111000)
/* HW_RF CHIP STEP */
#define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF)

View File

@ -350,9 +350,9 @@ void iwl_dbg_tlv_alloc(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv,
ret = dbg_tlv_alloc[tlv_idx](trans, tlv);
if (ret) {
IWL_ERR(trans,
"WRT: Failed to allocate TLV 0x%x, ret %d, (ext=%d)\n",
type, ret, ext);
IWL_WARN(trans,
"WRT: Failed to allocate TLV 0x%x, ret %d, (ext=%d)\n",
type, ret, ext);
goto out_err;
}
@ -1218,11 +1218,12 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync,
}
fwrt->trans->dbg.restart_required = FALSE;
IWL_DEBUG_INFO(fwrt, "WRT: tp %d, reset_fw %d\n",
tp, dump_data.trig->reset_fw);
IWL_DEBUG_INFO(fwrt, "WRT: restart_required %d, last_tp_resetfw %d\n",
fwrt->trans->dbg.restart_required,
fwrt->trans->dbg.last_tp_resetfw);
IWL_DEBUG_FW(fwrt, "WRT: tp %d, reset_fw %d\n",
tp, dump_data.trig->reset_fw);
IWL_DEBUG_FW(fwrt,
"WRT: restart_required %d, last_tp_resetfw %d\n",
fwrt->trans->dbg.restart_required,
fwrt->trans->dbg.last_tp_resetfw);
if (fwrt->trans->trans_cfg->device_family ==
IWL_DEVICE_FAMILY_9000) {
@ -1235,18 +1236,19 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync,
IWL_DEBUG_FW(fwrt, "WRT: FW_ASSERT due to reset_fw_mode-no restart\n");
} else if (le32_to_cpu(dump_data.trig->reset_fw) ==
IWL_FW_INI_RESET_FW_MODE_STOP_AND_RELOAD_FW) {
IWL_DEBUG_INFO(fwrt, "WRT: stop and reload firmware\n");
IWL_DEBUG_FW(fwrt, "WRT: stop and reload firmware\n");
fwrt->trans->dbg.restart_required = TRUE;
} else if (le32_to_cpu(dump_data.trig->reset_fw) ==
IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) {
IWL_DEBUG_INFO(fwrt, "WRT: stop only and no reload firmware\n");
IWL_DEBUG_FW(fwrt,
"WRT: stop only and no reload firmware\n");
fwrt->trans->dbg.restart_required = FALSE;
fwrt->trans->dbg.last_tp_resetfw =
le32_to_cpu(dump_data.trig->reset_fw);
} else if (le32_to_cpu(dump_data.trig->reset_fw) ==
IWL_FW_INI_RESET_FW_MODE_NOTHING) {
IWL_DEBUG_INFO(fwrt,
"WRT: nothing need to be done after debug collection\n");
IWL_DEBUG_FW(fwrt,
"WRT: nothing need to be done after debug collection\n");
} else {
IWL_ERR(fwrt, "WRT: wrong resetfw %d\n",
le32_to_cpu(dump_data.trig->reset_fw));

View File

@ -1084,6 +1084,11 @@ static const struct dmi_system_id dmi_tas_approved_list[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
},
},
{ .ident = "MSFT",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
},
},
/* keep last */
{}

View File

@ -654,7 +654,7 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
u32 action)
{
struct iwl_mac_ctx_cmd cmd = {};
u32 tfd_queue_msk = BIT(mvm->snif_queue);
u32 tfd_queue_msk = 0;
int ret;
WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
@ -669,6 +669,14 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
MAC_FILTER_ACCEPT_GRP);
ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);
/*
* the queue mask is only relevant for old TX API, and
* mvm->snif_queue isn't set here (it's still set to
* IWL_MVM_INVALID_QUEUE so the BIT() of it is UB)
*/
if (!iwl_mvm_has_new_tx_api(mvm))
tfd_queue_msk = BIT(mvm->snif_queue);
/* Allocate sniffer station */
ret = iwl_mvm_allocate_int_sta(mvm, &mvm->snif_sta, tfd_queue_msk,
vif->type, IWL_STA_GENERAL_PURPOSE);

View File

@ -1362,6 +1362,28 @@ static void iwl_mvm_channel_switch_disconnect_wk(struct work_struct *wk)
ieee80211_chswitch_done(vif, false);
}
static u8
iwl_mvm_chandef_get_primary_80(struct cfg80211_chan_def *chandef)
{
int data_start;
int control_start;
int bw;
if (chandef->width == NL80211_CHAN_WIDTH_320)
bw = 320;
else if (chandef->width == NL80211_CHAN_WIDTH_160)
bw = 160;
else
return 0;
/* data is bw wide so the start is half the width */
data_start = chandef->center_freq1 - bw / 2;
/* control is 20Mhz width */
control_start = chandef->chan->center_freq - 10;
return (control_start - data_start) / 80;
}
static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@ -1478,8 +1500,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
INIT_DELAYED_WORK(&mvmvif->csa_work,
iwl_mvm_channel_switch_disconnect_wk);
if (vif->type == NL80211_IFTYPE_MONITOR)
if (vif->type == NL80211_IFTYPE_MONITOR) {
mvm->monitor_on = true;
mvm->monitor_p80 =
iwl_mvm_chandef_get_primary_80(&vif->bss_conf.chandef);
}
iwl_mvm_vif_dbgfs_register(mvm, vif);
@ -5033,9 +5058,10 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
if (iwl_mvm_flush_sta(mvm, mvmsta, false))
IWL_ERR(mvm, "flush request fail\n");
} else {
msk |= mvmsta->tfd_queue_msk;
if (iwl_mvm_has_new_tx_api(mvm))
iwl_mvm_wait_sta_queues_empty(mvm, mvmsta);
else /* only used for !iwl_mvm_has_new_tx_api() below */
msk |= mvmsta->tfd_queue_msk;
}
}

View File

@ -1096,6 +1096,11 @@ struct iwl_mvm {
/* does a monitor vif exist (only one can exist hence bool) */
bool monitor_on;
/*
* primary channel position relative to he whole bandwidth,
* in steps of 80 MHz
*/
u8 monitor_p80;
/* sniffer data to include in radiotap */
__le16 cur_aid;

View File

@ -337,10 +337,14 @@ static void rs_fw_eht_set_enabled_rates(const struct ieee80211_sta *sta,
const struct ieee80211_eht_mcs_nss_supp_bw *mcs_tx =
rs_fw_rs_mcs2eht_mcs(bw, eht_tx_mcs);
/* got unsuppored index for bw */
/* got unsupported index for bw */
if (!mcs_rx || !mcs_tx)
continue;
/* break out if we don't support the bandwidth */
if (cmd->max_ch_width < (bw + IWL_TLC_MNG_CH_WIDTH_80MHZ))
break;
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
MAX_NSS_MCS(9, mcs_rx, mcs_tx), GENMASK(9, 0));
rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw,
@ -550,7 +554,7 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_tlc_config_cmd_v4 cfg_cmd = {
.sta_id = mvmsta->sta_id,
.max_ch_width = update ?
rs_fw_bw_from_sta_bw(sta) : RATE_MCS_CHAN_WIDTH_20,
rs_fw_bw_from_sta_bw(sta) : IWL_TLC_MNG_CH_WIDTH_20MHZ,
.flags = cpu_to_le16(rs_fw_get_config_flags(mvm, sta, sband)),
.chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
.sgi_ch_width_supp = rs_fw_sgi_cw_support(sta),

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
*
* Copyright(c) 2005 - 2014, 2018 - 2021 Intel Corporation. All rights reserved.
* Copyright(c) 2005 - 2014, 2018 - 2022 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*****************************************************************************/
@ -895,8 +895,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
WARN_ON_ONCE(1);
}
} else if (ucode_rate & RATE_MCS_VHT_MSK_V1) {
nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
nss = FIELD_GET(RATE_MCS_NSS_MSK, ucode_rate) + 1;
if (nss == 1) {
rate->type = LQ_VHT_SISO;
@ -910,8 +909,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
WARN_ON_ONCE(1);
}
} else if (ucode_rate & RATE_MCS_HE_MSK_V1) {
nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
nss = FIELD_GET(RATE_MCS_NSS_MSK, ucode_rate) + 1;
if (nss == 1) {
rate->type = LQ_HE_SISO;
@ -2885,8 +2883,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
nss = ((rate & RATE_HT_MCS_NSS_MSK_V1) >> RATE_HT_MCS_NSS_POS_V1) + 1;
} else if (rate & RATE_MCS_VHT_MSK_V1) {
mvm->drv_rx_stats.vht_frames++;
nss = ((rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
nss = FIELD_GET(RATE_MCS_NSS_MSK, rate) + 1;
} else {
mvm->drv_rx_stats.legacy_frames++;
}
@ -3665,8 +3662,7 @@ int rs_pretty_print_rate_v1(char *buf, int bufsz, const u32 rate)
if (rate & RATE_MCS_VHT_MSK_V1) {
type = "VHT";
mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK;
nss = ((rate & RATE_VHT_MCS_NSS_MSK)
>> RATE_VHT_MCS_NSS_POS) + 1;
nss = FIELD_GET(RATE_MCS_NSS_MSK, rate) + 1;
} else if (rate & RATE_MCS_HT_MSK_V1) {
type = "HT";
mcs = rate & RATE_HT_MCS_INDEX_MSK_V1;
@ -3675,8 +3671,7 @@ int rs_pretty_print_rate_v1(char *buf, int bufsz, const u32 rate)
} else if (rate & RATE_MCS_HE_MSK_V1) {
type = "HE";
mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK;
nss = ((rate & RATE_VHT_MCS_NSS_MSK)
>> RATE_VHT_MCS_NSS_POS) + 1;
nss = FIELD_GET(RATE_MCS_NSS_MSK, rate) + 1;
} else {
type = "Unknown"; /* shouldn't happen */
}

View File

@ -190,7 +190,7 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
default:
/* Expected in monitor (not having the keys) */
if (!mvm->monitor_on)
IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
IWL_WARN(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
}
return 0;
@ -253,8 +253,7 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
ARRAY_SIZE(thresh_tpt)))
return;
thr = thresh_tpt[rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK];
thr *= 1 + ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS);
thr *= 1 + FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags);
}
thr <<= ((rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK_V1) >>
@ -500,8 +499,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
RATE_MCS_STBC_POS;
rx_status->nss =
((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags) + 1;
rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
rx_status->encoding = RX_ENC_VHT;
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
* Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@ -205,37 +205,47 @@ static int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
return 0;
}
/* put a TLV on the skb and return data pointer
*
* Also pad to 4 the len and zero out all data part
*/
static void *
iwl_mvm_radiotap_put_tlv(struct sk_buff *skb, u16 type, u16 len)
{
struct ieee80211_radiotap_tlv *tlv;
tlv = skb_put(skb, sizeof(*tlv));
tlv->type = cpu_to_le16(type);
tlv->len = cpu_to_le16(len);
return skb_put_zero(skb, ALIGN(len, 4));
}
static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm,
struct sk_buff *skb)
{
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_vendor_radiotap *radiotap;
const int size = sizeof(*radiotap) + sizeof(__le16);
struct ieee80211_radiotap_vendor_content *radiotap;
const u16 vendor_data_len = sizeof(mvm->cur_aid);
if (!mvm->cur_aid)
return;
/* ensure alignment */
BUILD_BUG_ON((size + 2) % 4);
radiotap = iwl_mvm_radiotap_put_tlv(skb,
IEEE80211_RADIOTAP_VENDOR_NAMESPACE,
sizeof(*radiotap) + vendor_data_len);
radiotap = skb_put(skb, size + 2);
radiotap->align = 1;
/* Intel OUI */
radiotap->oui[0] = 0xf6;
radiotap->oui[1] = 0x54;
radiotap->oui[2] = 0x25;
/* radiotap sniffer config sub-namespace */
radiotap->subns = 1;
radiotap->present = 0x1;
radiotap->len = size - sizeof(*radiotap);
radiotap->pad = 2;
radiotap->oui_subtype = 1;
radiotap->vendor_type = 0;
/* fill the data now */
memcpy(radiotap->data, &mvm->cur_aid, sizeof(mvm->cur_aid));
/* and clear the padding */
memset(radiotap->data + sizeof(__le16), 0, radiotap->pad);
rx_status->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA;
rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END;
}
/* iwl_mvm_pass_packet_to_mac80211 - passes the packet for mac80211 */
@ -443,7 +453,7 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
*/
if (!is_multicast_ether_addr(hdr->addr1) &&
!mvm->monitor_on && net_ratelimit())
IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status);
IWL_WARN(mvm, "Unhandled alg: 0x%x\n", status);
}
return 0;
@ -1167,8 +1177,11 @@ static void iwl_mvm_flip_address(u8 *addr)
struct iwl_mvm_rx_phy_data {
enum iwl_rx_phy_info_type info_type;
__le32 d0, d1, d2, d3;
__le32 d0, d1, d2, d3, eht_d4, d5;
__le16 d4;
bool with_data;
bool first_subframe;
__le32 rx_vec[4];
u32 rate_n_flags;
u32 gp2_on_air_rise;
@ -1446,6 +1459,528 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
}
}
#define LE32_DEC_ENC(value, dec_bits, enc_bits) \
le32_encode_bits(le32_get_bits(value, dec_bits), enc_bits)
#define IWL_MVM_ENC_USIG_VALUE_MASK(usig, in_value, dec_bits, enc_bits) do { \
typeof(enc_bits) _enc_bits = enc_bits; \
typeof(usig) _usig = usig; \
(_usig)->mask |= cpu_to_le32(_enc_bits); \
(_usig)->value |= LE32_DEC_ENC(in_value, dec_bits, _enc_bits); \
} while (0)
#define __IWL_MVM_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \
eht->data[(rt_data)] |= \
(cpu_to_le32 \
(IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru ## _KNOWN) | \
LE32_DEC_ENC(data ## fw_data, \
IWL_RX_PHY_DATA ## fw_data ## _EHT_MU_EXT_RU_ALLOC_ ## fw_ru, \
IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru))
#define _IWL_MVM_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \
__IWL_MVM_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru)
#define IEEE80211_RADIOTAP_RU_DATA_1_1_1 1
#define IEEE80211_RADIOTAP_RU_DATA_2_1_1 2
#define IEEE80211_RADIOTAP_RU_DATA_1_1_2 2
#define IEEE80211_RADIOTAP_RU_DATA_2_1_2 2
#define IEEE80211_RADIOTAP_RU_DATA_1_2_1 3
#define IEEE80211_RADIOTAP_RU_DATA_2_2_1 3
#define IEEE80211_RADIOTAP_RU_DATA_1_2_2 3
#define IEEE80211_RADIOTAP_RU_DATA_2_2_2 4
#define IWL_RX_RU_DATA_A1 2
#define IWL_RX_RU_DATA_A2 2
#define IWL_RX_RU_DATA_B1 2
#define IWL_RX_RU_DATA_B2 3
#define IWL_RX_RU_DATA_C1 3
#define IWL_RX_RU_DATA_C2 3
#define IWL_RX_RU_DATA_D1 4
#define IWL_RX_RU_DATA_D2 4
#define IWL_MVM_ENC_EHT_RU(rt_ru, fw_ru) \
_IWL_MVM_ENC_EHT_RU(IEEE80211_RADIOTAP_RU_DATA_ ## rt_ru, \
rt_ru, \
IWL_RX_RU_DATA_ ## fw_ru, \
fw_ru)
static void iwl_mvm_decode_eht_ext_mu(struct iwl_mvm *mvm,
struct iwl_mvm_rx_phy_data *phy_data,
struct ieee80211_rx_status *rx_status,
struct ieee80211_radiotap_eht *eht,
struct ieee80211_radiotap_eht_usig *usig)
{
if (phy_data->with_data) {
__le32 data1 = phy_data->d1;
__le32 data2 = phy_data->d2;
__le32 data3 = phy_data->d3;
__le32 data4 = phy_data->eht_d4;
__le32 data5 = phy_data->d5;
u32 phy_bw = phy_data->rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK;
IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
IWL_RX_PHY_DATA5_EHT_MU_PUNC_CH_CODE,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, data4,
IWL_RX_PHY_DATA4_EHT_MU_EXT_SIGB_MCS,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS);
IWL_MVM_ENC_USIG_VALUE_MASK
(usig, data1, IWL_RX_PHY_DATA1_EHT_MU_NUM_SIG_SYM_USIGA2,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS);
eht->user_info[0] |=
cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN) |
LE32_DEC_ENC(data5, IWL_RX_PHY_DATA5_EHT_MU_STA_ID_USR,
IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID);
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_NR_NON_OFDMA_USERS_M);
eht->data[7] |= LE32_DEC_ENC
(data5, IWL_RX_PHY_DATA5_EHT_MU_NUM_USR_NON_OFDMA,
IEEE80211_RADIOTAP_EHT_DATA7_NUM_OF_NON_OFDMA_USERS);
/*
* Hardware labels the content channels/RU allocation values
* as follows:
* Content Channel 1 Content Channel 2
* 20 MHz: A1
* 40 MHz: A1 B1
* 80 MHz: A1 C1 B1 D1
* 160 MHz: A1 C1 A2 C2 B1 D1 B2 D2
* 320 MHz: A1 C1 A2 C2 A3 C3 A4 C4 B1 D1 B2 D2 B3 D3 B4 D4
*
* However firmware can only give us A1-D2, so the higher
* frequencies are missing.
*/
switch (phy_bw) {
case RATE_MCS_CHAN_WIDTH_320:
/* additional values are missing in RX metadata */
case RATE_MCS_CHAN_WIDTH_160:
/* content channel 1 */
IWL_MVM_ENC_EHT_RU(1_2_1, A2);
IWL_MVM_ENC_EHT_RU(1_2_2, C2);
/* content channel 2 */
IWL_MVM_ENC_EHT_RU(2_2_1, B2);
IWL_MVM_ENC_EHT_RU(2_2_2, D2);
fallthrough;
case RATE_MCS_CHAN_WIDTH_80:
/* content channel 1 */
IWL_MVM_ENC_EHT_RU(1_1_2, C1);
/* content channel 2 */
IWL_MVM_ENC_EHT_RU(2_1_2, D1);
fallthrough;
case RATE_MCS_CHAN_WIDTH_40:
/* content channel 2 */
IWL_MVM_ENC_EHT_RU(2_1_1, B1);
fallthrough;
case RATE_MCS_CHAN_WIDTH_20:
IWL_MVM_ENC_EHT_RU(1_1_1, A1);
break;
}
} else {
__le32 usig_a1 = phy_data->rx_vec[0];
__le32 usig_a2 = phy_data->rx_vec[1];
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a1,
IWL_RX_USIG_A1_DISREGARD,
IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a1,
IWL_RX_USIG_A1_VALIDATE,
IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_PPDU_TYPE,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_PUNC_CHANNEL,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B8,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_SIG_MCS,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS);
IWL_MVM_ENC_USIG_VALUE_MASK
(usig, usig_a2, IWL_RX_USIG_A2_EHT_SIG_SYM_NUM,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_CRC_OK,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B16_B19_CRC);
}
}
static void iwl_mvm_decode_eht_ext_tb(struct iwl_mvm *mvm,
struct iwl_mvm_rx_phy_data *phy_data,
struct ieee80211_rx_status *rx_status,
struct ieee80211_radiotap_eht *eht,
struct ieee80211_radiotap_eht_usig *usig)
{
if (phy_data->with_data) {
__le32 data5 = phy_data->d5;
IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE1,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE2,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2);
} else {
__le32 usig_a1 = phy_data->rx_vec[0];
__le32 usig_a2 = phy_data->rx_vec[1];
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a1,
IWL_RX_USIG_A1_DISREGARD,
IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_PPDU_TYPE,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_1,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_2,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_TRIG_USIG2_DISREGARD,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD);
IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
IWL_RX_USIG_A2_EHT_CRC_OK,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B16_B19_CRC);
}
}
static void iwl_mvm_decode_eht_ru(struct iwl_mvm *mvm,
struct ieee80211_rx_status *rx_status,
struct ieee80211_radiotap_eht *eht)
{
u32 ru = le32_get_bits(eht->data[8],
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1);
enum nl80211_eht_ru_alloc nl_ru;
/* Using D1.5 Table 9-53a - Encoding of PS160 and RU Allocation subfields
* in an EHT variant User Info field
*/
switch (ru) {
case 0 ... 36:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_26;
break;
case 37 ... 52:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_52;
break;
case 53 ... 60:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_106;
break;
case 61 ... 64:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_242;
break;
case 65 ... 66:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_484;
break;
case 67:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_996;
break;
case 68:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_2x996;
break;
case 69:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_4x996;
break;
case 70 ... 81:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_52P26;
break;
case 82 ... 89:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_106P26;
break;
case 90 ... 93:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_484P242;
break;
case 94 ... 95:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_996P484;
break;
case 96 ... 99:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242;
break;
case 100 ... 103:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484;
break;
case 104:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_3x996;
break;
case 105 ... 106:
nl_ru = NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484;
break;
default:
return;
}
rx_status->bw = RATE_INFO_BW_EHT_RU;
rx_status->eht.ru = nl_ru;
}
static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm,
struct iwl_mvm_rx_phy_data *phy_data,
struct ieee80211_rx_status *rx_status,
struct ieee80211_radiotap_eht *eht,
struct ieee80211_radiotap_eht_usig *usig)
{
__le32 data0 = phy_data->d0;
__le32 data1 = phy_data->d1;
__le32 usig_a1 = phy_data->rx_vec[0];
u8 info_type = phy_data->info_type;
/* Not in EHT range */
if (info_type < IWL_RX_PHY_INFO_TYPE_EHT_MU ||
info_type > IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT)
return;
usig->common |= cpu_to_le32
(IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN |
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN);
if (phy_data->with_data) {
usig->common |= LE32_DEC_ENC(data0,
IWL_RX_PHY_DATA0_EHT_UPLINK,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL);
usig->common |= LE32_DEC_ENC(data0,
IWL_RX_PHY_DATA0_EHT_BSS_COLOR_MASK,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR);
} else {
usig->common |= LE32_DEC_ENC(usig_a1,
IWL_RX_USIG_A1_UL_FLAG,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL);
usig->common |= LE32_DEC_ENC(usig_a1,
IWL_RX_USIG_A1_BSS_COLOR,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR);
}
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE);
eht->data[0] |= LE32_DEC_ENC(data0,
IWL_RX_PHY_DATA0_ETH_SPATIAL_REUSE_MASK,
IEEE80211_RADIOTAP_EHT_DATA0_SPATIAL_REUSE);
/* All RU allocating size/index is in TB format */
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT);
eht->data[8] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PS160,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160);
eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_B0,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0);
eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_B1_B7_ALLOC,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1);
iwl_mvm_decode_eht_ru(mvm, rx_status, eht);
/* We only get here in case of IWL_RX_MPDU_PHY_TSF_OVERLOAD is set
* which is on only in case of monitor mode so no need to check monitor
* mode
*/
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80);
eht->data[1] |=
le32_encode_bits(mvm->monitor_p80,
IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80);
usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN);
if (phy_data->with_data)
usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_TXOP_DUR_MASK,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP);
else
usig->common |= LE32_DEC_ENC(usig_a1, IWL_RX_USIG_A1_TXOP_DURATION,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP);
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM);
eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_LDPC_EXT_SYM,
IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM);
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM);
eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PRE_FEC_PAD_MASK,
IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM);
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM);
eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PE_DISAMBIG,
IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM);
/* TODO: what about IWL_RX_PHY_DATA0_EHT_BW320_SLOT */
if (!le32_get_bits(data0, IWL_RX_PHY_DATA0_EHT_SIGA_CRC_OK))
usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC);
usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN);
usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PHY_VER,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER);
/*
* TODO: what about TB - IWL_RX_PHY_DATA1_EHT_TB_PILOT_TYPE,
* IWL_RX_PHY_DATA1_EHT_TB_LOW_SS
*/
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF);
eht->data[0] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_SIG_LTF_NUM,
IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF);
if (info_type == IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT ||
info_type == IWL_RX_PHY_INFO_TYPE_EHT_TB)
iwl_mvm_decode_eht_ext_tb(mvm, phy_data, rx_status, eht, usig);
if (info_type == IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT ||
info_type == IWL_RX_PHY_INFO_TYPE_EHT_MU)
iwl_mvm_decode_eht_ext_mu(mvm, phy_data, rx_status, eht, usig);
}
static void iwl_mvm_rx_eht(struct iwl_mvm *mvm, struct sk_buff *skb,
struct iwl_mvm_rx_phy_data *phy_data,
int queue)
{
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_radiotap_eht *eht;
struct ieee80211_radiotap_eht_usig *usig;
size_t eht_len = sizeof(*eht);
u32 rate_n_flags = phy_data->rate_n_flags;
u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
/* EHT and HE have the same valus for LTF */
u8 ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN;
u16 phy_info = phy_data->phy_info;
u32 bw;
/* u32 for 1 user_info */
if (phy_data->with_data)
eht_len += sizeof(u32);
eht = iwl_mvm_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT, eht_len);
usig = iwl_mvm_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT_USIG,
sizeof(*usig));
rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END;
usig->common |=
cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN);
/* specific handling for 320MHz */
bw = FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, rate_n_flags);
if (bw == RATE_MCS_CHAN_WIDTH_320_VAL)
bw += FIELD_GET(IWL_RX_PHY_DATA0_EHT_BW320_SLOT,
le32_to_cpu(phy_data->d0));
usig->common |= cpu_to_le32
(FIELD_PREP(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW, bw));
/* report the AMPDU-EOF bit on single frames */
if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
/* update aggregation data for monitor sake on default queue */
if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) &&
(phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) {
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD)
iwl_mvm_decode_eht_phy_data(mvm, phy_data, rx_status, eht, usig);
#define CHECK_TYPE(F) \
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \
(RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS))
CHECK_TYPE(SU);
CHECK_TYPE(EXT_SU);
CHECK_TYPE(MU);
CHECK_TYPE(TRIG);
switch (FIELD_GET(RATE_MCS_HE_GI_LTF_MSK, rate_n_flags)) {
case 0:
if (he_type == RATE_MCS_HE_TYPE_TRIG) {
rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_1_6;
ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X;
} else {
rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_0_8;
ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X;
}
break;
case 1:
rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_1_6;
ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X;
break;
case 2:
ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
if (he_type == RATE_MCS_HE_TYPE_TRIG)
rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_3_2;
else
rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_0_8;
break;
case 3:
if (he_type != RATE_MCS_HE_TYPE_TRIG) {
ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_3_2;
}
break;
default:
/* nothing here */
break;
}
if (ltf != IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN) {
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_GI);
eht->data[0] |= cpu_to_le32
(FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_LTF,
ltf) |
FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_GI,
rx_status->eht.gi));
}
if (!phy_data->with_data) {
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_NSS_S |
IEEE80211_RADIOTAP_EHT_KNOWN_BEAMFORMED_S);
eht->data[7] |=
le32_encode_bits(le32_get_bits(phy_data->rx_vec[2],
RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK),
IEEE80211_RADIOTAP_EHT_DATA7_NSS_S);
if (rate_n_flags & RATE_MCS_BF_MSK)
eht->data[7] |=
cpu_to_le32(IEEE80211_RADIOTAP_EHT_DATA7_BEAMFORMED_S);
} else {
eht->user_info[0] |=
cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_MCS_KNOWN |
IEEE80211_RADIOTAP_EHT_USER_INFO_CODING_KNOWN |
IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_KNOWN_O |
IEEE80211_RADIOTAP_EHT_USER_INFO_BEAMFORMING_KNOWN_O |
IEEE80211_RADIOTAP_EHT_USER_INFO_DATA_FOR_USER);
if (rate_n_flags & RATE_MCS_BF_MSK)
eht->user_info[0] |=
cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_BEAMFORMING_O);
if (rate_n_flags & RATE_MCS_LDPC_MSK)
eht->user_info[0] |=
cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_CODING);
eht->user_info[0] |= cpu_to_le32
(FIELD_PREP(IEEE80211_RADIOTAP_EHT_USER_INFO_MCS,
FIELD_GET(RATE_VHT_MCS_RATE_CODE_MSK,
rate_n_flags)) |
FIELD_PREP(IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O,
FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags)));
}
}
static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
struct iwl_mvm_rx_phy_data *phy_data,
int queue)
@ -1497,15 +2032,10 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
/* update aggregation data for monitor sake on default queue */
if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) &&
(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
/* toggle is switched whenever new aggregation starts */
if (toggle_bit != mvm->ampdu_toggle) {
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
(phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) {
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
if (he_type == RATE_MCS_HE_TYPE_EXT_SU &&
@ -1593,6 +2123,10 @@ static void iwl_mvm_decode_lsig(struct sk_buff *skb,
case IWL_RX_PHY_INFO_TYPE_HE_MU:
case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT:
case IWL_RX_PHY_INFO_TYPE_HE_TB:
case IWL_RX_PHY_INFO_TYPE_EHT_MU:
case IWL_RX_PHY_INFO_TYPE_EHT_TB:
case IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT:
case IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT:
lsig = skb_put(skb, sizeof(*lsig));
lsig->data1 = cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN);
lsig->data2 = le16_encode_bits(le32_get_bits(phy_data->d1,
@ -1689,6 +2223,10 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,
iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags,
phy_data->energy_a, phy_data->energy_b);
/* using TLV format and must be after all fixed len fields */
if (format == RATE_MCS_EHT_MSK)
iwl_mvm_rx_eht(mvm, skb, phy_data, queue);
if (unlikely(mvm->monitor_on))
iwl_mvm_add_rtap_sniffer_config(mvm, skb);
@ -1788,6 +2326,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
phy_data.d1 = desc->v3.phy_data1;
phy_data.d2 = desc->v3.phy_data2;
phy_data.d3 = desc->v3.phy_data3;
phy_data.eht_d4 = desc->phy_eht_data4;
phy_data.d5 = desc->v3.phy_data5;
} else {
phy_data.rate_n_flags = le32_to_cpu(desc->v1.rate_n_flags);
phy_data.channel = desc->v1.channel;
@ -1817,6 +2357,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
return;
}
phy_data.with_data = true;
phy_data.phy_info = le16_to_cpu(desc->phy_info);
phy_data.d4 = desc->phy_data4;
@ -1897,6 +2438,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
if (mvm->ampdu_ref == 0)
mvm->ampdu_ref++;
mvm->ampdu_toggle = toggle_bit;
phy_data.first_subframe = true;
}
rx_status->ampdu_reference = mvm->ampdu_ref;
}
@ -2079,6 +2621,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
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);
phy_data.with_data = false;
if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
RX_NO_DATA_NOTIF, 0) < 2) {
@ -2097,6 +2640,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
sizeof(struct iwl_rx_no_data_ver_3)))
/* invalid len for ver 3 */
return;
memcpy(phy_data.rx_vec, desc->rx_vec, sizeof(phy_data.rx_vec));
} else {
if (format == RATE_MCS_EHT_MSK)
/* no support for EHT before version 3 API */
@ -2123,7 +2667,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING;
break;
case RX_NO_DATA_INFO_TYPE_MU_UNMATCHED:
case RX_NO_DATA_INFO_TYPE_HE_TB_UNMATCHED:
case RX_NO_DATA_INFO_TYPE_TB_UNMATCHED:
rx_status->zero_length_psdu_type =
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_NOT_CAPTURED;
break;
@ -2142,11 +2686,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
*
* We mark it as mac header, for upper layers to know where
* all radio tap header ends.
*
* Since data doesn't move data while putting data on skb and that is
* the only way we use, data + len is the next place that hdr would be put
*/
skb_set_mac_header(skb, skb->len);
skb_reset_mac_header(skb);
/*
* Override the nss from the rx_vec since the rate_n_flags has

View File

@ -1396,8 +1396,8 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
r->idx = rate;
} else if (format == RATE_MCS_VHT_MSK) {
ieee80211_rate_set_vht(r, rate,
((rate_n_flags & RATE_MCS_NSS_MSK) >>
RATE_MCS_NSS_POS) + 1);
FIELD_GET(RATE_MCS_NSS_MSK,
rate_n_flags) + 1);
r->flags |= IEEE80211_TX_RC_VHT_MCS;
} else if (format == RATE_MCS_HE_MSK) {
/* mac80211 cannot do this without ieee80211_tx_status_ext()
@ -1428,8 +1428,7 @@ void iwl_mvm_hwrate_to_tx_rate_v1(u32 rate_n_flags,
} else if (rate_n_flags & RATE_MCS_VHT_MSK_V1) {
ieee80211_rate_set_vht(
r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK,
((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1);
FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags) + 1);
r->flags |= IEEE80211_TX_RC_VHT_MCS;
} else {
r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,

View File

@ -1193,6 +1193,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bnj_a0_fm4_a0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP,
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bnj_b0_fm4_b0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY,
IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY,

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2017 Intel Deutschland GmbH
* Copyright (C) 2018-2021 Intel Corporation
* Copyright (C) 2018-2022 Intel Corporation
*/
#include "iwl-trans.h"
#include "iwl-prph.h"
@ -277,6 +277,9 @@ static void iwl_pcie_get_rf_name(struct iwl_trans *trans)
case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB):
pos = scnprintf(buf, buflen, "HRCDB");
break;
case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_MS):
pos = scnprintf(buf, buflen, "MS");
break;
default:
return;
}

View File

@ -1534,37 +1534,38 @@ static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb)
* the values accordingly.
*/
#ifdef HWSIM_RADIOTAP_OUI
struct ieee80211_vendor_radiotap *rtap;
struct ieee80211_radiotap_vendor_tlv *rtap;
static const char vendor_data[8] = "ABCDEFGH";
// Make sure no padding is needed
BUILD_BUG_ON(sizeof(vendor_data) % 4);
/* this is last radiotap info before the mac header, so
* skb_reset_mac_header for mac8022 to know the end of
* the radiotap TLV/beginning of the 802.11 header
*/
skb_reset_mac_header(skb);
/*
* Note that this code requires the headroom in the SKB
* that was allocated earlier.
*/
rtap = skb_push(skb, sizeof(*rtap) + 8 + 4);
rtap->oui[0] = HWSIM_RADIOTAP_OUI[0];
rtap->oui[1] = HWSIM_RADIOTAP_OUI[1];
rtap->oui[2] = HWSIM_RADIOTAP_OUI[2];
rtap->subns = 127;
rtap = skb_push(skb, sizeof(*rtap) + sizeof(vendor_data));
/*
* Radiotap vendor namespaces can (and should) also be
* split into fields by using the standard radiotap
* presence bitmap mechanism. Use just BIT(0) here for
* the presence bitmap.
*/
rtap->present = BIT(0);
/* We have 8 bytes of (dummy) data */
rtap->len = 8;
/* For testing, also require it to be aligned */
rtap->align = 8;
/* And also test that padding works, 4 bytes */
rtap->pad = 4;
/* push the data */
memcpy(rtap->data, "ABCDEFGH", 8);
/* make sure to clear padding, mac80211 doesn't */
memset(rtap->data + 8, 0, 4);
rtap->len = cpu_to_le16(sizeof(*rtap) -
sizeof(struct ieee80211_radiotap_tlv) +
sizeof(vendor_data));
rtap->type = cpu_to_le16(IEEE80211_RADIOTAP_VENDOR_NAMESPACE);
IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA;
rtap->content.oui[0] = HWSIM_RADIOTAP_OUI[0];
rtap->content.oui[1] = HWSIM_RADIOTAP_OUI[1];
rtap->content.oui[2] = HWSIM_RADIOTAP_OUI[2];
rtap->content.oui_subtype = 127;
/* clear reserved field */
rtap->content.reserved = 0;
rtap->content.vendor_type = 0;
memcpy(rtap->content.data, vendor_data, sizeof(vendor_data));
IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_TLV_AT_END;
#endif
}
@ -4446,6 +4447,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT);
hw->wiphy->interface_modes = param->iftypes;
/* ask mac80211 to reserve space for magic */

View File

@ -1699,6 +1699,12 @@ void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *s
dev_dbg(dev, "%s: len: %d items: %d\n", __func__, tx_rpt_len, items);
/* We only use macid 0, so only the first item is relevant.
* AP mode will use more of them if it's ever implemented.
*/
if (!priv->vif || priv->vif->type == NL80211_IFTYPE_STATION)
items = 1;
for (macid = 0; macid < items; macid++) {
valid = false;
@ -1741,12 +1747,6 @@ void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *s
min_rpt_time = ra->rpt_time;
rpt += TX_RPT2_ITEM_SIZE;
/*
* We only use macid 0, so only the first item is relevant.
* AP mode will use more of them if it's ever implemented.
*/
break;
}
if (min_rpt_time != ra->pre_min_rpt_time) {

View File

@ -1575,11 +1575,7 @@ rtl8xxxu_set_spec_sifs(struct rtl8xxxu_priv *priv, u16 cck, u16 ofdm)
static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv)
{
struct device *dev = &priv->udev->dev;
char cut = '?';
/* Currently always true: chip_cut is 4 bits. */
if (priv->chip_cut <= 15)
cut = 'A' + priv->chip_cut;
char cut = 'A' + priv->chip_cut;
dev_info(dev,
"RTL%s rev %c (%s) romver %d, %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n",

View File

@ -1428,7 +1428,9 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
for (rf_path = 0; rf_path < 2; rf_path++) {
for (i = 0; i < 3; i++) {
if (!autoload_fail) {
if (!autoload_fail &&
hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i] != 0xff &&
hwinfo[EEPROM_TXPOWERHT40_1S + rf_path * 3 + i] != 0xff) {
rtlefuse->
eeprom_chnlarea_txpwr_cck[rf_path][i] =
hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i];
@ -1448,7 +1450,8 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
for (i = 0; i < 3; i++) {
if (!autoload_fail)
if (!autoload_fail &&
hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i] != 0xff)
tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i];
else
tempval = EEPROM_DEFAULT_HT40_2SDIFF;
@ -1518,7 +1521,9 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
for (i = 0; i < 3; i++) {
if (!autoload_fail) {
if (!autoload_fail &&
hwinfo[EEPROM_TXPWR_GROUP + i] != 0xff &&
hwinfo[EEPROM_TXPWR_GROUP + 3 + i] != 0xff) {
rtlefuse->eeprom_pwrlimit_ht40[i] =
hwinfo[EEPROM_TXPWR_GROUP + i];
rtlefuse->eeprom_pwrlimit_ht20[i] =
@ -1563,7 +1568,8 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
for (i = 0; i < 14; i++) {
index = rtl92c_get_chnl_group((u8)i);
if (!autoload_fail)
if (!autoload_fail &&
hwinfo[EEPROM_TXPOWERHT20DIFF + index] != 0xff)
tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index];
else
tempval = EEPROM_DEFAULT_HT20_DIFF;
@ -1580,7 +1586,8 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
index = rtl92c_get_chnl_group((u8)i);
if (!autoload_fail)
if (!autoload_fail &&
hwinfo[EEPROM_TXPOWER_OFDMDIFF + index] != 0xff)
tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index];
else
tempval = EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF;
@ -1610,14 +1617,16 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
if (!autoload_fail)
if (!autoload_fail && hwinfo[RF_OPTION1] != 0xff)
rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
else
rtlefuse->eeprom_regulatory = 0;
RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
if (!autoload_fail) {
if (!autoload_fail &&
hwinfo[EEPROM_TSSI_A] != 0xff &&
hwinfo[EEPROM_TSSI_B] != 0xff) {
rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
rtlefuse->eeprom_tssi[RF90_PATH_B] = hwinfo[EEPROM_TSSI_B];
} else {
@ -1628,7 +1637,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
if (!autoload_fail)
if (!autoload_fail && hwinfo[EEPROM_THERMAL_METER] != 0xff)
tempval = hwinfo[EEPROM_THERMAL_METER];
else
tempval = EEPROM_DEFAULT_THERMALMETER;

View File

@ -1047,7 +1047,6 @@ static int _rtl92de_set_media_status(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
u8 bcnfunc_enable;
bt_msr &= 0xfc;
@ -1064,31 +1063,26 @@ static int _rtl92de_set_media_status(struct ieee80211_hw *hw,
"Set HW_VAR_MEDIA_STATUS: No such media status(%x)\n",
type);
}
bcnfunc_enable = rtl_read_byte(rtlpriv, REG_BCN_CTRL);
switch (type) {
case NL80211_IFTYPE_UNSPECIFIED:
bt_msr |= MSR_NOLINK;
ledaction = LED_CTL_LINK;
bcnfunc_enable &= 0xF7;
rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to NO LINK!\n");
break;
case NL80211_IFTYPE_ADHOC:
bt_msr |= MSR_ADHOC;
bcnfunc_enable |= 0x08;
rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to Ad Hoc!\n");
break;
case NL80211_IFTYPE_STATION:
bt_msr |= MSR_INFRA;
ledaction = LED_CTL_LINK;
bcnfunc_enable &= 0xF7;
rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to STA!\n");
break;
case NL80211_IFTYPE_AP:
bt_msr |= MSR_AP;
bcnfunc_enable |= 0x08;
rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to AP!\n");
break;

View File

@ -1552,8 +1552,6 @@ void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u16 bcntime_cfg = 0;
u16 bcn_cw = 6, bcn_ifs = 0xf;
u16 atim_window = 2;
/* ATIM Window (in unit of TU). */
@ -1576,13 +1574,6 @@ void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw)
* other ad hoc STA */
rtl_write_byte(rtlpriv, BCN_ERR_THRESH, 100);
/* Beacon Time Configuration */
if (mac->opmode == NL80211_IFTYPE_ADHOC)
bcntime_cfg |= (bcn_cw << BCN_TCFG_CW_SHIFT);
/* TODO: bcn_ifs may required to be changed on ASIC */
bcntime_cfg |= bcn_ifs << BCN_TCFG_IFS;
/*for beacon changed */
rtl92s_phy_set_beacon_hwreg(hw, mac->beacon_interval);
}

View File

@ -222,6 +222,9 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
case RTW_HCI_TYPE_USB:
intf_mask = RTW_PWR_INTF_USB_MSK;
break;
case RTW_HCI_TYPE_SDIO:
intf_mask = RTW_PWR_INTF_SDIO_MSK;
break;
default:
return -EINVAL;
}
@ -233,7 +236,7 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
ret = rtw_sub_pwr_seq_parser(rtwdev, intf_mask, cut_mask, cmd);
if (ret)
return -EBUSY;
return ret;
idx++;
} while (1);
@ -247,6 +250,7 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on)
const struct rtw_pwr_seq_cmd **pwr_seq;
u8 rpwm;
bool cur_pwr;
int ret;
if (rtw_chip_wcpu_11ac(rtwdev)) {
rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
@ -270,8 +274,9 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on)
return -EALREADY;
pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq;
if (rtw_pwr_seq_parser(rtwdev, pwr_seq))
return -EINVAL;
ret = rtw_pwr_seq_parser(rtwdev, pwr_seq);
if (ret)
return ret;
if (pwr_on)
set_bit(RTW_FLAG_POWERON, rtwdev->flags);
@ -1040,6 +1045,9 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev)
else
return -EINVAL;
break;
case RTW_HCI_TYPE_SDIO:
rqpn = &chip->rqpn_table[0];
break;
default:
return -EINVAL;
}
@ -1202,6 +1210,9 @@ static int priority_queue_cfg(struct rtw_dev *rtwdev)
else
return -EINVAL;
break;
case RTW_HCI_TYPE_SDIO:
pg_tbl = &chip->page_table[0];
break;
default:
return -EINVAL;
}

View File

@ -32,6 +32,12 @@ static void rtw8821cu_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->u.mac_addr);
}
static void rtw8821cs_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8821c_efuse *map)
{
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
enum rtw8821ce_rf_set {
SWITCH_TO_BTG,
SWITCH_TO_WLG,
@ -77,6 +83,9 @@ static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_USB:
rtw8821cu_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8821cs_efuse_parsing(efuse, map);
break;
default:
/* unsupported now */
return -ENOTSUPP;

View File

@ -65,6 +65,11 @@ struct rtw8821ce_efuse {
u8 res7;
};
struct rtw8821cs_efuse {
u8 res4[0x4a]; /* 0xd0 */
u8 mac_addr[ETH_ALEN]; /* 0x11a */
} __packed;
struct rtw8821c_efuse {
__le16 rtl_id;
u8 res0[0x0e];
@ -94,6 +99,7 @@ struct rtw8821c_efuse {
union {
struct rtw8821ce_efuse e;
struct rtw8821cu_efuse u;
struct rtw8821cs_efuse s;
};
};

View File

@ -32,6 +32,12 @@ static void rtw8822bu_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->u.mac_addr);
}
static void rtw8822bs_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8822b_efuse *map)
{
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
@ -65,6 +71,9 @@ static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_USB:
rtw8822bu_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8822bs_efuse_parsing(efuse, map);
break;
default:
/* unsupported now */
return -ENOTSUPP;

View File

@ -65,6 +65,11 @@ struct rtw8822be_efuse {
u8 res7;
};
struct rtw8822bs_efuse {
u8 res4[0x4a]; /* 0xd0 */
u8 mac_addr[ETH_ALEN]; /* 0x11a */
} __packed;
struct rtw8822b_efuse {
__le16 rtl_id;
u8 res0[0x0e];
@ -92,8 +97,9 @@ struct rtw8822b_efuse {
u8 country_code[2];
u8 res[3];
union {
struct rtw8822bu_efuse u;
struct rtw8822be_efuse e;
struct rtw8822bu_efuse u;
struct rtw8822bs_efuse s;
};
};

View File

@ -35,6 +35,12 @@ static void rtw8822cu_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->u.mac_addr);
}
static void rtw8822cs_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8822c_efuse *map)
{
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
@ -67,6 +73,9 @@ static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_USB:
rtw8822cu_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8822cs_efuse_parsing(efuse, map);
break;
default:
/* unsupported now */
return -ENOTSUPP;

View File

@ -16,6 +16,11 @@ struct rtw8822cu_efuse {
u8 res2[0x3d];
};
struct rtw8822cs_efuse {
u8 res0[0x4a]; /* 0x120 */
u8 mac_addr[ETH_ALEN]; /* 0x16a */
} __packed;
struct rtw8822ce_efuse {
u8 mac_addr[ETH_ALEN]; /* 0x120 */
u8 vender_id[2];
@ -91,8 +96,9 @@ struct rtw8822c_efuse {
u8 res9;
u8 res10[0x42];
union {
struct rtw8822cu_efuse u;
struct rtw8822ce_efuse e;
struct rtw8822cu_efuse u;
struct rtw8822cs_efuse s;
};
};

View File

@ -1400,6 +1400,34 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
}
}
static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev,
struct sk_buff *skb)
{
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
struct rtw89_pktofld_info *info;
const u8 *ies = mgmt->u.beacon.variable, *ssid_ie;
if (rx_status->band != NL80211_BAND_6GHZ)
return;
ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, skb->len);
list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) {
if (ether_addr_equal(info->bssid, mgmt->bssid)) {
rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
continue;
}
if (!ssid_ie || ssid_ie[1] != info->ssid_len || info->ssid_len == 0)
continue;
if (memcmp(&ssid_ie[2], info->ssid, info->ssid_len) == 0)
rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
}
}
static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@ -1412,6 +1440,11 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
const u8 *bssid = iter_data->bssid;
if (rtwdev->scanning &&
(ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control)))
rtw89_core_cancel_6ghz_probe_tx(rtwdev, skb);
if (!vif->bss_conf.bssid)
return;
@ -3372,7 +3405,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_TDLS_EXTERNAL_SETUP |
WIPHY_FLAG_AP_UAPSD;
WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_SPLIT_SCAN_6GHZ;
hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
hw->wiphy->max_scan_ssids = RTW89_SCANOFLD_MAX_SSID;

View File

@ -3023,7 +3023,7 @@ enum rtw89_fw_feature {
RTW89_FW_FEATURE_SCAN_OFFLOAD,
RTW89_FW_FEATURE_TX_WAKE,
RTW89_FW_FEATURE_CRASH_TRIGGER,
RTW89_FW_FEATURE_PACKET_DROP,
RTW89_FW_FEATURE_NO_PACKET_DROP,
RTW89_FW_FEATURE_NO_DEEP_PS,
RTW89_FW_FEATURE_NO_LPS_PG,
};

View File

@ -235,6 +235,7 @@ static bool __fw_feat_cond_ ## __cond(u32 suit_ver_code, u32 comp_ver_code) \
__DEF_FW_FEAT_COND(ge, >=); /* greater or equal */
__DEF_FW_FEAT_COND(le, <=); /* less or equal */
__DEF_FW_FEAT_COND(lt, <); /* less than */
struct __fw_feat_cfg {
enum rtw89_core_chip_id chip_id;
@ -256,9 +257,11 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 38, 0, PACKET_DROP),
__CFG_FW_FEAT(RTL8852A, lt, 0, 13, 38, 0, NO_PACKET_DROP),
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG),
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 20, 0, PACKET_DROP),
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE),
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER),
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD),
__CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS),
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE),
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD),
@ -2702,9 +2705,29 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
}
}
static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct rtw89_pktofld_info *info,
enum nl80211_band band, u8 ssid_idx)
{
struct cfg80211_scan_request *req = rtwvif->scan_req;
if (band != NL80211_BAND_6GHZ)
return false;
if (req->ssids[ssid_idx].ssid_len) {
memcpy(info->ssid, req->ssids[ssid_idx].ssid,
req->ssids[ssid_idx].ssid_len);
info->ssid_len = req->ssids[ssid_idx].ssid_len;
return false;
} else {
return true;
}
}
static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct sk_buff *skb)
struct sk_buff *skb, u8 ssid_idx)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
@ -2732,6 +2755,13 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
goto out;
}
if (rtw89_is_6ghz_wildcard_probe_req(rtwdev, rtwvif, info, band,
ssid_idx)) {
kfree_skb(new);
kfree(info);
goto out;
}
ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new);
if (ret) {
kfree_skb(new);
@ -2762,7 +2792,7 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
if (!skb)
return -ENOMEM;
ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb);
ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb, i);
kfree_skb(skb);
if (ret)
@ -2772,6 +2802,77 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
return 0;
}
static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev,
struct cfg80211_scan_request *req,
struct rtw89_mac_chinfo *ch_info)
{
struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
struct cfg80211_scan_6ghz_params *params;
struct rtw89_pktofld_info *info, *tmp;
struct ieee80211_hdr *hdr;
struct sk_buff *skb;
bool found;
int ret = 0;
u8 i;
if (!req->n_6ghz_params)
return 0;
for (i = 0; i < req->n_6ghz_params; i++) {
params = &req->scan_6ghz_params[i];
if (req->channels[params->channel_idx]->hw_value !=
ch_info->pri_ch)
continue;
found = false;
list_for_each_entry(tmp, &pkt_list[NL80211_BAND_6GHZ], list) {
if (ether_addr_equal(tmp->bssid, params->bssid)) {
found = true;
break;
}
}
if (found)
continue;
skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr,
NULL, 0, req->ie_len);
skb_put_data(skb, ies->ies[NL80211_BAND_6GHZ], ies->len[NL80211_BAND_6GHZ]);
skb_put_data(skb, ies->common_ies, ies->common_ie_len);
hdr = (struct ieee80211_hdr *)skb->data;
ether_addr_copy(hdr->addr3, params->bssid);
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
ret = -ENOMEM;
kfree_skb(skb);
goto out;
}
ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, skb);
if (ret) {
kfree_skb(skb);
kfree(info);
goto out;
}
ether_addr_copy(info->bssid, params->bssid);
info->channel_6ghz = req->channels[params->channel_idx]->hw_value;
list_add_tail(&info->list, &rtwdev->scan_info.pkt_list[NL80211_BAND_6GHZ]);
ch_info->tx_pkt = true;
ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G;
kfree_skb(skb);
}
out:
return ret;
}
static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
int ssid_num,
struct rtw89_mac_chinfo *ch_info)
@ -2782,6 +2883,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_pktofld_info *info;
u8 band, probe_count = 0;
int ret;
ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK;
ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS;
@ -2793,27 +2895,33 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
ch_info->pause_data = false;
ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE;
if (ssid_num) {
ch_info->num_pkt = ssid_num;
band = rtw89_hw_to_nl80211_band(ch_info->ch_band);
list_for_each_entry(info, &scan_info->pkt_list[band], list) {
ch_info->pkt_id[probe_count] = info->id;
if (++probe_count >= ssid_num)
break;
}
if (probe_count != ssid_num)
rtw89_err(rtwdev, "SSID num differs from list len\n");
}
if (ch_info->ch_band == RTW89_BAND_6G) {
if (ssid_num == 1 && req->ssids[0].ssid_len == 0) {
if ((ssid_num == 1 && req->ssids[0].ssid_len == 0) ||
!ch_info->is_psc) {
ch_info->tx_pkt = false;
if (!req->duration_mandatory)
ch_info->period -= RTW89_DWELL_TIME_6G;
}
}
ret = rtw89_update_6ghz_rnr_chan(rtwdev, req, ch_info);
if (ret)
rtw89_warn(rtwdev, "RNR fails: %d\n", ret);
if (ssid_num) {
band = rtw89_hw_to_nl80211_band(ch_info->ch_band);
list_for_each_entry(info, &scan_info->pkt_list[band], list) {
if (info->channel_6ghz &&
ch_info->pri_ch != info->channel_6ghz)
continue;
ch_info->pkt_id[probe_count++] = info->id;
if (probe_count >= RTW89_SCANOFLD_MAX_SSID)
break;
}
ch_info->num_pkt = probe_count;
}
switch (chan_type) {
case RTW89_CHAN_OPERATE:
ch_info->central_ch = scan_info->op_chan;
@ -2872,6 +2980,7 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
ch_info->central_ch = channel->hw_value;
ch_info->pri_ch = channel->hw_value;
ch_info->rand_seq_num = random_seq;
ch_info->is_psc = cfg80211_channel_is_psc(channel);
if (channel->flags &
(IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))

View File

@ -237,6 +237,7 @@ struct rtw89_mac_chinfo {
u16 tx_pwr_idx;
u8 rsvd1;
struct list_head list;
bool is_psc;
};
struct rtw89_scan_option {
@ -247,6 +248,12 @@ struct rtw89_scan_option {
struct rtw89_pktofld_info {
struct list_head list;
u8 id;
/* Below fields are for 6 GHz RNR use only */
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
u8 bssid[ETH_ALEN];
u16 channel_6ghz;
};
static inline void RTW89_SET_FWCMD_RA_IS_DIS(void *cmd, u32 val)

View File

@ -5426,7 +5426,7 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
for (i = 0; i < try_cnt; i++) {
ret = read_poll_timeout(mac_is_txq_empty, empty, empty, 50,
50000, false, rtwdev);
if (ret)
if (ret && !RTW89_CHK_FW_FEATURE(NO_PACKET_DROP, &rtwdev->fw))
rtw89_fw_h2c_pkt_drop(rtwdev, &params);
else
return 0;

View File

@ -676,7 +676,7 @@ static void rtw89_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
rtw89_leave_lps(rtwdev);
rtw89_hci_flush_queues(rtwdev, queues, drop);
if (drop && RTW89_CHK_FW_FEATURE(PACKET_DROP, &rtwdev->fw))
if (drop && !RTW89_CHK_FW_FEATURE(NO_PACKET_DROP, &rtwdev->fw))
__rtw89_drop_packets(rtwdev, vif);
else
rtw89_mac_flush_txq(rtwdev, queues, drop);

View File

@ -4294,3 +4294,75 @@ void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev,
data[RTW89_TSSI_SBW20]);
}
EXPORT_SYMBOL(rtw89_phy_tssi_ctrl_set_bandedge_cfg);
static
const u8 rtw89_ch_base_table[16] = {1, 0xff,
36, 100, 132, 149, 0xff,
1, 33, 65, 97, 129, 161, 193, 225, 0xff};
#define RTW89_CH_BASE_IDX_2G 0
#define RTW89_CH_BASE_IDX_5G_FIRST 2
#define RTW89_CH_BASE_IDX_5G_LAST 5
#define RTW89_CH_BASE_IDX_6G_FIRST 7
#define RTW89_CH_BASE_IDX_6G_LAST 14
#define RTW89_CH_BASE_IDX_MASK GENMASK(7, 4)
#define RTW89_CH_OFFSET_MASK GENMASK(3, 0)
u8 rtw89_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band)
{
u8 chan_idx;
u8 last, first;
u8 idx;
switch (band) {
case RTW89_BAND_2G:
chan_idx = FIELD_PREP(RTW89_CH_BASE_IDX_MASK, RTW89_CH_BASE_IDX_2G) |
FIELD_PREP(RTW89_CH_OFFSET_MASK, central_ch);
return chan_idx;
case RTW89_BAND_5G:
first = RTW89_CH_BASE_IDX_5G_FIRST;
last = RTW89_CH_BASE_IDX_5G_LAST;
break;
case RTW89_BAND_6G:
first = RTW89_CH_BASE_IDX_6G_FIRST;
last = RTW89_CH_BASE_IDX_6G_LAST;
break;
default:
rtw89_warn(rtwdev, "Unsupported band %d\n", band);
return 0;
}
for (idx = last; idx >= first; idx--)
if (central_ch >= rtw89_ch_base_table[idx])
break;
if (idx < first) {
rtw89_warn(rtwdev, "Unknown band %d channel %d\n", band, central_ch);
return 0;
}
chan_idx = FIELD_PREP(RTW89_CH_BASE_IDX_MASK, idx) |
FIELD_PREP(RTW89_CH_OFFSET_MASK,
(central_ch - rtw89_ch_base_table[idx]) >> 1);
return chan_idx;
}
EXPORT_SYMBOL(rtw89_encode_chan_idx);
void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx,
u8 *ch, enum nl80211_band *band)
{
u8 idx, offset;
idx = FIELD_GET(RTW89_CH_BASE_IDX_MASK, chan_idx);
offset = FIELD_GET(RTW89_CH_OFFSET_MASK, chan_idx);
if (idx == RTW89_CH_BASE_IDX_2G) {
*band = NL80211_BAND_2GHZ;
*ch = offset;
return;
}
*band = idx <= RTW89_CH_BASE_IDX_5G_LAST ? NL80211_BAND_5GHZ : NL80211_BAND_6GHZ;
*ch = rtw89_ch_base_table[idx] + (offset << 1);
}
EXPORT_SYMBOL(rtw89_decode_chan_idx);

View File

@ -555,5 +555,8 @@ void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev,
enum rtw89_tssi_bandedge_cfg bandedge_cfg);
void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev);
u8 rtw89_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band);
void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx,
u8 *ch, enum nl80211_band *band);
#endif

View File

@ -1422,6 +1422,7 @@ static void rtw8852b_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89
{
bool cck_en = chan->channel <= 14;
u8 pri_ch_idx = chan->pri_ch_idx;
u8 band = chan->band_type, chan_idx;
if (cck_en)
rtw8852b_ctrl_sco_cck(rtwdev, chan->primary_channel);
@ -1444,8 +1445,8 @@ static void rtw8852b_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89
B_BT_DYN_DC_EST_EN_MSK, 0x0);
rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0);
}
rtw89_phy_write32_mask(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0,
chan->primary_channel);
chan_idx = rtw89_encode_chan_idx(rtwdev, chan->primary_channel, band);
rtw89_phy_write32_mask(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0, chan_idx);
rtw8852b_5m_mask(rtwdev, chan, phy_idx);
rtw8852b_bb_set_pop(rtwdev);
rtw8852b_bb_reset_all(rtwdev, phy_idx);
@ -2299,13 +2300,14 @@ static void rtw8852b_fill_freq_with_ppdu(struct rtw89_dev *rtwdev,
struct ieee80211_rx_status *status)
{
u16 chan = phy_ppdu->chan_idx;
u8 band;
enum nl80211_band band;
u8 ch;
if (chan == 0)
return;
band = chan <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
status->freq = ieee80211_channel_to_frequency(chan, band);
rtw89_decode_chan_idx(rtwdev, chan, &ch, &band);
status->freq = ieee80211_channel_to_frequency(ch, band);
status->band = band;
}

View File

@ -852,76 +852,6 @@ static void rtw8852c_set_gain_error(struct rtw89_dev *rtwdev,
}
}
static
const u8 rtw8852c_ch_base_table[16] = {1, 0xff,
36, 100, 132, 149, 0xff,
1, 33, 65, 97, 129, 161, 193, 225, 0xff};
#define RTW8852C_CH_BASE_IDX_2G 0
#define RTW8852C_CH_BASE_IDX_5G_FIRST 2
#define RTW8852C_CH_BASE_IDX_5G_LAST 5
#define RTW8852C_CH_BASE_IDX_6G_FIRST 7
#define RTW8852C_CH_BASE_IDX_6G_LAST 14
#define RTW8852C_CH_BASE_IDX_MASK GENMASK(7, 4)
#define RTW8852C_CH_OFFSET_MASK GENMASK(3, 0)
static u8 rtw8852c_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band)
{
u8 chan_idx;
u8 last, first;
u8 idx;
switch (band) {
case RTW89_BAND_2G:
chan_idx = FIELD_PREP(RTW8852C_CH_BASE_IDX_MASK, RTW8852C_CH_BASE_IDX_2G) |
FIELD_PREP(RTW8852C_CH_OFFSET_MASK, central_ch);
return chan_idx;
case RTW89_BAND_5G:
first = RTW8852C_CH_BASE_IDX_5G_FIRST;
last = RTW8852C_CH_BASE_IDX_5G_LAST;
break;
case RTW89_BAND_6G:
first = RTW8852C_CH_BASE_IDX_6G_FIRST;
last = RTW8852C_CH_BASE_IDX_6G_LAST;
break;
default:
rtw89_warn(rtwdev, "Unsupported band %d\n", band);
return 0;
}
for (idx = last; idx >= first; idx--)
if (central_ch >= rtw8852c_ch_base_table[idx])
break;
if (idx < first) {
rtw89_warn(rtwdev, "Unknown band %d channel %d\n", band, central_ch);
return 0;
}
chan_idx = FIELD_PREP(RTW8852C_CH_BASE_IDX_MASK, idx) |
FIELD_PREP(RTW8852C_CH_OFFSET_MASK,
(central_ch - rtw8852c_ch_base_table[idx]) >> 1);
return chan_idx;
}
static void rtw8852c_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx,
u8 *ch, enum nl80211_band *band)
{
u8 idx, offset;
idx = FIELD_GET(RTW8852C_CH_BASE_IDX_MASK, chan_idx);
offset = FIELD_GET(RTW8852C_CH_OFFSET_MASK, chan_idx);
if (idx == RTW8852C_CH_BASE_IDX_2G) {
*band = NL80211_BAND_2GHZ;
*ch = offset;
return;
}
*band = idx <= RTW8852C_CH_BASE_IDX_5G_LAST ? NL80211_BAND_5GHZ : NL80211_BAND_6GHZ;
*ch = rtw8852c_ch_base_table[idx] + (offset << 1);
}
static void rtw8852c_set_gain_offset(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx,
@ -1084,7 +1014,7 @@ static void rtw8852c_ctrl_ch(struct rtw89_dev *rtwdev,
}
}
chan_idx = rtw8852c_encode_chan_idx(rtwdev, chan->primary_channel, band);
chan_idx = rtw89_encode_chan_idx(rtwdev, chan->primary_channel, band);
rtw89_phy_write32_idx(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0, chan_idx, phy_idx);
}
@ -2730,7 +2660,7 @@ static void rtw8852c_fill_freq_with_ppdu(struct rtw89_dev *rtwdev,
if (chan_idx == 0)
return;
rtw8852c_decode_chan_idx(rtwdev, chan_idx, &ch, &band);
rtw89_decode_chan_idx(rtwdev, chan_idx, &ch, &band);
status->freq = ieee80211_channel_to_frequency(ch, band);
status->band = band;
}

View File

@ -414,8 +414,11 @@ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt)
static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt)
{
struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser);
switch (evt) {
case SER_EV_STATE_IN:
cancel_delayed_work_sync(&rtwdev->track_work);
drv_stop_tx(ser);
if (hal_stop_dma(ser)) {
@ -446,6 +449,8 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt)
hal_enable_dma(ser);
drv_resume_rx(ser);
drv_resume_tx(ser);
ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work,
RTW89_TRACK_WORK_PERIOD);
break;
default:

View File

@ -358,13 +358,9 @@ int wfx_probe(struct wfx_dev *wdev)
wfx_bh_poll_irq(wdev);
err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ);
if (err <= 0) {
if (err == 0) {
dev_err(wdev->dev, "timeout while waiting for startup indication\n");
err = -ETIMEDOUT;
} else if (err == -ERESTARTSYS) {
dev_info(wdev->dev, "probe interrupted by user\n");
}
if (err == 0) {
dev_err(wdev->dev, "timeout while waiting for startup indication\n");
err = -ETIMEDOUT;
goto bh_unregister;
}

View File

@ -827,6 +827,18 @@ struct cfg80211_fils_aad {
const u8 *anonce;
};
/**
* struct cfg80211_set_hw_timestamp - enable/disable HW timestamping
* @macaddr: peer MAC address. NULL to enable/disable HW timestamping for all
* addresses.
* @enable: if set, enable HW timestamping for the specified MAC address.
* Otherwise disable HW timestamping for the specified MAC address.
*/
struct cfg80211_set_hw_timestamp {
const u8 *macaddr;
bool enable;
};
/**
* cfg80211_get_chandef_type - return old channel type from chandef
* @chandef: the channel definition
@ -4330,6 +4342,8 @@ struct mgmt_frame_regs {
* @add_link_station: Add a link to a station.
* @mod_link_station: Modify a link of a station.
* @del_link_station: Remove a link of a station.
*
* @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@ -4683,6 +4697,8 @@ struct cfg80211_ops {
struct link_station_parameters *params);
int (*del_link_station)(struct wiphy *wiphy, struct net_device *dev,
struct link_station_del_parameters *params);
int (*set_hw_timestamp)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_set_hw_timestamp *hwts);
};
/*
@ -5139,6 +5155,8 @@ struct wiphy_iftype_akm_suites {
int n_akm_suites;
};
#define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff
/**
* struct wiphy - wireless hardware description
* @mtx: mutex for the data (structures) of this device
@ -5348,6 +5366,13 @@ struct wiphy_iftype_akm_suites {
* NL80211_MAX_NR_AKM_SUITES in order to avoid compatibility issues with
* legacy userspace and maximum allowed value is
* CFG80211_MAX_NUM_AKM_SUITES.
*
* @hw_timestamp_max_peers: maximum number of peers that the driver supports
* enabling HW timestamping for concurrently. Setting this field to a
* non-zero value indicates that the driver supports HW timestamping.
* A value of %CFG80211_HW_TIMESTAMP_ALL_PEERS indicates the driver
* supports enabling HW timestamping for all peers (i.e. no need to
* specify a mac address).
*/
struct wiphy {
struct mutex mtx;
@ -5496,6 +5521,8 @@ struct wiphy {
u8 ema_max_profile_periodicity;
u16 max_num_akm_suites;
u16 hw_timestamp_max_peers;
char priv[] __aligned(NETDEV_ALIGN);
};
@ -6814,13 +6841,11 @@ enum cfg80211_bss_frame_type {
* @ie: IEs
* @ielen: length of IEs
* @band: enum nl80211_band of the channel
* @ftype: frame type
*
* Returns the channel number, or -1 if none could be determined.
*/
int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
enum nl80211_band band,
enum cfg80211_bss_frame_type ftype);
enum nl80211_band band);
/**
* cfg80211_inform_bss_data - inform cfg80211 of a new BSS
@ -8101,6 +8126,7 @@ void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie,
* responsible for any cleanup. The caller must also ensure that
* skb->protocol is set appropriately.
* @unencrypted: Whether the frame was received unencrypted
* @link_id: the link the frame was received on, -1 if not applicable or unknown
*
* This function is used to inform userspace about a received control port
* frame. It should only be used if userspace indicated it wants to receive
@ -8111,8 +8137,8 @@ void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie,
*
* Return: %true if the frame was passed to userspace
*/
bool cfg80211_rx_control_port(struct net_device *dev,
struct sk_buff *skb, bool unencrypted);
bool cfg80211_rx_control_port(struct net_device *dev, struct sk_buff *skb,
bool unencrypted, int link_id);
/**
* cfg80211_cqm_rssi_notify - connection quality monitoring rssi event

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2017 Intel Deutschland GmbH
* Copyright (c) 2018-2019, 2021 Intel Corporation
* Copyright (c) 2018-2019, 2021-2022 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -82,11 +82,14 @@ enum ieee80211_radiotap_presence {
IEEE80211_RADIOTAP_HE_MU = 24,
IEEE80211_RADIOTAP_ZERO_LEN_PSDU = 26,
IEEE80211_RADIOTAP_LSIG = 27,
IEEE80211_RADIOTAP_TLV = 28,
/* valid in every it_present bitmap, even vendor namespaces */
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
IEEE80211_RADIOTAP_EXT = 31
IEEE80211_RADIOTAP_EXT = 31,
IEEE80211_RADIOTAP_EHT_USIG = 33,
IEEE80211_RADIOTAP_EHT = 34,
};
/* for IEEE80211_RADIOTAP_FLAGS */
@ -360,6 +363,214 @@ enum ieee80211_radiotap_zero_len_psdu_type {
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR = 0xff,
};
struct ieee80211_radiotap_tlv {
__le16 type;
__le16 len;
u8 data[];
} __packed;
/**
* struct ieee80211_radiotap_vendor_content - radiotap vendor data content
* @oui: radiotap vendor namespace OUI
* @oui_subtype: radiotap vendor sub namespace
* @vendor_type: radiotap vendor type
* @reserved: should always be set to zero (to avoid leaking memory)
* @data: the actual vendor namespace data
*/
struct ieee80211_radiotap_vendor_content {
u8 oui[3];
u8 oui_subtype;
__le16 vendor_type;
__le16 reserved;
u8 data[];
} __packed;
/**
* struct ieee80211_radiotap_vendor_tlv - vendor radiotap data information
* @type: should always be set to IEEE80211_RADIOTAP_VENDOR_NAMESPACE
* @len: length of data
* @content: vendor content see @ieee80211_radiotap_vendor_content
*/
struct ieee80211_radiotap_vendor_tlv {
__le16 type; /* IEEE80211_RADIOTAP_VENDOR_NAMESPACE */
__le16 len;
struct ieee80211_radiotap_vendor_content content;
};
/* ieee80211_radiotap_eht_usig - content of U-SIG tlv (type 33)
* see www.radiotap.org/fields/U-SIG.html for details
*/
struct ieee80211_radiotap_eht_usig {
__le32 common;
__le32 value;
__le32 mask;
} __packed;
/* ieee80211_radiotap_eht - content of EHT tlv (type 34)
* see www.radiotap.org/fields/EHT.html for details
*/
struct ieee80211_radiotap_eht {
__le32 known;
__le32 data[9];
__le32 user_info[];
} __packed;
/* Known field for EHT TLV
* The ending defines for what the field applies as following
* O - OFDMA (including TB), M - MU-MIMO, S - EHT sounding.
*/
enum ieee80211_radiotap_eht_known {
IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE = 0x00000002,
IEEE80211_RADIOTAP_EHT_KNOWN_GI = 0x00000004,
IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF = 0x00000010,
IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM = 0x00000020,
IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM = 0x00000040,
IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM = 0x00000080,
IEEE80211_RADIOTAP_EHT_KNOWN_DISREGARD_O = 0x00000100,
IEEE80211_RADIOTAP_EHT_KNOWN_DISREGARD_S = 0x00000200,
IEEE80211_RADIOTAP_EHT_KNOWN_CRC1 = 0x00002000,
IEEE80211_RADIOTAP_EHT_KNOWN_TAIL1 = 0x00004000,
IEEE80211_RADIOTAP_EHT_KNOWN_CRC2_O = 0x00008000,
IEEE80211_RADIOTAP_EHT_KNOWN_TAIL2_O = 0x00010000,
IEEE80211_RADIOTAP_EHT_KNOWN_NSS_S = 0x00020000,
IEEE80211_RADIOTAP_EHT_KNOWN_BEAMFORMED_S = 0x00040000,
IEEE80211_RADIOTAP_EHT_KNOWN_NR_NON_OFDMA_USERS_M = 0x00080000,
IEEE80211_RADIOTAP_EHT_KNOWN_ENCODING_BLOCK_CRC_M = 0x00100000,
IEEE80211_RADIOTAP_EHT_KNOWN_ENCODING_BLOCK_TAIL_M = 0x00200000,
IEEE80211_RADIOTAP_EHT_KNOWN_RU_MRU_SIZE_OM = 0x00400000,
IEEE80211_RADIOTAP_EHT_KNOWN_RU_MRU_INDEX_OM = 0x00800000,
IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT = 0x01000000,
IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80 = 0x02000000,
};
enum ieee80211_radiotap_eht_data {
/* Data 0 */
IEEE80211_RADIOTAP_EHT_DATA0_SPATIAL_REUSE = 0x00000078,
IEEE80211_RADIOTAP_EHT_DATA0_GI = 0x00000180,
IEEE80211_RADIOTAP_EHT_DATA0_LTF = 0x00000600,
IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF = 0x00003800,
IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM = 0x00004000,
IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM = 0x00018000,
IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM = 0x00020000,
IEEE80211_RADIOTAP_EHT_DATA0_DISREGARD_S = 0x000c0000,
IEEE80211_RADIOTAP_EHT_DATA0_DISREGARD_O = 0x003c0000,
IEEE80211_RADIOTAP_EHT_DATA0_CRC1_O = 0x03c00000,
IEEE80211_RADIOTAP_EHT_DATA0_TAIL1_O = 0xfc000000,
/* Data 1 */
IEEE80211_RADIOTAP_EHT_DATA1_RU_SIZE = 0x0000001f,
IEEE80211_RADIOTAP_EHT_DATA1_RU_INDEX = 0x00001fe0,
IEEE80211_RADIOTAP_EHT_DATA1_RU_ALLOC_CC_1_1_1 = 0x003fe000,
IEEE80211_RADIOTAP_EHT_DATA1_RU_ALLOC_CC_1_1_1_KNOWN = 0x00400000,
IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80 = 0xc0000000,
/* Data 2 */
IEEE80211_RADIOTAP_EHT_DATA2_RU_ALLOC_CC_2_1_1 = 0x000001ff,
IEEE80211_RADIOTAP_EHT_DATA2_RU_ALLOC_CC_2_1_1_KNOWN = 0x00000200,
IEEE80211_RADIOTAP_EHT_DATA2_RU_ALLOC_CC_1_1_2 = 0x0007fc00,
IEEE80211_RADIOTAP_EHT_DATA2_RU_ALLOC_CC_1_1_2_KNOWN = 0x00080000,
IEEE80211_RADIOTAP_EHT_DATA2_RU_ALLOC_CC_2_1_2 = 0x1ff00000,
IEEE80211_RADIOTAP_EHT_DATA2_RU_ALLOC_CC_2_1_2_KNOWN = 0x20000000,
/* Data 3 */
IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_1_2_1 = 0x000001ff,
IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_1_2_1_KNOWN = 0x00000200,
IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_2_2_1 = 0x0007fc00,
IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_2_2_1_KNOWN = 0x00080000,
IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_1_2_2 = 0x1ff00000,
IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_1_2_2_KNOWN = 0x20000000,
/* Data 4 */
IEEE80211_RADIOTAP_EHT_DATA4_RU_ALLOC_CC_2_2_2 = 0x000001ff,
IEEE80211_RADIOTAP_EHT_DATA4_RU_ALLOC_CC_2_2_2_KNOWN = 0x00000200,
IEEE80211_RADIOTAP_EHT_DATA4_RU_ALLOC_CC_1_2_3 = 0x0007fc00,
IEEE80211_RADIOTAP_EHT_DATA4_RU_ALLOC_CC_1_2_3_KNOWN = 0x00080000,
IEEE80211_RADIOTAP_EHT_DATA4_RU_ALLOC_CC_2_2_3 = 0x1ff00000,
IEEE80211_RADIOTAP_EHT_DATA4_RU_ALLOC_CC_2_2_3_KNOWN = 0x20000000,
/* Data 5 */
IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_1_2_4 = 0x000001ff,
IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_1_2_4_KNOWN = 0x00000200,
IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_2_2_4 = 0x0007fc00,
IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_2_2_4_KNOWN = 0x00080000,
IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_1_2_5 = 0x1ff00000,
IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_1_2_5_KNOWN = 0x20000000,
/* Data 6 */
IEEE80211_RADIOTAP_EHT_DATA6_RU_ALLOC_CC_2_2_5 = 0x000001ff,
IEEE80211_RADIOTAP_EHT_DATA6_RU_ALLOC_CC_2_2_5_KNOWN = 0x00000200,
IEEE80211_RADIOTAP_EHT_DATA6_RU_ALLOC_CC_1_2_6 = 0x0007fc00,
IEEE80211_RADIOTAP_EHT_DATA6_RU_ALLOC_CC_1_2_6_KNOWN = 0x00080000,
IEEE80211_RADIOTAP_EHT_DATA6_RU_ALLOC_CC_2_2_6 = 0x1ff00000,
IEEE80211_RADIOTAP_EHT_DATA6_RU_ALLOC_CC_2_2_6_KNOWN = 0x20000000,
/* Data 7 */
IEEE80211_RADIOTAP_EHT_DATA7_CRC2_O = 0x0000000f,
IEEE80211_RADIOTAP_EHT_DATA7_TAIL_2_O = 0x000003f0,
IEEE80211_RADIOTAP_EHT_DATA7_NSS_S = 0x0000f000,
IEEE80211_RADIOTAP_EHT_DATA7_BEAMFORMED_S = 0x00010000,
IEEE80211_RADIOTAP_EHT_DATA7_NUM_OF_NON_OFDMA_USERS = 0x000e0000,
IEEE80211_RADIOTAP_EHT_DATA7_USER_ENCODING_BLOCK_CRC = 0x00f00000,
IEEE80211_RADIOTAP_EHT_DATA7_USER_ENCODING_BLOCK_TAIL = 0x3f000000,
/* Data 8 */
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160 = 0x00000001,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0 = 0x00000002,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1 = 0x000001fc,
};
enum ieee80211_radiotap_eht_user_info {
IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN = 0x00000001,
IEEE80211_RADIOTAP_EHT_USER_INFO_MCS_KNOWN = 0x00000002,
IEEE80211_RADIOTAP_EHT_USER_INFO_CODING_KNOWN = 0x00000004,
IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_KNOWN_O = 0x00000010,
IEEE80211_RADIOTAP_EHT_USER_INFO_BEAMFORMING_KNOWN_O = 0x00000020,
IEEE80211_RADIOTAP_EHT_USER_INFO_SPATIAL_CONFIG_KNOWN_M = 0x00000040,
IEEE80211_RADIOTAP_EHT_USER_INFO_DATA_FOR_USER = 0x00000080,
IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID = 0x0007ff00,
IEEE80211_RADIOTAP_EHT_USER_INFO_CODING = 0x00080000,
IEEE80211_RADIOTAP_EHT_USER_INFO_MCS = 0x00f00000,
IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O = 0x0f000000,
IEEE80211_RADIOTAP_EHT_USER_INFO_BEAMFORMING_O = 0x20000000,
IEEE80211_RADIOTAP_EHT_USER_INFO_SPATIAL_CONFIG_M = 0x3f000000,
IEEE80211_RADIOTAP_EHT_USER_INFO_RESEVED_c0000000 = 0xc0000000,
};
enum ieee80211_radiotap_eht_usig_common {
IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN = 0x00000001,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN = 0x00000002,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN = 0x00000004,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN = 0x00000008,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN = 0x00000010,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC = 0x00000020,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER = 0x00007000,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW = 0x00038000,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL = 0x00040000,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR = 0x01f80000,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP = 0xfe000000,
};
enum ieee80211_radiotap_eht_usig_mu {
/* MU-USIG-1 */
IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD = 0x0000001f,
IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE = 0x00000020,
/* MU-USIG-2 */
IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE = 0x000000c0,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE = 0x00000100,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO = 0x00003e00,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE = 0x00004000,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS = 0x00018000,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS = 0x003e0000,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B16_B19_CRC = 0x03c00000,
IEEE80211_RADIOTAP_EHT_USIG2_MU_B20_B25_TAIL = 0xfc000000,
};
enum ieee80211_radiotap_eht_usig_tb {
/* TB-USIG-1 */
IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD = 0x0000001f,
/* TB-USIG-2 */
IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE = 0x000000c0,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE = 0x00000100,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1 = 0x00001e00,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2 = 0x0001e000,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD = 0x003e0000,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B16_B19_CRC = 0x03c00000,
IEEE80211_RADIOTAP_EHT_USIG2_TB_B20_B25_TAIL = 0xfc000000,
};
/**
* ieee80211_get_radiotap_len - get radiotap header length
*/

View File

@ -534,6 +534,7 @@ struct ieee80211_fils_discovery {
* This structure keeps information about a BSS (and an association
* to that BSS) that can change during the lifetime of the BSS.
*
* @vif: reference to owning VIF
* @addr: (link) address used locally
* @link_id: link ID, or 0 for non-MLO
* @htc_trig_based_pkt_ext: default PE in 4us units, if BSS supports HE
@ -656,6 +657,9 @@ struct ieee80211_fils_discovery {
* write-protected by sdata_lock and local->mtx so holding either is fine
* for read access.
* @color_change_color: the bss color that will be used after the change.
* @ht_ldpc: in AP mode, indicates interface has HT LDPC capability.
* @vht_ldpc: in AP mode, indicates interface has VHT LDPC capability.
* @he_ldpc: in AP mode, indicates interface has HE LDPC capability.
* @vht_su_beamformer: in AP mode, does this BSS support operation as an VHT SU
* beamformer
* @vht_su_beamformee: in AP mode, does this BSS support operation as an VHT SU
@ -673,8 +677,16 @@ struct ieee80211_fils_discovery {
* @he_full_ul_mumimo: does this BSS support the reception (AP) or transmission
* (non-AP STA) of an HE TB PPDU on an RU that spans the entire PPDU
* bandwidth
* @eht_su_beamformer: in AP-mode, does this BSS enable operation as an EHT SU
* beamformer
* @eht_su_beamformee: in AP-mode, does this BSS enable operation as an EHT SU
* beamformee
* @eht_mu_beamformer: in AP-mode, does this BSS enable operation as an EHT MU
* beamformer
*/
struct ieee80211_bss_conf {
struct ieee80211_vif *vif;
const u8 *bssid;
unsigned int link_id;
u8 addr[ETH_ALEN] __aligned(2);
@ -750,6 +762,9 @@ struct ieee80211_bss_conf {
bool color_change_active;
u8 color_change_color;
bool ht_ldpc;
bool vht_ldpc;
bool he_ldpc;
bool vht_su_beamformer;
bool vht_su_beamformee;
bool vht_mu_beamformer;
@ -758,6 +773,9 @@ struct ieee80211_bss_conf {
bool he_su_beamformee;
bool he_mu_beamformer;
bool he_full_ul_mumimo;
bool eht_su_beamformer;
bool eht_su_beamformee;
bool eht_mu_beamformer;
};
/**
@ -1372,9 +1390,12 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* subframes share the same sequence number. Reported subframes can be
* either regular MSDU or singly A-MSDUs. Subframes must not be
* interleaved with other frames.
* @RX_FLAG_RADIOTAP_VENDOR_DATA: This frame contains vendor-specific
* radiotap data in the skb->data (before the frame) as described by
* the &struct ieee80211_vendor_radiotap.
* @RX_FLAG_RADIOTAP_TLV_AT_END: This frame contains radiotap TLVs in the
* skb->data (before the 802.11 header).
* If used, the SKB's mac_header pointer must be set to point
* to the 802.11 header after the TLVs, and any padding added after TLV
* data to align to 4 must be cleared by the driver putting the TLVs
* in the skb.
* @RX_FLAG_ALLOW_SAME_PN: Allow the same PN as same packet before.
* This is used for AMSDU subframes which can have the same PN as
* the first subframe.
@ -1426,7 +1447,7 @@ enum mac80211_rx_flags {
RX_FLAG_ONLY_MONITOR = BIT(17),
RX_FLAG_SKIP_MONITOR = BIT(18),
RX_FLAG_AMSDU_MORE = BIT(19),
RX_FLAG_RADIOTAP_VENDOR_DATA = BIT(20),
RX_FLAG_RADIOTAP_TLV_AT_END = BIT(20),
RX_FLAG_MIC_STRIPPED = BIT(21),
RX_FLAG_ALLOW_SAME_PN = BIT(22),
RX_FLAG_ICV_STRIPPED = BIT(23),
@ -1566,39 +1587,6 @@ ieee80211_rx_status_to_khz(struct ieee80211_rx_status *rx_status)
(rx_status->freq_offset ? 500 : 0);
}
/**
* struct ieee80211_vendor_radiotap - vendor radiotap data information
* @present: presence bitmap for this vendor namespace
* (this could be extended in the future if any vendor needs more
* bits, the radiotap spec does allow for that)
* @align: radiotap vendor namespace alignment. This defines the needed
* alignment for the @data field below, not for the vendor namespace
* description itself (which has a fixed 2-byte alignment)
* Must be a power of two, and be set to at least 1!
* @oui: radiotap vendor namespace OUI
* @subns: radiotap vendor sub namespace
* @len: radiotap vendor sub namespace skip length, if alignment is done
* then that's added to this, i.e. this is only the length of the
* @data field.
* @pad: number of bytes of padding after the @data, this exists so that
* the skb data alignment can be preserved even if the data has odd
* length
* @data: the actual vendor namespace data
*
* This struct, including the vendor data, goes into the skb->data before
* the 802.11 header. It's split up in mac80211 using the align/oui/subns
* data.
*/
struct ieee80211_vendor_radiotap {
u32 present;
u8 align;
u8 oui[3];
u8 subns;
u8 pad;
u16 len;
u8 data[];
} __packed;
/**
* enum ieee80211_conf_flags - configuration flags
*
@ -3841,6 +3829,12 @@ struct ieee80211_prep_tx_info {
* the station. See @sta_pre_rcu_remove if needed.
* This callback can sleep.
*
* @link_add_debugfs: Drivers can use this callback to add debugfs files
* when a link is added to a mac80211 vif. This callback should be within
* a CONFIG_MAC80211_DEBUGFS conditional. This callback can sleep.
* For non-MLO the callback will be called once for the default bss_conf
* with the vif's directory rather than a separate subdirectory.
*
* @sta_add_debugfs: Drivers can use this callback to add debugfs files
* when a station is added to mac80211's station list. This callback
* should be within a CONFIG_MAC80211_DEBUGFS conditional. This
@ -4230,6 +4224,9 @@ struct ieee80211_prep_tx_info {
* Note that a sta can also be inserted or removed with valid links,
* i.e. passed to @sta_add/@sta_state with sta->valid_links not zero.
* In fact, cannot change from having valid_links and not having them.
* @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames. This is
* not restored at HW reset by mac80211 so drivers need to take care of
* that.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@ -4319,6 +4316,10 @@ struct ieee80211_ops {
int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
#ifdef CONFIG_MAC80211_DEBUGFS
void (*link_add_debugfs)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct dentry *dir);
void (*sta_add_debugfs)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@ -4589,6 +4590,9 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
u16 old_links, u16 new_links);
int (*set_hw_timestamp)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_set_hw_timestamp *hwts);
};
/**
@ -5984,6 +5988,20 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
struct delayed_work *dwork,
unsigned long delay);
/**
* ieee80211_refresh_tx_agg_session_timer - Refresh a tx agg session timer.
* @sta: the station for which to start a BA session
* @tid: the TID to BA on.
*
* This function allows low level driver to refresh tx agg session timer
* to maintain BA session, the session level will still be managed by the
* mac80211.
*
* Note: must be called in an RCU critical section.
*/
void ieee80211_refresh_tx_agg_session_timer(struct ieee80211_sta *sta,
u16 tid);
/**
* ieee80211_start_tx_ba_session - Start a tx Block Ack session.
* @sta: the station for which to start a BA session

View File

@ -1299,6 +1299,16 @@
* @NL80211_CMD_MODIFY_LINK_STA: Modify a link of an MLD station
* @NL80211_CMD_REMOVE_LINK_STA: Remove a link of an MLD station
*
* @NL80211_CMD_SET_HW_TIMESTAMP: Enable/disable HW timestamping of Timing
* measurement and Fine timing measurement frames. If %NL80211_ATTR_MAC
* is included, enable/disable HW timestamping only for frames to/from the
* specified MAC address. Otherwise enable/disable HW timestamping for
* all TM/FTM frames (including ones that were enabled with specific MAC
* address). If %NL80211_ATTR_HW_TIMESTAMP_ENABLED is not included, disable
* HW timestamping.
* The number of peers that HW timestamping can be enabled for concurrently
* is indicated by %NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@ -1550,6 +1560,8 @@ enum nl80211_commands {
NL80211_CMD_MODIFY_LINK_STA,
NL80211_CMD_REMOVE_LINK_STA,
NL80211_CMD_SET_HW_TIMESTAMP,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -2775,6 +2787,13 @@ enum nl80211_commands {
* indicates that the sub-channel is punctured. Higher 16 bits are
* reserved.
*
* @NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS: Maximum number of peers that HW
* timestamping can be enabled for concurrently (u16), a wiphy attribute.
* A value of 0xffff indicates setting for all peers (i.e. not specifying
* an address with %NL80211_CMD_SET_HW_TIMESTAMP) is supported.
* @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should
* be enabled or not (flag attribute).
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -3306,6 +3325,9 @@ enum nl80211_attrs {
NL80211_ATTR_PUNCT_BITMAP,
NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
NL80211_ATTR_HW_TIMESTAMP_ENABLED,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -6326,6 +6348,10 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_SECURE_NAN: Device supports NAN Pairing which enables
* authentication, data encryption and message integrity.
*
* @NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA: Device supports randomized TA
* in authentication and deauthentication frames sent to unassociated peer
* using @NL80211_CMD_FRAME.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@ -6396,6 +6422,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_POWERED_ADDR_CHANGE,
NL80211_EXT_FEATURE_PUNCT,
NL80211_EXT_FEATURE_SECURE_NAN,
NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@ -6510,8 +6537,14 @@ enum nl80211_timeout_reason {
* @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with
* %NL80211_ATTR_SCAN_FREQ_KHZ. This also means
* %NL80211_ATTR_SCAN_FREQUENCIES will not be included.
* @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for colocated APs reported by
* 2.4/5 GHz APs
* @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for collocated APs reported by
* 2.4/5 GHz APs. When the flag is set, the scan logic will use the
* information from the RNR element found in beacons/probe responses
* received on the 2.4/5 GHz channels to actively scan only the 6GHz
* channels on which APs are expected to be found. Note that when not set,
* the scan logic would scan all 6GHz channels, but since transmission of
* probe requests on non PSC channels is limited, it is highly likely that
* these channels would passively be scanned.
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,

View File

@ -554,6 +554,23 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
ieee80211_send_addba_with_timeout(sta, tid_tx);
}
void ieee80211_refresh_tx_agg_session_timer(struct ieee80211_sta *pubsta,
u16 tid)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
struct tid_ampdu_tx *tid_tx;
if (WARN_ON_ONCE(tid >= IEEE80211_NUM_TIDS))
return;
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
if (!tid_tx)
return;
tid_tx->last_tx = jiffies;
}
EXPORT_SYMBOL(ieee80211_refresh_tx_agg_session_timer);
/*
* After accepting the AddBA Response we activated a timer,
* resetting it after each frame that we send.

View File

@ -1252,7 +1252,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
prev_beacon_int = link_conf->beacon_int;
link_conf->beacon_int = params->beacon_interval;
if (params->ht_cap)
link_conf->ht_ldpc =
params->ht_cap->cap_info &
cpu_to_le16(IEEE80211_HT_CAP_LDPC_CODING);
if (params->vht_cap) {
link_conf->vht_ldpc =
params->vht_cap->vht_cap_info &
cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC);
link_conf->vht_su_beamformer =
params->vht_cap->vht_cap_info &
cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
@ -1282,6 +1290,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
}
if (params->he_cap) {
link_conf->he_ldpc =
params->he_cap->phy_cap_info[1] &
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
link_conf->he_su_beamformer =
params->he_cap->phy_cap_info[3] &
IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
@ -1299,6 +1310,22 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (params->eht_cap) {
link_conf->eht_puncturing = params->punct_bitmap;
changed |= BSS_CHANGED_EHT_PUNCTURING;
link_conf->eht_su_beamformer =
params->eht_cap->fixed.phy_cap_info[0] &
IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER;
link_conf->eht_su_beamformee =
params->eht_cap->fixed.phy_cap_info[0] &
IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE;
link_conf->eht_mu_beamformer =
params->eht_cap->fixed.phy_cap_info[7] &
(IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ |
IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ |
IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ);
} else {
link_conf->eht_su_beamformer = false;
link_conf->eht_su_beamformee = false;
link_conf->eht_mu_beamformer = false;
}
if (sdata->vif.type == NL80211_IFTYPE_AP &&
@ -1788,7 +1815,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
(void *)params->he_6ghz_capa,
link_sta);
if (params->eht_capa)
if (params->he_capa && params->eht_capa)
ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
(u8 *)params->he_capa,
params->he_capa_len,
@ -4904,6 +4931,22 @@ ieee80211_del_link_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
static int ieee80211_set_hw_timestamp(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_set_hw_timestamp *hwts)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
if (!local->ops->set_hw_timestamp)
return -EOPNOTSUPP;
if (!check_sdata_in_driver(sdata))
return -EIO;
return local->ops->set_hw_timestamp(&local->hw, &sdata->vif, hwts);
}
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@ -5014,4 +5057,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.add_link_station = ieee80211_add_link_station,
.mod_link_station = ieee80211_mod_link_station,
.del_link_station = ieee80211_del_link_station,
.set_hw_timestamp = ieee80211_set_hw_timestamp,
};

View File

@ -23,16 +23,16 @@
#include "driver-ops.h"
static ssize_t ieee80211_if_read(
struct ieee80211_sub_if_data *sdata,
void *data,
char __user *userbuf,
size_t count, loff_t *ppos,
ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
ssize_t (*format)(const void *, char *, int))
{
char buf[200];
ssize_t ret = -EINVAL;
read_lock(&dev_base_lock);
ret = (*format)(sdata, buf, sizeof(buf));
ret = (*format)(data, buf, sizeof(buf));
read_unlock(&dev_base_lock);
if (ret >= 0)
@ -42,10 +42,10 @@ static ssize_t ieee80211_if_read(
}
static ssize_t ieee80211_if_write(
struct ieee80211_sub_if_data *sdata,
void *data,
const char __user *userbuf,
size_t count, loff_t *ppos,
ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
ssize_t (*write)(void *, const char *, int))
{
char buf[64];
ssize_t ret;
@ -58,64 +58,64 @@ static ssize_t ieee80211_if_write(
buf[count] = '\0';
rtnl_lock();
ret = (*write)(sdata, buf, count);
ret = (*write)(data, buf, count);
rtnl_unlock();
return ret;
}
#define IEEE80211_IF_FMT(name, field, format_string) \
#define IEEE80211_IF_FMT(name, type, field, format_string) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, char *buf, \
const type *data, char *buf, \
int buflen) \
{ \
return scnprintf(buf, buflen, format_string, sdata->field); \
return scnprintf(buf, buflen, format_string, data->field); \
}
#define IEEE80211_IF_FMT_DEC(name, field) \
IEEE80211_IF_FMT(name, field, "%d\n")
#define IEEE80211_IF_FMT_HEX(name, field) \
IEEE80211_IF_FMT(name, field, "%#x\n")
#define IEEE80211_IF_FMT_LHEX(name, field) \
IEEE80211_IF_FMT(name, field, "%#lx\n")
#define IEEE80211_IF_FMT_DEC(name, type, field) \
IEEE80211_IF_FMT(name, type, field, "%d\n")
#define IEEE80211_IF_FMT_HEX(name, type, field) \
IEEE80211_IF_FMT(name, type, field, "%#x\n")
#define IEEE80211_IF_FMT_LHEX(name, type, field) \
IEEE80211_IF_FMT(name, type, field, "%#lx\n")
#define IEEE80211_IF_FMT_HEXARRAY(name, field) \
#define IEEE80211_IF_FMT_HEXARRAY(name, type, field) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, \
const type *data, \
char *buf, int buflen) \
{ \
char *p = buf; \
int i; \
for (i = 0; i < sizeof(sdata->field); i++) { \
for (i = 0; i < sizeof(data->field); i++) { \
p += scnprintf(p, buflen + buf - p, "%.2x ", \
sdata->field[i]); \
data->field[i]); \
} \
p += scnprintf(p, buflen + buf - p, "\n"); \
return p - buf; \
}
#define IEEE80211_IF_FMT_ATOMIC(name, field) \
#define IEEE80211_IF_FMT_ATOMIC(name, type, field) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, \
const type *data, \
char *buf, int buflen) \
{ \
return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
return scnprintf(buf, buflen, "%d\n", atomic_read(&data->field));\
}
#define IEEE80211_IF_FMT_MAC(name, field) \
#define IEEE80211_IF_FMT_MAC(name, type, field) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, char *buf, \
const type *data, char *buf, \
int buflen) \
{ \
return scnprintf(buf, buflen, "%pM\n", sdata->field); \
return scnprintf(buf, buflen, "%pM\n", data->field); \
}
#define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, field) \
#define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, type, field) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, \
const type *data, \
char *buf, int buflen) \
{ \
return scnprintf(buf, buflen, "%d\n", \
jiffies_to_msecs(sdata->field)); \
jiffies_to_msecs(data->field)); \
}
#define _IEEE80211_IF_FILE_OPS(name, _read, _write) \
@ -126,43 +126,67 @@ static const struct file_operations name##_ops = { \
.llseek = generic_file_llseek, \
}
#define _IEEE80211_IF_FILE_R_FN(name) \
#define _IEEE80211_IF_FILE_R_FN(name, type) \
static ssize_t ieee80211_if_read_##name(struct file *file, \
char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
ssize_t (*fn)(const void *, char *, int) = (void *) \
((ssize_t (*)(const type, char *, int)) \
ieee80211_if_fmt_##name); \
return ieee80211_if_read(file->private_data, \
userbuf, count, ppos, \
ieee80211_if_fmt_##name); \
userbuf, count, ppos, fn); \
}
#define _IEEE80211_IF_FILE_W_FN(name) \
#define _IEEE80211_IF_FILE_W_FN(name, type) \
static ssize_t ieee80211_if_write_##name(struct file *file, \
const char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
ssize_t (*fn)(void *, const char *, int) = (void *) \
((ssize_t (*)(type, const char *, int)) \
ieee80211_if_parse_##name); \
return ieee80211_if_write(file->private_data, userbuf, count, \
ppos, ieee80211_if_parse_##name); \
ppos, fn); \
}
#define IEEE80211_IF_FILE_R(name) \
_IEEE80211_IF_FILE_R_FN(name) \
_IEEE80211_IF_FILE_R_FN(name, struct ieee80211_sub_if_data *) \
_IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, NULL)
#define IEEE80211_IF_FILE_W(name) \
_IEEE80211_IF_FILE_W_FN(name) \
_IEEE80211_IF_FILE_W_FN(name, struct ieee80211_sub_if_data *) \
_IEEE80211_IF_FILE_OPS(name, NULL, ieee80211_if_write_##name)
#define IEEE80211_IF_FILE_RW(name) \
_IEEE80211_IF_FILE_R_FN(name) \
_IEEE80211_IF_FILE_W_FN(name) \
_IEEE80211_IF_FILE_R_FN(name, struct ieee80211_sub_if_data *) \
_IEEE80211_IF_FILE_W_FN(name, struct ieee80211_sub_if_data *) \
_IEEE80211_IF_FILE_OPS(name, ieee80211_if_read_##name, \
ieee80211_if_write_##name)
#define IEEE80211_IF_FILE(name, field, format) \
IEEE80211_IF_FMT_##format(name, field) \
IEEE80211_IF_FMT_##format(name, struct ieee80211_sub_if_data, field) \
IEEE80211_IF_FILE_R(name)
/* Same but with a link_ prefix in the ops variable name and different type */
#define IEEE80211_IF_LINK_FILE_R(name) \
_IEEE80211_IF_FILE_R_FN(name, struct ieee80211_link_data *) \
_IEEE80211_IF_FILE_OPS(link_##name, ieee80211_if_read_##name, NULL)
#define IEEE80211_IF_LINK_FILE_W(name) \
_IEEE80211_IF_FILE_W_FN(name) \
_IEEE80211_IF_FILE_OPS(link_##name, NULL, ieee80211_if_write_##name)
#define IEEE80211_IF_LINK_FILE_RW(name) \
_IEEE80211_IF_FILE_R_FN(name, struct ieee80211_link_data *) \
_IEEE80211_IF_FILE_W_FN(name, struct ieee80211_link_data *) \
_IEEE80211_IF_FILE_OPS(link_##name, ieee80211_if_read_##name, \
ieee80211_if_write_##name)
#define IEEE80211_IF_LINK_FILE(name, field, format) \
IEEE80211_IF_FMT_##format(name, struct ieee80211_link_data, field) \
IEEE80211_IF_LINK_FILE_R(name)
/* common attributes */
IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[NL80211_BAND_2GHZ],
HEX);
@ -207,9 +231,9 @@ IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_5ghz);
IEEE80211_IF_FILE(flags, flags, HEX);
IEEE80211_IF_FILE(state, state, LHEX);
IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
IEEE80211_IF_FILE(ap_power_level, deflink.ap_power_level, DEC);
IEEE80211_IF_FILE(user_power_level, deflink.user_power_level, DEC);
IEEE80211_IF_LINK_FILE(txpower, conf->txpower, DEC);
IEEE80211_IF_LINK_FILE(ap_power_level, ap_power_level, DEC);
IEEE80211_IF_LINK_FILE(user_power_level, user_power_level, DEC);
static ssize_t
ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
@ -236,9 +260,10 @@ IEEE80211_IF_FILE(bssid, deflink.u.mgd.bssid, MAC);
IEEE80211_IF_FILE(aid, vif.cfg.aid, DEC);
IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
static int ieee80211_set_smps(struct ieee80211_link_data *link,
enum ieee80211_smps_mode smps_mode)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
int err;
@ -256,7 +281,7 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
return -EOPNOTSUPP;
sdata_lock(sdata);
err = __ieee80211_request_smps_mgd(sdata, &sdata->deflink, smps_mode);
err = __ieee80211_request_smps_mgd(link->sdata, link, smps_mode);
sdata_unlock(sdata);
return err;
@ -269,24 +294,24 @@ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
[IEEE80211_SMPS_DYNAMIC] = "dynamic",
};
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_link_data *link,
char *buf, int buflen)
{
if (sdata->vif.type == NL80211_IFTYPE_STATION)
if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
return snprintf(buf, buflen, "request: %s\nused: %s\n",
smps_modes[sdata->deflink.u.mgd.req_smps],
smps_modes[sdata->deflink.smps_mode]);
smps_modes[link->u.mgd.req_smps],
smps_modes[link->smps_mode]);
return -EINVAL;
}
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
static ssize_t ieee80211_if_parse_smps(struct ieee80211_link_data *link,
const char *buf, int buflen)
{
enum ieee80211_smps_mode mode;
for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
if (strncmp(buf, smps_modes[mode], buflen) == 0) {
int err = ieee80211_set_smps(sdata, mode);
int err = ieee80211_set_smps(link, mode);
if (!err)
return buflen;
return err;
@ -295,7 +320,7 @@ static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
return -EINVAL;
}
IEEE80211_IF_FILE_RW(smps);
IEEE80211_IF_LINK_FILE_RW(smps);
static ssize_t ieee80211_if_parse_tkip_mic_test(
struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
@ -595,6 +620,8 @@ static ssize_t ieee80211_if_parse_active_links(struct ieee80211_sub_if_data *sda
}
IEEE80211_IF_FILE_RW(active_links);
IEEE80211_IF_LINK_FILE(addr, conf->addr, MAC);
#ifdef CONFIG_MAC80211_MESH
IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
@ -685,7 +712,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(bssid);
DEBUGFS_ADD(aid);
DEBUGFS_ADD(beacon_timeout);
DEBUGFS_ADD_MODE(smps, 0600);
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
DEBUGFS_ADD_MODE(beacon_loss, 0200);
DEBUGFS_ADD_MODE(uapsd_queues, 0600);
@ -698,7 +724,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(num_mcast_sta);
DEBUGFS_ADD_MODE(smps, 0600);
DEBUGFS_ADD(num_sta_ps);
DEBUGFS_ADD(dtim_count);
DEBUGFS_ADD(num_buffered_multicast);
@ -789,9 +814,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(flags);
DEBUGFS_ADD(state);
DEBUGFS_ADD(txpower);
DEBUGFS_ADD(user_power_level);
DEBUGFS_ADD(ap_power_level);
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
add_common_files(sdata);
@ -821,6 +843,31 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
}
}
#undef DEBUGFS_ADD_MODE
#undef DEBUGFS_ADD
#define DEBUGFS_ADD_MODE(dentry, name, mode) \
debugfs_create_file(#name, mode, dentry, \
link, &link_##name##_ops)
#define DEBUGFS_ADD(dentry, name) DEBUGFS_ADD_MODE(dentry, name, 0400)
static void add_link_files(struct ieee80211_link_data *link,
struct dentry *dentry)
{
DEBUGFS_ADD(dentry, txpower);
DEBUGFS_ADD(dentry, user_power_level);
DEBUGFS_ADD(dentry, ap_power_level);
switch (link->sdata->vif.type) {
case NL80211_IFTYPE_STATION:
DEBUGFS_ADD_MODE(dentry, smps, 0600);
break;
default:
break;
}
}
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
{
char buf[10+IFNAMSIZ];
@ -831,6 +878,9 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
sdata->vif.debugfs_dir);
add_files(sdata);
if (!(sdata->local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO))
add_link_files(&sdata->deflink, sdata->vif.debugfs_dir);
}
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
@ -856,3 +906,66 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "netdev:%s", sdata->name);
debugfs_rename(dir->d_parent, dir, dir->d_parent, buf);
}
void ieee80211_link_debugfs_add(struct ieee80211_link_data *link)
{
char link_dir_name[10];
if (WARN_ON(!link->sdata->vif.debugfs_dir))
return;
/* For now, this should not be called for non-MLO capable drivers */
if (WARN_ON(!(link->sdata->local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)))
return;
snprintf(link_dir_name, sizeof(link_dir_name),
"link-%d", link->link_id);
link->debugfs_dir =
debugfs_create_dir(link_dir_name,
link->sdata->vif.debugfs_dir);
DEBUGFS_ADD(link->debugfs_dir, addr);
add_link_files(link, link->debugfs_dir);
}
void ieee80211_link_debugfs_remove(struct ieee80211_link_data *link)
{
if (!link->sdata->vif.debugfs_dir || !link->debugfs_dir) {
link->debugfs_dir = NULL;
return;
}
if (link->debugfs_dir == link->sdata->vif.debugfs_dir) {
WARN_ON(link != &link->sdata->deflink);
link->debugfs_dir = NULL;
return;
}
debugfs_remove_recursive(link->debugfs_dir);
link->debugfs_dir = NULL;
}
void ieee80211_link_debugfs_drv_add(struct ieee80211_link_data *link)
{
if (WARN_ON(!link->debugfs_dir))
return;
drv_link_add_debugfs(link->sdata->local, link->sdata,
link->conf, link->debugfs_dir);
}
void ieee80211_link_debugfs_drv_remove(struct ieee80211_link_data *link)
{
if (!link || !link->debugfs_dir)
return;
if (WARN_ON(link->debugfs_dir == link->sdata->vif.debugfs_dir))
return;
/* Recreate the directory excluding the driver data */
debugfs_remove_recursive(link->debugfs_dir);
link->debugfs_dir = NULL;
ieee80211_link_debugfs_add(link);
}

View File

@ -10,6 +10,12 @@
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata);
void ieee80211_link_debugfs_add(struct ieee80211_link_data *link);
void ieee80211_link_debugfs_remove(struct ieee80211_link_data *link);
void ieee80211_link_debugfs_drv_add(struct ieee80211_link_data *link);
void ieee80211_link_debugfs_drv_remove(struct ieee80211_link_data *link);
#else
static inline void ieee80211_debugfs_add_netdev(
struct ieee80211_sub_if_data *sdata)
@ -20,6 +26,16 @@ static inline void ieee80211_debugfs_remove_netdev(
static inline void ieee80211_debugfs_rename_netdev(
struct ieee80211_sub_if_data *sdata)
{}
static inline void ieee80211_link_debugfs_add(struct ieee80211_link_data *link)
{}
static inline void ieee80211_link_debugfs_remove(struct ieee80211_link_data *link)
{}
static inline void ieee80211_link_debugfs_drv_add(struct ieee80211_link_data *link)
{}
static inline void ieee80211_link_debugfs_drv_remove(struct ieee80211_link_data *link)
{}
#endif
#endif /* __IEEE80211_DEBUGFS_NETDEV_H */

View File

@ -8,6 +8,7 @@
#include "trace.h"
#include "driver-ops.h"
#include "debugfs_sta.h"
#include "debugfs_netdev.h"
int drv_start(struct ieee80211_local *local)
{
@ -477,6 +478,10 @@ int drv_change_vif_links(struct ieee80211_local *local,
u16 old_links, u16 new_links,
struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
{
struct ieee80211_link_data *link;
unsigned long links_to_add;
unsigned long links_to_rem;
unsigned int link_id;
int ret = -EOPNOTSUPP;
might_sleep();
@ -487,13 +492,31 @@ int drv_change_vif_links(struct ieee80211_local *local,
if (old_links == new_links)
return 0;
links_to_add = ~old_links & new_links;
links_to_rem = old_links & ~new_links;
for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) {
link = rcu_access_pointer(sdata->link[link_id]);
ieee80211_link_debugfs_drv_remove(link);
}
trace_drv_change_vif_links(local, sdata, old_links, new_links);
if (local->ops->change_vif_links)
ret = local->ops->change_vif_links(&local->hw, &sdata->vif,
old_links, new_links, old);
trace_drv_return_int(local, ret);
return ret;
if (ret)
return ret;
for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
link = rcu_access_pointer(sdata->link[link_id]);
ieee80211_link_debugfs_drv_add(link);
}
return 0;
}
int drv_change_sta_links(struct ieee80211_local *local,

View File

@ -465,6 +465,22 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
}
#ifdef CONFIG_MAC80211_DEBUGFS
static inline void drv_link_add_debugfs(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *link_conf,
struct dentry *dir)
{
might_sleep();
sdata = get_bss_sdata(sdata);
if (!check_sdata_in_driver(sdata))
return;
if (local->ops->link_add_debugfs)
local->ops->link_add_debugfs(&local->hw, &sdata->vif,
link_conf, dir);
}
static inline void drv_sta_add_debugfs(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta,

View File

@ -999,6 +999,10 @@ struct ieee80211_link_data {
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
struct ieee80211_bss_conf *conf;
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *debugfs_dir;
#endif
};
struct ieee80211_sub_if_data {

View File

@ -10,6 +10,7 @@
#include "ieee80211_i.h"
#include "driver-ops.h"
#include "key.h"
#include "debugfs_netdev.h"
void ieee80211_link_setup(struct ieee80211_link_data *link)
{
@ -34,6 +35,7 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
link->link_id = link_id;
link->conf = link_conf;
link_conf->link_id = link_id;
link_conf->vif = &sdata->vif;
INIT_WORK(&link->csa_finalize_work,
ieee80211_csa_finalize_work);
@ -60,6 +62,8 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
default:
WARN_ON(1);
}
ieee80211_link_debugfs_add(link);
}
}
@ -93,6 +97,7 @@ static void ieee80211_tear_down_links(struct ieee80211_sub_if_data *sdata,
if (WARN_ON(!link))
continue;
ieee80211_remove_link_keys(link, &keys);
ieee80211_link_debugfs_remove(link);
ieee80211_link_stop(link);
}

View File

@ -2744,7 +2744,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_link_data *link,
return changed;
}
static u32 ieee80211_link_set_associated(struct ieee80211_link_data *link,
static u64 ieee80211_link_set_associated(struct ieee80211_link_data *link,
struct cfg80211_bss *cbss)
{
struct ieee80211_sub_if_data *sdata = link->sdata;
@ -3227,7 +3227,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
bool already = false;
if (WARN_ON(sdata->vif.valid_links))
if (WARN_ON_ONCE(sdata->vif.valid_links))
return;
if (!ieee80211_sdata_running(sdata))
@ -5893,7 +5893,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
goto free;
}
if (sta && elems->opmode_notif)
if (elems->opmode_notif)
ieee80211_vht_handle_opmode(sdata, link_sta,
*elems->opmode_notif,
rx_status->band);

View File

@ -43,6 +43,7 @@ static struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb,
unsigned int present_fcs_len,
unsigned int rtap_space)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr;
unsigned int hdrlen;
__le16 fc;
@ -51,6 +52,14 @@ static struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb,
__pskb_trim(skb, skb->len - present_fcs_len);
pskb_pull(skb, rtap_space);
/* After pulling radiotap header, clear all flags that indicate
* info in skb->data.
*/
status->flag &= ~(RX_FLAG_RADIOTAP_TLV_AT_END |
RX_FLAG_RADIOTAP_LSIG |
RX_FLAG_RADIOTAP_HE_MU |
RX_FLAG_RADIOTAP_HE);
hdr = (void *)skb->data;
fc = hdr->frame_control;
@ -117,9 +126,6 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
/* allocate extra bitmaps */
if (status->chains)
len += 4 * hweight8(status->chains);
/* vendor presence bitmap */
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)
len += 4;
if (ieee80211_have_rx_timestamp(status)) {
len = ALIGN(len, 8);
@ -181,34 +187,28 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
len += 2 * hweight8(status->chains);
}
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
struct ieee80211_vendor_radiotap *rtap;
int vendor_data_offset = 0;
if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END) {
int tlv_offset = 0;
/*
* The position to look at depends on the existence (or non-
* existence) of other elements, so take that into account...
*/
if (status->flag & RX_FLAG_RADIOTAP_HE)
vendor_data_offset +=
tlv_offset +=
sizeof(struct ieee80211_radiotap_he);
if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
vendor_data_offset +=
tlv_offset +=
sizeof(struct ieee80211_radiotap_he_mu);
if (status->flag & RX_FLAG_RADIOTAP_LSIG)
vendor_data_offset +=
tlv_offset +=
sizeof(struct ieee80211_radiotap_lsig);
rtap = (void *)&skb->data[vendor_data_offset];
/* ensure 4 byte alignment for TLV */
len = ALIGN(len, 4);
/* alignment for fixed 6-byte vendor data header */
len = ALIGN(len, 2);
/* vendor data header */
len += 6;
if (WARN_ON(rtap->align == 0))
rtap->align = 1;
len = ALIGN(len, rtap->align);
len += rtap->len + rtap->pad;
/* TLVs until the mac header */
len += skb_mac_header(skb) - &skb->data[tlv_offset];
}
return len;
@ -304,9 +304,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
u32 it_present_val;
u16 rx_flags = 0;
u16 channel_flags = 0;
u32 tlvs_len = 0;
int mpdulen, chain;
unsigned long chains = status->chains;
struct ieee80211_vendor_radiotap rtap = {};
struct ieee80211_radiotap_he he = {};
struct ieee80211_radiotap_he_mu he_mu = {};
struct ieee80211_radiotap_lsig lsig = {};
@ -327,18 +327,17 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
skb_pull(skb, sizeof(lsig));
}
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
rtap = *(struct ieee80211_vendor_radiotap *)skb->data;
/* rtap.len and rtap.pad are undone immediately */
skb_pull(skb, sizeof(rtap) + rtap.len + rtap.pad);
if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END) {
/* data is pointer at tlv all other info was pulled off */
tlvs_len = skb_mac_header(skb) - skb->data;
}
mpdulen = skb->len;
if (!(has_fcs && ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)))
mpdulen += FCS_LEN;
rthdr = skb_push(skb, rtap_len);
memset(rthdr, 0, rtap_len - rtap.len - rtap.pad);
rthdr = skb_push(skb, rtap_len - tlvs_len);
memset(rthdr, 0, rtap_len - tlvs_len);
it_present = &rthdr->it_present;
/* radiotap header, set always present flags */
@ -360,13 +359,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
}
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |
BIT(IEEE80211_RADIOTAP_EXT);
put_unaligned_le32(it_present_val, it_present);
it_present++;
it_present_val = rtap.present;
}
if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END)
it_present_val |= BIT(IEEE80211_RADIOTAP_TLV);
put_unaligned_le32(it_present_val, it_present);
@ -697,22 +691,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
*pos++ = status->chain_signal[chain];
*pos++ = chain;
}
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
/* ensure 2 byte alignment for the vendor field as required */
if ((pos - (u8 *)rthdr) & 1)
*pos++ = 0;
*pos++ = rtap.oui[0];
*pos++ = rtap.oui[1];
*pos++ = rtap.oui[2];
*pos++ = rtap.subns;
put_unaligned_le16(rtap.len, pos);
pos += 2;
/* align the actual payload as requested */
while ((pos - (u8 *)rthdr) & (rtap.align - 1))
*pos++ = 0;
/* data (and possible padding) already follows */
}
}
static struct sk_buff *
@ -788,6 +766,13 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
bool only_monitor = false;
unsigned int min_head_len;
if (WARN_ON_ONCE(status->flag & RX_FLAG_RADIOTAP_TLV_AT_END &&
!skb_mac_header_was_set(origskb))) {
/* with this skb no way to know where frame payload starts */
dev_kfree_skb(origskb);
return NULL;
}
if (status->flag & RX_FLAG_RADIOTAP_HE)
rtap_space += sizeof(struct ieee80211_radiotap_he);
@ -797,12 +782,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (status->flag & RX_FLAG_RADIOTAP_LSIG)
rtap_space += sizeof(struct ieee80211_radiotap_lsig);
if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) {
struct ieee80211_vendor_radiotap *rtap =
(void *)(origskb->data + rtap_space);
rtap_space += sizeof(*rtap) + rtap->len + rtap->pad;
}
if (status->flag & RX_FLAG_RADIOTAP_TLV_AT_END)
rtap_space += skb_mac_header(origskb) - &origskb->data[rtap_space];
min_head_len = rtap_space;
@ -2582,7 +2563,7 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
bool noencrypt = !(status->flag & RX_FLAG_DECRYPTED);
cfg80211_rx_control_port(dev, skb, noencrypt);
cfg80211_rx_control_port(dev, skb, noencrypt, rx->link_id);
dev_kfree_skb(skb);
} else {
struct ethhdr *ehdr = (void *)skb_mac_header(skb);
@ -3916,8 +3897,6 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
if (!local->cooked_mntrs)
goto out_free_skb;
/* vendor data is long removed here */
status->flag &= ~RX_FLAG_RADIOTAP_VENDOR_DATA;
/* room for the radiotap header based on driver features */
needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb);

View File

@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2013-2015 Intel Mobile Communications GmbH
* Copyright 2016-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2021 Intel Corporation
* Copyright (C) 2018-2022 Intel Corporation
*/
#include <linux/if_arp.h>
@ -1246,11 +1246,11 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
return ret;
}
/*
* Only call this function when a scan can't be queued -- under RTNL.
*/
void ieee80211_scan_cancel(struct ieee80211_local *local)
{
/* ensure a new scan cannot be queued */
lockdep_assert_wiphy(local->hw.wiphy);
/*
* We are canceling software scan, or deferred scan that was not
* yet really started (see __ieee80211_start_scan ).

View File

@ -5115,6 +5115,16 @@ static int ieee80211_beacon_protect(struct sk_buff *skb,
tx.key = rcu_dereference(link->default_beacon_key);
if (!tx.key)
return 0;
if (unlikely(tx.key->flags & KEY_FLAG_TAINTED)) {
tx.key = NULL;
return -EINVAL;
}
if (!(tx.key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT_TX) &&
tx.key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
IEEE80211_SKB_CB(skb)->control.hw_key = &tx.key->conf;
tx.local = local;
tx.sdata = sdata;
__skb_queue_head_init(&tx.skbs);

View File

@ -673,6 +673,39 @@ static bool cfg80211_allowed_address(struct wireless_dev *wdev, const u8 *addr)
return ether_addr_equal(addr, wdev_address(wdev));
}
static bool cfg80211_allowed_random_address(struct wireless_dev *wdev,
const struct ieee80211_mgmt *mgmt)
{
if (ieee80211_is_auth(mgmt->frame_control) ||
ieee80211_is_deauth(mgmt->frame_control)) {
/* Allow random TA to be used with authentication and
* deauthentication frames if the driver has indicated support.
*/
if (wiphy_ext_feature_isset(
wdev->wiphy,
NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA))
return true;
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
/* Allow random TA to be used with Public Action frames if the
* driver has indicated support.
*/
if (!wdev->connected &&
wiphy_ext_feature_isset(
wdev->wiphy,
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
return true;
if (wdev->connected &&
wiphy_ext_feature_isset(
wdev->wiphy,
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
return true;
}
return false;
}
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
@ -774,25 +807,9 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return err;
}
if (!cfg80211_allowed_address(wdev, mgmt->sa)) {
/* Allow random TA to be used with Public Action frames if the
* driver has indicated support for this. Otherwise, only allow
* the local address to be used.
*/
if (!ieee80211_is_action(mgmt->frame_control) ||
mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
return -EINVAL;
if (!wdev->connected &&
!wiphy_ext_feature_isset(
&rdev->wiphy,
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
return -EINVAL;
if (wdev->connected &&
!wiphy_ext_feature_isset(
&rdev->wiphy,
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
return -EINVAL;
}
if (!cfg80211_allowed_address(wdev, mgmt->sa) &&
!cfg80211_allowed_random_address(wdev, mgmt))
return -EINVAL;
/* Transmit the management frame as requested by user space */
return rdev_mgmt_tx(rdev, wdev, params, cookie);

View File

@ -806,6 +806,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG },
[NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT },
[NL80211_ATTR_PUNCT_BITMAP] = NLA_POLICY_RANGE(NLA_U8, 0, 0xffff),
[NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS] = { .type = NLA_U16 },
[NL80211_ATTR_HW_TIMESTAMP_ENABLED] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@ -2964,6 +2967,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO)
nla_put_flag(msg, NL80211_ATTR_MLO_SUPPORT);
if (rdev->wiphy.hw_timestamp_max_peers &&
nla_put_u16(msg, NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
rdev->wiphy.hw_timestamp_max_peers))
goto nla_put_failure;
/* done */
state->split_start = 0;
break;
@ -9019,7 +9027,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
struct nlattr *attr;
struct wiphy *wiphy;
int err, tmp, n_ssids = 0, n_channels, i;
size_t ie_len;
size_t ie_len, size;
wiphy = &rdev->wiphy;
@ -9064,10 +9072,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (ie_len > wiphy->max_scan_ie_len)
return -EINVAL;
request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids
+ sizeof(*request->channels) * n_channels
+ ie_len, GFP_KERNEL);
size = struct_size(request, channels, n_channels);
size = size_add(size, array_size(sizeof(*request->ssids), n_ssids));
size = size_add(size, ie_len);
request = kzalloc(size, GFP_KERNEL);
if (!request)
return -ENOMEM;
@ -9400,7 +9408,7 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
struct nlattr *attr;
int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
enum nl80211_band band;
size_t ie_len;
size_t ie_len, size;
struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
@ -9509,12 +9517,14 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
return ERR_PTR(-EINVAL);
request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids
+ sizeof(*request->match_sets) * n_match_sets
+ sizeof(*request->scan_plans) * n_plans
+ sizeof(*request->channels) * n_channels
+ ie_len, GFP_KERNEL);
size = struct_size(request, channels, n_channels);
size = size_add(size, array_size(sizeof(*request->ssids), n_ssids));
size = size_add(size, array_size(sizeof(*request->match_sets),
n_match_sets));
size = size_add(size, array_size(sizeof(*request->scan_plans),
n_plans));
size = size_add(size, ie_len);
request = kzalloc(size, GFP_KERNEL);
if (!request)
return ERR_PTR(-ENOMEM);
@ -16162,6 +16172,29 @@ nl80211_remove_link_station(struct sk_buff *skb, struct genl_info *info)
return ret;
}
static int nl80211_set_hw_timestamp(struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct cfg80211_set_hw_timestamp hwts = {};
if (!rdev->wiphy.hw_timestamp_max_peers)
return -EOPNOTSUPP;
if (!info->attrs[NL80211_ATTR_MAC] &&
rdev->wiphy.hw_timestamp_max_peers != CFG80211_HW_TIMESTAMP_ALL_PEERS)
return -EOPNOTSUPP;
if (info->attrs[NL80211_ATTR_MAC])
hwts.macaddr = nla_data(info->attrs[NL80211_ATTR_MAC]);
hwts.enable =
nla_get_flag(info->attrs[NL80211_ATTR_HW_TIMESTAMP_ENABLED]);
return rdev_set_hw_timestamp(rdev, dev, &hwts);
}
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@ -17336,6 +17369,12 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_MLO_VALID_LINK_ID),
},
{
.cmd = NL80211_CMD_SET_HW_TIMESTAMP,
.doit = nl80211_set_hw_timestamp,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
},
};
static struct genl_family nl80211_fam __ro_after_init = {
@ -18717,7 +18756,9 @@ EXPORT_SYMBOL(cfg80211_mgmt_tx_status_ext);
static int __nl80211_rx_control_port(struct net_device *dev,
struct sk_buff *skb,
bool unencrypted, gfp_t gfp)
bool unencrypted,
int link_id,
gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@ -18749,6 +18790,8 @@ static int __nl80211_rx_control_port(struct net_device *dev,
NL80211_ATTR_PAD) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
(link_id >= 0 &&
nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) ||
(unencrypted && nla_put_flag(msg,
NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
goto nla_put_failure;
@ -18767,13 +18810,14 @@ static int __nl80211_rx_control_port(struct net_device *dev,
return -ENOBUFS;
}
bool cfg80211_rx_control_port(struct net_device *dev,
struct sk_buff *skb, bool unencrypted)
bool cfg80211_rx_control_port(struct net_device *dev, struct sk_buff *skb,
bool unencrypted, int link_id)
{
int ret;
trace_cfg80211_rx_control_port(dev, skb, unencrypted);
ret = __nl80211_rx_control_port(dev, skb, unencrypted, GFP_ATOMIC);
trace_cfg80211_rx_control_port(dev, skb, unencrypted, link_id);
ret = __nl80211_rx_control_port(dev, skb, unencrypted, link_id,
GFP_ATOMIC);
trace_cfg80211_return_bool(ret == 0);
return ret == 0;
}

View File

@ -1494,4 +1494,21 @@ rdev_del_link_station(struct cfg80211_registered_device *rdev,
return ret;
}
static inline int
rdev_set_hw_timestamp(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_set_hw_timestamp *hwts)
{
struct wiphy *wiphy = &rdev->wiphy;
int ret;
if (!rdev->ops->set_hw_timestamp)
return -EOPNOTSUPP;
trace_rdev_set_hw_timestamp(wiphy, dev, hwts);
ret = rdev->ops->set_hw_timestamp(wiphy, dev, hwts);
trace_rdev_return_int(wiphy, ret);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */

View File

@ -1810,8 +1810,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
}
int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
enum nl80211_band band,
enum cfg80211_bss_frame_type ftype)
enum nl80211_band band)
{
const struct element *tmp;
@ -1830,9 +1829,7 @@ int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
if (!he_6ghz_oper)
return -1;
if (ftype != CFG80211_BSS_FTYPE_BEACON ||
he_6ghz_oper->control & IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON)
return he_6ghz_oper->primary;
return he_6ghz_oper->primary;
}
} else if (band == NL80211_BAND_S1GHZ) {
tmp = cfg80211_find_elem(WLAN_EID_S1G_OPERATION, ie, ielen);
@ -1870,15 +1867,14 @@ EXPORT_SYMBOL(cfg80211_get_ies_channel_number);
static struct ieee80211_channel *
cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
struct ieee80211_channel *channel,
enum nl80211_bss_scan_width scan_width,
enum cfg80211_bss_frame_type ftype)
enum nl80211_bss_scan_width scan_width)
{
u32 freq;
int channel_number;
struct ieee80211_channel *alt_channel;
channel_number = cfg80211_get_ies_channel_number(ie, ielen,
channel->band, ftype);
channel->band);
if (channel_number < 0) {
/* No channel information in frame payload */
@ -1888,22 +1884,21 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
/*
* In 6GHz, duplicated beacon indication is relevant for
* beacons only.
* Frame info (beacon/prob res) is the same as received channel,
* no need for further processing.
*/
if (channel->band == NL80211_BAND_6GHZ &&
(freq == channel->center_freq ||
abs(freq - channel->center_freq) > 80))
if (freq == ieee80211_channel_to_khz(channel))
return channel;
alt_channel = ieee80211_get_channel_khz(wiphy, freq);
if (!alt_channel) {
if (channel->band == NL80211_BAND_2GHZ) {
if (channel->band == NL80211_BAND_2GHZ ||
channel->band == NL80211_BAND_6GHZ) {
/*
* Better not allow unexpected channels when that could
* be going beyond the 1-11 range (e.g., discovering
* BSS on channel 12 when radio is configured for
* channel 11.
* channel 11) or beyond the 6 GHz channel range.
*/
return NULL;
}
@ -1957,7 +1952,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
return NULL;
channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan,
data->scan_width, ftype);
data->scan_width);
if (!channel)
return NULL;
@ -2391,7 +2386,6 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
int bss_type;
enum cfg80211_bss_frame_type ftype;
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
offsetof(struct ieee80211_mgmt, u.beacon.variable));
@ -2428,16 +2422,8 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
variable = ext->u.s1g_beacon.variable;
}
if (ieee80211_is_beacon(mgmt->frame_control))
ftype = CFG80211_BSS_FTYPE_BEACON;
else if (ieee80211_is_probe_resp(mgmt->frame_control))
ftype = CFG80211_BSS_FTYPE_PRESP;
else
ftype = CFG80211_BSS_FTYPE_UNKNOWN;
channel = cfg80211_get_bss_channel(wiphy, variable,
ielen, data->chan, data->scan_width,
ftype);
ielen, data->chan, data->scan_width);
if (!channel)
return NULL;

View File

@ -3165,14 +3165,15 @@ TRACE_EVENT(cfg80211_control_port_tx_status,
TRACE_EVENT(cfg80211_rx_control_port,
TP_PROTO(struct net_device *netdev, struct sk_buff *skb,
bool unencrypted),
TP_ARGS(netdev, skb, unencrypted),
bool unencrypted, int link_id),
TP_ARGS(netdev, skb, unencrypted, link_id),
TP_STRUCT__entry(
NETDEV_ENTRY
__field(int, len)
MAC_ENTRY(from)
__field(u16, proto)
__field(bool, unencrypted)
__field(int, link_id)
),
TP_fast_assign(
NETDEV_ASSIGN;
@ -3180,10 +3181,12 @@ TRACE_EVENT(cfg80211_rx_control_port,
MAC_ASSIGN(from, eth_hdr(skb)->h_source);
__entry->proto = be16_to_cpu(skb->protocol);
__entry->unencrypted = unencrypted;
__entry->link_id = link_id;
),
TP_printk(NETDEV_PR_FMT ", len=%d, %pM, proto: 0x%x, unencrypted: %s",
TP_printk(NETDEV_PR_FMT ", len=%d, %pM, proto: 0x%x, unencrypted: %s, link: %d",
NETDEV_PR_ARG, __entry->len, __entry->from,
__entry->proto, BOOL_TO_STR(__entry->unencrypted))
__entry->proto, BOOL_TO_STR(__entry->unencrypted),
__entry->link_id)
);
TRACE_EVENT(cfg80211_cqm_rssi_notify,
@ -3918,6 +3921,31 @@ TRACE_EVENT(rdev_del_link_station,
__entry->link_id)
);
TRACE_EVENT(rdev_set_hw_timestamp,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_set_hw_timestamp *hwts),
TP_ARGS(wiphy, netdev, hwts),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(macaddr)
__field(bool, enable)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(macaddr, hwts->macaddr);
__entry->enable = hwts->enable;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", mac %pM, enable: %u",
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->macaddr,
__entry->enable)
);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH