Skip to contentSkip to conversation

wifi: ath12k: MLO support part 8

PATCH Applied Kalle Valo 2 participants 14 messages Dec 9, 2024 – Dec 16, 2024 Qualcomm ATH12K wireless driver

lore
Share & tools
lore

Kalle Valo

author
#0 lore raw

cover wifi: ath12k: MLO support part 8

From: Kalle Valo <[email protected]>

Getting MLO to work with QCN9274 is getting close, this should be the second to last patchset. Small patches this time. Minor changes to data path to support MLO, some interface combination rework and few fixes.

Please review.

Aditya Kumar Singh (3):
wifi: ath12k: fix ath12k_qmi_alloc_chunk() to handle too large
allocations
wifi: ath12k: fix ar->supports_6ghz usage during hw register
wifi: ath12k: pass link ID during MLO while delivering skb

Karthikeyan Periyasamy (6):
wifi: ath12k: move to HW link id based reveive handling
wifi: ath12k: add partner device buffer support in receive data path
wifi: ath12k: add helper function to init partner cmem configuration
wifi: ath12k: introduce interface combination cleanup helper
wifi: ath12k: Refactor radio frequency information
wifi: ath12k: advertise multi device interface combination

 drivers/net/wireless/ath/ath12k/core.c   |   5 +-
 drivers/net/wireless/ath/ath12k/core.h   |  17 +-
 drivers/net/wireless/ath/ath12k/dp.c     |  14 ++
 drivers/net/wireless/ath/ath12k/dp.h     |   4 +-
 drivers/net/wireless/ath/ath12k/dp_mon.c |   8 +-
 drivers/net/wireless/ath/ath12k/dp_rx.c  | 213 +++++++++++++------
 drivers/net/wireless/ath/ath12k/mac.c    | 247 +++++++++++++++++++----
 drivers/net/wireless/ath/ath12k/peer.c   |   2 +
 drivers/net/wireless/ath/ath12k/peer.h   |   3 +
 drivers/net/wireless/ath/ath12k/qmi.c    |  10 +-
 10 files changed, 414 insertions(+), 109 deletions(-)

base-commit: 400568fb3b022247c1603fdbdd6444b3ef14ffce
prerequisite-patch-id: 721655de1e9eb1b723c3340c80f52be7ab6e73a7
prerequisite-patch-id: 99576487c570edbaf46b35e8ba6b9e20ad9bf85c
prerequisite-patch-id: f0a242859176e986640595256e7f488561683309
prerequisite-patch-id: 532325a3a8da40d6b43ef643f38dca5389750820
prerequisite-patch-id: 1a0adfd0f7ad52c7d0ddd6466659e7a8a229013b
prerequisite-patch-id: e1a1418434e24374ef1ad04a49249436de602dd8
prerequisite-patch-id: 8847add439503b799079f8cfa043b15b57691d7f
prerequisite-patch-id: 017994ce11ee18d218464d1bb5ffb50ac8d941a5

Signature · 1 line
2.39.5
author
#1 lore raw

PATCH 1/9 wifi: ath12k: move to HW link id based reveive handling

From: Karthikeyan Periyasamy <[email protected]>

Currently, all the rx processing treats the hardware link id as the MAC id. The HW link id is a unique identifier for all hardware links participating in the multi link group. Therefore, the current MAC id derivation is insufficient to process the partner rx buffer in the Multi-Link Operation. So derive the MAC id from the HW link id and implementing this change in rx processing will enable the scaling of partner buffer processing in Multi-Link Operation.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/core.h  |  8 +++-
 drivers/net/wireless/ath/ath12k/dp_rx.c | 49 +++++++++++++++----------
 drivers/net/wireless/ath/ath12k/mac.c   |  3 ++
 3 files changed, 39 insertions(+), 21 deletions(-)
