Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+80 −71
Original line number Original line Diff line number Diff line
@@ -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)
	ret = ath10k_pci_wait_for_target_init(ar);
{
	if (ret) {
	int i, ret;
		ath10k_warn(ar, "failed to wait for target after cold reset: %d\n",

			    ret);
	/*
		return 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);
	}
	}


	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)
	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)