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: Ben Greear <greearb@candelatech.com> Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
parent
46acf7bb9b
commit
95bf21f97f
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -83,7 +83,7 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
|
||||
__clear_bit(msdu_id, htt->used_msdu_ids);
|
||||
}
|
||||
|
||||
int ath10k_htt_tx_attach(struct ath10k_htt *htt)
|
||||
int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
||||
{
|
||||
spin_lock_init(&htt->tx_lock);
|
||||
init_waitqueue_head(&htt->empty_tx_wq);
|
||||
@ -120,7 +120,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
|
||||
static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
struct htt_tx_done tx_done = {0};
|
||||
int msdu_id;
|
||||
@ -141,9 +141,9 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_detach(struct ath10k_htt *htt)
|
||||
void ath10k_htt_tx_free(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_htt_tx_cleanup_pending(htt);
|
||||
ath10k_htt_tx_free_pending(htt);
|
||||
kfree(htt->pending_tx);
|
||||
kfree(htt->used_msdu_ids);
|
||||
dma_pool_destroy(htt->tx_pool);
|
||||
|
@ -2375,7 +2375,7 @@ void ath10k_wmi_detach(struct ath10k *ar)
|
||||
ar->wmi.num_mem_chunks = 0;
|
||||
}
|
||||
|
||||
int ath10k_wmi_connect_htc_service(struct ath10k *ar)
|
||||
int ath10k_wmi_connect(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
|
@ -4259,7 +4259,7 @@ void ath10k_wmi_detach(struct ath10k *ar);
|
||||
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
|
||||
int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
|
||||
|
||||
int ath10k_wmi_connect_htc_service(struct ath10k *ar);
|
||||
int ath10k_wmi_connect(struct ath10k *ar);
|
||||
int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
|
||||
const struct wmi_channel_arg *);
|
||||
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
|
||||
|
Loading…
Reference in New Issue
Block a user