drivers/net/wireless/ath/ath12k/core.h +7 -1
index dc01f7b3fd73..9386e9592dff 100644
@@ -136,7 +136,7 @@ struct ath12k_skb_rxcb {
 	struct hal_rx_desc *rx_desc;
 	u8 err_rel_src;
 	u8 err_code;
-	u8 mac_id;
+	u8 hw_link_id;
 	u8 unmapped;
 	u8 is_frag;
 	u8 tid;
@@ -831,6 +831,11 @@ struct ath12k_mlo_memory {
 	bool init_done;
 };
 
+struct ath12k_hw_link {
+	u8 device_id;
+	u8 pdev_idx;
+};
+
 /* Holds info on the group of devices that are registered as a single
  * wiphy, protected with struct ath12k_hw_group::mutex.
  */
@@ -857,6 +862,7 @@ struct ath12k_hw_group {
 	bool mlo_capable;
 	struct device_node *wsi_node[ATH12K_MAX_SOCS];
 	struct ath12k_mlo_memory mlo_mem;
+	struct ath12k_hw_link hw_links[ATH12K_GROUP_MAX_RADIO];
 };
 
 /* Holds WSI info specific to each device, excluding WSI group info */
drivers/net/wireless/ath/ath12k/dp_rx.c +29 -20

141 lines not on this page · raw message

drivers/net/wireless/ath/ath12k/mac.c +3 -0
index 23c5c8fd952d..7e8eb0feb871 100644
@@ -11050,6 +11050,9 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,
 		ar->pdev_idx = pdev_idx;
 		pdev->ar = ar;
 
+		ag->hw_links[ar->hw_link_id].device_id = ab->device_id;
+		ag->hw_links[ar->hw_link_id].pdev_idx = pdev_idx;
+
 		ath12k_mac_setup(ar);
 		ath12k_dp_pdev_pre_alloc(ar);
 	}
Signature · 1 line
2.39.5
#2 lore raw

Re: [PATCH 1/9] wifi: ath12k: move to HW link id based reveive handling

Subject nit: s/reveive/receive/

I'll fixup in 'pending' if there are no additional comments on this series

author
#3 lore raw

Re: [PATCH 1/9] wifi: ath12k: move to HW link id based reveive handling

Quoted 3 lines · Jeff Johnson

Subject nit: s/reveive/receive/

I'll fixup in 'pending' if there are no additional comments on this series

Great, thanks.

Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
author
#4 lore raw

PATCH 2/9 wifi: ath12k: add partner device buffer support in receive data path

In reply to Kalle Valo

From: Karthikeyan Periyasamy <[email protected]>

Currently, partner device buffer is not handled in the receive data path. In Multi-Link Operation, the partner device buffer is reported to the primary upper MAC rings. Therefore, add partner device buffer processing in the REO and Exception ring handler.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/core.h  |   6 +
 drivers/net/wireless/ath/ath12k/dp.c    |   1 +
 drivers/net/wireless/ath/ath12k/dp.h    |   3 +-
 drivers/net/wireless/ath/ath12k/dp_rx.c | 179 +++++++++++++++++-------
 4 files changed, 140 insertions(+), 49 deletions(-)
drivers/net/wireless/ath/ath12k/core.h +6 -0
index 9386e9592dff..d7caa58bb262 100644
@@ -1229,4 +1229,10 @@ static inline void ath12k_core_stopped(struct ath12k_base *ab)
 	ab->ag->num_started--;
 }
 
+static inline struct ath12k_base *ath12k_ag_to_ab(struct ath12k_hw_group *ag,
+						  u8 device_id)
+{
+	return ag->ab[device_id];
+}
+
 #endif /* _CORE_H_ */
drivers/net/wireless/ath/ath12k/dp.c +1 -0
index 68abe9d4ab45..9a7df54bf570 100644
@@ -1445,6 +1445,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
 		for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
 			rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(cookie_ppt_idx, j);
 			rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC;
+			rx_descs[j].device_id = ab->device_id;
 			list_add_tail(&rx_descs[j].list, &dp->rx_desc_free_list);
 
 			/* Update descriptor VA in SPT */
drivers/net/wireless/ath/ath12k/dp.h +2 -1
index 021cd9e8ee1d..d3f3d39a1cd0 100644
@@ -287,7 +287,8 @@ struct ath12k_rx_desc_info {
 	u32 cookie;
 	u32 magic;
 	u8 in_use	: 1,
-	   reserved	: 7;
+	   device_id	: 3,
+	   reserved	: 4;
 };
 
 struct ath12k_tx_desc_info {
drivers/net/wireless/ath/ath12k/dp_rx.c +131 -48

357 lines not on this page · raw message

Signature · 1 line
2.39.5
author
#5 lore raw

PATCH 3/9 wifi: ath12k: add helper function to init partner cmem configuration

In reply to Kalle Valo

From: Karthikeyan Periyasamy <[email protected]>

In the Inter Multi-Link Operation, the primary device is expected to receive the partner device buffer. Therefore, each device initializes the partner device buffer in their cmem configuration. So add a helper function to initialize the partner device buffer in their cmem configuration.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/core.c |  5 ++++-
 drivers/net/wireless/ath/ath12k/dp.c   | 13 +++++++++++++
 drivers/net/wireless/ath/ath12k/dp.h   |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/ath12k/core.c +4 -1
index af642b466ea0..ff79cb910523 100644
@@ -930,7 +930,7 @@ int ath12k_mac_mlo_ready(struct ath12k_hw_group *ag)
 
 static int ath12k_core_mlo_setup(struct ath12k_hw_group *ag)
 {
-	int ret;
+	int ret, i;
 
 	if (!ag->mlo_capable || ag->num_devices == 1)
 		return 0;
@@ -939,6 +939,9 @@ static int ath12k_core_mlo_setup(struct ath12k_hw_group *ag)
 	if (ret)
 		return ret;
 
+	for (i = 0; i < ag->num_devices; i++)
+		ath12k_dp_partner_cc_init(ag->ab[i]);
+
 	ret = ath12k_mac_mlo_ready(ag);
 	if (ret)
 		goto err_mlo_teardown;
drivers/net/wireless/ath/ath12k/dp.c +13 -0
index 9a7df54bf570..9e5a4e75f2f6 100644
@@ -1522,6 +1522,19 @@ static int ath12k_dp_cmem_init(struct ath12k_base *ab,
 	return 0;
 }
 
+void ath12k_dp_partner_cc_init(struct ath12k_base *ab)
+{
+	struct ath12k_hw_group *ag = ab->ag;
+	int i;
+
+	for (i = 0; i < ag->num_devices; i++) {
+		if (ag->ab[i] == ab)
+			continue;
+
+		ath12k_dp_cmem_init(ab, &ag->ab[i]->dp, ATH12K_DP_RX_DESC);
+	}
+}
+
 static int ath12k_dp_cc_init(struct ath12k_base *ab)
 {
 	struct ath12k_dp *dp = &ab->dp;
drivers/net/wireless/ath/ath12k/dp.h +1 -0
index d3f3d39a1cd0..7700828375e3 100644
@@ -1806,6 +1806,7 @@ void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif);
 void ath12k_dp_free(struct ath12k_base *ab);
 int ath12k_dp_alloc(struct ath12k_base *ab);
 void ath12k_dp_cc_config(struct ath12k_base *ab);
+void ath12k_dp_partner_cc_init(struct ath12k_base *ab);
 int ath12k_dp_pdev_alloc(struct ath12k_base *ab);
 void ath12k_dp_pdev_pre_alloc(struct ath12k *ar);
 void ath12k_dp_pdev_free(struct ath12k_base *ab);
Signature · 1 line
2.39.5
author
#6 lore raw

PATCH 4/9 wifi: ath12k: introduce interface combination cleanup helper

In reply to Kalle Valo

From: Karthikeyan Periyasamy <[email protected]>

Introduce a cleanup helper function to avoid redundant code for interface combination cleanup. Remove the cleanup code from ath12k_mac_hw_unregister() and ath12k_mac_hw_register() and replace it with a new cleanup helper function.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/mac.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)
drivers/net/wireless/ath/ath12k/mac.c +13 -8
index 7e8eb0feb871..dc61fe761090 100644
@@ -10351,6 +10351,14 @@ static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah,
 	return is_enable;
 }
 
