Skip to content

Commit

Permalink
wifi: ath12k: introduce device group abstraction
Browse files Browse the repository at this point in the history
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>
Link: https://patch.msgid.link/20241204163216.433795-4-kvalo@kernel.org
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
  • Loading branch information
Karthikeyan Periyasamy authored and Jeff Johnson committed Dec 5, 2024
1 parent 46d16f7 commit 6f245ea
Show file tree
Hide file tree
Showing 3 changed files with 236 additions and 13 deletions.
231 changes: 218 additions & 13 deletions drivers/net/wireless/ath/ath12k/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
return (ag->num_probed == ag->num_devices);
}

static struct ath12k_hw_group *ath12k_core_hw_group_alloc(u8 id, u8 max_devices)
{
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;
}

ret = ath12k_core_panic_notifier_register(ab);
if (ret)
ath12k_warn(ab, "failed to register panic handler: %d\n", ret);
ath12k_dbg(ab, ATH12K_DBG_BOOT, "single device added to hardware group\n");

return 0;
ab->device_id = ag->num_probed++;
ag->ab[ab->device_id] = ab;
ab->ag = ag;

return ag;
}

void ath12k_core_deinit(struct ath12k_base *ab)
void ath12k_core_hw_group_unassign(struct ath12k_base *ab)
{
ath12k_core_panic_notifier_unregister(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);
Expand All @@ -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)
Expand Down
17 changes: 17 additions & 0 deletions drivers/net/wireless/ath/ath12k/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 *));
};
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath12k/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit 6f245ea

Please sign in to comment.