2023-02-14 09:19:31

by Hector Martin

[permalink] [raw]
Subject: [PATCH 00/10] BCM4387 / Apple M1 platform support

Hi all,

This series adds the missing bits to support the BCM4387 found in newer
Apple Silicon platforms and its Apple firmware.

* Patches 1-2 add support for hardware oddities of these chips.
* Patches 3-6 add support for firmware oddities of these chips.
* Patch 7 adds the IDs themselves
* Patches 8-10 add support for Apple oddities (also applicable to other
chips already upstreamed, but which are still missing this
functionality).

These patches were already reviewed last year as part of v2 of the
`brcmfmac: Support Apple T2 and M1 platforms` series. This version
just incorporates a few bits of review feedback from that last round,
plus rebasing. In particular, I checked that the patches do not
introduce any cfg80211.c endiannness warnings with make C=2.

Hector Martin (10):
brcmfmac: chip: Only disable D11 cores; handle an arbitrary number
brcmfmac: chip: Handle 1024-unit sizes for TCM blocks
brcmfmac: cfg80211: Add support for scan params v2
brcmfmac: feature: Add support for setting feats based on WLC version
brcmfmac: cfg80211: Add support for PMKID_V3 operations
brcmfmac: cfg80211: Pass the PMK in binary instead of hex
brcmfmac: pcie: Add IDs/properties for BCM4387
brcmfmac: common: Add support for downloading TxCap blobs
brcmfmac: pcie: Load and provide TxCap blobs
brcmfmac: common: Add support for external calibration blobs

.../broadcom/brcm80211/brcmfmac/bus.h | 1 +
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 310 ++++++++++++------
.../broadcom/brcm80211/brcmfmac/chip.c | 25 +-
.../broadcom/brcm80211/brcmfmac/common.c | 117 +++++--
.../broadcom/brcm80211/brcmfmac/common.h | 2 +
.../broadcom/brcm80211/brcmfmac/feature.c | 49 +++
.../broadcom/brcm80211/brcmfmac/feature.h | 6 +-
.../broadcom/brcm80211/brcmfmac/fwil_types.h | 157 ++++++++-
.../wireless/broadcom/brcm80211/brcmfmac/of.c | 7 +
.../broadcom/brcm80211/brcmfmac/pcie.c | 21 ++
.../broadcom/brcm80211/include/brcm_hw_ids.h | 2 +
11 files changed, 567 insertions(+), 130 deletions(-)

--
2.35.1



2023-02-14 09:25:41

by Hector Martin

[permalink] [raw]
Subject: [PATCH 01/10] brcmfmac: chip: Only disable D11 cores; handle an arbitrary number

At least on BCM4387, the D11 cores are held in reset on cold startup and
firmware expects to release reset itself. Just assert reset here and let
firmware deassert it. Premature deassertion results in the firmware
failing to initialize properly some of the time, with strange AXI bus
errors.

Also, BCM4387 has 3 cores, up from 2. The logic for handling that is in
brcmf_chip_ai_resetcore(), but since we aren't using that any more, just
handle it here.

Reviewed-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index 8073f31be27d..a6239051404b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -1292,15 +1292,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)
--
2.35.1


2023-02-14 09:25:43

by Hector Martin

[permalink] [raw]
Subject: [PATCH 02/10] brcmfmac: chip: Handle 1024-unit sizes for TCM blocks

BCM4387 has trailing odd-sized blocks as part of TCM which have
their size described as a multiple of 1024 instead of 8192. Handle this
so we can compute the TCM size properly.

Reviewed-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index a6239051404b..50e0c015cf43 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -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;
--
2.35.1


2023-02-14 09:25:55

by Hector Martin

[permalink] [raw]
Subject: [PATCH 03/10] brcmfmac: cfg80211: Add support for scan params v2

This new API version is required for at least the BCM4387 firmware. Add
support for it, with a fallback to the v1 API.

Acked-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 245 +++++++++++-------
.../broadcom/brcm80211/brcmfmac/feature.c | 1 +
.../broadcom/brcm80211/brcmfmac/feature.h | 4 +-
.../broadcom/brcm80211/brcmfmac/fwil_types.h | 49 +++-
4 files changed, 209 insertions(+), 90 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index a9690ec4c850..3e006b783f3f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -1039,12 +1039,134 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
}
}

+static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le,
+ struct brcmf_scan_params_le *params_le)
+{
+ size_t params_size;
+ u32 ch;
+ int n_channels, n_ssids;
+
+ memcpy(&params_le->ssid_le, &params_v2_le->ssid_le,
+ sizeof(params_le->ssid_le));
+ memcpy(&params_le->bssid, &params_v2_le->bssid,
+ sizeof(params_le->bssid));
+
+ params_le->bss_type = params_v2_le->bss_type;
+ params_le->scan_type = le32_to_cpu(params_v2_le->scan_type);
+ params_le->nprobes = params_v2_le->nprobes;
+ params_le->active_time = params_v2_le->active_time;
+ params_le->passive_time = params_v2_le->passive_time;
+ params_le->home_time = params_v2_le->home_time;
+ params_le->channel_num = params_v2_le->channel_num;
+
+ ch = le32_to_cpu(params_v2_le->channel_num);
+ n_channels = ch & BRCMF_SCAN_PARAMS_COUNT_MASK;
+ n_ssids = ch >> BRCMF_SCAN_PARAMS_NSSID_SHIFT;
+
+ params_size = sizeof(u16) * n_channels;
+ if (n_ssids > 0) {
+ params_size = roundup(params_size, sizeof(u32));
+ params_size += sizeof(struct brcmf_ssid_le) * n_ssids;
+ }
+
+ memcpy(&params_le->channel_list[0],
+ &params_v2_le->channel_list[0], params_size);
+}
+
+static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_scan_params_v2_le *params_le,
+ struct cfg80211_scan_request *request)
+{
+ u32 n_ssids;
+ u32 n_channels;
+ s32 i;
+ s32 offset;
+ u16 chanspec;
+ char *ptr;
+ int length;
+ struct brcmf_ssid_le ssid_le;
+
+ eth_broadcast_addr(params_le->bssid);
+
+ length = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
+
+ params_le->version = cpu_to_le16(BRCMF_SCAN_PARAMS_VERSION_V2);
+ params_le->bss_type = DOT11_BSSTYPE_ANY;
+ params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_ACTIVE);
+ params_le->channel_num = 0;
+ params_le->nprobes = cpu_to_le32(-1);
+ params_le->active_time = cpu_to_le32(-1);
+ params_le->passive_time = cpu_to_le32(-1);
+ params_le->home_time = cpu_to_le32(-1);
+ memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
+
+ /* Scan abort */
+ if (!request) {
+ length += sizeof(u16);
+ params_le->channel_num = cpu_to_le32(1);
+ params_le->channel_list[0] = cpu_to_le16(-1);
+ params_le->length = cpu_to_le16(length);
+ return;
+ }
+
+ n_ssids = request->n_ssids;
+ n_channels = request->n_channels;
+
+ /* Copy channel array if applicable */
+ brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
+ n_channels);
+ if (n_channels > 0) {
+ length += roundup(sizeof(u16) * n_channels, sizeof(u32));
+ for (i = 0; i < n_channels; i++) {
+ chanspec = channel_to_chanspec(&cfg->d11inf,
+ request->channels[i]);
+ brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
+ request->channels[i]->hw_value, chanspec);
+ params_le->channel_list[i] = cpu_to_le16(chanspec);
+ }
+ } else {
+ brcmf_dbg(SCAN, "Scanning all channels\n");
+ }
+
+ /* Copy ssid array if applicable */
+ brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
+ if (n_ssids > 0) {
+ offset = offsetof(struct brcmf_scan_params_v2_le, channel_list) +
+ n_channels * sizeof(u16);
+ offset = roundup(offset, sizeof(u32));
+ length += sizeof(ssid_le) * n_ssids,
+ ptr = (char *)params_le + offset;
+ for (i = 0; i < n_ssids; i++) {
+ memset(&ssid_le, 0, sizeof(ssid_le));
+ ssid_le.SSID_len =
+ cpu_to_le32(request->ssids[i].ssid_len);
+ memcpy(ssid_le.SSID, request->ssids[i].ssid,
+ request->ssids[i].ssid_len);
+ if (!ssid_le.SSID_len)
+ brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
+ else
+ brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
+ i, ssid_le.SSID, ssid_le.SSID_len);
+ memcpy(ptr, &ssid_le, sizeof(ssid_le));
+ ptr += sizeof(ssid_le);
+ }
+ } else {
+ brcmf_dbg(SCAN, "Performing passive scan\n");
+ params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_PASSIVE);
+ }
+ params_le->length = cpu_to_le16(length);
+ /* Adding mask to channel numbers */
+ params_le->channel_num =
+ cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
+ (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
+}
+
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp, bool aborted,
bool fw_abort)
{
struct brcmf_pub *drvr = cfg->pub;
- struct brcmf_scan_params_le params_le;
+ struct brcmf_scan_params_v2_le params_v2_le;
struct cfg80211_scan_request *scan_request;
u64 reqid;
u32 bucket;
@@ -1063,20 +1185,23 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
if (fw_abort) {
/* Do a scan abort to stop the driver's scan engine */
brcmf_dbg(SCAN, "ABORT scan in firmware\n");
- memset(&params_le, 0, sizeof(params_le));
- eth_broadcast_addr(params_le.bssid);
- params_le.bss_type = DOT11_BSSTYPE_ANY;
- params_le.scan_type = 0;
- params_le.channel_num = cpu_to_le32(1);
- params_le.nprobes = cpu_to_le32(1);
- params_le.active_time = cpu_to_le32(-1);
- params_le.passive_time = cpu_to_le32(-1);
- params_le.home_time = cpu_to_le32(-1);
- /* Scan is aborted by setting channel_list[0] to -1 */
- params_le.channel_list[0] = cpu_to_le16(-1);
+
+ brcmf_escan_prep(cfg, &params_v2_le, NULL);
+
/* E-Scan (or anyother type) can be aborted by SCAN */
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
- &params_le, sizeof(params_le));
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
+ &params_v2_le,
+ sizeof(params_v2_le));
+ } else {
+ struct brcmf_scan_params_le params_le;
+
+ brcmf_scan_params_v2_to_v1(&params_v2_le, &params_le);
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
+ &params_le,
+ sizeof(params_le));
+ }
+
if (err)
bphy_err(drvr, "Scan abort failed\n");
}
@@ -1295,83 +1420,13 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
return err;
}

-static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
- struct brcmf_scan_params_le *params_le,
- struct cfg80211_scan_request *request)
-{
- u32 n_ssids;
- u32 n_channels;
- s32 i;
- s32 offset;
- u16 chanspec;
- char *ptr;
- struct brcmf_ssid_le ssid_le;
-
- eth_broadcast_addr(params_le->bssid);
- params_le->bss_type = DOT11_BSSTYPE_ANY;
- params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
- params_le->channel_num = 0;
- params_le->nprobes = cpu_to_le32(-1);
- params_le->active_time = cpu_to_le32(-1);
- params_le->passive_time = cpu_to_le32(-1);
- params_le->home_time = cpu_to_le32(-1);
- memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
-
- n_ssids = request->n_ssids;
- n_channels = request->n_channels;
-
- /* Copy channel array if applicable */
- brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
- n_channels);
- if (n_channels > 0) {
- for (i = 0; i < n_channels; i++) {
- chanspec = channel_to_chanspec(&cfg->d11inf,
- request->channels[i]);
- brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
- request->channels[i]->hw_value, chanspec);
- params_le->channel_list[i] = cpu_to_le16(chanspec);
- }
- } else {
- brcmf_dbg(SCAN, "Scanning all channels\n");
- }
- /* Copy ssid array if applicable */
- brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
- if (n_ssids > 0) {
- offset = offsetof(struct brcmf_scan_params_le, channel_list) +
- n_channels * sizeof(u16);
- offset = roundup(offset, sizeof(u32));
- ptr = (char *)params_le + offset;
- for (i = 0; i < n_ssids; i++) {
- memset(&ssid_le, 0, sizeof(ssid_le));
- ssid_le.SSID_len =
- cpu_to_le32(request->ssids[i].ssid_len);
- memcpy(ssid_le.SSID, request->ssids[i].ssid,
- request->ssids[i].ssid_len);
- if (!ssid_le.SSID_len)
- brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
- else
- brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
- i, ssid_le.SSID, ssid_le.SSID_len);
- memcpy(ptr, &ssid_le, sizeof(ssid_le));
- ptr += sizeof(ssid_le);
- }
- } else {
- brcmf_dbg(SCAN, "Performing passive scan\n");
- params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
- }
- /* Adding mask to channel numbers */
- params_le->channel_num =
- cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
- (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
-}
-
static s32
brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
struct cfg80211_scan_request *request)
{
struct brcmf_pub *drvr = cfg->pub;
- s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
- offsetof(struct brcmf_escan_params_le, params_le);
+ s32 params_size = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE +
+ offsetof(struct brcmf_escan_params_le, params_v2_le);
struct brcmf_escan_params_le *params;
s32 err = 0;

@@ -1391,8 +1446,22 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
goto exit;
}
BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
- brcmf_escan_prep(cfg, &params->params_le, request);
- params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
+ brcmf_escan_prep(cfg, &params->params_v2_le, request);
+
+ params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION_V2);
+
+ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
+ struct brcmf_escan_params_le *params_v1;
+
+ params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
+ params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE;
+ params_v1 = kzalloc(params_size, GFP_KERNEL);
+ params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
+ brcmf_scan_params_v2_to_v1(&params->params_v2_le, &params_v1->params_le);
+ kfree(params);
+ params = params_v1;
+ }
+
params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
params->sync_id = cpu_to_le16(0x1234);

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 10bac865d724..b6797f800e55 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -290,6 +290,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",
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index f1b086a69d73..549298c55b55 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -30,6 +30,7 @@
* SAE: simultaneous authentication of equals
* FWAUTH: Firmware authenticator
* DUMP_OBSS: Firmware has capable to dump obss info to support ACS
+ * SCAN_V2: Version 2 scan params
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
@@ -53,7 +54,8 @@
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)

