@@ -563,6 +563,9 @@ u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab)
static void ath12k_core_stop(struct ath12k_base *ab)
{
+ clear_bit(ATH12K_FLAG_CORE_STARTED, &ab->dev_flags);
+ ath12k_dec_num_core_started(ab);
+
if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
ath12k_qmi_firmware_stop(ab);
@@ -689,11 +692,15 @@ static int ath12k_core_pdev_create(struct ath12k_base *ab)
return ret;
}
+ set_bit(ATH12K_FLAG_PDEV_CREATED, &ab->dev_flags);
+
return 0;
}
static void ath12k_core_pdev_destroy(struct ath12k_base *ab)
{
+ clear_bit(ATH12K_FLAG_PDEV_CREATED, &ab->dev_flags);
+
ath12k_dp_pdev_free(ab);
}
@@ -702,6 +709,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);
@@ -795,6 +804,11 @@ 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);
+ /* Indicate the core start in the appropriate group */
+ ath12k_inc_num_core_started(ab);
+
+ set_bit(ATH12K_FLAG_CORE_STARTED, &ab->dev_flags);
+
return 0;
err_reo_cleanup:
@@ -806,6 +820,109 @@ 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);
+
+ if (test_and_clear_bit(ATH12K_FLAG_CORE_HIF_IRQ_ENABLED, &ab->dev_flags))
+ ath12k_hif_irq_disable(ab);
+
+ if (test_bit(ATH12K_FLAG_PDEV_CREATED, &ab->dev_flags))
+ ath12k_core_pdev_destroy(ab);
+
+ if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) {
+ 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_lock);
+
+ 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;
+ bool is_registered;
+
+ lockdep_assert_held(&ag->mutex_lock);
+
+ 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.
+ */
+ is_registered = test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags);
+
+ if (is_registered)
+ 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;
+ }
+
+ ret = ath12k_core_rfkill_config(ab);
+ if (ret && ret != -EOPNOTSUPP) {
+ mutex_unlock(&ab->core_lock);
+ goto err;
+ }
+
+ ath12k_hif_irq_enable(ab);
+
+ set_bit(ATH12K_FLAG_CORE_HIF_IRQ_ENABLED, &ab->dev_flags);
+
+ mutex_unlock(&ab->core_lock);
+ }
+
+ set_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
+
+ 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)
{
@@ -823,9 +940,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_lock);
+
+ return (ag->num_started == ag->num_devices);
+}
+
int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
{
- int ret;
+ struct ath12k_hw_group *ag;
+ int ret, i;
ret = ath12k_core_start_firmware(ab, ATH12K_FIRMWARE_MODE_NORMAL);
if (ret) {
@@ -845,59 +971,50 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
goto err_firmware_stop;
}
+ ag = ath12k_ab_to_ag(ab);
+
+ mutex_lock(&ag->mutex_lock);
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;
}
+ mutex_unlock(&ab->core_lock);
- 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;
+ 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_lock);
- ret = ath12k_core_pdev_create(ab);
- if (ret) {
- ath12k_err(ab, "failed to create pdev core: %d\n", ret);
- goto err_mac_unregister;
- }
+ return 0;
- ath12k_hif_irq_enable(ab);
+err_core_stop:
+ for (i = ag->num_devices - 1; i >= 0; i--) {
+ ab = ag->ab[i];
+ if (!ab)
+ continue;
- ret = ath12k_core_rfkill_config(ab);
- if (ret && ret != -EOPNOTSUPP) {
- ath12k_err(ab, "failed to config rfkill: %d\n", ret);
- goto err_core_pdev_destroy;
+ mutex_lock(&ab->core_lock);
+ if (test_bit(ATH12K_FLAG_CORE_STARTED, &ab->dev_flags))
+ ath12k_core_stop(ab);
+ mutex_unlock(&ab->core_lock);
}
+ goto exit;
- mutex_unlock(&ab->core_lock);
-
- return 0;
-
-err_core_pdev_destroy:
- 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);
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_lock);
return ret;
}
@@ -1149,6 +1266,10 @@ static void ath12k_core_reset(struct work_struct *work)
ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset starting\n");
+ mutex_lock(&ab->ag->mutex_lock);
+ ath12k_dec_num_core_started(ab);
+ mutex_unlock(&ab->ag->mutex_lock);
+
ab->is_reset = true;
atomic_set(&ab->recovery_start_count, 0);
reinit_completion(&ab->recovery_start);
@@ -1258,7 +1379,7 @@ static struct ath12k_hw_group *ath12k_core_assign_hw_group(struct ath12k_base *a
void ath12k_core_unassign_hw_group(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;
@@ -1292,19 +1413,6 @@ void ath12k_core_unassign_hw_group(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;
@@ -1332,14 +1440,20 @@ static void ath12k_core_hw_group_cleanup(struct ath12k_hw_group *ag)
return;
mutex_lock(&ag->mutex_lock);
+ if (test_and_clear_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags))
+ ath12k_core_hw_group_stop(ag);
+
for (i = 0; i < ag->num_devices; i++) {
ab = ag->ab[i];
if (!ab)
continue;
- if (test_bit(ATH12K_FLAG_QMI_FW_READY_COMPLETE, &ab->dev_flags))
- ath12k_core_device_cleanup(ab);
+ mutex_lock(&ab->core_lock);
+ if (test_bit(ATH12K_FLAG_CORE_STARTED, &ab->dev_flags))
+ ath12k_core_stop(ab);
+ mutex_unlock(&ab->core_lock);
}
+
mutex_unlock(&ag->mutex_lock);
}
@@ -200,6 +200,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,
@@ -214,6 +218,9 @@ enum ath12k_dev_flags {
ATH12K_FLAG_EXT_IRQ_ENABLED,
ATH12K_FLAG_QMI_FW_READY_COMPLETE,
ATH12K_FLAG_HW_GROUP_ATTACHED,
+ ATH12K_FLAG_PDEV_CREATED,
+ ATH12K_FLAG_CORE_STARTED,
+ ATH12K_FLAG_CORE_HIF_IRQ_ENABLED,
};
struct ath12k_tx_conf {
@@ -736,6 +743,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];
/* To synchronize group create, assign, start, stop */
struct mutex mutex_lock;
@@ -1087,4 +1096,27 @@ 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_inc_num_core_started(struct ath12k_base *ab)
+{
+ lockdep_assert_held(&ab->ag->mutex_lock);
+
+ ab->ag->num_started++;
+}
+
+static inline
+void ath12k_dec_num_core_started(struct ath12k_base *ab)
+{
+ lockdep_assert_held(&ab->ag->mutex_lock);
+
+ ab->ag->num_started--;
+}
+
#endif /* _CORE_H_ */