From: Kang Yang <kang.yang@oss.qualcomm.com>
To: Vitor Soares <ivitro@gmail.com>, Jeff Johnson <jjohnson@kernel.org>
Cc: Vitor Soares <vitor.soares@toradex.com>,
linux-wireless@vger.kernel.org, ath12k@lists.infradead.org,
linux-kernel@vger.kernel.org, baochen.qiang@oss.qualcomm.com
Subject: Re: [PATCH ath-next v2] wifi: ath12k: provide MAC address list for single-radio wiphys
Date: Wed, 16 Sep 2026 15:17:09 +0800 [thread overview]
Message-ID: <5e5a76ec-7aad-4ea4-a07d-19910722738d@oss.qualcomm.com> (raw)
In-Reply-To: <20260915152815.254016-2-ivitro@gmail.com>
On 9/15/2026 11:28 PM, Vitor Soares wrote:
> From: Vitor Soares <vitor.soares@toradex.com>
>
> ath12k supports creating vdevs with addresses provided by mac80211.
> Userspace can already make concurrent interfaces work by explicitly
> assigning different locally administered addresses.
>
> However, ath12k does not advertise an address list, so when a second
> interface is created without an explicit address, mac80211 has nothing
> to pick from and falls back to the permanent address. If the first
> interface is already running with that address, bringing up the second
> one fails with -ENOTUNIQ.
>
> As in ath11k, provide a list of usable addresses so
> ieee80211_assign_perm_addr() can hand each new interface an unused one.
> Keep the first entry as the radio's own MAC address. Generate the
> remaining entries as locally administered variants by changing only the
> upper nibble of the first octet, which naturally limits the pool to 16
> unique addresses.
>
> The wiphy->addresses semantics are hardware-specific in ath12k: some
@n_addresses: number of addresses in @addresses.
@addresses: If the device has more than one address, set this pointer to
a list of addresses (6 bytes each). The first one will be used by
default for perm_addr. In this case, the mask should be set to
all-zeroes. In this case it is assumed that the device can handle the
same number of arbitrary MAC addresses.
The cfg80211 definition of wiphy->addresses does not specify where the
addresses must come from. As a result, different ath12k platforms have
historically used it in different ways (interface MAC pool vs.
firmware-provided per-radio MAC addresses). That's why we suggest gating
this behavior with a hw capability flag, so existing platform behavior
remains unchanged.
> platforms use it as an interface MAC address pool, while others use it
> for firmware-provided per-radio addresses. Gate host-generated addresses
> behind host_alloc_iface_mac and enable it for WCN7850.
>
> Handle only single-radio WCN7850 wiphys. Wiphys with more than one radio
> and other hardware families behave exactly as before.
>
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
>
> Assisted-by: LLM
> Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
> ---
> v2:
> - Gate generated interface MAC address list behind hw_params
> host_alloc_iface_mac, as suggested by Kang Yang.
> - Enable it only for WCN7850, the only part available for testing here.
> - Add Assisted-by: tag.
> - Link for v1: https://lore.kernel.org/all/20260902082219.3010793-2-ivitro@gmail.com/
> ---
> drivers/net/wireless/ath/ath12k/hw.h | 1 +
> drivers/net/wireless/ath/ath12k/mac.c | 52 ++++++++++++++++++++++
> drivers/net/wireless/ath/ath12k/wifi7/hw.c | 6 +++
> 3 files changed, 59 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
> index 011bb22e21c7..03cb35071e0b 100644
> --- a/drivers/net/wireless/ath/ath12k/hw.h
> +++ b/drivers/net/wireless/ath/ath12k/hw.h
> @@ -238,6 +238,7 @@ struct ath12k_hw_params {
> } client;
>
> bool host_alloc_ml_id;
> + bool host_alloc_iface_mac;
Please notice that, ath12k only reports address pool, and the allocation
is done by mac80211, so advertise_iface_mac_pool maybe better.
> };
>
> struct ath12k_hw_ops {
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index d4116ba0da08..45be5b08aa40 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -14743,6 +14743,54 @@ static void ath12k_mac_cleanup_unregister(struct ath12k *ar)
> kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
> }
>
> +static void ath12k_mac_cleanup_mac_address_list(struct ath12k_hw *ah)
> +{
> + kfree(ah->hw->wiphy->addresses);
wiphy->addresses = NULL;
wiphy->n_addresses = 0;
> +}
> +
> +static void ath12k_mac_setup_mac_address_list(struct ath12k_hw *ah,
> + const u8 *mac_addr)
> +{
> + struct mac_address *addresses;
> + struct ath12k *ar;
> + u16 n_addresses;
> + int i;
> +
> + /* The pool is derived from one base address, so it can describe only a
> + * single-radio wiphy: with more radios each radio has its own base
> + * address, possibly from a different ath12k_base.
> + */
> + if (ah->num_radio != 1)
> + return;
> +
Delete this num_radio check, please use hw_params check only. We cannot
make sure other chips won't have one radio products in the future(Maybe
they already have).
> + ar = ath12k_ah_to_ar(ah, 0);
> + if (!ar->ab->hw_params->host_alloc_iface_mac)
> + return;
> +
> + /* Only the upper nibble of the first octet is varied, so at most 16
> + * addresses can be derived from one base.
> + */
> + n_addresses = min_t(u16, TARGET_NUM_VDEVS(ar->ab), 16);
> + if (n_addresses <= 1)
> + return;
> +
> + addresses = kzalloc_objs(*addresses, n_addresses);
> + if (!addresses)
> + return;
> +
> + ether_addr_copy(addresses[0].addr, mac_addr);
> + for (i = 1; i < n_addresses; i++) {
> + ether_addr_copy(addresses[i].addr, mac_addr);
> + /* set Local Administered Address bit */
> + addresses[i].addr[0] |= 0x2;
> +
> + addresses[i].addr[0] += i << 4;
> + }
> +
> + ah->hw->wiphy->addresses = addresses;
> + ah->hw->wiphy->n_addresses = n_addresses;
> +}
> +
> static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
> {
> struct ieee80211_hw *hw = ah->hw;
> @@ -14762,6 +14810,7 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
> ath12k_mac_cleanup_unregister(ar);
>
> ath12k_mac_cleanup_iface_combinations(ah);
> + ath12k_mac_cleanup_mac_address_list(ah);
>
> SET_IEEE80211_DEV(hw, NULL);
> }
> @@ -14878,6 +14927,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
> wiphy->available_antennas_tx = antennas_tx;
>
> SET_IEEE80211_PERM_ADDR(hw, mac_addr);
> + ath12k_mac_setup_mac_address_list(ah, mac_addr);
> SET_IEEE80211_DEV(hw, ab->dev);
>
> ret = ath12k_mac_setup_iface_combinations(ah);
> @@ -15120,6 +15170,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
> ath12k_mac_cleanup_unregister(ar);
> }
>
> + ath12k_mac_cleanup_mac_address_list(ah);
> +
> SET_IEEE80211_DEV(hw, NULL);
>
> return ret;
> diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
> index a20c21807344..8658828ea47d 100644
> --- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
> +++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
> @@ -445,6 +445,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
> },
>
> .host_alloc_ml_id = true,
> + .host_alloc_iface_mac = false,
> },
> {
> .name = "wcn7850 hw2.0",
> @@ -539,6 +540,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
> },
>
> .host_alloc_ml_id = false,
> + .host_alloc_iface_mac = true,
> },
> {
> .name = "qcn9274 hw2.0",
> @@ -629,6 +631,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
> },
>
> .host_alloc_ml_id = true,
> + .host_alloc_iface_mac = false,
> },
> {
> .name = "ipq5332 hw1.0",
> @@ -713,6 +716,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
> },
>
> .host_alloc_ml_id = true,
> + .host_alloc_iface_mac = false,
> },
> {
> .name = "qcc2072 hw1.0",
> @@ -808,6 +812,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
> },
>
> .host_alloc_ml_id = false,
> + .host_alloc_iface_mac = false,
> },
For QCC2072, i suggest true. And you can mention in commit message for
WCN7850/QCC2072.
> {
> .name = "ipq5424 hw1.0",
> @@ -895,6 +900,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
> },
>
> .host_alloc_ml_id = true,
> + .host_alloc_iface_mac = false,
> },
> };
>
prev parent reply other threads:[~2026-09-16 7:17 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-15 15:28 Vitor Soares
2026-09-16 6:31 ` Baochen Qiang
2026-09-16 7:17 ` Kang Yang [this message]
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=5e5a76ec-7aad-4ea4-a07d-19910722738d@oss.qualcomm.com \
--to=kang.yang@oss.qualcomm.com \
--cc=ath12k@lists.infradead.org \
--cc=baochen.qiang@oss.qualcomm.com \
--cc=ivitro@gmail.com \
--cc=jjohnson@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=vitor.soares@toradex.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
all inboxes | Powered by JetHome®