/*
* Quirks:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 04e1beedfd81..b3844d0d1adb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -48,6 +48,10 @@

/* size of brcmf_scan_params not including variable length array */
#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
+#define BRCMF_SCAN_PARAMS_V2_FIXED_SIZE 72
+
+/* version of brcmf_scan_params structure */
+#define BRCMF_SCAN_PARAMS_VERSION_V2 2

/* masks for channel and ssid count */
#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
@@ -67,6 +71,7 @@
#define BRCMF_PRIMARY_KEY (1 << 1)
#define DOT11_BSSTYPE_ANY 2
#define BRCMF_ESCAN_REQ_VERSION 1
+#define BRCMF_ESCAN_REQ_VERSION_V2 2

#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */

@@ -386,6 +391,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 +441,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 {
--
2.35.1


2023-02-14 09:26:05

by Hector Martin

[permalink] [raw]
Subject: [PATCH 04/10] brcmfmac: feature: Add support for setting feats based on WLC version

The "wlc_ver" iovar returns information on the WLC and EPI versions.
This can be used to determine whether the PMKID_V2 and _V3 features are
supported.

Reviewed-by: Linus Walleij <[email protected]>
Acked-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../broadcom/brcm80211/brcmfmac/feature.c | 48 +++++++++++++++++++
.../broadcom/brcm80211/brcmfmac/feature.h | 4 +-
.../broadcom/brcm80211/brcmfmac/fwil_types.h | 25 ++++++++++
3 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index b6797f800e55..6d10c9efbe93 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -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.
*
@@ -299,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 */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index 549298c55b55..7f4f0b3e4a7b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -55,7 +55,9 @@
BRCMF_FEAT_DEF(SAE) \
BRCMF_FEAT_DEF(FWAUTH) \
BRCMF_FEAT_DEF(DUMP_OBSS) \
- BRCMF_FEAT_DEF(SCAN_V2)
+ BRCMF_FEAT_DEF(SCAN_V2) \
+ BRCMF_FEAT_DEF(PMKID_V2) \
+ BRCMF_FEAT_DEF(PMKID_V3)

/*
* Quirks:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index b3844d0d1adb..801709c26b7b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -788,6 +788,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.
*
--
2.35.1


2023-02-14 09:26:22

by Hector Martin

[permalink] [raw]
Subject: [PATCH 05/10] brcmfmac: cfg80211: Add support for PMKID_V3 operations

Add support for the new PMKID_V3 API, which allows performing PMKID
mutations individually, instead of requiring the driver to keep track of
the full list. This new API is required by at least BCM4387.

Note that PMKID_V2 is not implemented yet.

Reviewed-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 52 +++++++++++-
.../broadcom/brcm80211/brcmfmac/fwil_types.h | 83 +++++++++++++++++++
2 files changed, 132 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 3e006b783f3f..f3450b4db156 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -4306,6 +4306,37 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
return 0;
}

+static s32
+brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa,
+ bool alive)
+{
+ struct brcmf_pmk_op_v3_le *pmk_op;
+ int length = offsetof(struct brcmf_pmk_op_v3_le, pmk);
+ int ret;
+
+ pmk_op = kzalloc(sizeof(*pmk_op), GFP_KERNEL);
+ pmk_op->version = cpu_to_le16(BRCMF_PMKSA_VER_3);
+
+ if (!pmksa) {
+ /* Flush operation, operate on entire list */
+ pmk_op->count = cpu_to_le16(0);
+ } else {
+ /* Single PMK operation */
+ pmk_op->count = cpu_to_le16(1);
+ length += sizeof(struct brcmf_pmksa_v3);
+ memcpy(pmk_op->pmk[0].bssid, pmksa->bssid, ETH_ALEN);
+ memcpy(pmk_op->pmk[0].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
+ pmk_op->pmk[0].pmkid_len = WLAN_PMKID_LEN;
+ pmk_op->pmk[0].time_left = cpu_to_le32(alive ? BRCMF_PMKSA_NO_EXPIRY : 0);
+ }
+
+ pmk_op->length = cpu_to_le16(length);
+
+ ret = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_op, sizeof(*pmk_op));
+ kfree(pmk_op);
+ return ret;
+}
+
static __used s32
brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
{
@@ -4339,6 +4370,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))
@@ -4355,9 +4394,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");
@@ -4381,6 +4417,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))
@@ -4417,6 +4458,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);

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 801709c26b7b..792adaf880b4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -174,6 +174,10 @@

#define BRCMF_HE_CAP_MCS_MAP_NSS_MAX 8

+#define BRCMF_PMKSA_VER_2 2
+#define BRCMF_PMKSA_VER_3 3
+#define BRCMF_PMKSA_NO_EXPIRY 0xffffffff
+
/* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each
* ioctl. It is relatively small because firmware has small maximum size input
* playload restriction for ioctls.
@@ -355,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 */
@@ -875,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.
*
@@ -886,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
*
--
2.35.1


2023-02-14 09:26:49

