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

Commit 818bdd16 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo
Browse files

ath10k: defer hw setup to start/stop mac80211 hooks



This fixes suspend-to-disk. The hardware is now
re-initialized upon freeze/thaw properly.

This also makes suspend/resume re-initialize the
hardware as WoWLAN support is not done yet.

With some little work it should be possible to
support hw reconfiguration for hw/fw recovery.

HW must be initialized once before registering to
mac80211 because FW determinates what hw
capabilities can be advertised.

Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent a96d7745
Loading
Loading
Loading
Loading
+37 −9
Original line number Diff line number Diff line
@@ -601,6 +601,7 @@ int ath10k_core_start(struct ath10k *ar)
err:
	return status;
}
EXPORT_SYMBOL(ath10k_core_start);

void ath10k_core_stop(struct ath10k *ar)
{
@@ -608,18 +609,49 @@ void ath10k_core_stop(struct ath10k *ar)
	ath10k_htt_detach(&ar->htt);
	ath10k_wmi_detach(ar);
}
EXPORT_SYMBOL(ath10k_core_stop);

/* mac80211 manages fw/hw initialization through start/stop hooks. However in
 * order to know what hw capabilities should be advertised to mac80211 it is
 * necessary to load the firmware (and tear it down immediately since start
 * hook will try to init it again) before registering */
static int ath10k_core_probe_fw(struct ath10k *ar)
{
	int ret;

	ret = ath10k_hif_power_up(ar);
	if (ret) {
		ath10k_err("could not start pci hif (%d)\n", ret);
		return ret;
	}

	ret = ath10k_core_start(ar);
	if (ret) {
		ath10k_err("could not init core (%d)\n", ret);
		ath10k_hif_power_down(ar);
		return ret;
	}

	ath10k_core_stop(ar);
	ath10k_hif_power_down(ar);
	return 0;
}

int ath10k_core_register(struct ath10k *ar)
{
	int status;

	status = ath10k_core_start(ar);
	if (status)
		goto err;
	status = ath10k_core_probe_fw(ar);
	if (status) {
		ath10k_err("could not probe fw (%d)\n", status);
		return status;
	}

	status = ath10k_mac_register(ar);
	if (status)
		goto err_core_stop;
	if (status) {
		ath10k_err("could not register to mac80211 (%d)\n", status);
		return status;
	}

	status = ath10k_debug_create(ar);
	if (status) {
@@ -631,9 +663,6 @@ int ath10k_core_register(struct ath10k *ar)

err_unregister_mac:
	ath10k_mac_unregister(ar);
err_core_stop:
	ath10k_core_stop(ar);
err:
	return status;
}
EXPORT_SYMBOL(ath10k_core_register);
@@ -644,7 +673,6 @@ void ath10k_core_unregister(struct ath10k *ar)
	 * Otherwise we will fail to submit commands to FW and mac80211 will be
	 * unhappy about callback failures. */
	ath10k_mac_unregister(ar);
	ath10k_core_stop(ar);
}
EXPORT_SYMBOL(ath10k_core_unregister);

+43 −13
Original line number Diff line number Diff line
@@ -1738,13 +1738,52 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/*
 * Initialize various parameters with default vaules.
 */
static void ath10k_halt(struct ath10k *ar)
{
	lockdep_assert_held(&ar->conf_mutex);

	del_timer_sync(&ar->scan.timeout);
	ath10k_offchan_tx_purge(ar);
	ath10k_peer_cleanup_all(ar);
	ath10k_core_stop(ar);
	ath10k_hif_power_down(ar);

	spin_lock_bh(&ar->data_lock);
	if (ar->scan.in_progress) {
		del_timer(&ar->scan.timeout);
		ar->scan.in_progress = false;
		ieee80211_scan_completed(ar->hw, true);
	}
	spin_unlock_bh(&ar->data_lock);
}

static int ath10k_start(struct ieee80211_hw *hw)
{
	struct ath10k *ar = hw->priv;
	int ret;
	int ret = 0;

	mutex_lock(&ar->conf_mutex);

	if (ar->state != ATH10K_STATE_OFF) {
		ret = -EINVAL;
		goto exit;
	}

	ret = ath10k_hif_power_up(ar);
	if (ret) {
		ath10k_err("could not init hif (%d)\n", ret);
		ar->state = ATH10K_STATE_OFF;
		goto exit;
	}

	ret = ath10k_core_start(ar);
	if (ret) {
		ath10k_err("could not init core (%d)\n", ret);
		ath10k_hif_power_down(ar);
		ar->state = ATH10K_STATE_OFF;
		goto exit;
	}

	ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1);
	if (ret)
		ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
@@ -1755,9 +1794,9 @@ static int ath10k_start(struct ieee80211_hw *hw)
		ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
			    ret);

	ar->state = ATH10K_STATE_ON;
	ath10k_regd_update(ar);

exit:
	mutex_unlock(&ar->conf_mutex);
	return 0;
}
@@ -1767,17 +1806,8 @@ static void ath10k_stop(struct ieee80211_hw *hw)
	struct ath10k *ar = hw->priv;

	mutex_lock(&ar->conf_mutex);
	del_timer_sync(&ar->scan.timeout);
	ath10k_offchan_tx_purge(ar);
	ath10k_peer_cleanup_all(ar);

	spin_lock_bh(&ar->data_lock);
	if (ar->scan.in_progress) {
		del_timer(&ar->scan.timeout);
		ar->scan.in_progress = false;
		ieee80211_scan_completed(ar->hw, true);
	}
	spin_unlock_bh(&ar->data_lock);
	if (ar->state == ATH10K_STATE_ON)
		ath10k_halt(ar);

	ar->state = ATH10K_STATE_OFF;
	mutex_unlock(&ar->conf_mutex);
+1 −10
Original line number Diff line number Diff line
@@ -2362,22 +2362,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
		goto err_iomap;
	}

	ret = ath10k_pci_hif_power_up(ar);
	if (ret) {
		ath10k_err("could not start pci hif (%d)\n", ret);
		goto err_intr;
	}

	ret = ath10k_core_register(ar);
	if (ret) {
		ath10k_err("could not register driver core (%d)\n", ret);
		goto err_hif;
		goto err_intr;
	}

	return 0;

err_hif:
	ath10k_pci_hif_power_down(ar);
err_intr:
	ath10k_pci_stop_intr(ar);
err_iomap:
@@ -2416,7 +2408,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
	tasklet_kill(&ar_pci->msi_fw_err);

	ath10k_core_unregister(ar);
	ath10k_pci_hif_power_down(ar);
	ath10k_pci_stop_intr(ar);

	pci_set_drvdata(pdev, NULL);