@@ -566,6 +566,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);
@@ -692,11 +695,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);
}
@@ -705,6 +712,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);
@@ -798,6 +807,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:
@@ -809,6 +823,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)
{
@@ -826,9 +943,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) {
@@ -848,59 +974,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;
}
@@ -1152,6 +1269,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);
@@ -1261,7 +1382,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;
@@ -1295,19 +1416,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;
@@ -1335,14 +1443,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);
}
@@ -202,6 +202,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,
@@ -216,6 +220,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,
};
enum ath12k_monitor_flags {
@@ -743,6 +750,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;
@@ -1094,4 +1103,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_ */