]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: refactor core start based on hardware group
authorKarthikeyan Periyasamy <quic_periyasa@quicinc.com>
Wed, 4 Dec 2024 16:32:13 +0000 (18:32 +0200)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Thu, 5 Dec 2024 22:34:10 +0000 (14:34 -0800)
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>
Link: https://patch.msgid.link/20241204163216.433795-5-kvalo@kernel.org
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/core.c
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/qmi.c

index 41e3454b60f501d8256761699c0951d921b88adb..dea2c53bcc0794b63ccc4a9edbe3ca9100efb514 100644 (file)
@@ -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 @@ err_wmi_detach:
        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);
+       mutex_unlock(&ab->core_lock);
 
-       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;
+       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(&ab->core_lock);
+       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);
index dca4b9a3538f4024dafb235e09d7623704dd0a55..b8b1ee8d330289976b2a7dbba1e4dbcc4c740633 100644 (file)
@@ -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_ */
index efcf2dfac4ac9741b55a1c668c775300accd0a93..8b4d500fe426aa7b2a9b31c891913ab688e8763b 100644 (file)
@@ -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,