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

Commit 95bf21f9 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo
Browse files

ath10k: fix core start sequence



It was possible to call hif_stop() 2 times through
ath10k_htc_connect_init() timeout failpath which
could lead to double free_irq() kernel splat for
multiple MSI interrupt case.

Re-order init sequence to avoid this problem. The
HTC stop shouldn't stop HIF implicitly since it
doesn't implicitly start it. Since the re-ordering
required some functions to be split/removed/renamed
rename a few functions to make more sense while at
it.

Reported-By: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 46acf7bb
Loading
Loading
Loading
Loading
+55 −46
Original line number Diff line number Diff line
@@ -58,36 +58,6 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
	complete(&ar->target_suspend);
}

static int ath10k_init_connect_htc(struct ath10k *ar)
{
	int status;

	status = ath10k_wmi_connect_htc_service(ar);
	if (status)
		goto conn_fail;

	/* Start HTC */
	status = ath10k_htc_start(&ar->htc);
	if (status)
		goto conn_fail;

	/* Wait for WMI event to be ready */
	status = ath10k_wmi_wait_for_service_ready(ar);
	if (status <= 0) {
		ath10k_warn("wmi service ready event not received");
		status = -ETIMEDOUT;
		goto timeout;
	}

	ath10k_dbg(ATH10K_DBG_BOOT, "boot wmi ready\n");
	return 0;

timeout:
	ath10k_htc_stop(&ar->htc);
conn_fail:
	return status;
}

static int ath10k_init_configure_target(struct ath10k *ar)
{
	u32 param_host;
@@ -805,10 +775,28 @@ int ath10k_core_start(struct ath10k *ar)
		goto err;
	}

	status = ath10k_htt_init(ar);
	if (status) {
		ath10k_err("failed to init htt: %d\n", status);
		goto err_wmi_detach;
	}

	status = ath10k_htt_tx_alloc(&ar->htt);
	if (status) {
		ath10k_err("failed to alloc htt tx: %d\n", status);
		goto err_wmi_detach;
	}

	status = ath10k_htt_rx_alloc(&ar->htt);
	if (status) {
		ath10k_err("failed to alloc htt rx: %d\n", status);
		goto err_htt_tx_detach;
	}

	status = ath10k_hif_start(ar);
	if (status) {
		ath10k_err("could not start HIF: %d\n", status);
		goto err_wmi_detach;
		goto err_htt_rx_detach;
	}

	status = ath10k_htc_wait_target(&ar->htc);
@@ -817,15 +805,30 @@ int ath10k_core_start(struct ath10k *ar)
		goto err_hif_stop;
	}

	status = ath10k_htt_attach(ar);
	status = ath10k_htt_connect(&ar->htt);
	if (status) {
		ath10k_err("could not attach htt (%d)\n", status);
		ath10k_err("failed to connect htt (%d)\n", status);
		goto err_hif_stop;
	}

	status = ath10k_init_connect_htc(ar);
	if (status)
		goto err_htt_detach;
	status = ath10k_wmi_connect(ar);
	if (status) {
		ath10k_err("could not connect wmi: %d\n", status);
		goto err_hif_stop;
	}

	status = ath10k_htc_start(&ar->htc);
	if (status) {
		ath10k_err("failed to start htc: %d\n", status);
		goto err_hif_stop;
	}

	status = ath10k_wmi_wait_for_service_ready(ar);
	if (status <= 0) {
		ath10k_warn("wmi service ready event not received");
		status = -ETIMEDOUT;
		goto err_htc_stop;
	}

	ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
		   ar->hw->wiphy->fw_version);
@@ -833,23 +836,25 @@ int ath10k_core_start(struct ath10k *ar)
	status = ath10k_wmi_cmd_init(ar);
	if (status) {
		ath10k_err("could not send WMI init command (%d)\n", status);
		goto err_disconnect_htc;
		goto err_htc_stop;
	}

	status = ath10k_wmi_wait_for_unified_ready(ar);
	if (status <= 0) {
		ath10k_err("wmi unified ready event not received\n");
		status = -ETIMEDOUT;
		goto err_disconnect_htc;
		goto err_htc_stop;
	}

	status = ath10k_htt_attach_target(&ar->htt);
	if (status)
		goto err_disconnect_htc;
	status = ath10k_htt_setup(&ar->htt);
	if (status) {
		ath10k_err("failed to setup htt: %d\n", status);
		goto err_htc_stop;
	}

	status = ath10k_debug_start(ar);
	if (status)
		goto err_disconnect_htc;
		goto err_htc_stop;

	ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
	INIT_LIST_HEAD(&ar->arvifs);
@@ -868,12 +873,14 @@ int ath10k_core_start(struct ath10k *ar)

	return 0;

err_disconnect_htc:
err_htc_stop:
	ath10k_htc_stop(&ar->htc);
err_htt_detach:
	ath10k_htt_detach(&ar->htt);
err_hif_stop:
	ath10k_hif_stop(ar);
err_htt_rx_detach:
	ath10k_htt_rx_free(&ar->htt);
err_htt_tx_detach:
	ath10k_htt_tx_free(&ar->htt);
err_wmi_detach:
	ath10k_wmi_detach(ar);
err:
@@ -913,7 +920,9 @@ void ath10k_core_stop(struct ath10k *ar)

	ath10k_debug_stop(ar);
	ath10k_htc_stop(&ar->htc);
	ath10k_htt_detach(&ar->htt);
	ath10k_hif_stop(ar);
	ath10k_htt_tx_free(&ar->htt);
	ath10k_htt_rx_free(&ar->htt);
	ath10k_wmi_detach(ar);
}
EXPORT_SYMBOL(ath10k_core_stop);
+0 −6
Original line number Diff line number Diff line
@@ -830,17 +830,11 @@ int ath10k_htc_start(struct ath10k_htc *htc)
	return 0;
}

/*
 * stop HTC communications, i.e. stop interrupt reception, and flush all
 * queued buffers
 */
void ath10k_htc_stop(struct ath10k_htc *htc)
{
	spin_lock_bh(&htc->tx_lock);
	htc->stopped = true;
	spin_unlock_bh(&htc->tx_lock);

	ath10k_hif_stop(htc->ar);
}

/* registered target arrival callback from the HIF layer */
+3 −39
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@
#include "core.h"
#include "debug.h"

static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
int ath10k_htt_connect(struct ath10k_htt *htt)
{
	struct ath10k_htc_svc_conn_req conn_req;
	struct ath10k_htc_svc_conn_resp conn_resp;
@@ -48,38 +48,13 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
	return 0;
}

int ath10k_htt_attach(struct ath10k *ar)
int ath10k_htt_init(struct ath10k *ar)
{
	struct ath10k_htt *htt = &ar->htt;
	int ret;

	htt->ar = ar;
	htt->max_throughput_mbps = 800;

	/*
	 * Connect to HTC service.
	 * This has to be done before calling ath10k_htt_rx_attach,
	 * since ath10k_htt_rx_attach involves sending a rx ring configure
	 * message to the target.
	 */
	ret = ath10k_htt_htc_attach(htt);
	if (ret) {
		ath10k_err("could not attach htt htc (%d)\n", ret);
		goto err_htc_attach;
	}

	ret = ath10k_htt_tx_attach(htt);
	if (ret) {
		ath10k_err("could not attach htt tx (%d)\n", ret);
		goto err_htc_attach;
	}

	ret = ath10k_htt_rx_attach(htt);
	if (ret) {
		ath10k_err("could not attach htt rx (%d)\n", ret);
		goto err_rx_attach;
	}

	/*
	 * Prefetch enough data to satisfy target
	 * classification engine.
@@ -93,11 +68,6 @@ int ath10k_htt_attach(struct ath10k *ar)
		2; /* ip4 dscp or ip6 priority */

	return 0;

err_rx_attach:
	ath10k_htt_tx_detach(htt);
err_htc_attach:
	return ret;
}

#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
@@ -117,7 +87,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt)
	return 0;
}

int ath10k_htt_attach_target(struct ath10k_htt *htt)
int ath10k_htt_setup(struct ath10k_htt *htt)
{
	int status;

@@ -140,9 +110,3 @@ int ath10k_htt_attach_target(struct ath10k_htt *htt)

	return ath10k_htt_send_rx_ring_cfg_ll(htt);
}

void ath10k_htt_detach(struct ath10k_htt *htt)
{
	ath10k_htt_rx_detach(htt);
	ath10k_htt_tx_detach(htt);
}
+10 −8
Original line number Diff line number Diff line
@@ -1328,14 +1328,16 @@ struct htt_rx_desc {
#define HTT_LOG2_MAX_CACHE_LINE_SIZE 7	/* 2^7 = 128 */
#define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1)

int ath10k_htt_attach(struct ath10k *ar);
int ath10k_htt_attach_target(struct ath10k_htt *htt);
void ath10k_htt_detach(struct ath10k_htt *htt);

int ath10k_htt_tx_attach(struct ath10k_htt *htt);
void ath10k_htt_tx_detach(struct ath10k_htt *htt);
int ath10k_htt_rx_attach(struct ath10k_htt *htt);
void ath10k_htt_rx_detach(struct ath10k_htt *htt);
int ath10k_htt_connect(struct ath10k_htt *htt);
int ath10k_htt_init(struct ath10k *ar);
int ath10k_htt_setup(struct ath10k_htt *htt);

int ath10k_htt_tx_alloc(struct ath10k_htt *htt);
void ath10k_htt_tx_free(struct ath10k_htt *htt);

int ath10k_htt_rx_alloc(struct ath10k_htt *htt);
void ath10k_htt_rx_free(struct ath10k_htt *htt);

void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
+2 −2
Original line number Diff line number Diff line
@@ -243,7 +243,7 @@ static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt)
	}
}

void ath10k_htt_rx_detach(struct ath10k_htt *htt)
void ath10k_htt_rx_free(struct ath10k_htt *htt)
{
	del_timer_sync(&htt->rx_ring.refill_retry_timer);
	tasklet_kill(&htt->rx_replenish_task);
@@ -492,7 +492,7 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr)
	ath10k_htt_rx_msdu_buff_replenish(htt);
}

int ath10k_htt_rx_attach(struct ath10k_htt *htt)
int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
{
	dma_addr_t paddr;
	void *vaddr;
Loading