Commit 0bc14d06 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: split reset logic from power up

The power up procedure was overly complex due to
warm/cold reset workarounds and issues.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 61c1648b
...@@ -1792,83 +1792,78 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) ...@@ -1792,83 +1792,78 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
return 0; return 0;
} }
static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) static int ath10k_pci_chip_reset(struct ath10k *ar)
{ {
int ret; int i, ret;
u32 val;
/* ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset\n");
* Bring the target up cleanly.
/* Some hardware revisions (e.g. CUS223v2) has issues with cold reset.
* It is thus preferred to use warm reset which is safer but may not be
* able to recover the device from all possible fail scenarios.
* *
* The target may be in an undefined state with an AUX-powered Target * Warm reset doesn't always work on first try so attempt it a few
* and a Host in WoW mode. If the Host crashes, loses power, or is * times before giving up.
* restarted (without unloading the driver) then the Target is left
* (aux) powered and running. On a subsequent driver load, the Target
* is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe.
*/ */
if (cold_reset) for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) {
ret = ath10k_pci_cold_reset(ar);
else
ret = ath10k_pci_warm_reset(ar); ret = ath10k_pci_warm_reset(ar);
if (ret) { if (ret) {
ath10k_err(ar, "failed to reset target: %d\n", ret); ath10k_warn(ar, "failed to warm reset attempt %d of %d: %d\n",
goto err; i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS,
ret);
continue;
} }
/* FIXME: Sometimes copy engine doesn't recover after warm
* reset. In most cases this needs cold reset. In some of these
* cases the device is in such a state that a cold reset may
* lock up the host.
*
* Reading any host interest register via copy engine is
* sufficient to verify if device is capable of booting
* firmware blob.
*/
ret = ath10k_pci_init_pipes(ar); ret = ath10k_pci_init_pipes(ar);
if (ret) { if (ret) {
ath10k_err(ar, "failed to initialize CE: %d\n", ret); ath10k_warn(ar, "failed to init copy engine: %d\n",
goto err; ret);
continue;
} }
ret = ath10k_pci_wait_for_target_init(ar); ret = ath10k_pci_diag_read32(ar, QCA988X_HOST_INTEREST_ADDRESS,
&val);
if (ret) { if (ret) {
ath10k_err(ar, "failed to wait for target to init: %d\n", ret); ath10k_warn(ar, "failed to poke copy engine: %d\n",
goto err_ce; ret);
continue;
} }
ret = ath10k_pci_init_config(ar); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (warm)\n");
if (ret) { return 0;
ath10k_err(ar, "failed to setup init config: %d\n", ret);
goto err_ce;
} }
ret = ath10k_pci_wake_target_cpu(ar); if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) {
if (ret) { ath10k_warn(ar, "refusing cold reset as requested\n");
ath10k_err(ar, "could not wake up target CPU: %d\n", ret); return -EPERM;
goto err_ce;
} }
return 0; ret = ath10k_pci_cold_reset(ar);
if (ret) {
err_ce: ath10k_warn(ar, "failed to cold reset: %d\n", ret);
ath10k_pci_ce_deinit(ar);
ath10k_pci_warm_reset(ar);
err:
return ret; return ret;
}
static int ath10k_pci_hif_power_up_warm(struct ath10k *ar)
{
int i, ret;
/*
* Sometime warm reset succeeds after retries.
*
* FIXME: It might be possible to tune ath10k_pci_warm_reset() to work
* at first try.
*/
for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) {
ret = __ath10k_pci_hif_power_up(ar, false);
if (ret == 0)
break;
ath10k_warn(ar, "failed to warm reset (attempt %d out of %d): %d\n",
i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret);
} }
ret = ath10k_pci_wait_for_target_init(ar);
if (ret) {
ath10k_warn(ar, "failed to wait for target after cold reset: %d\n",
ret);
return ret; return ret;
}
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (cold)\n");
return 0;
} }
static int ath10k_pci_hif_power_up(struct ath10k *ar) static int ath10k_pci_hif_power_up(struct ath10k *ar)
...@@ -1878,32 +1873,46 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ...@@ -1878,32 +1873,46 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n"); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
/* /*
* Hardware CUS232 version 2 has some issues with cold reset and the * Bring the target up cleanly.
* preferred (and safer) way to perform a device reset is through a
* warm reset.
* *
* Warm reset doesn't always work though so fall back to cold reset may * The target may be in an undefined state with an AUX-powered Target
* be necessary. * and a Host in WoW mode. If the Host crashes, loses power, or is
* restarted (without unloading the driver) then the Target is left
* (aux) powered and running. On a subsequent driver load, the Target
* is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe.
*/ */
ret = ath10k_pci_hif_power_up_warm(ar); ret = ath10k_pci_chip_reset(ar);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to power up target using warm reset: %d\n", ath10k_err(ar, "failed to reset chip: %d\n", ret);
ret); goto err;
}
if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY)
return ret;
ath10k_warn(ar, "trying cold reset\n"); ret = ath10k_pci_init_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to initialize CE: %d\n", ret);
goto err;
}
ret = __ath10k_pci_hif_power_up(ar, true); ret = ath10k_pci_init_config(ar);
if (ret) { if (ret) {
ath10k_err(ar, "failed to power up target using cold reset too (%d)\n", ath10k_err(ar, "failed to setup init config: %d\n", ret);
ret); goto err_ce;
return ret;
} }
ret = ath10k_pci_wake_target_cpu(ar);
if (ret) {
ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
goto err_ce;
} }
return 0; return 0;
err_ce:
ath10k_pci_ce_deinit(ar);
err:
return ret;
} }
static void ath10k_pci_hif_power_down(struct ath10k *ar) static void ath10k_pci_hif_power_down(struct ath10k *ar)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment