From: Shivesh <chanelshivesh@gmail.com>
To: arend.vanspriel@broadcom.com
Cc: linux-wireless@vger.kernel.org, brcm80211@lists.linux.dev,
brcm80211-dev-list.pdl@broadcom.com,
linux-kernel@vger.kernel.org, Shivesh <shivesh@example.com>
Subject: [PATCH 4/8] wifi: brcmfmac: cfg80211: implement PMKID_V2 and fix delay busy-wait
Date: Thu, 30 Jul 2026 16:03:52 +0000 [thread overview]
Message-ID: <20260730160425.11933-4-shivesh@example.com> (raw)
In-Reply-To: <20260730160425.11933-1-shivesh@example.com>
Implements PMKID_V2 for FILS fast-roaming support instead of falling
through to the V1 path. Additionally replaces a harmful mdelay() busy-wait
in brcmf_delay with usleep_range() to prevent CPU stalls.
Signed-off-by: Shivesh <shivesh@example.com>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 118 ++++++++++++++++--
.../broadcom/brcm80211/brcmfmac/cfg80211.h | 4 +-
2 files changed, 110 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 0b55d445895f..7d7e5ececd22 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -3989,12 +3989,10 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
static __always_inline void brcmf_delay(u32 ms)
{
- if (ms < 1000 / HZ) {
- cond_resched();
- mdelay(ms);
- } else {
+ if (ms <= 20)
+ usleep_range(ms * 1000, ms * 1000 + 1000);
+ else
msleep(ms);
- }
}
static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
@@ -4364,6 +4362,104 @@ brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa,
return ret;
}
+/**
+ * brcmf_pmksa_v2_op - update firmware PMKSA cache using the V2 list interface.
+ *
+ * V2 firmware (revision 12) uses a versioned flat list structure
+ * (brcmf_pmk_list_v2_le) rather than the per-entry operation model of V3.
+ * Each entry carries FILS-specific fields (raw PMK material, SSID, and
+ * fils_cache_id) in addition to the basic BSSID + PMKID pair, enabling
+ * FILS fast-roaming on devices that do not support V3.
+ *
+ * @cfg: driver config structure holding the shadow V2 PMKSA list
+ * @ifp: interface pointer
+ * @pmksa: the PMKSA to add/remove, or NULL for a flush
+ * @alive: true = add (set time_left to no-expiry), false = remove/flush
+ */
+static s32
+brcmf_pmksa_v2_op(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
+ struct cfg80211_pmksa *pmksa, bool alive)
+{
+ struct brcmf_pub *drvr = cfg->pub;
+ struct brcmf_pmk_list_v2_le *list = &cfg->pmk_list_v2;
+ struct brcmf_pmksa_v2 *pmk = list->pmk;
+ u32 npmk = le16_to_cpu(list->length);
+ u32 i;
+
+ /* npmk here stores the count of valid entries, repurposing the
+ * length field of the shadow list as a counter. We convert to
+ * the wire format (byte length) when sending to firmware.
+ */
+ if (!pmksa) {
+ /* Flush: zero the shadow list and push an empty V2 list. */
+ memset(list, 0, sizeof(*list));
+ goto send;
+ }
+
+ if (alive) {
+ /* Set: search for existing BSSID match first. */
+ for (i = 0; i < npmk; i++)
+ if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
+ break;
+
+ if (i >= BRCMF_MAXPMKID) {
+ bphy_err(drvr, "V2 PMKSA cache full (%d entries)\n",
+ npmk);
+ return -EINVAL;
+ }
+
+ memset(&pmk[i], 0, sizeof(pmk[i]));
+ pmk[i].length = cpu_to_le16(sizeof(struct brcmf_pmksa_v2));
+ if (pmksa->bssid)
+ memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
+ if (pmksa->pmkid)
+ memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
+ if (pmksa->pmk && pmksa->pmk_len &&
+ pmksa->pmk_len <= WLAN_PMK_LEN_SUITE_B_192) {
+ memcpy(pmk[i].pmk, pmksa->pmk, pmksa->pmk_len);
+ pmk[i].pmk_len = cpu_to_le16(pmksa->pmk_len);
+ }
+ if (pmksa->ssid && pmksa->ssid_len) {
+ memcpy(pmk[i].ssid.SSID, pmksa->ssid, pmksa->ssid_len);
+ pmk[i].ssid.SSID_len = pmksa->ssid_len;
+ }
+ if (pmksa->fils_cache_id)
+ pmk[i].fils_cache_id = *pmksa->fils_cache_id;
+
+ if (i == npmk)
+ npmk++;
+ } else {
+ /* Delete: find by BSSID and compact the list. */
+ for (i = 0; i < npmk; i++)
+ if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
+ break;
+
+ if (i >= npmk) {
+ bphy_err(drvr, "V2 PMKSA entry not found\n");
+ return -EINVAL;
+ }
+
+ for (; i < npmk - 1; i++)
+ memcpy(&pmk[i], &pmk[i + 1], sizeof(pmk[i]));
+ memset(&pmk[npmk - 1], 0, sizeof(pmk[npmk - 1]));
+ npmk--;
+ }
+
+ /* Update shadow entry count (stored in length field). */
+ list->length = cpu_to_le16(npmk);
+
+send:
+ /* Build the wire-format header and send the full list to firmware.
+ * version and length on the wire reflect the actual byte footprint.
+ */
+ list->version = cpu_to_le16(BRCMF_PMKSA_VER_2);
+ list->length = cpu_to_le16(offsetof(struct brcmf_pmk_list_v2_le, pmk) +
+ npmk * sizeof(struct brcmf_pmksa_v2));
+
+ return brcmf_fil_iovar_data_set(ifp, "pmkid_info", list, sizeof(*list));
+}
+
+
static __used s32
brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
{
@@ -4402,8 +4498,8 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
return brcmf_pmksa_v3_op(ifp, pmksa, true);
-
- /* TODO: implement PMKID_V2 */
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))
+ return brcmf_pmksa_v2_op(cfg, ifp, pmksa, true);
npmk = le32_to_cpu(cfg->pmk_list.npmk);
for (i = 0; i < npmk; i++)
@@ -4446,8 +4542,8 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
return brcmf_pmksa_v3_op(ifp, pmksa, false);
-
- /* TODO: implement PMKID_V2 */
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))
+ return brcmf_pmksa_v2_op(cfg, ifp, pmksa, false);
npmk = le32_to_cpu(cfg->pmk_list.npmk);
for (i = 0; i < npmk; i++)
@@ -4487,8 +4583,8 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3))
return brcmf_pmksa_v3_op(ifp, NULL, false);
-
- /* TODO: implement PMKID_V2 */
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V2))
+ return brcmf_pmksa_v2_op(cfg, ifp, NULL, false);
memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
err = brcmf_update_pmklist(cfg, ifp);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 6ceb30142905..57167fde5ba1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -344,7 +344,8 @@ struct brcmf_cfg80211_wowl {
* @bss_list: bss_list holding scanned ap information.
* @bss_info: bss information for cfg80211 layer.
* @conn_info: association info.
- * @pmk_list: wpa2 pmk list.
+ * @pmk_list: wpa2 pmk list (V1 firmware).
+ * @pmk_list_v2: wpa2 pmk list for V2 firmware (FILS-capable, firmware rev 12).
* @scan_status: scan activity on the dongle.
* @pub: common driver information.
* @channel: current channel.
@@ -376,6 +377,7 @@ struct brcmf_cfg80211_info {
struct wl_cfg80211_bss_info *bss_info;
struct brcmf_cfg80211_connect_info conn_info;
struct brcmf_pmk_list_le pmk_list;
+ struct brcmf_pmk_list_v2_le pmk_list_v2;
unsigned long scan_status;
struct brcmf_pub *pub;
u32 channel;
--
2.53.0
next prev parent reply other threads:[~2026-07-30 16:04 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-30 16:03 [PATCH 1/8] wifi: brcmfmac: flowring: replace O(N) loop with atomic counter Shivesh
2026-07-30 16:03 ` [PATCH 2/8] wifi: brcmfmac: sdio: coalesce host locks in rx path Shivesh
2026-07-30 16:03 ` [PATCH 3/8] wifi: brcmfmac: core: populate radiotap header with RSSI Shivesh
2026-07-30 16:03 ` Shivesh [this message]
2026-07-30 16:03 ` [PATCH 5/8] wifi: brcmfmac: msgbuf: tune thresholds and optimize sleep latency Shivesh
2026-07-30 16:03 ` [PATCH 6/8] wifi: brcmfmac: pcie: optimize latency and irq teardown Shivesh
2026-07-30 16:03 ` [PATCH 7/8] wifi: brcmfmac: fwsignal: safe no-op on duplicate MAC add Shivesh
2026-07-30 16:03 ` [PATCH 8/8] wifi: brcmsmac: ampdu: clarify standard compliance on QoS change Shivesh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260730160425.11933-4-shivesh@example.com \
--to=chanelshivesh@gmail.com \
--cc=arend.vanspriel@broadcom.com \
--cc=brcm80211-dev-list.pdl@broadcom.com \
--cc=brcm80211@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=shivesh@example.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox