mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-06 21:14:18 +00:00
wifi: ath12k: enable MLO setup and teardown from core
In case of multi device group abstraction, host has to exchange the multi-link operation commands such as setup and ready to firmware before registering the device group to mac80211. The multi-link operation commands - setup, ready and teardown are necessary for many commands such as WMI_PEER_ASSOC_CMD, WMI_BCN_TMPL_CMD in case of multi-link interfaces. 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> Link: https://patch.msgid.link/20241211153432.775335-8-kvalo@kernel.org Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
parent
cc64deef0b
commit
b716a10d99
@ -887,6 +887,70 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
|
|||||||
ath12k_mac_destroy(ag);
|
ath12k_mac_destroy(ag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __ath12k_mac_mlo_ready(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ath12k_wmi_mlo_ready(ar);
|
||||||
|
if (ret) {
|
||||||
|
ath12k_err(ar->ab, "MLO ready failed for pdev %d: %d\n",
|
||||||
|
ar->pdev_idx, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mlo ready done for pdev %d\n",
|
||||||
|
ar->pdev_idx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ath12k_mac_mlo_ready(struct ath12k_hw_group *ag)
|
||||||
|
{
|
||||||
|
struct ath12k_hw *ah;
|
||||||
|
struct ath12k *ar;
|
||||||
|
int ret;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < ag->num_hw; i++) {
|
||||||
|
ah = ag->ah[i];
|
||||||
|
if (!ah)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for_each_ar(ah, ar, j) {
|
||||||
|
ar = &ah->radio[j];
|
||||||
|
ret = __ath12k_mac_mlo_ready(ar);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath12k_core_mlo_setup(struct ath12k_hw_group *ag)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!ag->mlo_capable || ag->num_devices == 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = ath12k_mac_mlo_setup(ag);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ath12k_mac_mlo_ready(ag);
|
||||||
|
if (ret)
|
||||||
|
goto err_mlo_teardown;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_mlo_teardown:
|
||||||
|
ath12k_mac_mlo_teardown(ag);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
|
static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
|
||||||
{
|
{
|
||||||
struct ath12k_base *ab;
|
struct ath12k_base *ab;
|
||||||
@ -901,10 +965,14 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
|
|||||||
if (WARN_ON(ret))
|
if (WARN_ON(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = ath12k_mac_register(ag);
|
ret = ath12k_core_mlo_setup(ag);
|
||||||
if (WARN_ON(ret))
|
if (WARN_ON(ret))
|
||||||
goto err_mac_destroy;
|
goto err_mac_destroy;
|
||||||
|
|
||||||
|
ret = ath12k_mac_register(ag);
|
||||||
|
if (WARN_ON(ret))
|
||||||
|
goto err_mlo_teardown;
|
||||||
|
|
||||||
set_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
|
set_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
|
||||||
|
|
||||||
core_pdev_create:
|
core_pdev_create:
|
||||||
@ -939,6 +1007,9 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
|
|||||||
ath12k_core_hw_group_stop(ag);
|
ath12k_core_hw_group_stop(ag);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
err_mlo_teardown:
|
||||||
|
ath12k_mac_mlo_teardown(ag);
|
||||||
|
|
||||||
err_mac_destroy:
|
err_mac_destroy:
|
||||||
ath12k_mac_destroy(ag);
|
ath12k_mac_destroy(ag);
|
||||||
|
|
||||||
|
@ -715,6 +715,9 @@ struct ath12k {
|
|||||||
u32 freq_high;
|
u32 freq_high;
|
||||||
|
|
||||||
bool nlo_enabled;
|
bool nlo_enabled;
|
||||||
|
|
||||||
|
struct completion mlo_setup_done;
|
||||||
|
u32 mlo_setup_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath12k_hw {
|
struct ath12k_hw {
|
||||||
|
@ -10810,6 +10810,7 @@ static void ath12k_mac_setup(struct ath12k *ar)
|
|||||||
init_completion(&ar->scan.started);
|
init_completion(&ar->scan.started);
|
||||||
init_completion(&ar->scan.completed);
|
init_completion(&ar->scan.completed);
|
||||||
init_completion(&ar->scan.on_channel);
|
init_completion(&ar->scan.on_channel);
|
||||||
|
init_completion(&ar->mlo_setup_done);
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
|
INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
|
||||||
INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work);
|
INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work);
|
||||||
@ -10818,6 +10819,147 @@ static void ath12k_mac_setup(struct ath12k *ar)
|
|||||||
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
|
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __ath12k_mac_mlo_setup(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
u8 num_link = 0, partner_link_id[ATH12K_GROUP_MAX_RADIO] = {};
|
||||||
|
struct ath12k_base *partner_ab, *ab = ar->ab;
|
||||||
|
struct ath12k_hw_group *ag = ab->ag;
|
||||||
|
struct wmi_mlo_setup_arg mlo = {};
|
||||||
|
struct ath12k_pdev *pdev;
|
||||||
|
unsigned long time_left;
|
||||||
|
int i, j, ret;
|
||||||
|
|
||||||
|
lockdep_assert_held(&ag->mutex);
|
||||||
|
|
||||||
|
reinit_completion(&ar->mlo_setup_done);
|
||||||
|
|
||||||
|
for (i = 0; i < ag->num_devices; i++) {
|
||||||
|
partner_ab = ag->ab[i];
|
||||||
|
|
||||||
|
for (j = 0; j < partner_ab->num_radios; j++) {
|
||||||
|
pdev = &partner_ab->pdevs[j];
|
||||||
|
|
||||||
|
/* Avoid the self link */
|
||||||
|
if (ar == pdev->ar)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
partner_link_id[num_link] = pdev->hw_link_id;
|
||||||
|
num_link++;
|
||||||
|
|
||||||
|
ath12k_dbg(ab, ATH12K_DBG_MAC, "device %d pdev %d hw_link_id %d num_link %d\n",
|
||||||
|
i, j, pdev->hw_link_id, num_link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mlo.group_id = cpu_to_le32(ag->id);
|
||||||
|
mlo.partner_link_id = partner_link_id;
|
||||||
|
mlo.num_partner_links = num_link;
|
||||||
|
ar->mlo_setup_status = 0;
|
||||||
|
|
||||||
|
ath12k_dbg(ab, ATH12K_DBG_MAC, "group id %d num_link %d\n", ag->id, num_link);
|
||||||
|
|
||||||
|
ret = ath12k_wmi_mlo_setup(ar, &mlo);
|
||||||
|
if (ret) {
|
||||||
|
ath12k_err(ab, "failed to send setup MLO WMI command for pdev %d: %d\n",
|
||||||
|
ar->pdev_idx, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_left = wait_for_completion_timeout(&ar->mlo_setup_done,
|
||||||
|
WMI_MLO_CMD_TIMEOUT_HZ);
|
||||||
|
|
||||||
|
if (!time_left || ar->mlo_setup_status)
|
||||||
|
return ar->mlo_setup_status ? : -ETIMEDOUT;
|
||||||
|
|
||||||
|
ath12k_dbg(ab, ATH12K_DBG_MAC, "mlo setup done for pdev %d\n", ar->pdev_idx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __ath12k_mac_mlo_teardown(struct ath12k *ar)
|
||||||
|
{
|
||||||
|
struct ath12k_base *ab = ar->ab;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (test_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = ath12k_wmi_mlo_teardown(ar);
|
||||||
|
if (ret) {
|
||||||
|
ath12k_warn(ab, "failed to send MLO teardown WMI command for pdev %d: %d\n",
|
||||||
|
ar->pdev_idx, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath12k_dbg(ab, ATH12K_DBG_MAC, "mlo teardown for pdev %d\n", ar->pdev_idx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ath12k_mac_mlo_setup(struct ath12k_hw_group *ag)
|
||||||
|
{
|
||||||
|
struct ath12k_hw *ah;
|
||||||
|
struct ath12k *ar;
|
||||||
|
int ret;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < ag->num_hw; i++) {
|
||||||
|
ah = ag->ah[i];
|
||||||
|
if (!ah)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for_each_ar(ah, ar, j) {
|
||||||
|
ar = &ah->radio[j];
|
||||||
|
ret = __ath12k_mac_mlo_setup(ar);
|
||||||
|
if (ret) {
|
||||||
|
ath12k_err(ar->ab, "failed to setup MLO: %d\n", ret);
|
||||||
|
goto err_setup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_setup:
|
||||||
|
for (i = i - 1; i >= 0; i--) {
|
||||||
|
ah = ag->ah[i];
|
||||||
|
if (!ah)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = j - 1; j >= 0; j--) {
|
||||||
|
ar = &ah->radio[j];
|
||||||
|
if (!ar)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
__ath12k_mac_mlo_teardown(ar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ath12k_mac_mlo_teardown(struct ath12k_hw_group *ag)
|
||||||
|
{
|
||||||
|
struct ath12k_hw *ah;
|
||||||
|
struct ath12k *ar;
|
||||||
|
int ret, i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < ag->num_hw; i++) {
|
||||||
|
ah = ag->ah[i];
|
||||||
|
if (!ah)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for_each_ar(ah, ar, j) {
|
||||||
|
ar = &ah->radio[j];
|
||||||
|
ret = __ath12k_mac_mlo_teardown(ar);
|
||||||
|
if (ret) {
|
||||||
|
ath12k_err(ar->ab, "failed to teardown MLO: %d\n", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ath12k_mac_register(struct ath12k_hw_group *ag)
|
int ath12k_mac_register(struct ath12k_hw_group *ag)
|
||||||
{
|
{
|
||||||
struct ath12k_base *ab = ag->ab[0];
|
struct ath12k_base *ab = ag->ab[0];
|
||||||
|
@ -96,6 +96,9 @@ int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif,
|
|||||||
enum wmi_sta_keepalive_method method,
|
enum wmi_sta_keepalive_method method,
|
||||||
u32 interval);
|
u32 interval);
|
||||||
u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar);
|
u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar);
|
||||||
|
int ath12k_mac_mlo_setup(struct ath12k_hw_group *ag);
|
||||||
|
int ath12k_mac_mlo_ready(struct ath12k_hw_group *ag);
|
||||||
|
void ath12k_mac_mlo_teardown(struct ath12k_hw_group *ag);
|
||||||
int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif);
|
int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7369,6 +7369,9 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ar->mlo_setup_status = le32_to_cpu(ev->status);
|
||||||
|
complete(&ar->mlo_setup_done);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(tb);
|
kfree(tb);
|
||||||
}
|
}
|
||||||
|
@ -4938,6 +4938,7 @@ struct wmi_probe_tmpl_cmd {
|
|||||||
|
|
||||||
#define MAX_RADIOS 2
|
#define MAX_RADIOS 2
|
||||||
|
|
||||||
|
#define WMI_MLO_CMD_TIMEOUT_HZ (5 * HZ)
|
||||||
#define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ)
|
#define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ)
|
||||||
#define WMI_SEND_TIMEOUT_HZ (3 * HZ)
|
#define WMI_SEND_TIMEOUT_HZ (3 * HZ)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user