+static void ath12k_mac_cleanup_iface_combinations(struct ath12k_hw *ah)
+{
+	struct wiphy *wiphy = ah->hw->wiphy;
+
+	kfree(wiphy->iface_combinations[0].limits);
+	kfree(wiphy->iface_combinations);
+}
+
 static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah)
 {
 	struct wiphy *wiphy = ah->hw->wiphy;
@@ -10479,7 +10487,6 @@ static void ath12k_mac_cleanup_unregister(struct ath12k *ar)
 static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
 {
 	struct ieee80211_hw *hw = ah->hw;
-	struct wiphy *wiphy = hw->wiphy;
 	struct ath12k *ar;
 	int i;
 
@@ -10493,8 +10500,7 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
 	for_each_ar(ah, ar, i)
 		ath12k_mac_cleanup_unregister(ar);
 
-	kfree(wiphy->iface_combinations[0].limits);
-	kfree(wiphy->iface_combinations);
+	ath12k_mac_cleanup_iface_combinations(ah);
 
 	SET_IEEE80211_DEV(hw, NULL);
 }
@@ -10724,13 +10730,13 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
 	ret = ath12k_wow_init(ar);
 	if (ret) {
 		ath12k_warn(ar->ab, "failed to init wow: %d\n", ret);
-		goto err_free_if_combs;
+		goto err_cleanup_if_combs;
 	}
 
 	ret = ieee80211_register_hw(hw);
 	if (ret) {
 		ath12k_err(ab, "ieee80211 registration failed: %d\n", ret);
-		goto err_free_if_combs;
+		goto err_cleanup_if_combs;
 	}
 
 	if (is_monitor_disable)
@@ -10760,9 +10766,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
 
 	ieee80211_unregister_hw(hw);
 
-err_free_if_combs:
-	kfree(wiphy->iface_combinations[0].limits);
-	kfree(wiphy->iface_combinations);
+err_cleanup_if_combs:
+	ath12k_mac_cleanup_iface_combinations(ah);
 
 err_complete_cleanup_unregister:
 	i = ah->num_radio;
Signature · 1 line
2.39.5
author
#7 lore raw

PATCH 5/9 wifi: ath12k: Refactor radio frequency information

In reply to Kalle Valo

From: Karthikeyan Periyasamy <[email protected]>

Currently, radio stores the low frequency and high frequency information as separate variables. However, cfg80211 already provides a suitable data structure struct wiphy_radio_freq_range to store this information efficiently. Additionally, for multi radio per wiphy infrastructure, this frequency range information is essential. In future patches using struct wiphy_radio_freq_range makes the code simpler.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/core.h | 3 +--
 drivers/net/wireless/ath/ath12k/mac.c  | 8 ++++----
 2 files changed, 5 insertions(+), 6 deletions(-)
drivers/net/wireless/ath/ath12k/core.h +1 -2
index d7caa58bb262..d09ebcdde94f 100644
@@ -711,8 +711,7 @@ struct ath12k {
 	bool monitor_started;
 	int monitor_vdev_id;
 
-	u32 freq_low;
-	u32 freq_high;
+	struct wiphy_radio_freq_range freq_range;
 
 	bool nlo_enabled;
 
drivers/net/wireless/ath/ath12k/mac.c +4 -4
index dc61fe761090..1bf89be1cccc 100644
@@ -708,8 +708,8 @@ static struct ath12k *ath12k_mac_get_ar_by_chan(struct ieee80211_hw *hw,
 		return ar;
 
 	for_each_ar(ah, ar, i) {
-		if (channel->center_freq >= ar->freq_low &&
-		    channel->center_freq <= ar->freq_high)
+		if (channel->center_freq >= KHZ_TO_MHZ(ar->freq_range.start_freq) &&
+		    channel->center_freq <= KHZ_TO_MHZ(ar->freq_range.end_freq))
 			return ar;
 	}
 	return NULL;
@@ -10203,8 +10203,8 @@ static void ath12k_mac_update_ch_list(struct ath12k *ar,
 			band->channels[i].flags |= IEEE80211_CHAN_DISABLED;
 	}
 
-	ar->freq_low = freq_low;
-	ar->freq_high = freq_high;
+	ar->freq_range.start_freq = MHZ_TO_KHZ(freq_low);
+	ar->freq_range.end_freq = MHZ_TO_KHZ(freq_high);
 }
 
 static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band)
Signature · 1 line
2.39.5
author
#8 lore raw

PATCH 6/9 wifi: ath12k: advertise multi device interface combination

In reply to Kalle Valo

From: Karthikeyan Periyasamy <[email protected]>

The prerequisite for MLO support in cfg80211/mac80211 requires that all the links participating in MLO belong to the same wiphy/struct ieee80211_hw. The driver needs to group multiple discrete hardware components, each acting as a link in MLO, under one wiphy. Consequently, the driver advertises multi-hardware device interface combination capabilities specific to the radio, including supported frequencies. The global interface combination represent the combined interface capabilities.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/mac.c | 222 +++++++++++++++++++++-----
 1 file changed, 185 insertions(+), 37 deletions(-)
drivers/net/wireless/ath/ath12k/mac.c +185 -37
index 1bf89be1cccc..de2f55f4ea03 100644
@@ -10336,14 +10336,20 @@ static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah,
 {
 	struct ath12k *ar;
 	int i;
-	u16 interface_modes, mode;
-	bool is_enable = true;
+	u16 interface_modes, mode = 0;
+	bool is_enable = false;
+
+	if (type == NL80211_IFTYPE_MESH_POINT) {
+		if (IS_ENABLED(CONFIG_MAC80211_MESH))
+			mode = BIT(type);
+	} else {
+		mode = BIT(type);
+	}
 
-	mode = BIT(type);
 	for_each_ar(ah, ar, i) {
 		interface_modes = ar->ab->hw_params->interface_modes;
-		if (!(interface_modes & mode)) {
-			is_enable = false;
+		if (interface_modes & mode) {
+			is_enable = true;
 			break;
 		}
 	}
@@ -10351,31 +10357,20 @@ static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah,
 	return is_enable;
 }
 
-static void ath12k_mac_cleanup_iface_combinations(struct ath12k_hw *ah)
+static int
+ath12k_mac_setup_radio_iface_comb(struct ath12k *ar,
+				  struct ieee80211_iface_combination *comb)
 {
-	struct wiphy *wiphy = ah->hw->wiphy;
-
-	kfree(wiphy->iface_combinations[0].limits);
-	kfree(wiphy->iface_combinations);
-}
-
-static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah)
-{
-	struct wiphy *wiphy = ah->hw->wiphy;
-	struct ieee80211_iface_combination *combinations;
+	u16 interface_modes = ar->ab->hw_params->interface_modes;
 	struct ieee80211_iface_limit *limits;
 	int n_limits, max_interfaces;
 	bool ap, mesh, p2p;
 
-	ap = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_AP);
-	p2p = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_P2P_DEVICE);
+	ap = interface_modes & BIT(NL80211_IFTYPE_AP);
+	p2p = interface_modes & BIT(NL80211_IFTYPE_P2P_DEVICE);
 
 	mesh = IS_ENABLED(CONFIG_MAC80211_MESH) &&
-		ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT);
-
-	combinations = kzalloc(sizeof(*combinations), GFP_KERNEL);
-	if (!combinations)
-		return -ENOMEM;
+	       (interface_modes & BIT(NL80211_IFTYPE_MESH_POINT));
 
 	if ((ap || mesh) && !p2p) {
 		n_limits = 2;
@@ -10392,10 +10387,8 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah)
 	}
 
 	limits = kcalloc(n_limits, sizeof(*limits), GFP_KERNEL);
-	if (!limits) {
-		kfree(combinations);
+	if (!limits)
 		return -ENOMEM;
-	}
 
 	limits[0].max = 1;
 	limits[0].types |= BIT(NL80211_IFTYPE_STATION);
@@ -10411,26 +10404,181 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah)
 
 	if (p2p) {
 		limits[1].types |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
-				   BIT(NL80211_IFTYPE_P2P_GO);
+					BIT(NL80211_IFTYPE_P2P_GO);
 		limits[2].max = 1;
 		limits[2].types |= BIT(NL80211_IFTYPE_P2P_DEVICE);
 	}
 
-	combinations[0].limits = limits;
-	combinations[0].n_limits = n_limits;
-	combinations[0].max_interfaces = max_interfaces;
-	combinations[0].num_different_channels = 1;
-	combinations[0].beacon_int_infra_match = true;
-	combinations[0].beacon_int_min_gcd = 100;
-	combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
-						BIT(NL80211_CHAN_WIDTH_20) |
-						BIT(NL80211_CHAN_WIDTH_40) |
-						BIT(NL80211_CHAN_WIDTH_80);
+	comb[0].limits = limits;
+	comb[0].n_limits = n_limits;
+	comb[0].max_interfaces = max_interfaces;
+	comb[0].num_different_channels = 1;
+	comb[0].beacon_int_infra_match = true;
+	comb[0].beacon_int_min_gcd = 100;
+	comb[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+					BIT(NL80211_CHAN_WIDTH_20) |
+					BIT(NL80211_CHAN_WIDTH_40) |
+					BIT(NL80211_CHAN_WIDTH_80);
 
+	return 0;
+}
+
+static int
+ath12k_mac_setup_global_iface_comb(struct ath12k_hw *ah,
+				   struct wiphy_radio *radio,
+				   u8 n_radio,
+				   struct ieee80211_iface_combination *comb)
+{
+	const struct ieee80211_iface_combination *iter_comb;
+	struct ieee80211_iface_limit *limits;
+	int i, j, n_limits;
+	bool ap, mesh, p2p;
+
+	if (!n_radio)
+		return 0;
+
+	ap = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_AP);
+	p2p = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_P2P_DEVICE);
+	mesh = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT);
+
+	if ((ap || mesh) && !p2p)
+		n_limits = 2;
+	else if (p2p)
+		n_limits = 3;
+	else
+		n_limits = 1;
+
+	limits = kcalloc(n_limits, sizeof(*limits), GFP_KERNEL);
+	if (!limits)
+		return -ENOMEM;
+
+	for (i = 0; i < n_radio; i++) {
+		iter_comb = radio[i].iface_combinations;
+		for (j = 0; j < iter_comb->n_limits && j < n_limits; j++) {
+			limits[j].types |= iter_comb->limits[j].types;
+			limits[j].max += iter_comb->limits[j].max;
+		}
+
+		comb->max_interfaces += iter_comb->max_interfaces;
+		comb->num_different_channels += iter_comb->num_different_channels;
+		comb->radar_detect_widths |= iter_comb->radar_detect_widths;
+	}
+
+	comb->limits = limits;
+	comb->n_limits = n_limits;
+	comb->beacon_int_infra_match = true;
+	comb->beacon_int_min_gcd = 100;
+
+	return 0;
+}
+
+static
+void ath12k_mac_cleanup_iface_comb(const struct ieee80211_iface_combination *iface_comb)
+{
+	kfree(iface_comb[0].limits);
+	kfree(iface_comb);
+}
+
+static void ath12k_mac_cleanup_iface_combinations(struct ath12k_hw *ah)
+{
+	struct wiphy *wiphy = ah->hw->wiphy;
+	const struct wiphy_radio *radio;
+	int i;
+
+	if (wiphy->n_radio > 0) {
+		radio = wiphy->radio;
+		for (i = 0; i < wiphy->n_radio; i++)
+			ath12k_mac_cleanup_iface_comb(radio[i].iface_combinations);
+
+		kfree(wiphy->radio);
+	}
+
+	ath12k_mac_cleanup_iface_comb(wiphy->iface_combinations);
+}
+
+static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah)
+{
+	struct ieee80211_iface_combination *combinations, *comb;
+	struct wiphy *wiphy = ah->hw->wiphy;
+	struct wiphy_radio *radio;
+	struct ath12k *ar;
+	int i, ret;
+
+	combinations = kzalloc(sizeof(*combinations), GFP_KERNEL);
+	if (!combinations)
+		return -ENOMEM;
+
+	if (ah->num_radio == 1) {
+		ret = ath12k_mac_setup_radio_iface_comb(&ah->radio[0],
+							combinations);
+		if (ret) {
+			ath12k_hw_warn(ah, "failed to setup radio interface combinations for one radio: %d",
+				       ret);
+			goto err_free_combinations;
+		}
+
+		goto out;
+	}
+
+	/* there are multiple radios */
+
+	radio = kcalloc(ah->num_radio, sizeof(*radio), GFP_KERNEL);
+	if (!radio) {
+		ret = -ENOMEM;
+		goto err_free_combinations;
+	}
+
+	for_each_ar(ah, ar, i) {
+		comb = kzalloc(sizeof(*comb), GFP_KERNEL);
+		if (!comb) {
+			ret = -ENOMEM;
+			goto err_free_radios;
+		}
+
+		ret = ath12k_mac_setup_radio_iface_comb(ar, comb);
+		if (ret) {
+			ath12k_hw_warn(ah, "failed to setup radio interface combinations for radio %d: %d",
+				       i, ret);
+			kfree(comb);
+			goto err_free_radios;
+		}
+
+		radio[i].freq_range = &ar->freq_range;
+		radio[i].n_freq_range = 1;
+
+		radio[i].iface_combinations = comb;
+		radio[i].n_iface_combinations = 1;
+	}
+
+	ret = ath12k_mac_setup_global_iface_comb(ah, radio, ah->num_radio, combinations);
+	if (ret) {
+		ath12k_hw_warn(ah, "failed to setup global interface combinations: %d",
+			       ret);
+		goto err_free_all_radios;
+	}
+
+	wiphy->radio = radio;
+	wiphy->n_radio = ah->num_radio;
+
+out:
 	wiphy->iface_combinations = combinations;
 	wiphy->n_iface_combinations = 1;
 
 	return 0;
+
+err_free_all_radios:
+	i = ah->num_radio;
+
+err_free_radios:
+	while (i--)
+		ath12k_mac_cleanup_iface_comb(radio[i].iface_combinations);
+
+	kfree(radio);
+
+err_free_combinations:
+	kfree(combinations);
+
+	return ret;
 }
 
 static const u8 ath12k_if_types_ext_capa[] = {
Signature · 1 line
2.39.5
author
#9 lore raw

PATCH 7/9 wifi: ath12k: fix ath12k_qmi_alloc_chunk() to handle too large allocations

In reply to Kalle Valo

From: Aditya Kumar Singh <[email protected]>

If the requested memory chunk is too large, an error message is logged, but the request continues to be processed. However, no actual memory is allocated to the firmware from this request. Instead, the firmware sends another request with smaller chunks, where memory will be allocated accordingly. Therefore, it is pointless to proceed with parsing the request if at least one of the requests cannot be fulfilled.

Hence, return -EAGAIN immediately and proceed to process the new request.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/qmi.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/ath12k/qmi.c +9 -1
index e7846aaca10a..964d350be748 100644
@@ -2497,7 +2497,7 @@ static int ath12k_qmi_alloc_chunk(struct ath12k_base *ab,
 				    chunk->size,
 				    chunk->type);
 			ath12k_qmi_free_target_mem_chunk(ab);
-			return 0;
+			return -EAGAIN;
 		}
 		ath12k_warn(ab, "memory allocation failure for %u size: %d\n",
 			    chunk->type, chunk->size);
@@ -2600,6 +2600,14 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab)
 
 	mutex_unlock(&ag->mutex);
 
+	/* The firmware will attempt to request memory in smaller chunks
+	 * on the next try. However, the current caller should be notified
+	 * that this instance of request parsing was successful.
+	 * Therefore, return 0 only.
+	 */
+	if (ret == -EAGAIN)
+		ret = 0;
+
 	return ret;
 }
 
Signature · 1 line
2.39.5
author
#10 lore raw

PATCH 8/9 wifi: ath12k: fix ar->supports_6ghz usage during hw register

In reply to Kalle Valo

From: Aditya Kumar Singh <[email protected]>

In the ath12k_mac_hw_register() function's context, ar is an iterator variable, and there is no assurance that the last ar will be the one with 6 GHz enabled. Therefore, checking directly ar->supports_6ghz outside the loop is not appropriate.

Additionally, 6 GHz lacks HT capabilities. To obtain the super set of HT capabilities across all grouped radios, 6 GHz should be excluded.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/mac.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath12k/mac.c +6 -3
index de2f55f4ea03..6f4a34c91038 100644
@@ -10723,7 +10723,10 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
 		if (ret)
 			goto err_cleanup_unregister;
 
-		ht_cap &= ht_cap_info;
+		/* 6 GHz does not support HT Cap, hence do not consider it */
+		if (!ar->supports_6ghz)
+			ht_cap &= ht_cap_info;
+
 		wiphy->max_ap_assoc_sta += ar->max_num_stations;
 
 		/* Advertise the max antenna support of all radios, driver can handle
@@ -10787,7 +10790,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
 	ieee80211_hw_set(hw, SUPPORTS_TX_FRAG);
 	ieee80211_hw_set(hw, REPORTS_LOW_ACK);
 
-	if ((ht_cap & WMI_HT_CAP_ENABLED) || ar->supports_6ghz) {
+	if ((ht_cap & WMI_HT_CAP_ENABLED) || is_6ghz) {
 		ieee80211_hw_set(hw, AMPDU_AGGREGATION);
 		ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
 		ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
@@ -10803,7 +10806,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
 	 * handle it when the ht capability different for each band.
 	 */
 	if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS ||