by Hector Martin

[permalink] [raw]
Subject: [PATCH 06/10] brcmfmac: cfg80211: Pass the PMK in binary instead of hex

Apparently the hex passphrase mechanism does not work on newer
chips/firmware (e.g. BCM4387). It seems there was a simple way of
passing it in binary all along, so use that and avoid the hexification.

OpenBSD has been doing it like this from the beginning, so this should
work on all chips.

Also clear the structure before setting the PMK. This was leaking
uninitialized stack contents to the device.

Reviewed-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index f3450b4db156..18e6699d4024 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -1686,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,
--
2.35.1


2023-02-14 09:27:01

by Hector Martin

[permalink] [raw]
Subject: [PATCH 07/10] brcmfmac: pcie: Add IDs/properties for BCM4387

This chip is present on Apple M1 Pro/Max (t600x) platforms:

* maldives (apple,j314s): MacBook Pro (14-inch, M1 Pro, 2021)
* maldives (apple,j314c): MacBook Pro (14-inch, M1 Max, 2021)
* madagascar (apple,j316s): MacBook Pro (16-inch, M1 Pro, 2021)
* madagascar (apple,j316c): MacBook Pro (16-inch, M1 Max, 2021)

Reviewed-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 2 ++
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 8 ++++++++
.../net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 2 ++
3 files changed, 12 insertions(+)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index 50e0c015cf43..9f9bf08a70bb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -743,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;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index a9b9b2dc62d4..09076a3cc4de 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -66,6 +66,7 @@ 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(4387C2, "brcmfmac4387c2-pcie");

/* firmware config files */
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt");
@@ -100,6 +101,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
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_4387_CHIP_ID, 0xFFFFFFFF, 4387C2), /* revision ID 7 */
};

#define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */
@@ -2016,6 +2018,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;
@@ -2630,6 +2637,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 */ }
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
index 896615f57952..44684bf1b9ac 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
@@ -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 */
--
2.35.1


2023-02-14 09:27:17

by Hector Martin

[permalink] [raw]
Subject: [PATCH 08/10] brcmfmac: common: Add support for downloading TxCap blobs

The TxCap blobs are additional data blobs used on Apple devices, and
are uploaded analogously to CLM blobs. Add core support for doing this.

Acked-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../broadcom/brcm80211/brcmfmac/bus.h | 1 +
.../broadcom/brcm80211/brcmfmac/common.c | 93 ++++++++++++++-----
2 files changed, 70 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 501136e011b5..fe31051a9e11 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -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;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index f235beaddddb..be68dd0cbbd2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -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;
}

@@ -291,6 +329,13 @@ 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;
+ }
+
/* 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));
--
2.35.1


2023-02-14 09:27:33

by Hector Martin

[permalink] [raw]
Subject: [PATCH 09/10] brcmfmac: pcie: Load and provide TxCap blobs

These blobs are named .txcap_blob, and exist alongside the existing
.clm_blob files. Use the existing firmware machinery to provide them to
the core.

Reviewed-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 09076a3cc4de..7ee532ab8e85 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -75,6 +75,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),
@@ -328,7 +329,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;
@@ -1519,6 +1522,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;
}
@@ -2080,6 +2087,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)
@@ -2106,6 +2114,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);
@@ -2187,6 +2196,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,
@@ -2201,6 +2211,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;
@@ -2498,6 +2510,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);
--
2.35.1


2023-02-14 09:27:42

by Hector Martin

[permalink] [raw]
Subject: [PATCH 10/10] brcmfmac: common: Add support for external calibration blobs

The calibration blob for a chip is normally stored in SROM and loaded
internally by the firmware. However, Apple ARM64 platforms instead store
it as part of platform configuration data, and provide it via the Apple
Device Tree. We forward this into the Linux DT in the bootloader.

Add support for taking this blob from the DT and loading it into the
dongle. The loading mechanism is the same as used for the CLM and TxCap
blobs.

Reviewed-by: Linus Walleij <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Hector Martin <[email protected]>
---
.../broadcom/brcm80211/brcmfmac/common.c | 24 +++++++++++++++++++
.../broadcom/brcm80211/brcmfmac/common.h | 2 ++
.../wireless/broadcom/brcm80211/brcmfmac/of.c | 7 ++++++
3 files changed, 33 insertions(+)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index be68dd0cbbd2..2d0d7c9296f2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -246,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;
@@ -336,6 +353,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
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));
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index aa25abffcc7d..378a051b34b7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -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;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index fdd0c9abc1a1..52527b61341e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -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) {
--
2.35.1


2023-02-14 09:56:57

by Arend van Spriel

[permalink] [raw]
Subject: Re: [PATCH 03/10] brcmfmac: cfg80211: Add support for scan params v2

On 2/14/2023 10:24 AM, Hector Martin wrote:
> This new API version is required for at least the BCM4387 firmware. Add
> support for it, with a fallback to the v1 API.

This one is on my TODO list because both WCC and BCA chips have a
scanv2, but they are different. Anyway, I will have to sort that out
afterwards ;-)

Thanks,
Arend

> Acked-by: Linus Walleij <[email protected]>
> Reviewed-by: Arend van Spriel <[email protected]>
> Signed-off-by: Hector Martin <[email protected]>
> ---
> .../broadcom/brcm80211/brcmfmac/cfg80211.c | 245 +++++++++++-------
> .../broadcom/brcm80211/brcmfmac/feature.c | 1 +
> .../broadcom/brcm80211/brcmfmac/feature.h | 4 +-
> .../broadcom/brcm80211/brcmfmac/fwil_types.h | 49 +++-
> 4 files changed, 209 insertions(+), 90 deletions(-)
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> index a9690ec4c850..3e006b783f3f 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> @@ -1039,12 +1039,134 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
> }
> }
>
> +static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le,
> + struct brcmf_scan_params_le *params_le)
> +{
> + size_t params_size;
> + u32 ch;
> + int n_channels, n_ssids;
> +
> + memcpy(&params_le->ssid_le, &params_v2_le->ssid_le,
> + sizeof(params_le->ssid_le));
> + memcpy(&params_le->bssid, &params_v2_le->bssid,
> + sizeof(params_le->bssid));
> +
> + params_le->bss_type = params_v2_le->bss_type;
> + params_le->scan_type = le32_to_cpu(params_v2_le->scan_type);
> + params_le->nprobes = params_v2_le->nprobes;
> + params_le->active_time = params_v2_le->active_time;
> + params_le->passive_time = params_v2_le->passive_time;
> + params_le->home_time = params_v2_le->home_time;
> + params_le->channel_num = params_v2_le->channel_num;
> +
> + ch = le32_to_cpu(params_v2_le->channel_num);
> + n_channels = ch & BRCMF_SCAN_PARAMS_COUNT_MASK;
> + n_ssids = ch >> BRCMF_SCAN_PARAMS_NSSID_SHIFT;
> +
> + params_size = sizeof(u16) * n_channels;
> + if (n_ssids > 0) {
> + params_size = roundup(params_size, sizeof(u32));
> + params_size += sizeof(struct brcmf_ssid_le) * n_ssids;
> + }
> +
> + memcpy(&params_le->channel_list[0],
> + &params_v2_le->channel_list[0], params_size);
> +}
> +
> +static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
> + struct brcmf_scan_params_v2_le *params_le,
> + struct cfg80211_scan_request *request)
> +{
> + u32 n_ssids;
> + u32 n_channels;
> + s32 i;
> + s32 offset;
> + u16 chanspec;
> + char *ptr;
> + int length;
> + struct brcmf_ssid_le ssid_le;
> +
> + eth_broadcast_addr(params_le->bssid);
> +
> + length = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
> +
> + params_le->version = cpu_to_le16(BRCMF_SCAN_PARAMS_VERSION_V2);
> + params_le->bss_type = DOT11_BSSTYPE_ANY;
> + params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_ACTIVE);
> + params_le->channel_num = 0;
> + params_le->nprobes = cpu_to_le32(-1);
> + params_le->active_time = cpu_to_le32(-1);
> + params_le->passive_time = cpu_to_le32(-1);
> + params_le->home_time = cpu_to_le32(-1);
> + memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
> +
> + /* Scan abort */
> + if (!request) {
> + length += sizeof(u16);
> + params_le->channel_num = cpu_to_le32(1);
> + params_le->channel_list[0] = cpu_to_le16(-1);
> + params_le->length = cpu_to_le16(length);
> + return;
> + }
> +
> + n_ssids = request->n_ssids;
> + n_channels = request->n_channels;
> +
> + /* Copy channel array if applicable */
> + brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
> + n_channels);
> + if (n_channels > 0) {
> + length += roundup(sizeof(u16) * n_channels, sizeof(u32));
> + for (i = 0; i < n_channels; i++) {
> + chanspec = channel_to_chanspec(&cfg->d11inf,
> + request->channels[i]);
> + brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
> + request->channels[i]->hw_value, chanspec);
> + params_le->channel_list[i] = cpu_to_le16(chanspec);
> + }
> + } else {
> + brcmf_dbg(SCAN, "Scanning all channels\n");
> + }
> +
> + /* Copy ssid array if applicable */
> + brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
> + if (n_ssids > 0) {
> + offset = offsetof(struct brcmf_scan_params_v2_le, channel_list) +
> + n_channels * sizeof(u16);
> + offset = roundup(offset, sizeof(u32));
> + length += sizeof(ssid_le) * n_ssids,
> + ptr = (char *)params_le + offset;
> + for (i = 0; i < n_ssids; i++) {
> + memset(&ssid_le, 0, sizeof(ssid_le));
> + ssid_le.SSID_len =
> + cpu_to_le32(request->ssids[i].ssid_len);
> + memcpy(ssid_le.SSID, request->ssids[i].ssid,
> + request->ssids[i].ssid_len);
> + if (!ssid_le.SSID_len)
> + brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
> + else
> + brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
> + i, ssid_le.SSID, ssid_le.SSID_len);
> + memcpy(ptr, &ssid_le, sizeof(ssid_le));
> + ptr += sizeof(ssid_le);
> + }
> + } else {
> + brcmf_dbg(SCAN, "Performing passive scan\n");
> + params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_PASSIVE);
> + }
> + params_le->length = cpu_to_le16(length);
> + /* Adding mask to channel numbers */
> + params_le->channel_num =
> + cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
> + (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
> +}
> +
> s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
> struct brcmf_if *ifp, bool aborted,
> bool fw_abort)
> {
> struct brcmf_pub *drvr = cfg->pub;
> - struct brcmf_scan_params_le params_le;
> + struct brcmf_scan_params_v2_le params_v2_le;
> struct cfg80211_scan_request *scan_request;
> u64 reqid;
> u32 bucket;
> @@ -1063,20 +1185,23 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
> if (fw_abort) {
> /* Do a scan abort to stop the driver's scan engine */
> brcmf_dbg(SCAN, "ABORT scan in firmware\n");
> - memset(&params_le, 0, sizeof(params_le));
> - eth_broadcast_addr(params_le.bssid);
> - params_le.bss_type = DOT11_BSSTYPE_ANY;
> - params_le.scan_type = 0;
> - params_le.channel_num = cpu_to_le32(1);
> - params_le.nprobes = cpu_to_le32(1);
> - params_le.active_time = cpu_to_le32(-1);
> - params_le.passive_time = cpu_to_le32(-1);
> - params_le.home_time = cpu_to_le32(-1);
> - /* Scan is aborted by setting channel_list[0] to -1 */
> - params_le.channel_list[0] = cpu_to_le16(-1);
> +
> + brcmf_escan_prep(cfg, &params_v2_le, NULL);
> +
> /* E-Scan (or anyother type) can be aborted by SCAN */
> - err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
> - &params_le, sizeof(params_le));
> + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
> + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
> + &params_v2_le,
> + sizeof(params_v2_le));
> + } else {
> + struct brcmf_scan_params_le params_le;
> +
> + brcmf_scan_params_v2_to_v1(&params_v2_le, &params_le);
> + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
> + &params_le,
> + sizeof(params_le));
> + }
> +
> if (err)
> bphy_err(drvr, "Scan abort failed\n");
> }
> @@ -1295,83 +1420,13 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
> return err;
> }
>
> -static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
> - struct brcmf_scan_params_le *params_le,
> - struct cfg80211_scan_request *request)
> -{
> - u32 n_ssids;
> - u32 n_channels;
> - s32 i;
> - s32 offset;
> - u16 chanspec;
> - char *ptr;
> - struct brcmf_ssid_le ssid_le;
> -
> - eth_broadcast_addr(params_le->bssid);
> - params_le->bss_type = DOT11_BSSTYPE_ANY;
> - params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
> - params_le->channel_num = 0;
> - params_le->nprobes = cpu_to_le32(-1);
> - params_le->active_time = cpu_to_le32(-1);
> - params_le->passive_time = cpu_to_le32(-1);
> - params_le->home_time = cpu_to_le32(-1);
> - memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
> -
> - n_ssids = request->n_ssids;
> - n_channels = request->n_channels;
> -
> - /* Copy channel array if applicable */
> - brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
> - n_channels);
> - if (n_channels > 0) {
> - for (i = 0; i < n_channels; i++) {
> - chanspec = channel_to_chanspec(&cfg->d11inf,
> - request->channels[i]);
> - brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
> - request->channels[i]->hw_value, chanspec);
> - params_le->channel_list[i] = cpu_to_le16(chanspec);
> - }
> - } else {
> - brcmf_dbg(SCAN, "Scanning all channels\n");
> - }
> - /* Copy ssid array if applicable */
> - brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
> - if (n_ssids > 0) {
> - offset = offsetof(struct brcmf_scan_params_le, channel_list) +
> - n_channels * sizeof(u16);
> - offset = roundup(offset, sizeof(u32));
> - ptr = (char *)params_le + offset;
> - for (i = 0; i < n_ssids; i++) {
> - memset(&ssid_le, 0, sizeof(ssid_le));
> - ssid_le.SSID_len =
> - cpu_to_le32(request->ssids[i].ssid_len);
> - memcpy(ssid_le.SSID, request->ssids[i].ssid,
> - request->ssids[i].ssid_len);
> - if (!ssid_le.SSID_len)
> - brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
> - else
> - brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
> - i, ssid_le.SSID, ssid_le.SSID_len);
> - memcpy(ptr, &ssid_le, sizeof(ssid_le));
> - ptr += sizeof(ssid_le);
> - }
> - } else {
> - brcmf_dbg(SCAN, "Performing passive scan\n");
> - params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
> - }
> - /* Adding mask to channel numbers */
> - params_le->channel_num =
> - cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
> - (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
> -}
> -
> static s32
> brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
> struct cfg80211_scan_request *request)
> {
> struct brcmf_pub *drvr = cfg->pub;
> - s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
> - offsetof(struct brcmf_escan_params_le, params_le);
> + s32 params_size = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE +
> + offsetof(struct brcmf_escan_params_le, params_v2_le);
> struct brcmf_escan_params_le *params;
> s32 err = 0;
>
> @@ -1391,8 +1446,22 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
> goto exit;
> }
> BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
> - brcmf_escan_prep(cfg, &params->params_le, request);
> - params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
> + brcmf_escan_prep(cfg, &params->params_v2_le, request);
> +
> + params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION_V2);
> +
> + if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
> + struct brcmf_escan_params_le *params_v1;
> +
> + params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
> + params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE;
> + params_v1 = kzalloc(params_size, GFP_KERNEL);
> + params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
> + brcmf_scan_params_v2_to_v1(&params->params_v2_le, &params_v1->params_le);
> + kfree(params);
> + params = params_v1;
> + }
> +
> params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
> params->sync_id = cpu_to_le16(0x1234);
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
> index 10bac865d724..b6797f800e55 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
> @@ -290,6 +290,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",
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> index f1b086a69d73..549298c55b55 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> @@ -30,6 +30,7 @@
> * SAE: simultaneous authentication of equals
> * FWAUTH: Firmware authenticator
> * DUMP_OBSS: Firmware has capable to dump obss info to support ACS
> + * SCAN_V2: Version 2 scan params
> */
> #define BRCMF_FEAT_LIST \
> BRCMF_FEAT_DEF(MBSS) \
> @@ -53,7 +54,8 @@
> 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)
>
> /*
> * Quirks:
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
> index 04e1beedfd81..b3844d0d1adb 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
> @@ -48,6 +48,10 @@
>
> /* size of brcmf_scan_params not including variable length array */
> #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
> +#define BRCMF_SCAN_PARAMS_V2_FIXED_SIZE 72
> +
> +/* version of brcmf_scan_params structure */
> +#define BRCMF_SCAN_PARAMS_VERSION_V2 2
>
> /* masks for channel and ssid count */
> #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
> @@ -67,6 +71,7 @@
> #define BRCMF_PRIMARY_KEY (1 << 1)
> #define DOT11_BSSTYPE_ANY 2
> #define BRCMF_ESCAN_REQ_VERSION 1
> +#define BRCMF_ESCAN_REQ_VERSION_V2 2
>
> #define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
>
> @@ -386,6 +391,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 +441,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 {


Attachments:
smime.p7s (4.12 kB)
S/MIME Cryptographic Signature

2023-02-27 15:00:51

by Kalle Valo

[permalink] [raw]
Subject: Re: [01/10] wifi: brcmfmac: chip: Only disable D11 cores; handle an arbitrary number

Hector Martin <[email protected]> wrote:

> At least on BCM4387, the D11 cores are held in reset on cold startup and
> firmware expects to release reset itself. Just assert reset here and let
> firmware deassert it. Premature deassertion results in the firmware
> failing to initialize properly some of the time, with strange AXI bus
> errors.
>
> Also, BCM4387 has 3 cores, up from 2. The logic for handling that is in
> brcmf_chip_ai_resetcore(), but since we aren't using that any more, just
> handle it here.
>
> Reviewed-by: Linus Walleij <[email protected]>
> Reviewed-by: Arend van Spriel <[email protected]>
> Signed-off-by: Hector Martin <[email protected]>

10 patches applied to wireless-next.git, thanks.

3c7c07ca7ab1 wifi: brcmfmac: chip: Only disable D11 cores; handle an arbitrary number
098e0b105ce1 wifi: brcmfmac: chip: Handle 1024-unit sizes for TCM blocks
398ce273d6b1 wifi: brcmfmac: cfg80211: Add support for scan params v2
d75ef1f81e42 wifi: brcmfmac: feature: Add support for setting feats based on WLC version
a96202acaea4 wifi: brcmfmac: cfg80211: Add support for PMKID_V3 operations
89b89e52153f wifi: brcmfmac: cfg80211: Pass the PMK in binary instead of hex
117ace4014cc wifi: brcmfmac: pcie: Add IDs/properties for BCM4387
dd7e55401fec wifi: brcmfmac: common: Add support for downloading TxCap blobs
75102b7543ed wifi: brcmfmac: pcie: Load and provide TxCap blobs
5b3ee9987f58 wifi: brcmfmac: common: Add support for external calibration blobs

--
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches