Merge tag 'wireless-next-2023-03-10' of git://git.kernel.org/pub/scm/linux/kernel...
authorJakub Kicinski <kuba@kernel.org>
Sat, 11 Mar 2023 02:22:28 +0000 (18:22 -0800)
committerJakub Kicinski <kuba@kernel.org>
Sat, 11 Mar 2023 02:22:29 +0000 (18:22 -0800)
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>
77 files changed:
drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c [new file with mode: 0644]
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
drivers/net/wireless/intel/iwlwifi/cfg/22000.c
drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
drivers/net/wireless/intel/iwlwifi/fw/rs.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/iwl-csr.h
drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/rx.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c
drivers/net/wireless/realtek/rtw88/mac.c
drivers/net/wireless/realtek/rtw88/rtw8821c.c
drivers/net/wireless/realtek/rtw88/rtw8821c.h
drivers/net/wireless/realtek/rtw88/rtw8822b.c
drivers/net/wireless/realtek/rtw88/rtw8822b.h
drivers/net/wireless/realtek/rtw88/rtw8822c.c
drivers/net/wireless/realtek/rtw88/rtw8822c.h
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h
drivers/net/wireless/realtek/rtw89/mac.c
drivers/net/wireless/realtek/rtw89/mac80211.c
drivers/net/wireless/realtek/rtw89/phy.c
drivers/net/wireless/realtek/rtw89/phy.h
drivers/net/wireless/realtek/rtw89/rtw8852b.c
drivers/net/wireless/realtek/rtw89/rtw8852c.c
drivers/net/wireless/realtek/rtw89/ser.c
drivers/net/wireless/silabs/wfx/main.c
include/net/cfg80211.h
include/net/ieee80211_radiotap.h
include/net/mac80211.h
include/uapi/linux/nl80211.h
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_netdev.h
net/mac80211/driver-ops.c
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h
net/mac80211/link.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/tx.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/scan.c
net/wireless/trace.h

index 0e996cf24f882915c2652ddec28cc332c2ceda35..dc6d27a36faa970e1ddc495eef8e41a674a46da5 100644 (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/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c
new file mode 100644 (file)
index 0000000..c4a5486
--- /dev/null
@@ -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");
+       }
+}
index 501136e011b552ab3b9192f0c1307281a7d024aa..fe31051a9e11b1df64f0d560301a9bc5adc7ce2b 100644 (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;
index a9690ec4c850c352e7079f571cbec21ac36989d2..e0a70a671550c83311c076e61490fcb4f5ae1180 100644 (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 @@ done:
        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;
+
+       memset(&pmk, 0, sizeof(pmk));
 
-       /* 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]);
+       /* 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 @@ exit:
        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;
index 8073f31be27d952edc82dd7c9915b54e157018f2..9f9bf08a70bb46ca3f9d59d3b89413559b28a220 100644 (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)
index f235beaddddba20132f26963a5a287e7bc6cd6d2..a194b0e68eb53a9e650ed4058d84c1f6cd4bc76b 100644 (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;
 }
index aa25abffcc7dbc4556b084770af9e07769187678..2be2986d2110a2c6caa47063c0ab13d5e561e1ae 100644 (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);
index 10bac865d724352bc7ebc03567d1be41237664ec..6d10c9efbe93d8f7af2fcd5602ce16fb27c0debb 100644 (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 */
index f1b086a69d735ca857092d2797e8ccd81b98cf1a..7f4f0b3e4a7b4a39e06f7e183d3504d1879c072f 100644 (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) \
        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:
index 04e1beedfd81f4bf058d10a28111da02cf555256..792adaf880b4448451b7a50bba0732bfdedcc961 100644 (file)
 
 /* 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 */
 
 
 #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
  *
index fdd0c9abc1a10dbf109ff68a9f92cec4e37401f2..52527b61341edd1dffddb4029d4944f048e3955b 100644 (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) {
index a9b9b2dc62d4fcec40f27346eda67d386fe8b07c..59f3e9c5e13907bec4902210ddc7024829b2024d 100644 (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 */ }
 };
index 896615f5795227286876e87b72f989091fc9f947..44684bf1b9acc69b5aaeae17ea33e6b2c733df0d 100644 (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 */
index 3bdd6774716dde9856a6fc60c5ca3566fe0df8d4..05720352e49f12ace3fed3871b7b98bd9f926c35 100644 (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-"
        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));
index ddacd5b45aeab6829999fa8af582511237931d93..c9a48fc5fac88bdfe14e8bc98364ed2ccd472953 100644 (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
index 1c4e84932058568d62b3408bb43eb0abf7468652..fdd8b01f09e4ca00d0003a67bddd3a849a56e7f8 100644 (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 {
+               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;
+                       };
+               };
                /**
-                * @l3l4_flags: &enum iwl_rx_l3l4_flags
-                */
-               __le16 l3l4_flags;
-
-               /**
-                * @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 {
index e128d2e07f38c0a9a8cf025b205c0e8b5f0cc8a3..b09e68dbf5a9369fc1eaadc8fb8cf0b3d1304833 100644 (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;
index cfa5e1b3c3f689abda73370a821a98665d2d68f0..eaa0ff2736c50d2b9d9701aace238633f804310e 100644 (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__ */
index 3e1f011e93aaf20b75dad19e3445b82a839d76f5..bece76b1a5145db906cd60d5a779280873072d96 100644 (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)
index 48e7376a5fea73d8a2e5981106b454165981167d..87366b70b17f1413081d5f8dd9ec1106c9ee3c6b 100644 (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));
index 0c6b49fcb00d4ed4eb2fed38ef4aa09d7d1fa584..45981e22b2dbd9e6236eec52dfd947aedba1fdbe 100644 (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 */
        {}
index aa791dbc3066f3b89445ba48664443d0005a38b2..114c96ba39eeb9f86690b33e056bc520801c06d9 100644 (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);
index 565522466eba5465f15be91a72b370f40afae71e..ab02c6076276c62f71ddf2820b346aa110e1fba4 100644 (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;
                }
        }
 
index 90bc95d96a78e8894a5b5bc6f0eba4d8ac9037da..6bd1a4c72a129ea3b2db4ad1b296753ef79ec0cd 100644 (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;
index f30eeab5505b76ce8b4e5616bcb6bd2796755f97..e3fb1b2cea6ddcc1441c1c7b8a91feff7e8b5283 100644 (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),
index 0b50b816684a0201e72ab6029215088e2c4adf8c..1f81dff71bc47d3a8c8706982e7da804eca56d23 100644 (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 */
        }
index 49ca1e168fc5bc10d50c2360921e88f0f5ace07b..d2ce414879aa4d5346af8c533d712758a8ec2612 100644 (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;
index 549dbe0be223ace5a40960333b44cd1d01bad33f..91556d43735a7cf7546d12e4e4d2e419e9988d9b 100644 (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
index 9813d7fa1800705950bdc656f5db6958a7cef545..a6d69885cd3fbcb1267e8b9f11b6978a53e2bbb9 100644 (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,
index 99768d6a6032204acebb7c7a83cc0a6dc305bd85..8aa8a678475cbed0f0f7efa2f6b6ca91ebc21287 100644 (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,
index 94f40c4d24217105c8cf58717cd6acbd8d82d22f..1e263154e9ebefc60383d74cc0ba5e1a2f79dc9d 100644 (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;
        }
index 4cc4eaf80b1466b15c8f778cc67b086a9f42c347..f4bdc243ea0d191e64c17a0941b671a34ede14e1 100644 (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;
-
-       /*
-        * 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);
-
-       IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA;
+       rtap = skb_push(skb, sizeof(*rtap) + sizeof(vendor_data));
+
+       rtap->len = cpu_to_le16(sizeof(*rtap) -
+                               sizeof(struct ieee80211_radiotap_tlv) +
+                               sizeof(vendor_data));
+       rtap->type = cpu_to_le16(IEEE80211_RADIOTAP_VENDOR_NAMESPACE);
+
+       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 */
index a99ddb41cd244c84d42f2df7ad9fc78acc208485..f15b099899e5c1bfa0e40c6c540dcc3ff61e8821 100644 (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) {
index 620a5cc2bfdd1c45c2c1d8a54d9c3b172a29462d..54ca6f2ced3f38ef064aa59e801e993ee118290b 100644 (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",
index b9c62640d2cbd9db027e781c792e5325af07088a..dc480323c9cbff5729d950964737aa60a4d8b653 100644 (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;
index 2aecb2583f75ed3ffd609477a0213e89dd8cb380..df1e36fbc348ac123d663d6460baf94c5f829b37 100644 (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;
index bd0b7e365edb0d3d3cc335b9b0569a95dc3d499f..a8b5bf45b1bba33b19ae5681f770a41deed9d43d 100644 (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);
 }
index dae64901bac5add1cc98699ee9425531462afb7a..f3a566cf979b5ffcf6fd0a7844d4b25a59723b1e 100644 (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;
        }
index 17f800f6efbd09ca71b1698d59a74f91f22b3b10..7ae0541d7b995e4ebb2c7c39a0f97e164164f078 100644 (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;
index 1c81260f3a542722ce94433ed7828d164bae164c..fcff31688c453a1da2930cd3b70f8554eeca5d84 100644 (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;
        };
 };
 
index 74dfb89b2c948b6d63f7fa7732112a0ba1d9735c..531b67787e2eb443abcae36e210304a62ce0406b 100644 (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;
index 01d3644e0c9469dba3149e973433073430cbdd5a..2dc3a6660f06a5f3e3bfd45121f9d84b6100301b 100644 (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;
        };
 };
 
index 964e27887fe2d80e41faac34b60e5f78829edd03..5a2c004b12df1f85004f868e8e6c4663c1e71f6f 100644 (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;
index 479d5d769c5207f18f3c3044ae0fef9d2ec1241b..1bc0e7f5d6bb1f0367fe34ca3b3fb465ac6ccf86 100644 (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;
        };
 };
 
index f09361bc4a4d1148b244b194fc30ca1ed48ff4a4..489fa7a86160d6d386e8edba8c90098cc9880634 100644 (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;
index 41365ffb7e5ea79b829aae10f386e2074e10a770..b1a886898c5a088cd5459c7e753543997b864972 100644 (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,
 };
index 0b73dc2e9ad777f0cfb1ded09d9b84f3283bdfba..1a4ff24078fb934279eb2839669f2920efc34dac 100644 (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,25 +2895,31 @@ 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 (ch_info->ch_band == RTW89_BAND_6G) {
+               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) {
-               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)
+                       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;
                }
-               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) {
-                       ch_info->tx_pkt = false;
-                       if (!req->duration_mandatory)
-                               ch_info->period -= RTW89_DWELL_TIME_6G;
-               }
+               ch_info->num_pkt = probe_count;
        }
 
        switch (chan_type) {
@@ -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))
index cae07e325326df742e171e3fcfe22478fe59e47f..3f6e0871381df148edae37f0f022e5a21133814b 100644 (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)
index 2e2a2b6eab09d4a3c6c9b2ca1c1d1d77683cddd2..3d1e4ffef1b16c1d9456a93837f8833a33e6be8a 100644 (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;
index d43281f7335b139c636f2fd6fabf2a0245384839..367a7bf319daeb8446e7f5f88ad50489345e1cf9 100644 (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);
index d9f61ba3d1765cf1d5c2c1ceb7c948f702db6979..d8b035972dd48d671491cc769d4d2c1344dd3a68 100644 (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);
index 21233f094644b0bf121e06a63009006bea5a893e..de0a9abf646e3f9a98eb3ebf66f0cda754c9ef63 100644 (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
index ee8dba7e0074a262712966746391b317cfedff72..499ae0389c715f87b64176a361eb6bc70defb164 100644 (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;
 }
 
index d2dde21d3daf58b2ba2c1d1efb6ea1d12807ce23..8af813132f71d59beb9b398d0e21f1b9f0eb58bf 100644 (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;
 }
index 61db7189fdab8df6aa955faa65128af9f89c395b..9e9f6947e7f14874c0dae1192cc41d05b3ab117c 100644 (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:
index 6b9864e478ac850cc96ef4f86407bc0892d9f94f..0b50f7058bbbc5daa93e1a1a33cae1ab5045fc0c 100644 (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;
        }
 
index f115b25503096a355a5bf26725f2cc9a5daefcd8..7cebba1c41356b80e96c16e131e302fbe1e919cb 100644 (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
index 598f53d2a3a0bb3586f60fd4328cbe2907fbf777..f980a72f2ce6e79c8ef0209248ba7f677650d8d9 100644 (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
  */
index 219fd15893b06c925e3bd3907e77b12d46edefa3..f12edca660ba0d73c84e84200657d5e9c9740759 100644 (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
index f14621a954e10936d491a4f685c18a03fb91d44b..9a0ac0363f1fc9665cd29f8f6c42fd035b165185 100644 (file)
  * @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,
index f9514bacbd4a184d677226ce65fd7a0635fcb5d1..3b651e7f5a73b8a4980f5e2fad45869c28072f10 100644 (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.
index 8eb3423008687a3f09c3512d8adbb00b19579695..760ad934f9e12e7713df0d040ba459a14da7df3b 100644 (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,
 };
index 0bac9af3ca966e69ed9fea793cc16aa9529937eb..b0cef37eb3948eac1289ec34bdaf8fe64e37719a 100644 (file)
 #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);
+}
index a7e9d8d518f9724bf48dfd5e594a7afe3840ec28..99e688dcabd69ad628a5ee941cffddd2f7959f0c 100644 (file)
 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 */
index cfb09e4aed4d3e8abd47bb78e05fbbedf4f42df2..30cd0c905a24f61c5996b877eee42aa2bc1ecc36 100644 (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,
index 5d13a3dfd3664bb3820b4a9baa42b23f087d95de..a68d606e6987222e37e7d0ab33ff5885910989fb 100644 (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,
index ecc232eb1ee82f9f3a143a65b5b258a2dbd32773..3d4edc25a69e04cdbc76d38af0c37cfa4a3bede3 100644 (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 {
index 8c8869cc1fb4ce15a39ee6d9a5794846ec8c58be..e82db88a47f8f4e05c14a1849a946cc1ea79e94e 100644 (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);
        }
 
index 60792dfabc9d6224bd413088b76c025eb06395a2..e13a0354c3970ff4231a75326aeceaa930b83715 100644 (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);
index f7fdfe710951faa1c9402cfd8d71ced290864f3e..0255c5745e1ceaeddb9ce5cd3d50980c8d4f5647 100644 (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);
 
index dc3cdee51e6604d8713b0c1915743dbe2212bfbc..32fa8aca7005650c37b20db64afe4d66875731ac 100644 (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 ).
index 7699fb41067015b582eb114acee471e9dda05171..628d60f3db2ab7c33757fe930c2b68de7ecd8a17 100644 (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);
index 81d3f40d623570a945ed7451e264a7f3fc97e432..ac059cefbeb39e107d6e34c694dc05e0082fb687 100644 (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);
index 112b4bb009c80f648748256b322d9a5e7a7e8514..0a31b1d2845d5d4f4e0a5f517a06d7fb10fde647 100644 (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;
 }
index 13b209a8db2879aaf2ee0d8400246e3a1ea3d1db..2e497cf26ef286a2d9bd2f7aa9a04e6620ec3184 100644 (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 */
index 790bc31cf82ea0ae401219b7abb4d8fb3b385d81..a1382255fab35d9976d2c36a6d915a66e6995cef 100644 (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;
 
index ca7474eec723432ebfdd636f5fd1bcb7e1ccb29d..716a1fa7006977eac3e3369a1a8e9fa4028c5c02 100644 (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