* [PATCH 0/7] wifi: ath12k: MLO support part 6
@ 2024-12-04 16:32 Kalle Valo
2024-12-04 16:32 ` [PATCH 1/7] wifi: ath12k: move ATH12K_FLAG_REGISTERED handling to ath12k_mac_register() Kalle Valo
` (7 more replies)
0 siblings, 8 replies; 13+ messages in thread
From: Kalle Valo @ 2024-12-04 16:32 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
From: Kalle Valo <quic_kvalo@quicinc.com>
In this patchset there's refactoring to support hardware grouping, meaning
multiple hardware devices can be registered to mac80211 as a single device.
Please review.
Aditya Kumar Singh (1):
wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp
Karthikeyan Periyasamy (6):
wifi: ath12k: move ATH12K_FLAG_REGISTERED handling to
ath12k_mac_register()
wifi: ath12k: introduce device group abstraction
wifi: ath12k: refactor core start based on hardware group
wifi: ath12k: move struct ath12k_hw from per device to group
wifi: ath12k: send QMI host capability after device group is ready
wifi: ath12k: introduce mlo_capable flag for device group
drivers/net/wireless/ath/ath12k/core.c | 449 ++++++++++++++++++++++---
drivers/net/wireless/ath/ath12k/core.h | 88 +++--
drivers/net/wireless/ath/ath12k/dp.c | 19 +-
drivers/net/wireless/ath/ath12k/dp.h | 2 +-
drivers/net/wireless/ath/ath12k/mac.c | 97 ++++--
drivers/net/wireless/ath/ath12k/mac.h | 9 +-
drivers/net/wireless/ath/ath12k/pci.c | 1 +
drivers/net/wireless/ath/ath12k/qmi.c | 123 +++++--
drivers/net/wireless/ath/ath12k/qmi.h | 20 ++
9 files changed, 658 insertions(+), 150 deletions(-)
base-commit: 3b2ab397d31f926523f2781d7f0a14a387415bf4
--
2.39.5
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/7] wifi: ath12k: move ATH12K_FLAG_REGISTERED handling to ath12k_mac_register()
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
@ 2024-12-04 16:32 ` Kalle Valo
2024-12-04 16:32 ` [PATCH 2/7] wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp Kalle Valo
` (6 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Kalle Valo @ 2024-12-04 16:32 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
When hardware device group abstraction is introduced, a group abstraction is
registered to mac80211 rather than a particular single device. So we cannot
set the device registered when the QMI firmware ready event is received, only
after all the devices in group have received the event. To do that set and
unset ATH12K_FLAG_REGISTERED flag inside ath12k_mac_register() and
ath12k_mac_unregister() respectively.
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
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
---
drivers/net/wireless/ath/ath12k/mac.c | 4 ++++
drivers/net/wireless/ath/ath12k/qmi.c | 4 +---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 129607ac6c1a..1180070278da 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -10839,6 +10839,8 @@ int ath12k_mac_register(struct ath12k_base *ab)
goto err;
}
+ set_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags);
+
return 0;
err:
@@ -10858,6 +10860,8 @@ void ath12k_mac_unregister(struct ath12k_base *ab)
struct ath12k_hw *ah;
int i;
+ clear_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags);
+
for (i = ath12k_get_num_hw(ab) - 1; i >= 0; i--) {
ah = ath12k_ab_to_ah(ab, i);
if (!ah)
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index 77d8ee14bf33..20382b751829 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -3349,11 +3349,9 @@ static void ath12k_qmi_driver_event_work(struct work_struct *work)
&ab->dev_flags);
clear_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags);
ret = ath12k_core_qmi_firmware_ready(ab);
- if (!ret) {
+ if (!ret)
set_bit(ATH12K_FLAG_QMI_FW_READY_COMPLETE,
&ab->dev_flags);
- set_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags);
- }
break;
default:
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/7] wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
2024-12-04 16:32 ` [PATCH 1/7] wifi: ath12k: move ATH12K_FLAG_REGISTERED handling to ath12k_mac_register() Kalle Valo
@ 2024-12-04 16:32 ` Kalle Valo
2024-12-05 22:32 ` Jeff Johnson
2024-12-04 16:32 ` [PATCH 3/7] wifi: ath12k: introduce device group abstraction Kalle Valo
` (5 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: Kalle Valo @ 2024-12-04 16:32 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
At present, the mlo_capable_flags in ath12k_base is used to indicate whether
the chip supports inter (QCN9274) or intra (WCN7850) chip MLO. However, it’s
possible that the chip supports neither, especially with older firmware
versions. Additionally, if intra chip MLO is not supported, inter chip MLO will
also be non-functional. Therefore, having two separate flags for this is
unnecessary.
Therefore, rename this flag to single_chip_mlo_supp. At the same time convert
it into a bool data type. Also, get rid of the enums defined earlier.
For the QCN9274 family of chipsets, this will be set only when firmware
advertises the support during the QMI exchange.
For the WCN7850 family of chipsets, since the event is not supported,
assumption is made that single chip MLO is supported.
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
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
---
drivers/net/wireless/ath/ath12k/core.c | 2 +-
drivers/net/wireless/ath/ath12k/core.h | 23 ++---------------------
drivers/net/wireless/ath/ath12k/qmi.c | 13 +++++--------
3 files changed, 8 insertions(+), 30 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 4da147f7bfac..568c9b6e2c1c 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1325,7 +1325,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
ab->dev = dev;
ab->hif.bus = bus;
ab->qmi.num_radios = U8_MAX;
- ab->mlo_capable_flags = ATH12K_INTRA_DEVICE_MLO_SUPPORT;
+ ab->single_chip_mlo_supp = false;
/* Device index used to identify the devices in a group.
*
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 9ddced140056..d93ba844f61d 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -816,21 +816,6 @@ struct ath12k_soc_dp_stats {
struct ath12k_soc_dp_tx_err_stats tx_err;
};
-/**
- * enum ath12k_link_capable_flags - link capable flags
- *
- * Single/Multi link capability information
- *
- * @ATH12K_INTRA_DEVICE_MLO_SUPPORT: SLO/MLO form between the radio, where all
- * the links (radios) present within a device.
- * @ATH12K_INTER_DEVICE_MLO_SUPPORT: SLO/MLO form between the radio, where all
- * the links (radios) present across the devices.
- */
-enum ath12k_link_capable_flags {
- ATH12K_INTRA_DEVICE_MLO_SUPPORT = BIT(0),
- ATH12K_INTER_DEVICE_MLO_SUPPORT = BIT(1),
-};
-
/* Master structure to hold the hw data which may be used in core module */
struct ath12k_base {
enum ath12k_hw_rev hw_rev;
@@ -996,12 +981,8 @@ struct ath12k_base {
const struct hal_rx_ops *hal_rx_ops;
- /* mlo_capable_flags denotes the single/multi link operation
- * capabilities of the Device.
- *
- * See enum ath12k_link_capable_flags
- */
- u8 mlo_capable_flags;
+ /* Denotes the whether MLO is possible within the chip */
+ bool single_chip_mlo_supp;
struct completion restart_completed;
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index 20382b751829..efcf2dfac4ac 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -2023,14 +2023,14 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
u8 hw_link_id = 0;
int i;
- if (!(ab->mlo_capable_flags & ATH12K_INTRA_DEVICE_MLO_SUPPORT)) {
+ if (!ab->single_chip_mlo_supp) {
ath12k_dbg(ab, ATH12K_DBG_QMI,
"intra device MLO is disabled hence skip QMI MLO cap");
return;
}
if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) {
- ab->mlo_capable_flags = 0;
+ ab->single_chip_mlo_supp = false;
ath12k_dbg(ab, ATH12K_DBG_QMI,
"skip QMI MLO cap due to invalid num_radio %d\n",
@@ -2176,12 +2176,9 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
goto out;
}
- if (resp.single_chip_mlo_support_valid) {
- if (resp.single_chip_mlo_support)
- ab->mlo_capable_flags |= ATH12K_INTRA_DEVICE_MLO_SUPPORT;
- else
- ab->mlo_capable_flags &= ~ATH12K_INTRA_DEVICE_MLO_SUPPORT;
- }
+ if (resp.single_chip_mlo_support_valid &&
+ resp.single_chip_mlo_support)
+ ab->single_chip_mlo_supp = true;
if (!resp.num_phy_valid) {
ret = -ENODATA;
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/7] wifi: ath12k: introduce device group abstraction
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
2024-12-04 16:32 ` [PATCH 1/7] wifi: ath12k: move ATH12K_FLAG_REGISTERED handling to ath12k_mac_register() Kalle Valo
2024-12-04 16:32 ` [PATCH 2/7] wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp Kalle Valo
@ 2024-12-04 16:32 ` Kalle Valo
2024-12-04 16:32 ` [PATCH 4/7] wifi: ath12k: refactor core start based on hardware group Kalle Valo
` (4 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Kalle Valo @ 2024-12-04 16:32 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Currently, single device is probed, and once firmware is ready, the device
is registered to mac80211. For Multi-Link Operation, different bands of
different devices or same device are part of a single wiphy and for
this, hardware device group abstraction is needed.
Hardware device group abstraction - when there are multiple devices (with
single radio or dual radio) that are connected by any means of interface
for communicating between them, then these devices can be combined
together as a single group using a group id to form a group abstraction
and register to mac80211.
The grouping information of multiple devices would be based on device tree
during device probe (will be implemented in future patches). If no such
information is available, then a single device will be part of group abstraction
and registered to mac80211, else multiple devices advertised in device tree are
combined and then registered to mac80211.
For device group abstraction, a base structure ath12k_hw_group (ag) and the
helpers are implemented. These helpers are used during device probe and mapping
the group to the devices involved.
An illustration of how multiple devices might be combined together in
future based on group id:
+------------------------------------------------------------------------+
| +-------------------------------------+ +-------------------+ |
| | +-----------+ | | +-----------+ | | +-----------+ | |
| | | ar (2GHz) | | | | ar (5GHz) | | | | ar (6GHz) | | |
| | +-----------+ | | +-----------+ | | +-----------+ | |
| | ath12k_base (ab) | | ath12k_base (ab) | |
| | (Dual band device) | | | |
| +-------------------------------------+ +-------------------+ |
| ath12k_hw_group (ag) based on group id |
+------------------------------------------------------------------------+
In the above representation, two devices are combined into single group
based on group id.
Add base code changes where single device would be part of a group with an
invalid group id forming an group abstraction. Multi device grouping will
be introduced in future.
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
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Co-developed-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
---
drivers/net/wireless/ath/ath12k/core.c | 237 +++++++++++++++++++++++--
drivers/net/wireless/ath/ath12k/core.h | 17 ++
drivers/net/wireless/ath/ath12k/pci.c | 1 +
3 files changed, 239 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 568c9b6e2c1c..41e3454b60f5 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -22,6 +22,11 @@ unsigned int ath12k_debug_mask;
module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
MODULE_PARM_DESC(debug_mask, "Debugging mask");
+/* protected with ath12k_hw_group_mutex */
+static struct list_head ath12k_hw_group_list = LIST_HEAD_INIT(ath12k_hw_group_list);
+
+static DEFINE_MUTEX(ath12k_hw_group_mutex);
+
static int ath12k_core_rfkill_config(struct ath12k_base *ab)
{
struct ath12k *ar;
@@ -1244,27 +1249,112 @@ static void ath12k_core_panic_notifier_unregister(struct ath12k_base *ab)
&ab->panic_nb);
}
-int ath12k_core_init(struct ath12k_base *ab)
+static inline
+bool ath12k_core_hw_group_create_ready(struct ath12k_hw_group *ag)
{
- int ret;
+ lockdep_assert_held(&ag->mutex);
- ret = ath12k_core_soc_create(ab);
- if (ret) {
- ath12k_err(ab, "failed to create soc core: %d\n", ret);
- return ret;
- }
-
- ret = ath12k_core_panic_notifier_register(ab);
- if (ret)
- ath12k_warn(ab, "failed to register panic handler: %d\n", ret);
-
- return 0;
+ return (ag->num_probed == ag->num_devices);
}
-void ath12k_core_deinit(struct ath12k_base *ab)
+static struct ath12k_hw_group *ath12k_core_hw_group_alloc(u8 id, u8 max_devices)
{
- ath12k_core_panic_notifier_unregister(ab);
+ struct ath12k_hw_group *ag;
+ lockdep_assert_held(&ath12k_hw_group_mutex);
+
+ ag = kzalloc(sizeof(*ag), GFP_KERNEL);
+ if (!ag)
+ return NULL;
+
+ ag->id = id;
+ ag->num_devices = max_devices;
+ list_add(&ag->list, &ath12k_hw_group_list);
+ mutex_init(&ag->mutex);
+
+ return ag;
+}
+
+static void ath12k_core_hw_group_free(struct ath12k_hw_group *ag)
+{
+ mutex_lock(&ath12k_hw_group_mutex);
+
+ list_del(&ag->list);
+ kfree(ag);
+
+ mutex_unlock(&ath12k_hw_group_mutex);
+}
+
+static struct ath12k_hw_group *ath12k_core_hw_group_assign(struct ath12k_base *ab)
+{
+ u32 group_id = ATH12K_INVALID_GROUP_ID;
+ struct ath12k_hw_group *ag;
+
+ lockdep_assert_held(&ath12k_hw_group_mutex);
+
+ /* The grouping of multiple devices will be done based on device tree file.
+ * TODO: device tree file parsing to know about the devices involved in group.
+ *
+ * The platforms that do not have any valid group information would have each
+ * device to be part of its own invalid group.
+ *
+ * Currently, we are not parsing any device tree information and hence, grouping
+ * of multiple devices is not involved. Thus, single device is added to device
+ * group.
+ */
+ ag = ath12k_core_hw_group_alloc(group_id, 1);
+ if (!ag) {
+ ath12k_warn(ab, "unable to create new hw group\n");
+ return NULL;
+ }
+
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "single device added to hardware group\n");
+
+ ab->device_id = ag->num_probed++;
+ ag->ab[ab->device_id] = ab;
+ ab->ag = ag;
+
+ return ag;
+}
+
+void ath12k_core_hw_group_unassign(struct ath12k_base *ab)
+{
+ struct ath12k_hw_group *ag = ab->ag;
+ u8 device_id = ab->device_id;
+ int num_probed;
+
+ if (!ag)
+ return;
+
+ mutex_lock(&ag->mutex);
+
+ if (WARN_ON(device_id >= ag->num_devices)) {
+ mutex_unlock(&ag->mutex);
+ return;
+ }
+
+ if (WARN_ON(ag->ab[device_id] != ab)) {
+ mutex_unlock(&ag->mutex);
+ return;
+ }
+
+ ag->ab[device_id] = NULL;
+ ab->ag = NULL;
+ ab->device_id = ATH12K_INVALID_DEVICE_ID;
+
+ if (ag->num_probed)
+ ag->num_probed--;
+
+ num_probed = ag->num_probed;
+
+ mutex_unlock(&ag->mutex);
+
+ if (!num_probed)
+ ath12k_core_hw_group_free(ag);
+}
+
+static void ath12k_core_device_cleanup(struct ath12k_base *ab)
+{
mutex_lock(&ab->core_lock);
ath12k_hif_irq_disable(ab);
@@ -1274,8 +1364,123 @@ void ath12k_core_deinit(struct ath12k_base *ab)
ath12k_core_stop(ab);
mutex_unlock(&ab->core_lock);
+}
- ath12k_core_soc_destroy(ab);
+static void ath12k_core_hw_group_destroy(struct ath12k_hw_group *ag)
+{
+ struct ath12k_base *ab;
+ int i;
+
+ if (WARN_ON(!ag))
+ return;
+
+ for (i = 0; i < ag->num_devices; i++) {
+ ab = ag->ab[i];
+ if (!ab)
+ continue;
+
+ ath12k_core_soc_destroy(ab);
+ }
+}
+
+static void ath12k_core_hw_group_cleanup(struct ath12k_hw_group *ag)
+{
+ struct ath12k_base *ab;
+ int i;
+
+ if (!ag)
+ return;
+
+ mutex_lock(&ag->mutex);
+
+ for (i = 0; i < ag->num_devices; i++) {
+ ab = ag->ab[i];
+ if (!ab)
+ continue;
+
+ ath12k_core_device_cleanup(ab);
+ }
+
+ mutex_unlock(&ag->mutex);
+}
+
+static int ath12k_core_hw_group_create(struct ath12k_hw_group *ag)
+{
+ struct ath12k_base *ab;
+ int i, ret;
+
+ lockdep_assert_held(&ag->mutex);
+
+ for (i = 0; i < ag->num_devices; i++) {
+ ab = ag->ab[i];
+ if (!ab)
+ continue;
+
+ mutex_lock(&ab->core_lock);
+
+ ret = ath12k_core_soc_create(ab);
+ if (ret) {
+ mutex_unlock(&ab->core_lock);
+ ath12k_err(ab, "failed to create soc core: %d\n", ret);
+ return ret;
+ }
+
+ mutex_unlock(&ab->core_lock);
+ }
+
+ return 0;
+}
+
+int ath12k_core_init(struct ath12k_base *ab)
+{
+ struct ath12k_hw_group *ag;
+ int ret;
+
+ ret = ath12k_core_panic_notifier_register(ab);
+ if (ret)
+ ath12k_warn(ab, "failed to register panic handler: %d\n", ret);
+
+ mutex_lock(&ath12k_hw_group_mutex);
+
+ ag = ath12k_core_hw_group_assign(ab);
+ if (!ag) {
+ mutex_unlock(&ath12k_hw_group_mutex);
+ ath12k_warn(ab, "unable to get hw group\n");
+ return -ENODEV;
+ }
+
+ mutex_unlock(&ath12k_hw_group_mutex);
+
+ mutex_lock(&ag->mutex);
+
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "num devices %d num probed %d\n",
+ ag->num_devices, ag->num_probed);
+
+ if (ath12k_core_hw_group_create_ready(ag)) {
+ ret = ath12k_core_hw_group_create(ag);
+ if (ret) {
+ mutex_unlock(&ag->mutex);
+ ath12k_warn(ab, "unable to create hw group\n");
+ goto err;
+ }
+ }
+
+ mutex_unlock(&ag->mutex);
+
+ return 0;
+
+err:
+ ath12k_core_hw_group_destroy(ab->ag);
+ ath12k_core_hw_group_unassign(ab);
+ return ret;
+}
+
+void ath12k_core_deinit(struct ath12k_base *ab)
+{
+ ath12k_core_panic_notifier_unregister(ab);
+ ath12k_core_hw_group_cleanup(ab->ag);
+ ath12k_core_hw_group_destroy(ab->ag);
+ ath12k_core_hw_group_unassign(ab);
}
void ath12k_core_free(struct ath12k_base *ab)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d93ba844f61d..dca4b9a3538f 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -816,6 +816,20 @@ struct ath12k_soc_dp_stats {
struct ath12k_soc_dp_tx_err_stats tx_err;
};
+/* Holds info on the group of devices that are registered as a single
+ * wiphy, protected with struct ath12k_hw_group::mutex.
+ */
+struct ath12k_hw_group {
+ struct list_head list;
+ u8 id;
+ u8 num_devices;
+ u8 num_probed;
+ struct ath12k_base *ab[ATH12K_MAX_SOCS];
+
+ /* protects access to this struct */
+ struct mutex mutex;
+};
+
/* Master structure to hold the hw data which may be used in core module */
struct ath12k_base {
enum ath12k_hw_rev hw_rev;
@@ -1005,6 +1019,8 @@ struct ath12k_base {
struct notifier_block panic_nb;
+ struct ath12k_hw_group *ag;
+
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
};
@@ -1035,6 +1051,7 @@ int ath12k_core_resume_early(struct ath12k_base *ab);
int ath12k_core_resume(struct ath12k_base *ab);
int ath12k_core_suspend(struct ath12k_base *ab);
int ath12k_core_suspend_late(struct ath12k_base *ab);
+void ath12k_core_hw_group_unassign(struct ath12k_base *ab);
const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
const char *filename);
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 8dbc7377ae7c..06cff3849ab8 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1725,6 +1725,7 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
if (test_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath12k_pci_power_down(ab, false);
ath12k_qmi_deinit_service(ab);
+ ath12k_core_hw_group_unassign(ab);
goto qmi_fail;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/7] wifi: ath12k: refactor core start based on hardware group
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
` (2 preceding siblings ...)
2024-12-04 16:32 ` [PATCH 3/7] wifi: ath12k: introduce device group abstraction Kalle Valo
@ 2024-12-04 16:32 ` Kalle Valo
2024-12-04 16:32 ` [PATCH 5/7] wifi: ath12k: move struct ath12k_hw from per device to group Kalle Valo
` (3 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Kalle Valo @ 2024-12-04 16:32 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Currently, mac allocate/register and core_pdev_create are initiated immediately
when QMI firmware ready event is received for a particular device. With
hardware device group abstraction, QMI firmware ready event can be received
simultaneously for different devices in the group and so, it should not be
registered immediately rather it has to be deferred until all devices in the
group has received QMI firmware ready.
To handle this, refactor the code of core start to have registering within
ath12k_core_hw_group_start() and unregistering in ath12k_core_hw_group_stop().
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
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Co-developed-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
---
drivers/net/wireless/ath/ath12k/core.c | 199 ++++++++++++++++++-------
drivers/net/wireless/ath/ath12k/core.h | 22 +++
drivers/net/wireless/ath/ath12k/qmi.c | 4 +-
3 files changed, 172 insertions(+), 53 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 41e3454b60f5..dea2c53bcc07 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -604,6 +604,8 @@ u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab)
static void ath12k_core_stop(struct ath12k_base *ab)
{
+ ath12k_core_stopped(ab);
+
if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
ath12k_qmi_firmware_stop(ab);
@@ -743,6 +745,8 @@ static int ath12k_core_start(struct ath12k_base *ab,
{
int ret;
+ lockdep_assert_held(&ab->core_lock);
+
ret = ath12k_wmi_attach(ab);
if (ret) {
ath12k_err(ab, "failed to attach wmi: %d\n", ret);
@@ -836,6 +840,10 @@ static int ath12k_core_start(struct ath12k_base *ab,
/* ACPI is optional so continue in case of an error */
ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi failed: %d\n", ret);
+ if (!test_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags))
+ /* Indicate the core start in the appropriate group */
+ ath12k_core_started(ab);
+
return 0;
err_reo_cleanup:
@@ -847,6 +855,96 @@ static int ath12k_core_start(struct ath12k_base *ab,
return ret;
}
+static void ath12k_core_device_cleanup(struct ath12k_base *ab)
+{
+ mutex_lock(&ab->core_lock);
+
+ ath12k_hif_irq_disable(ab);
+ ath12k_core_pdev_destroy(ab);
+ ath12k_mac_unregister(ab);
+ ath12k_mac_destroy(ab);
+
+ mutex_unlock(&ab->core_lock);
+}
+
+static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
+{
+ struct ath12k_base *ab;
+ int i;
+
+ lockdep_assert_held(&ag->mutex);
+
+ for (i = ag->num_devices - 1; i >= 0; i--) {
+ ab = ag->ab[i];
+ if (!ab)
+ continue;
+ ath12k_core_device_cleanup(ab);
+ }
+}
+
+static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
+{
+ struct ath12k_base *ab;
+ int ret, i;
+
+ lockdep_assert_held(&ag->mutex);
+
+ for (i = 0; i < ag->num_devices; i++) {
+ ab = ag->ab[i];
+ if (!ab)
+ continue;
+
+ mutex_lock(&ab->core_lock);
+
+ /* Check if already registered or not, since same flow
+ * execute for HW restart case.
+ */
+ if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
+ goto core_pdev_create;
+
+ ret = ath12k_mac_allocate(ab);
+ if (ret) {
+ ath12k_err(ab, "failed to create new hw device with mac80211 :%d\n",
+ ret);
+ mutex_unlock(&ab->core_lock);
+ return ret;
+ }
+
+ ret = ath12k_mac_register(ab);
+ if (ret) {
+ ath12k_err(ab, "failed to register radio with mac80211: %d\n",
+ ret);
+ mutex_unlock(&ab->core_lock);
+ goto err;
+ }
+
+core_pdev_create:
+ ret = ath12k_core_pdev_create(ab);
+ if (ret) {
+ ath12k_err(ab, "failed to create pdev core %d\n", ret);
+ mutex_unlock(&ab->core_lock);
+ goto err;
+ }
+
+ ath12k_hif_irq_enable(ab);
+
+ ret = ath12k_core_rfkill_config(ab);
+ if (ret && ret != -EOPNOTSUPP) {
+ mutex_unlock(&ab->core_lock);
+ goto err;
+ }
+
+ mutex_unlock(&ab->core_lock);
+ }
+
+ return 0;
+
+err:
+ ath12k_core_hw_group_stop(ag);
+
+ return ret;
+}
+
static int ath12k_core_start_firmware(struct ath12k_base *ab,
enum ath12k_firmware_mode mode)
{
@@ -864,9 +962,18 @@ static int ath12k_core_start_firmware(struct ath12k_base *ab,
return ret;
}
+static inline
+bool ath12k_core_hw_group_start_ready(struct ath12k_hw_group *ag)
+{
+ lockdep_assert_held(&ag->mutex);
+
+ return (ag->num_started == ag->num_devices);
+}
+
int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
{
- int ret;
+ struct ath12k_hw_group *ag = ath12k_ab_to_ag(ab);
+ int ret, i;
ret = ath12k_core_start_firmware(ab, ATH12K_FIRMWARE_MODE_NORMAL);
if (ret) {
@@ -886,59 +993,50 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
goto err_firmware_stop;
}
+ mutex_lock(&ag->mutex);
mutex_lock(&ab->core_lock);
+
ret = ath12k_core_start(ab, ATH12K_FIRMWARE_MODE_NORMAL);
if (ret) {
ath12k_err(ab, "failed to start core: %d\n", ret);
goto err_dp_free;
}
- ret = ath12k_mac_allocate(ab);
- if (ret) {
- ath12k_err(ab, "failed to create new hw device with mac80211 :%d\n",
- ret);
- goto err_core_stop;
- }
-
- ret = ath12k_mac_register(ab);
- if (ret) {
- ath12k_err(ab, "failed register the radio with mac80211: %d\n", ret);
- goto err_mac_destroy;
- }
-
- ret = ath12k_core_pdev_create(ab);
- if (ret) {
- ath12k_err(ab, "failed to create pdev core: %d\n", ret);
- goto err_mac_unregister;
- }
-
- ath12k_hif_irq_enable(ab);
-
- ret = ath12k_core_rfkill_config(ab);
- if (ret && ret != -EOPNOTSUPP) {
- ath12k_err(ab, "failed to config rfkill: %d\n", ret);
- goto err_hif_irq_disable;
- }
-
mutex_unlock(&ab->core_lock);
+ if (ath12k_core_hw_group_start_ready(ag)) {
+ ret = ath12k_core_hw_group_start(ag);
+ if (ret) {
+ ath12k_warn(ab, "unable to start hw group\n");
+ goto err_core_stop;
+ }
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "group %d started\n", ag->id);
+ }
+
+ mutex_unlock(&ag->mutex);
+
return 0;
-err_hif_irq_disable:
- ath12k_hif_irq_disable(ab);
- ath12k_core_pdev_destroy(ab);
-err_mac_unregister:
- ath12k_mac_unregister(ab);
-err_mac_destroy:
- ath12k_mac_destroy(ab);
err_core_stop:
- ath12k_core_stop(ab);
+ for (i = ag->num_devices - 1; i >= 0; i--) {
+ ab = ag->ab[i];
+ if (!ab)
+ continue;
+
+ mutex_lock(&ab->core_lock);
+ ath12k_core_stop(ab);
+ mutex_unlock(&ab->core_lock);
+ }
+ goto exit;
+
err_dp_free:
ath12k_dp_free(ab);
mutex_unlock(&ab->core_lock);
err_firmware_stop:
ath12k_qmi_firmware_stop(ab);
+exit:
+ mutex_unlock(&ag->mutex);
return ret;
}
@@ -1135,6 +1233,14 @@ static void ath12k_core_restart(struct work_struct *work)
}
if (ab->is_reset) {
+ if (!test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) {
+ atomic_dec(&ab->reset_count);
+ complete(&ab->reset_complete);
+ ab->is_reset = false;
+ atomic_set(&ab->fail_cont_count, 0);
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset success\n");
+ }
+
for (i = 0; i < ath12k_get_num_hw(ab); i++) {
ah = ath12k_ab_to_ah(ab, i);
ieee80211_restart_hw(ah->hw);
@@ -1319,7 +1425,7 @@ static struct ath12k_hw_group *ath12k_core_hw_group_assign(struct ath12k_base *a
void ath12k_core_hw_group_unassign(struct ath12k_base *ab)
{
- struct ath12k_hw_group *ag = ab->ag;
+ struct ath12k_hw_group *ag = ath12k_ab_to_ag(ab);
u8 device_id = ab->device_id;
int num_probed;
@@ -1353,19 +1459,6 @@ void ath12k_core_hw_group_unassign(struct ath12k_base *ab)
ath12k_core_hw_group_free(ag);
}
-static void ath12k_core_device_cleanup(struct ath12k_base *ab)
-{
- mutex_lock(&ab->core_lock);
-
- ath12k_hif_irq_disable(ab);
- ath12k_core_pdev_destroy(ab);
- ath12k_mac_unregister(ab);
- ath12k_mac_destroy(ab);
- ath12k_core_stop(ab);
-
- mutex_unlock(&ab->core_lock);
-}
-
static void ath12k_core_hw_group_destroy(struct ath12k_hw_group *ag)
{
struct ath12k_base *ab;
@@ -1393,12 +1486,16 @@ static void ath12k_core_hw_group_cleanup(struct ath12k_hw_group *ag)
mutex_lock(&ag->mutex);
+ ath12k_core_hw_group_stop(ag);
+
for (i = 0; i < ag->num_devices; i++) {
ab = ag->ab[i];
if (!ab)
continue;
- ath12k_core_device_cleanup(ab);
+ mutex_lock(&ab->core_lock);
+ ath12k_core_stop(ab);
+ mutex_unlock(&ab->core_lock);
}
mutex_unlock(&ag->mutex);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index dca4b9a3538f..b8b1ee8d3302 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -824,6 +824,8 @@ struct ath12k_hw_group {
u8 id;
u8 num_devices;
u8 num_probed;
+ u8 num_started;
+ unsigned long flags;
struct ath12k_base *ab[ATH12K_MAX_SOCS];
/* protects access to this struct */
@@ -1175,4 +1177,24 @@ static inline int ath12k_get_num_hw(struct ath12k_base *ab)
{
return ab->num_hw;
}
+
+static inline struct ath12k_hw_group *ath12k_ab_to_ag(struct ath12k_base *ab)
+{
+ return ab->ag;
+}
+
+static inline void ath12k_core_started(struct ath12k_base *ab)
+{
+ lockdep_assert_held(&ab->ag->mutex);
+
+ ab->ag->num_started++;
+}
+
+static inline void ath12k_core_stopped(struct ath12k_base *ab)
+{
+ lockdep_assert_held(&ab->ag->mutex);
+
+ ab->ag->num_started--;
+}
+
#endif /* _CORE_H_ */
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index efcf2dfac4ac..8b4d500fe426 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -3321,7 +3321,6 @@ static void ath12k_qmi_driver_event_work(struct work_struct *work)
break;
case ATH12K_QMI_EVENT_SERVER_EXIT:
set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags);
- set_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags);
break;
case ATH12K_QMI_EVENT_REQUEST_MEM:
ret = ath12k_qmi_event_mem_request(qmi);
@@ -3338,13 +3337,14 @@ static void ath12k_qmi_driver_event_work(struct work_struct *work)
if (test_bit(ATH12K_FLAG_QMI_FW_READY_COMPLETE, &ab->dev_flags)) {
if (ab->is_reset)
ath12k_hal_dump_srng_stats(ab);
+
+ set_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags);
queue_work(ab->workqueue, &ab->restart_work);
break;
}
clear_bit(ATH12K_FLAG_CRASH_FLUSH,
&ab->dev_flags);
- clear_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags);
ret = ath12k_core_qmi_firmware_ready(ab);
if (!ret)
set_bit(ATH12K_FLAG_QMI_FW_READY_COMPLETE,
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/7] wifi: ath12k: move struct ath12k_hw from per device to group
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
` (3 preceding siblings ...)
2024-12-04 16:32 ` [PATCH 4/7] wifi: ath12k: refactor core start based on hardware group Kalle Valo
@ 2024-12-04 16:32 ` Kalle Valo
2024-12-10 20:58 ` Kees Bakker
2024-12-04 16:32 ` [PATCH 6/7] wifi: ath12k: send QMI host capability after device group is ready Kalle Valo
` (2 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: Kalle Valo @ 2024-12-04 16:32 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Currently, hardware abstractions (ah) of different radio bands are tightly
coupled to a single device (ab). But, with hardware device group abstraction
(ag), multiple radios across different devices in a group can form different
combinations of hardware abstractions (ah) within the group. Hence, the mapping
between ah to ab can be removed and instead it can be mapped with struct
ath12k_hw_group (ag).
Current mapping between struct ath12k_hw (ah), struct ath12k_base (ab) and struct
ath12k_hw_group (ag):
+------------------------------------------------+
| +-------------------------------------+ |
| | +---------------+ +---------------+ | |
| | |ath12k_hw (ah) | |ath12k_hw (ah) | | |
| | +---------------+ +---------------+ | |
| | | |
| | +-----------+ | +-----------+ | |
| | | ar (2GHz) | | | ar (5GHz) | | |
| | +-----------+ | +-----------+ | |
| | Dual band device-1 (ab) | |
| +-------------------------------------+ |
| ath12k_hw_group (ag) based on group id |
+------------------------------------------------+
After hardware device group abstraction moving ah array out of ab to ag:
+----------------------------------------------+
| +---------------+ +---------------+ |
| |ath12k_hw (ah) | |ath12k_hw (ah) | |
| +---------------+ +---------------+ |
| +-------------------------------------+ |
| | +-----------+ +-----------+ | |
| | | ar (2GHz) | | ar (5GHz) | | |
| | +-----------+ +-----------+ | |
| | Dual band device-1 (ab) | |
| +-------------------------------------+ |
| ath12k_hw_group (ag) based on group id |
+----------------------------------------------+
This decoupling of struct ath12k_hw (ah) from struct ath12k_base (ab) and
mapping it to struct ath12k_hw_group (ag) will help in forming different
combinations of multi-link devices.
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
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
---
drivers/net/wireless/ath/ath12k/core.c | 49 +++++++-------
drivers/net/wireless/ath/ath12k/core.h | 29 +++++----
drivers/net/wireless/ath/ath12k/dp.c | 19 ++----
drivers/net/wireless/ath/ath12k/dp.h | 2 +-
drivers/net/wireless/ath/ath12k/mac.c | 89 ++++++++++++++++++--------
drivers/net/wireless/ath/ath12k/mac.h | 9 +--
6 files changed, 115 insertions(+), 82 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index dea2c53bcc07..bbfa57d097af 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -861,8 +861,6 @@ static void ath12k_core_device_cleanup(struct ath12k_base *ab)
ath12k_hif_irq_disable(ab);
ath12k_core_pdev_destroy(ab);
- ath12k_mac_unregister(ab);
- ath12k_mac_destroy(ab);
mutex_unlock(&ab->core_lock);
}
@@ -874,12 +872,18 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
lockdep_assert_held(&ag->mutex);
+ clear_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
+
+ ath12k_mac_unregister(ag);
+
for (i = ag->num_devices - 1; i >= 0; i--) {
ab = ag->ab[i];
if (!ab)
continue;
ath12k_core_device_cleanup(ab);
}
+
+ ath12k_mac_destroy(ag);
}
static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
@@ -889,6 +893,20 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
lockdep_assert_held(&ag->mutex);
+ if (test_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags))
+ goto core_pdev_create;
+
+ ret = ath12k_mac_allocate(ag);
+ if (WARN_ON(ret))
+ return ret;
+
+ ret = ath12k_mac_register(ag);
+ if (WARN_ON(ret))
+ goto err_mac_destroy;
+
+ set_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
+
+core_pdev_create:
for (i = 0; i < ag->num_devices; i++) {
ab = ag->ab[i];
if (!ab)
@@ -896,29 +914,6 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
mutex_lock(&ab->core_lock);
- /* Check if already registered or not, since same flow
- * execute for HW restart case.
- */
- if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
- goto core_pdev_create;
-
- ret = ath12k_mac_allocate(ab);
- if (ret) {
- ath12k_err(ab, "failed to create new hw device with mac80211 :%d\n",
- ret);
- mutex_unlock(&ab->core_lock);
- return ret;
- }
-
- ret = ath12k_mac_register(ab);
- if (ret) {
- ath12k_err(ab, "failed to register radio with mac80211: %d\n",
- ret);
- mutex_unlock(&ab->core_lock);
- goto err;
- }
-
-core_pdev_create:
ret = ath12k_core_pdev_create(ab);
if (ret) {
ath12k_err(ab, "failed to create pdev core %d\n", ret);
@@ -941,6 +936,10 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
err:
ath12k_core_hw_group_stop(ag);
+ return ret;
+
+err_mac_destroy:
+ ath12k_mac_destroy(ag);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index b8b1ee8d3302..64252d6491cd 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -64,6 +64,7 @@
#define ATH12K_RECOVER_START_TIMEOUT_HZ (20 * HZ)
#define ATH12K_MAX_SOCS 3
+#define ATH12K_GROUP_MAX_RADIO (ATH12K_MAX_SOCS * MAX_RADIOS)
#define ATH12K_INVALID_GROUP_ID 0xFF
#define ATH12K_INVALID_DEVICE_ID 0xFF
@@ -216,6 +217,10 @@ enum ath12k_scan_state {
ATH12K_SCAN_ABORTING,
};
+enum ath12k_hw_group_flags {
+ ATH12K_GROUP_FLAG_REGISTERED,
+};
+
enum ath12k_dev_flags {
ATH12K_CAC_RUNNING,
ATH12K_FLAG_CRASH_FLUSH,
@@ -830,6 +835,15 @@ struct ath12k_hw_group {
/* protects access to this struct */
struct mutex mutex;
+
+ /* Holds information of wiphy (hw) registration.
+ *
+ * In Multi/Single Link Operation case, all pdevs are registered as
+ * a single wiphy. In other (legacy/Non-MLO) cases, each pdev is
+ * registered as separate wiphys.
+ */
+ struct ath12k_hw *ah[ATH12K_GROUP_MAX_RADIO];
+ u8 num_hw;
};
/* Master structure to hold the hw data which may be used in core module */
@@ -895,15 +909,6 @@ struct ath12k_base {
struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS];
- /* Holds information of wiphy (hw) registration.
- *
- * In Multi/Single Link Operation case, all pdevs are registered as
- * a single wiphy. In other (legacy/Non-MLO) cases, each pdev is
- * registered as separate wiphys.
- */
- struct ath12k_hw *ah[MAX_RADIOS];
- u8 num_hw;
-
struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS];
unsigned long long free_vdev_map;
unsigned long long free_vdev_stats_id_map;
@@ -1164,18 +1169,18 @@ static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar)
static inline struct ath12k_hw *ath12k_ab_to_ah(struct ath12k_base *ab, int idx)
{
- return ab->ah[idx];
+ return ab->ag->ah[idx];
}
static inline void ath12k_ab_set_ah(struct ath12k_base *ab, int idx,
struct ath12k_hw *ah)
{
- ab->ah[idx] = ah;
+ ab->ag->ah[idx] = ah;
}
static inline int ath12k_get_num_hw(struct ath12k_base *ab)
{
- return ab->num_hw;
+ return ab->ag->num_hw;
}
static inline struct ath12k_hw_group *ath12k_ab_to_ag(struct ath12k_base *ab)
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index ce823b1c175f..68abe9d4ab45 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -991,21 +991,14 @@ void ath12k_dp_pdev_free(struct ath12k_base *ab)
ath12k_dp_rx_pdev_free(ab, i);
}
-void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab)
+void ath12k_dp_pdev_pre_alloc(struct ath12k *ar)
{
- struct ath12k *ar;
- struct ath12k_pdev_dp *dp;
- int i;
+ struct ath12k_pdev_dp *dp = &ar->dp;
- for (i = 0; i < ab->num_radios; i++) {
- ar = ab->pdevs[i].ar;
- dp = &ar->dp;
- dp->mac_id = i;
- atomic_set(&dp->num_tx_pending, 0);
- init_waitqueue_head(&dp->tx_empty_waitq);
-
- /* TODO: Add any RXDMA setup required per pdev */
- }
+ dp->mac_id = ar->pdev_idx;
+ atomic_set(&dp->num_tx_pending, 0);
+ init_waitqueue_head(&dp->tx_empty_waitq);
+ /* TODO: Add any RXDMA setup required per pdev */
}
bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab)
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index a120b7a8477d..021cd9e8ee1d 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -1806,7 +1806,7 @@ 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);
int ath12k_dp_pdev_alloc(struct ath12k_base *ab);
-void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab);
+void ath12k_dp_pdev_pre_alloc(struct ath12k *ar);
void ath12k_dp_pdev_free(struct ath12k_base *ab);
int ath12k_dp_tx_htt_srng_setup(struct ath12k_base *ab, u32 ring_id,
int mac_id, enum hal_ring_type ring_type);
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 1180070278da..1cf724a530b5 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -10818,19 +10818,13 @@ static void ath12k_mac_setup(struct ath12k *ar)
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
}
-int ath12k_mac_register(struct ath12k_base *ab)
+int ath12k_mac_register(struct ath12k_hw_group *ag)
{
+ struct ath12k_base *ab = ag->ab[0];
struct ath12k_hw *ah;
int i;
int ret;
- if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
- return 0;
-
- /* Initialize channel counters frequency value in hertz */
- ab->cc_freq_hz = 320000;
- ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
-
for (i = 0; i < ath12k_get_num_hw(ab); i++) {
ah = ath12k_ab_to_ah(ab, i);
@@ -10855,8 +10849,9 @@ int ath12k_mac_register(struct ath12k_base *ab)
return ret;
}
-void ath12k_mac_unregister(struct ath12k_base *ab)
+void ath12k_mac_unregister(struct ath12k_hw_group *ag)
{
+ struct ath12k_base *ab = ag->ab[0];
struct ath12k_hw *ah;
int i;
@@ -10876,12 +10871,13 @@ static void ath12k_mac_hw_destroy(struct ath12k_hw *ah)
ieee80211_free_hw(ah->hw);
}
-static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,
+static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,
struct ath12k_pdev_map *pdev_map,
u8 num_pdev_map)
{
struct ieee80211_hw *hw;
struct ath12k *ar;
+ struct ath12k_base *ab;
struct ath12k_pdev *pdev;
struct ath12k_hw *ah;
int i;
@@ -10913,23 +10909,30 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,
pdev->ar = ar;
ath12k_mac_setup(ar);
+ ath12k_dp_pdev_pre_alloc(ar);
}
return ah;
}
-void ath12k_mac_destroy(struct ath12k_base *ab)
+void ath12k_mac_destroy(struct ath12k_hw_group *ag)
{
struct ath12k_pdev *pdev;
+ struct ath12k_base *ab = ag->ab[0];
+ int i, j;
struct ath12k_hw *ah;
- int i;
- for (i = 0; i < ab->num_radios; i++) {
- pdev = &ab->pdevs[i];
- if (!pdev->ar)
+ for (i = 0; i < ag->num_devices; i++) {
+ ab = ag->ab[i];
+ if (!ab)
continue;
- pdev->ar = NULL;
+ for (j = 0; j < ab->num_radios; j++) {
+ pdev = &ab->pdevs[j];
+ if (!pdev->ar)
+ continue;
+ pdev->ar = NULL;
+ }
}
for (i = 0; i < ath12k_get_num_hw(ab); i++) {
@@ -10942,26 +10945,59 @@ void ath12k_mac_destroy(struct ath12k_base *ab)
}
}
-int ath12k_mac_allocate(struct ath12k_base *ab)
+static void ath12k_mac_set_device_defaults(struct ath12k_base *ab)
{
+ /* Initialize channel counters frequency value in hertz */
+ ab->cc_freq_hz = 320000;
+ ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
+}
+
+int ath12k_mac_allocate(struct ath12k_hw_group *ag)
+{
+ struct ath12k_pdev_map pdev_map[ATH12K_GROUP_MAX_RADIO];
+ int mac_id, device_id, total_radio, num_hw;
+ struct ath12k_base *ab;
struct ath12k_hw *ah;
- struct ath12k_pdev_map pdev_map[MAX_RADIOS];
int ret, i, j;
u8 radio_per_hw;
- if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
- return 0;
+ total_radio = 0;
+ for (i = 0; i < ag->num_devices; i++)
+ total_radio += ag->ab[i]->num_radios;
- ab->num_hw = ab->num_radios;
+ /* All pdev get combined and register as single wiphy based on
+ * hardware group which participate in multi-link operation else
+ * each pdev get register separately.
+ *
+ * Currently, registering as single pdevs.
+ */
radio_per_hw = 1;
+ num_hw = total_radio / radio_per_hw;
- for (i = 0; i < ath12k_get_num_hw(ab); i++) {
+ if (WARN_ON(num_hw >= ATH12K_GROUP_MAX_RADIO))
+ return -ENOSPC;
+
+ ag->num_hw = 0;
+ device_id = 0;
+ mac_id = 0;
+ for (i = 0; i < num_hw; i++) {
for (j = 0; j < radio_per_hw; j++) {
+ ab = ag->ab[device_id];
pdev_map[j].ab = ab;
- pdev_map[j].pdev_idx = (i * radio_per_hw) + j;
+ pdev_map[j].pdev_idx = mac_id;
+ mac_id++;
+
+ /* If mac_id falls beyond the current device MACs then
+ * move to next device
+ */
+ if (mac_id >= ab->num_radios) {
+ mac_id = 0;
+ device_id++;
+ ath12k_mac_set_device_defaults(ab);
+ }
}
- ah = ath12k_mac_hw_allocate(ab, pdev_map, radio_per_hw);
+ ah = ath12k_mac_hw_allocate(ag, pdev_map, radio_per_hw);
if (!ah) {
ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n",
i);
@@ -10971,11 +11007,10 @@ int ath12k_mac_allocate(struct ath12k_base *ab)
ah->dev = ab->dev;
- ath12k_ab_set_ah(ab, i, ah);
+ ag->ah[i] = ah;
+ ag->num_hw++;
}
- ath12k_dp_pdev_pre_alloc(ab);
-
return 0;
err:
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index abdc9a6c0740..ccfc215d83ff 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -14,6 +14,7 @@
struct ath12k;
struct ath12k_base;
struct ath12k_hw;
+struct ath12k_hw_group;
struct ath12k_pdev_map;
struct ath12k_generic_iter {
@@ -60,10 +61,10 @@ enum ath12k_supported_bw {
extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;
-void ath12k_mac_destroy(struct ath12k_base *ab);
-void ath12k_mac_unregister(struct ath12k_base *ab);
-int ath12k_mac_register(struct ath12k_base *ab);
-int ath12k_mac_allocate(struct ath12k_base *ab);
+void ath12k_mac_destroy(struct ath12k_hw_group *ag);
+void ath12k_mac_unregister(struct ath12k_hw_group *ag);
+int ath12k_mac_register(struct ath12k_hw_group *ag);
+int ath12k_mac_allocate(struct ath12k_hw_group *ag);
int ath12k_mac_hw_ratecode_to_legacy_rate(u8 hw_rc, u8 preamble, u8 *rateidx,
u16 *rate);
u8 ath12k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 6/7] wifi: ath12k: send QMI host capability after device group is ready
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
` (4 preceding siblings ...)
2024-12-04 16:32 ` [PATCH 5/7] wifi: ath12k: move struct ath12k_hw from per device to group Kalle Valo
@ 2024-12-04 16:32 ` Kalle Valo
2024-12-04 16:32 ` [PATCH 7/7] wifi: ath12k: introduce mlo_capable flag for device group Kalle Valo
2024-12-06 15:42 ` [PATCH 0/7] wifi: ath12k: MLO support part 6 Jeff Johnson
7 siblings, 0 replies; 13+ messages in thread
From: Kalle Valo @ 2024-12-04 16:32 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
QMI host capability has the information regarding MLO parameters such as
device_id, MLO capability, group id and the information of each devices
involved in the group and sent immediately on QMI server arrive event.
Currently, only one device is involved in the group and hence, single
device information is sent as part of MLO capability of host.
But, in future when multi device group abstraction is introduced, host
should send all the device information involved in the group as part
of QMI MLO host capability rather than single device. Hence, sending
QMI host capability immediately on server arrive of a device might not
be ideal for multi device group abstraction as the details of other
devices in the group would not be available.
Hence, once QMI server arrive event is received, request for QMI PHY
capabilities of device, and defer the host capability send for that device.
After QMI PHY capability is received for all the devices in the group
trigger the host capability event for the deferred devices in the group.
Hence, add changes to defer the QMI host capability event until the device
group is ready and then resume the QMI exchange for all the device with
host 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
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
---
drivers/net/wireless/ath/ath12k/core.c | 21 ++++++
drivers/net/wireless/ath/ath12k/qmi.c | 98 ++++++++++++++++++++++++--
drivers/net/wireless/ath/ath12k/qmi.h | 20 ++++++
3 files changed, 134 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index bbfa57d097af..18b29515c6ae 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -969,6 +969,25 @@ bool ath12k_core_hw_group_start_ready(struct ath12k_hw_group *ag)
return (ag->num_started == ag->num_devices);
}
+static void ath12k_core_trigger_partner(struct ath12k_base *ab)
+{
+ struct ath12k_hw_group *ag = ab->ag;
+ struct ath12k_base *partner_ab;
+ bool found = false;
+ int i;
+
+ for (i = 0; i < ag->num_devices; i++) {
+ partner_ab = ag->ab[i];
+ if (!partner_ab)
+ continue;
+
+ if (found)
+ ath12k_qmi_trigger_host_cap(partner_ab);
+
+ found = (partner_ab == ab);
+ }
+}
+
int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
{
struct ath12k_hw_group *ag = ath12k_ab_to_ag(ab);
@@ -1010,6 +1029,8 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
goto err_core_stop;
}
ath12k_dbg(ab, ATH12K_DBG_BOOT, "group %d started\n", ag->id);
+ } else {
+ ath12k_core_trigger_partner(ab);
}
mutex_unlock(&ag->mutex);
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index 8b4d500fe426..2591d132a3fc 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -3088,11 +3088,69 @@ ath12k_qmi_driver_event_post(struct ath12k_qmi *qmi,
return 0;
}
+void ath12k_qmi_trigger_host_cap(struct ath12k_base *ab)
+{
+ struct ath12k_qmi *qmi = &ab->qmi;
+
+ spin_lock(&qmi->event_lock);
+
+ if (ath12k_qmi_get_event_block(qmi))
+ ath12k_qmi_set_event_block(qmi, false);
+
+ spin_unlock(&qmi->event_lock);
+
+ ath12k_dbg(ab, ATH12K_DBG_QMI, "trigger host cap for device id %d\n",
+ ab->device_id);
+
+ ath12k_qmi_driver_event_post(qmi, ATH12K_QMI_EVENT_HOST_CAP, NULL);
+}
+
+static bool ath12k_qmi_hw_group_host_cap_ready(struct ath12k_hw_group *ag)
+{
+ struct ath12k_base *ab;
+ int i;
+
+ for (i = 0; i < ag->num_devices; i++) {
+ ab = ag->ab[i];
+
+ if (!(ab && ab->qmi.num_radios != U8_MAX))
+ return false;
+ }
+
+ return true;
+}
+
+static struct ath12k_base *ath12k_qmi_hw_group_find_blocked(struct ath12k_hw_group *ag)
+{
+ struct ath12k_base *ab;
+ int i;
+
+ lockdep_assert_held(&ag->mutex);
+
+ for (i = 0; i < ag->num_devices; i++) {
+ ab = ag->ab[i];
+ if (!ab)
+ continue;
+
+ spin_lock(&ab->qmi.event_lock);
+
+ if (ath12k_qmi_get_event_block(&ab->qmi)) {
+ spin_unlock(&ab->qmi.event_lock);
+ return ab;
+ }
+
+ spin_unlock(&ab->qmi.event_lock);
+ }
+
+ return NULL;
+}
+
/* clang stack usage explodes if this is inlined */
static noinline_for_stack
int ath12k_qmi_event_server_arrive(struct ath12k_qmi *qmi)
{
- struct ath12k_base *ab = qmi->ab;
+ struct ath12k_base *ab = qmi->ab, *block_ab;
+ struct ath12k_hw_group *ag = ab->ag;
int ret;
ath12k_qmi_phy_cap_send(ab);
@@ -3103,12 +3161,22 @@ int ath12k_qmi_event_server_arrive(struct ath12k_qmi *qmi)
return ret;
}
- ret = ath12k_qmi_host_cap_send(ab);
- if (ret < 0) {
- ath12k_warn(ab, "qmi failed to send host cap QMI:%d\n", ret);
- return ret;
+ spin_lock(&qmi->event_lock);
+
+ ath12k_qmi_set_event_block(qmi, true);
+
+ spin_unlock(&qmi->event_lock);
+
+ mutex_lock(&ag->mutex);
+
+ if (ath12k_qmi_hw_group_host_cap_ready(ag)) {
+ block_ab = ath12k_qmi_hw_group_find_blocked(ag);
+ if (block_ab)
+ ath12k_qmi_trigger_host_cap(block_ab);
}
+ mutex_unlock(&ag->mutex);
+
return ret;
}
@@ -3295,6 +3363,21 @@ static const struct qmi_ops ath12k_qmi_ops = {
.del_server = ath12k_qmi_ops_del_server,
};
+static int ath12k_qmi_event_host_cap(struct ath12k_qmi *qmi)
+{
+ struct ath12k_base *ab = qmi->ab;
+ int ret;
+
+ ret = ath12k_qmi_host_cap_send(ab);
+ if (ret < 0) {
+ ath12k_warn(ab, "failed to send qmi host cap for device id %d: %d\n",
+ ab->device_id, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
static void ath12k_qmi_driver_event_work(struct work_struct *work)
{
struct ath12k_qmi *qmi = container_of(work, struct ath12k_qmi,
@@ -3351,6 +3434,11 @@ static void ath12k_qmi_driver_event_work(struct work_struct *work)
&ab->dev_flags);
break;
+ case ATH12K_QMI_EVENT_HOST_CAP:
+ ret = ath12k_qmi_event_host_cap(qmi);
+ if (ret < 0)
+ set_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags);
+ break;
default:
ath12k_warn(ab, "invalid event type: %d", event->type);
break;
diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h
index 0dfcbd8cb59b..98f6009ab21e 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.h
+++ b/drivers/net/wireless/ath/ath12k/qmi.h
@@ -68,6 +68,7 @@ enum ath12k_qmi_event_type {
ATH12K_QMI_EVENT_FORCE_FW_ASSERT,
ATH12K_QMI_EVENT_POWER_UP,
ATH12K_QMI_EVENT_POWER_DOWN,
+ ATH12K_QMI_EVENT_HOST_CAP,
ATH12K_QMI_EVENT_MAX,
};
@@ -142,6 +143,10 @@ struct ath12k_qmi {
u32 target_mem_mode;
bool target_mem_delayed;
u8 cal_done;
+
+ /* protected with struct ath12k_qmi::event_lock */
+ bool block_event;
+
u8 num_radios;
struct target_info target;
struct m3_mem_region m3_mem;
@@ -594,11 +599,26 @@ struct qmi_wlanfw_wlan_ini_resp_msg_v01 {
struct qmi_response_type_v01 resp;
};
+static inline void ath12k_qmi_set_event_block(struct ath12k_qmi *qmi, bool block)
+{
+ lockdep_assert_held(&qmi->event_lock);
+
+ qmi->block_event = block;
+}
+
+static inline bool ath12k_qmi_get_event_block(struct ath12k_qmi *qmi)
+{
+ lockdep_assert_held(&qmi->event_lock);
+
+ return qmi->block_event;
+}
+
int ath12k_qmi_firmware_start(struct ath12k_base *ab,
u32 mode);
void ath12k_qmi_firmware_stop(struct ath12k_base *ab);
void ath12k_qmi_deinit_service(struct ath12k_base *ab);
int ath12k_qmi_init_service(struct ath12k_base *ab);
void ath12k_qmi_free_resource(struct ath12k_base *ab);
+void ath12k_qmi_trigger_host_cap(struct ath12k_base *ab);
#endif
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 7/7] wifi: ath12k: introduce mlo_capable flag for device group
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
` (5 preceding siblings ...)
2024-12-04 16:32 ` [PATCH 6/7] wifi: ath12k: send QMI host capability after device group is ready Kalle Valo
@ 2024-12-04 16:32 ` Kalle Valo
2024-12-06 15:42 ` [PATCH 0/7] wifi: ath12k: MLO support part 6 Jeff Johnson
7 siblings, 0 replies; 13+ messages in thread
From: Kalle Valo @ 2024-12-04 16:32 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Currently, during mac80211 allocate and register single device is
considered for the registration. But, in future, during multi device
group abstraction is introduced, all the devices has to be combined
together as a single abstraction and then hardware should be allocated.
All the devices in the group should be combined together only if it
supports inter device mlo capability. The decision of whether to combine
the devices or not can be based on the mlo capability flag in
ath12k_hw_group.
By default, mlo_capable flag in the group would be set as false. During
QMI PHY capability exchange, only when we have more than one chip in the
group or if one chip, then that chip supports inter MLO, then mlo_capable
flag in the group will be enabled.
Add changes to introduce mlo_capable flag for device group and refactor
ath12k_mac_hw_allocate() api based on device group (ag) rather than
device (ab).
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
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
---
drivers/net/wireless/ath/ath12k/core.c | 17 +++++++++++++++++
drivers/net/wireless/ath/ath12k/core.h | 3 +++
drivers/net/wireless/ath/ath12k/mac.c | 8 +++++---
drivers/net/wireless/ath/ath12k/qmi.c | 6 ++++--
4 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 18b29515c6ae..49d1ac15cb7a 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1439,6 +1439,7 @@ static struct ath12k_hw_group *ath12k_core_hw_group_assign(struct ath12k_base *a
ab->device_id = ag->num_probed++;
ag->ab[ab->device_id] = ab;
ab->ag = ag;
+ ag->mlo_capable = false;
return ag;
}
@@ -1548,6 +1549,22 @@ static int ath12k_core_hw_group_create(struct ath12k_hw_group *ag)
return 0;
}
+void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag)
+{
+ lockdep_assert_held(&ag->mutex);
+
+ /* If more than one devices are grouped, then inter MLO
+ * functionality can work still independent of whether internally
+ * each device supports single_chip_mlo or not.
+ * Only when there is one device, then it depends whether the
+ * device can support intra chip MLO or not
+ */
+ if (ag->num_devices > 1)
+ ag->mlo_capable = true;
+ else
+ ag->mlo_capable = ag->ab[0]->single_chip_mlo_supp;
+}
+
int ath12k_core_init(struct ath12k_base *ab)
{
struct ath12k_hw_group *ag;
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 64252d6491cd..458e3d0071a8 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -844,6 +844,7 @@ struct ath12k_hw_group {
*/
struct ath12k_hw *ah[ATH12K_GROUP_MAX_RADIO];
u8 num_hw;
+ bool mlo_capable;
};
/* Master structure to hold the hw data which may be used in core module */
@@ -1066,6 +1067,8 @@ u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab);
u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab);
u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab);
+void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag);
+
static inline const char *ath12k_scan_state_str(enum ath12k_scan_state state)
{
switch (state) {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 1cf724a530b5..c4eab4c1c10e 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -10968,10 +10968,12 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
/* All pdev get combined and register as single wiphy based on
* hardware group which participate in multi-link operation else
* each pdev get register separately.
- *
- * Currently, registering as single pdevs.
*/
- radio_per_hw = 1;
+ if (ag->mlo_capable)
+ radio_per_hw = total_radio;
+ else
+ radio_per_hw = 1;
+
num_hw = total_radio / radio_per_hw;
if (WARN_ON(num_hw >= ATH12K_GROUP_MAX_RADIO))
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index 2591d132a3fc..ba3cd2342465 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -2023,9 +2023,9 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
u8 hw_link_id = 0;
int i;
- if (!ab->single_chip_mlo_supp) {
+ if (!ab->ag->mlo_capable) {
ath12k_dbg(ab, ATH12K_DBG_QMI,
- "intra device MLO is disabled hence skip QMI MLO cap");
+ "MLO is disabled hence skip QMI MLO cap");
return;
}
@@ -3170,6 +3170,8 @@ int ath12k_qmi_event_server_arrive(struct ath12k_qmi *qmi)
mutex_lock(&ag->mutex);
if (ath12k_qmi_hw_group_host_cap_ready(ag)) {
+ ath12k_core_hw_group_set_mlo_capable(ag);
+
block_ab = ath12k_qmi_hw_group_find_blocked(ag);
if (block_ab)
ath12k_qmi_trigger_host_cap(block_ab);
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 2/7] wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp
2024-12-04 16:32 ` [PATCH 2/7] wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp Kalle Valo
@ 2024-12-05 22:32 ` Jeff Johnson
2024-12-06 7:47 ` Kalle Valo
0 siblings, 1 reply; 13+ messages in thread
From: Jeff Johnson @ 2024-12-05 22:32 UTC (permalink / raw)
To: Kalle Valo, ath12k; +Cc: linux-wireless
On 12/4/2024 8:32 AM, Kalle Valo wrote:
> From: Aditya Kumar Singh <quic_adisi@quicinc.com>
>
> At present, the mlo_capable_flags in ath12k_base is used to indicate whether
> the chip supports inter (QCN9274) or intra (WCN7850) chip MLO. However, it’s
> possible that the chip supports neither, especially with older firmware
> versions. Additionally, if intra chip MLO is not supported, inter chip MLO will
> also be non-functional. Therefore, having two separate flags for this is
> unnecessary.
>
> Therefore, rename this flag to single_chip_mlo_supp. At the same time convert
> it into a bool data type. Also, get rid of the enums defined earlier.
>
> For the QCN9274 family of chipsets, this will be set only when firmware
> advertises the support during the QMI exchange.
>
> For the WCN7850 family of chipsets, since the event is not supported,
> assumption is made that single chip MLO is supported.
>
> 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
>
> Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Kalle, this patch is missing your SOB.
Please reply with the tag and I'll fix in 'pending'
> ---
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/7] wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp
2024-12-05 22:32 ` Jeff Johnson
@ 2024-12-06 7:47 ` Kalle Valo
0 siblings, 0 replies; 13+ messages in thread
From: Kalle Valo @ 2024-12-06 7:47 UTC (permalink / raw)
To: Jeff Johnson; +Cc: ath12k, linux-wireless
Jeff Johnson <jeff.johnson@oss.qualcomm.com> writes:
> On 12/4/2024 8:32 AM, Kalle Valo wrote:
>
>> From: Aditya Kumar Singh <quic_adisi@quicinc.com>
>>
>> At present, the mlo_capable_flags in ath12k_base is used to indicate whether
>> the chip supports inter (QCN9274) or intra (WCN7850) chip MLO. However, it’s
>> possible that the chip supports neither, especially with older firmware
>> versions. Additionally, if intra chip MLO is not supported, inter chip MLO will
>> also be non-functional. Therefore, having two separate flags for this is
>> unnecessary.
>>
>> Therefore, rename this flag to single_chip_mlo_supp. At the same time convert
>> it into a bool data type. Also, get rid of the enums defined earlier.
>>
>> For the QCN9274 family of chipsets, this will be set only when firmware
>> advertises the support during the QMI exchange.
>>
>> For the WCN7850 family of chipsets, since the event is not supported,
>> assumption is made that single chip MLO is supported.
>>
>> 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
>>
>> Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
>
> Kalle, this patch is missing your SOB.
> Please reply with the tag and I'll fix in 'pending'
Oh darn, sorry about that. Here it is:
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/7] wifi: ath12k: MLO support part 6
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
` (6 preceding siblings ...)
2024-12-04 16:32 ` [PATCH 7/7] wifi: ath12k: introduce mlo_capable flag for device group Kalle Valo
@ 2024-12-06 15:42 ` Jeff Johnson
7 siblings, 0 replies; 13+ messages in thread
From: Jeff Johnson @ 2024-12-06 15:42 UTC (permalink / raw)
To: ath12k, Kalle Valo; +Cc: linux-wireless
On Wed, 04 Dec 2024 18:32:09 +0200, Kalle Valo wrote:
> In this patchset there's refactoring to support hardware grouping, meaning
> multiple hardware devices can be registered to mac80211 as a single device.
>
> Please review.
>
> Aditya Kumar Singh (1):
> wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp
>
> [...]
Applied, thanks!
[1/7] wifi: ath12k: move ATH12K_FLAG_REGISTERED handling to ath12k_mac_register()
commit: a5686ae820fa7ab03226a3b0ff529720b7bac599
[2/7] wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp
commit: 46d16f7e1d1413ad7ff99c1334d8874623717745
[3/7] wifi: ath12k: introduce device group abstraction
commit: 6f245ea0ec6c29b90c8fa4fdf6e178c646125d7e
[4/7] wifi: ath12k: refactor core start based on hardware group
commit: ee146e11b4d9183e01d8b7e4963941730ed4af6d
[5/7] wifi: ath12k: move struct ath12k_hw from per device to group
commit: a343d97f27f514015e6d5e789672cf4ab4111720
[6/7] wifi: ath12k: send QMI host capability after device group is ready
commit: d302ac65ac938516487f57ae20f11e9cf6327606
[7/7] wifi: ath12k: introduce mlo_capable flag for device group
commit: da8656797ae10b524a7a0c3d5eeb6237fa3ddd70
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/7] wifi: ath12k: move struct ath12k_hw from per device to group
2024-12-04 16:32 ` [PATCH 5/7] wifi: ath12k: move struct ath12k_hw from per device to group Kalle Valo
@ 2024-12-10 20:58 ` Kees Bakker
2024-12-10 22:57 ` Jeff Johnson
0 siblings, 1 reply; 13+ messages in thread
From: Kees Bakker @ 2024-12-10 20:58 UTC (permalink / raw)
To: Kalle Valo, ath12k, Karthikeyan Periyasamy, Harshitha Prem,
Jeff Johnson
Cc: linux-wireless
Op 04-12-2024 om 17:32 schreef Kalle Valo:
> From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
>
> Currently, hardware abstractions (ah) of different radio bands are tightly
> coupled to a single device (ab). But, with hardware device group abstraction
> (ag), multiple radios across different devices in a group can form different
> combinations of hardware abstractions (ah) within the group. Hence, the mapping
> between ah to ab can be removed and instead it can be mapped with struct
> ath12k_hw_group (ag).
> [...]
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> [...]
> -void ath12k_mac_destroy(struct ath12k_base *ab)
> +void ath12k_mac_destroy(struct ath12k_hw_group *ag)
> {
> struct ath12k_pdev *pdev;
> + struct ath12k_base *ab = ag->ab[0];
> + int i, j;
> struct ath12k_hw *ah;
> - int i;
>
> - for (i = 0; i < ab->num_radios; i++) {
> - pdev = &ab->pdevs[i];
> - if (!pdev->ar)
> + for (i = 0; i < ag->num_devices; i++) {
> + ab = ag->ab[i];
> + if (!ab)
> continue;
>
> - pdev->ar = NULL;
> + for (j = 0; j < ab->num_radios; j++) {
> + pdev = &ab->pdevs[j];
> + if (!pdev->ar)
> + continue;
> + pdev->ar = NULL;
> + }
> }
>
> for (i = 0; i < ath12k_get_num_hw(ab); i++) {
> @@ -10942,26 +10945,59 @@ void ath12k_mac_destroy(struct ath12k_base *ab)
> }
> }
>
The new ath12k_mac_destroy() looks suspicious with respect to "ab".
Here is the new function with comments.
void ath12k_mac_destroy(struct ath12k_hw_group *ag)
{
struct ath12k_pdev *pdev;
struct ath12k_base *ab = ag->ab[0];
==> here ag->ab[0] is used before checking if ag->num_devices is greater
than zero
==> If ag->num_devices will never be zero then this first assignment
will be repeated in the next for-loop
==> if ag->num_devices can be zero then you need to confirm that
ag->ab[0] is non-NULL
int i, j;
struct ath12k_hw *ah;
for (i = 0; i < ag->num_devices; i++) {
ab = ag->ab[i];
if (!ab)
=>> This if check indicates that ab can be NULL
continue;
for (j = 0; j < ab->num_radios; j++) {
pdev = &ab->pdevs[j];
if (!pdev->ar)
continue;
pdev->ar = NULL;
}
}
==> Now ab is going to be used, but as shown above, ab can be NULL
for (i = 0; i < ath12k_get_num_hw(ab); i++) {
ah = ath12k_ab_to_ah(ab, i);
if (!ah)
continue;
ath12k_mac_hw_destroy(ah);
ath12k_ab_set_ah(ab, i, NULL);
}
}
--
Kees
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/7] wifi: ath12k: move struct ath12k_hw from per device to group
2024-12-10 20:58 ` Kees Bakker
@ 2024-12-10 22:57 ` Jeff Johnson
0 siblings, 0 replies; 13+ messages in thread
From: Jeff Johnson @ 2024-12-10 22:57 UTC (permalink / raw)
To: Kees Bakker, Kalle Valo, ath12k, Karthikeyan Periyasamy,
Harshitha Prem, Jeff Johnson
Cc: linux-wireless
On 12/10/2024 12:58 PM, Kees Bakker wrote:
> Op 04-12-2024 om 17:32 schreef Kalle Valo:
>> From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
>>
>> Currently, hardware abstractions (ah) of different radio bands are tightly
>> coupled to a single device (ab). But, with hardware device group abstraction
>> (ag), multiple radios across different devices in a group can form different
>> combinations of hardware abstractions (ah) within the group. Hence, the mapping
>> between ah to ab can be removed and instead it can be mapped with struct
>> ath12k_hw_group (ag).
>> [...]
>> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
>> [...]
>> -void ath12k_mac_destroy(struct ath12k_base *ab)
>> +void ath12k_mac_destroy(struct ath12k_hw_group *ag)
>> {
>> struct ath12k_pdev *pdev;
>> + struct ath12k_base *ab = ag->ab[0];
>> + int i, j;
>> struct ath12k_hw *ah;
>> - int i;
>>
>> - for (i = 0; i < ab->num_radios; i++) {
>> - pdev = &ab->pdevs[i];
>> - if (!pdev->ar)
>> + for (i = 0; i < ag->num_devices; i++) {
>> + ab = ag->ab[i];
>> + if (!ab)
>> continue;
>>
>> - pdev->ar = NULL;
>> + for (j = 0; j < ab->num_radios; j++) {
>> + pdev = &ab->pdevs[j];
>> + if (!pdev->ar)
>> + continue;
>> + pdev->ar = NULL;
>> + }
>> }
>>
>> for (i = 0; i < ath12k_get_num_hw(ab); i++) {
>> @@ -10942,26 +10945,59 @@ void ath12k_mac_destroy(struct ath12k_base *ab)
>> }
>> }
>>
> The new ath12k_mac_destroy() looks suspicious with respect to "ab".
There is already a patch in the internal pipeline to address this linux-next
Coverity CID
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2024-12-10 22:58 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-04 16:32 [PATCH 0/7] wifi: ath12k: MLO support part 6 Kalle Valo
2024-12-04 16:32 ` [PATCH 1/7] wifi: ath12k: move ATH12K_FLAG_REGISTERED handling to ath12k_mac_register() Kalle Valo
2024-12-04 16:32 ` [PATCH 2/7] wifi: ath12k: rename mlo_capable_flags to single_chip_mlo_supp Kalle Valo
2024-12-05 22:32 ` Jeff Johnson
2024-12-06 7:47 ` Kalle Valo
2024-12-04 16:32 ` [PATCH 3/7] wifi: ath12k: introduce device group abstraction Kalle Valo
2024-12-04 16:32 ` [PATCH 4/7] wifi: ath12k: refactor core start based on hardware group Kalle Valo
2024-12-04 16:32 ` [PATCH 5/7] wifi: ath12k: move struct ath12k_hw from per device to group Kalle Valo
2024-12-10 20:58 ` Kees Bakker
2024-12-10 22:57 ` Jeff Johnson
2024-12-04 16:32 ` [PATCH 6/7] wifi: ath12k: send QMI host capability after device group is ready Kalle Valo
2024-12-04 16:32 ` [PATCH 7/7] wifi: ath12k: introduce mlo_capable flag for device group Kalle Valo
2024-12-06 15:42 ` [PATCH 0/7] wifi: ath12k: MLO support part 6 Jeff Johnson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).