-	    (ar->supports_6ghz && ab->hw_params->supports_dynamic_smps_6ghz))
+	    (is_6ghz && ab->hw_params->supports_dynamic_smps_6ghz))
 		wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
 
 	wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID;
Signature · 1 line
2.39.5
author
#11 lore raw

PATCH 9/9 wifi: ath12k: pass link ID during MLO while delivering skb

In reply to Kalle Valo

From: Aditya Kumar Singh <[email protected]>

mac80211 expects link_id in some scenarios or else the packet might get dropped. Hence, add link_id information before delivering the skb.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

---
 drivers/net/wireless/ath/ath12k/dp_mon.c | 8 +++++++-
 drivers/net/wireless/ath/ath12k/dp_rx.c  | 5 +++++
 drivers/net/wireless/ath/ath12k/peer.c   | 2 ++
 drivers/net/wireless/ath/ath12k/peer.h   | 3 +++
 4 files changed, 17 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/ath12k/dp_mon.c +7 -1
index 494984133a91..2d53404095d6 100644
@@ -1093,8 +1093,14 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
 		decap = ath12k_dp_rx_h_decap_type(ar->ab, rxcb->rx_desc);
 	spin_lock_bh(&ar->ab->base_lock);
 	peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu);
-	if (peer && peer->sta)
+	if (peer && peer->sta) {
 		pubsta = peer->sta;
+		if (pubsta->valid_links) {
+			status->link_valid = 1;
+			status->link_id = peer->link_id;
+		}
+	}
+
 	spin_unlock_bh(&ar->ab->base_lock);
 
 	ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
drivers/net/wireless/ath/ath12k/dp_rx.c +5 -0
index adbd7bbcef6f..1cc7f6ce55b9 100644
@@ -2474,6 +2474,11 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
 
 	pubsta = peer ? peer->sta : NULL;
 
+	if (pubsta && pubsta->valid_links) {
+		status->link_valid = 1;
+		status->link_id = peer->link_id;
+	}
+
 	spin_unlock_bh(&ab->base_lock);
 
 	ath12k_dbg(ab, ATH12K_DBG_DATA,
drivers/net/wireless/ath/ath12k/peer.c +2 -0
index 5763c5a40cfc..792cca8a3fb1 100644
@@ -388,6 +388,8 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
 		arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy,
 					  ahsta->link[link_id]);
 
+		peer->link_id = arsta->link_id;
+
 		/* Fill ML info into created peer */
 		if (sta->mlo) {
 			ml_peer_id = ahsta->ml_peer_id;
drivers/net/wireless/ath/ath12k/peer.h +3 -0
index 7e6231cb2b52..5870ee11a8c7 100644
@@ -59,6 +59,9 @@ struct ath12k_peer {
 
 	/* To ensure only certain work related to dp is done once */
 	bool primary_link;
+
+	/* for reference to ath12k_link_sta */
+	u8 link_id;
 };
 
 struct ath12k_ml_peer {
Signature · 1 line
2.39.5
author
#12 lore raw
In reply to Kalle Valo
Quoted 7 lines · Kalle Valo

From: Kalle Valo <[email protected]>

Getting MLO to work with QCN9274 is getting close, this should be the second to last patchset. Small patches this time. Minor changes to data path to support MLO, some interface combination rework and few fixes.

Please review.

I forgot to mention that this (naturally) depends on part 7:

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

Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Applied
#13 lore raw
In reply to Kalle Valo
Quoted 6 lines · Kalle Valo

Getting MLO to work with QCN9274 is getting close, this should be the second to last patchset. Small patches this time. Minor changes to data path to support MLO, some interface combination rework and few fixes.

Please review.

Quoted 7 lines

Aditya Kumar Singh (3):
wifi: ath12k: fix ath12k_qmi_alloc_chunk() to handle too large
allocations
wifi: ath12k: fix ar->supports_6ghz usage during hw register
wifi: ath12k: pass link ID during MLO while delivering skb

[...]

Applied, thanks!

[1/9] wifi: ath12k: move to HW link id based reveive handling

      commit: e536c8690cf423f47e5e2f491134d3511edbbaf2
[2/9] wifi: ath12k: add partner device buffer support in receive data path
      commit: fc1e7e004b1808da38c862d57fccfad631a1445a
[3/9] wifi: ath12k: add helper function to init partner cmem configuration
      commit: 5a8abdf88deac066c4c4a224e45b80088ea94ff0
[4/9] wifi: ath12k: introduce interface combination cleanup helper
      commit: 2e4b8a49191ea9df8430cb6e8af7429eadd54709
[5/9] wifi: ath12k: Refactor radio frequency information
      commit: 4b861d256235c0c94d1a09e4dd888accc0eec5e9
[6/9] wifi: ath12k: advertise multi device interface combination
      commit: 03156d08d9ae768bffc0eba5eeeede868f52331f
[7/9] wifi: ath12k: fix ath12k_qmi_alloc_chunk() to handle too large allocations
      commit: c14725f359ef982923f3bc7e222c7687ffe4e496
[8/9] wifi: ath12k: fix ar->supports_6ghz usage during hw register
      commit: 95740fb0d3dbe276bf414c44cea0c35948407800
[9/9] wifi: ath12k: pass link ID during MLO while delivering skb
      commit: 1d015d783da57b002fda75b29aa3b886724c0129

Best regards,

Signature · 1 line
Jeff Johnson <[email protected]>