wifi: ath11k: provide address list if chip supports 2 stations
authorCarl Huang <quic_cjhuang@quicinc.com>
Wed, 14 Feb 2024 08:38:10 +0000 (10:38 +0200)
committerKalle Valo <quic_kvalo@quicinc.com>
Thu, 15 Feb 2024 11:22:46 +0000 (13:22 +0200)
Provide address list to mac80211 so user doesn't need to specify addresses when
a second interface is added because the address can be allocated from the list
by mac80211.

The derived addresses have LAA (Local Administered Address) bit set, and only
the first byte is changed. Take the 00:03:7f:xx:xx:xx as example to derive:

addresses[0] is unchanged, it's still 00:03:7f:xx:xx:xx,
addresses[1] is 02:03:7f:xx:xx:xx,
addresses[2] is 12:03:7f:xx:xx:xx,
addresses[3] is 22:03:7f:xx:xx:xx,
addresses[4] is 32:03:7f:xx:xx:xx.

However as only 3 addresses are reported now, so addresses[3] and addresses[4]
aren't actually derived.

Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3

Signed-off-by: Carl Huang <quic_cjhuang@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20230714023801.2621802-3-quic_cjhuang@quicinc.com
drivers/net/wireless/ath/ath11k/mac.c

index 7180ce9dbf982ad02b1591c01ca44cb5c0a37698..7f18a6a68b815a7cc5be1a8cad901439a3db768d 100644 (file)
@@ -9824,6 +9824,33 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar,
        return 0;
 }
 
+static void ath11k_mac_setup_mac_address_list(struct ath11k *ar)
+{
+       struct mac_address *addresses;
+       u16 n_addresses;
+       int i;
+
+       if (!ar->ab->hw_params.support_dual_stations)
+               return;
+
+       n_addresses = ar->ab->hw_params.num_vdevs;
+       addresses = kcalloc(n_addresses, sizeof(*addresses), GFP_KERNEL);
+       if (!addresses)
+               return;
+
+       memcpy(addresses[0].addr, ar->mac_addr, ETH_ALEN);
+       for (i = 1; i < n_addresses; i++) {
+               memcpy(addresses[i].addr, ar->mac_addr, ETH_ALEN);
+               /* set Local Administered Address bit */
+               addresses[i].addr[0] |= 0x2;
+
+               addresses[i].addr[0] += (i - 1) << 4;
+       }
+
+       ar->hw->wiphy->addresses = addresses;
+       ar->hw->wiphy->n_addresses = n_addresses;
+}
+
 static int ath11k_mac_setup_iface_combinations(struct ath11k *ar)
 {
        struct ath11k_base *ab = ar->ab;
@@ -9947,6 +9974,8 @@ static void __ath11k_mac_unregister(struct ath11k *ar)
        kfree(ar->hw->wiphy->iface_combinations[0].limits);
        kfree(ar->hw->wiphy->iface_combinations);
 
+       kfree(ar->hw->wiphy->addresses);
+
        SET_IEEE80211_DEV(ar->hw, NULL);
 }
 
@@ -9989,6 +10018,7 @@ static int __ath11k_mac_register(struct ath11k *ar)
        ath11k_pdev_caps_update(ar);
 
        SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr);
+       ath11k_mac_setup_mac_address_list(ar);
 
        SET_IEEE80211_DEV(ar->hw, ab->dev);